Implement a comprehensive evaluation strategy for LLM applications using automated metrics, human feedback, and benchmarks. Use it to test LLM performance, measure the quality of AI applications, or establish evaluation frameworks.
自動メトリクスから人間による評価、A/Bテストまで、LLMアプリケーションの包括的な評価戦略をマスターします。
計算されたスコアを使用した、高速で再現性があり、スケーラブルな評価。
テキスト生成:
分類:
検索 (RAG):
自動化が難しい品質面の手動評価。
次元:
より強力なLLMを使用して、より弱いモデルの出力を評価します。
アプローチ:
from llm_eval import EvaluationSuite, Metric
# 評価スイートを定義
suite = EvaluationSuite([
Metric.accuracy(),
Metric.bleu(),
Metric.bertscore(),
Metric.custom(name="groundedness", fn=check_groundedness)
])
# テストケースを準備
test_cases = [
{
"input": "What is the capital of France?",
"expected": "Paris",
"context": "France is a country in Europe. Paris is its capital."
},
# ... その他のテストケース
]
# 評価を実行
results = suite.evaluate(
model=your_model,
test_cases=test_cases
)
print(f"Overall Accuracy: {results.metrics['accuracy']}")
print(f"BLEU Score: {results.metrics['bleu']}")
from nltk.translate.bleu_score import sentence_bleu, SmoothingFunction
def calculate_bleu(reference, hypothesis):
"""リファレンスと仮説の間のBLEUスコアを計算します。"""
smoothie = SmoothingFunction().method4
return sentence_bleu(
[reference.split()],
hypothesis.split(),
smoothing_function=smoothie
)
# 使用法
bleu = calculate_bleu(
reference="The cat sat on the mat",
hypothesis="A cat is sitting on the mat"
)
from rouge_score import rouge_scorer
def calculate_rouge(reference, hypothesis):
"""ROUGEスコアを計算します。"""
scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
scores = scorer.score(reference, hypothesis)
return {
'rouge1': scores['rouge1'].fmeasure,
'rouge2': scores['rouge2'].fmeasure,
'rougeL': scores['rougeL'].fmeasure
}
from bert_score import score
def calculate_bertscore(references, hypotheses):
"""事前学習済みBERTを使用してBERTScoreを計算します。"""
P, R, F1 = score(
hypotheses,
references,
lang='en',
model_type='microsoft/deberta-xlarge-mnli'
)
return {
'precision': P.mean().item(),
'recall': R.mean().item(),
'f1': F1.mean().item()
}
def calculate_groundedness(response, context):
"""回答が提供されたコンテキストに基づいているか確認します。"""
# 含意を確認するためにNLIモデルを使用
from transformers import pipeline
nli = pipeline("text-classification", model="microsoft/deberta-large-mnli")
result = nli(f"{context} [SEP] {response}")[0]
# 回答がコンテキストによって含意される確信度を返す
return result['score'] if result['label'] == 'ENTAILMENT' else 0.0
def calculate_toxicity(text):
"""生成されたテキストの毒性を測定します。"""
from detoxify import Detoxify
results = Detoxify('original').predict(text)
return max(results.values()) # 最も高い毒性スコアを返す
def calculate_factuality(claim, knowledge_base):
"""ナレッジベースに対して事実の主張を検証します。"""
# 実装はナレッジベースに依存します
# 検索 + NLI、またはファクトチェックAPIを使用できます
pass
def llm_judge_quality(response, question):
"""GPT-5を使用して回答品質を判断します。"""
prompt = f"""以下の回答を1-10のスケールで評価してください:
1. 正確性(事実として正しい)
2. 有用性(質問に答えている)
3. 明確性(よく書かれていて理解しやすい)
質問: {question}
回答: {response}
JSON形式で評価を提供してください:
{{
"accuracy": <1-10>,
"helpfulness": <1-10>,
"clarity": <1-10>,
"reasoning": "<短い説明>"
}}
"""
result = openai.ChatCompletion.create(
model="gpt-5",
messages=[{"role": "user", "content": prompt}],
temperature=0
)
return json.loads(result.choices[0].message.content)
def compare_responses(question, response_a, response_b):
"""LLMジャッジを使用して2つの回答を比較します。"""
prompt = f"""質問に対するこれら2つの回答を比較し、どちらが優れているか判断してください。
質問: {question}
回答 A: {response_a}
回答 B: {response_b}
どちらの回答が優れていますか?その理由は?正確性、有用性、明確性を考慮してください。
JSONで答えてください:
{{
"winner": "A" または "B" または "tie",
"reasoning": "<説明>",
"confidence": <1-10>
}}
"""
result = openai.ChatCompletion.create(
model="gpt-5",
messages=[{"role": "user", "content": prompt}],
temperature=0
)
return json.loads(result.choices[0].message.content)
class AnnotationTask:
"""人間によるアノテーションタスクの構造。"""
def __init__(self, response, question, context=None):
self.response = response
self.question = question
self.context = context
def get_annotation_form(self):
return {
"question": self.question,
"context": self.context,
"response": self.response,
"ratings": {
"accuracy": {
"scale": "1-5",
"description": "回答は事実として正しいですか?"
},
"relevance": {
"scale": "1-5",
"description": "質問に答えていますか?"
},
"coherence": {
"scale": "1-5",
"description": "論理的に一貫していますか?"
}
},
"issues": {
"factual_error": False,
"hallucination": False,
"off_topic": False,
"unsafe_content": False
},
"feedback": ""
}
from sklearn.metrics import cohen_kappa_score
def calculate_agreement(rater1_scores, rater2_scores):
"""評価者間一致率を計算します。"""
kappa = cohen_kappa_score(rater1_scores, rater2_scores)
interpretation = {
kappa < 0: "Poor",
kappa < 0.2: "Slight",
kappa < 0.4: "Fair",
kappa < 0.6: "Moderate",
kappa < 0.8: "Substantial",
kappa <= 1.0: "Almost Perfect"
}
return {
"kappa": kappa,
"interpretation": interpretation[True]
}
from scipy import stats
import numpy as np
class ABTest:
def __init__(self, variant_a_name="A", variant_b_name="B"):
self.variant_a = {"name": variant_a_name, "scores": []}
self.variant_b = {"name": variant_b_name, "scores": []}
def add_result(self, variant, score):
"""バリアントの評価結果を追加します。"""
if variant == "A":
self.variant_a["scores"].append(score)
else:
self.variant_b["scores"].append(score)
def analyze(self, alpha=0.05):
"""統計分析を実行します。"""
a_scores = self.variant_a["scores"]
b_scores = self.variant_b["scores"]
# T検定
t_stat, p_value = stats.ttest_ind(a_scores, b_scores)
# 効果量 (Cohen's d)
pooled_std = np.sqrt((np.std(a_scores)**2 + np.std(b_scores)**2) / 2)
cohens_d = (np.mean(b_scores) - np.mean(a_scores)) / pooled_std
return {
"variant_a_mean": np.mean(a_scores),
"variant_b_mean": np.mean(b_scores),
"difference": np.mean(b_scores) - np.mean(a_scores),
"relative_improvement": (np.mean(b_scores) - np.mean(a_scores)) / np.mean(a_scores),
"p_value": p_value,
"statistically_significant": p_value < alpha,
"cohens_d": cohens_d,
"effect_size": self.interpret_cohens_d(cohens_d),
"winner": "B" if np.mean(b_scores) > np.mean(a_scores) else "A"
}
@staticmethod
def interpret_cohens_d(d):
"""Cohen's d 効果量を解釈します。"""
abs_d = abs(d)
if abs_d < 0.2:
return "negligible"
elif abs_d < 0.5:
return "small"
elif abs_d < 0.8:
return "medium"
else:
return "large"
class RegressionDetector:
def __init__(self, baseline_results, threshold=0.05):
self.baseline = baseline_results
self.threshold = threshold
def check_for_regression(self, new_results):
"""新しい結果が回帰を示しているか検出します。"""
regressions = []
for metric in self.baseline.keys():
baseline_score = self.baseline[metric]
new_score = new_results.get(metric)
if new_score is None:
continue
# 相対変化を計算
relative_change = (new_score - baseline_score) / baseline_score
# 有意な減少がある場合はフラグを立てる
if relative_change < -self.threshold:
regressions.append({
"metric": metric,
"baseline": baseline_score,
"current": new_score,
"change": relative_change
})
return {
"has_regression": len(regressions) > 0,
"regressions": regressions
}
class BenchmarkRunner:
def __init__(self, benchmark_dataset):
self.dataset = benchmark_dataset
def run_benchmark(self, model, metrics):
"""ベンチマークでモデルを実行し、メトリクスを計算します。"""
results = {metric.name: [] for metric in metrics}
for example in self.dataset:
# 予測を生成
prediction = model.predict(example["input"])
# 各メトリクスを計算
for metric in metrics:
score = metric.calculate(
prediction=prediction,
reference=example["reference"],
context=example.get("context")
)
results[metric.name].append(score)
# 結果を集計
return {
metric: {
"mean": np.mean(scores),
"std": np.std(scores),
"min": min(scores),
"max": max(scores)
}
for metric, scores in results.items()
}
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer