name: llm-evaluation description: 使用自动指标、人工反馈和基准测试实施LLM应用的全面评估策略。用于测试LLM性能、测量AI应用质量或建立评估框架。
LLM评估
掌握LLM应用的全面评估策略,从自动指标到人工评估和A/B测试。
何时使用此技能
- 系统测量LLM应用性能
- 比较不同模型或提示
- 部署前检测性能回归
- 验证提示更改的改进
- 建立对生产系统的信心
- 建立基线并随时间跟踪进展
- 调试意外模型行为
核心评估类型
1. 自动指标
快速、可重复、可扩展的评估使用计算分数。
文本生成:
- BLEU: N-gram重叠(翻译)
- ROUGE: 面向召回(摘要)
- METEOR: 语义相似度
- BERTScore: 基于嵌入的相似度
- Perplexity: 语言模型置信度
分类:
- Accuracy: 正确百分比
- Precision/Recall/F1: 类特定性能
- Confusion Matrix: 错误模式
- AUC-ROC: 排名质量
检索(RAG):
- MRR: 平均倒数排名
- NDCG: 标准化折扣累积增益
- Precision@K: 前K个相关
- Recall@K: 前K个覆盖率
2. 人工评估
手动评估难以自动化的质量方面。
维度:
- Accuracy: 事实正确性
- Coherence: 逻辑流
- Relevance: 回答问题
- Fluency: 自然语言质量
- Safety: 无有害内容
- Helpfulness: 对用户有用
3. LLM-as-Judge
使用更强的LLM评估较弱模型的输出。
方法:
- Pointwise: 评分单个响应
- Pairwise: 比较两个响应
- Reference-based: 与黄金标准比较
- Reference-free: 无地面实况判断
快速开始
from llm_eval import EvaluationSuite, Metric
# 定义评估套件
suite = EvaluationSuite([
Metric.accuracy(),
Metric.bleu(),
Metric.bertscore(),
Metric.custom(name="groundedness", fn=check_groundedness)
])
# 准备测试用例
test_cases = [
{
"input": "法国的首都是什么?",
"expected": "巴黎",
"context": "法国是欧洲的一个国家。巴黎是其首都。"
},
# ... 更多测试用例
]
# 运行评估
results = suite.evaluate(
model=your_model,
test_cases=test_cases
)
print(f"总体准确率: {results.metrics['accuracy']}")
print(f"BLEU分数: {results.metrics['bleu']}")
自动指标实现
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="猫坐在垫子上",
hypothesis="一只猫正坐在垫子上"
)
ROUGE分数
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
}
BERTScore
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
LLM-as-Judge模式
单输出评估
def llm_judge_quality(response, question):
"""使用GPT-4判断响应质量。"""
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-4",
messages=[{"role": "user", "content": prompt}],
temperature=0
)
return json.loads(result.choices[0].message.content)
成对比较
def compare_responses(question, response_a, response_b):
"""使用LLM法官比较两个响应。"""
prompt = f"""比较这两个对问题的响应,并确定哪个更好。
问题: {question}
响应 A: {response_a}
响应 B: {response_b}
哪个响应更好,为什么?考虑准确性、有帮助性和清晰度。
以JSON回答:
{{
"winner": "A" 或 "B" 或 "tie",
"reasoning": "<解释>",
"confidence": <1-10>
}}
"""
result = openai.ChatCompletion.create(
model="gpt-4",
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: "差",
kappa < 0.2: "轻微",
kappa < 0.4: "公平",
kappa < 0.6: "中等",
kappa < 0.8: "实质性",
kappa <= 1.0: "几乎完美"
}
return {
"kappa": kappa,
"interpretation": interpretation[True]
}
A/B测试
统计测试框架
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 "可忽略"
elif abs_d < 0.5:
return "小"
elif abs_d < 0.8:
return "中"
else:
return "大"
回归测试
回归检测
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()
}
资源
- references/metrics.md: 全面指标指南
- references/human-evaluation.md: 注释最佳实践
- references/benchmarking.md: 标准基准
- references/a-b-testing.md: 统计测试指南
- references/regression-testing.md: CI/CD集成
- assets/evaluation-framework.py: 完整评估框架
- assets/benchmark-dataset.jsonl: 示例数据集
- scripts/evaluate-model.py: 自动评估运行器
最佳实践
- 多个指标: 使用多样化指标进行全面视图
- 代表性数据: 在真实世界、多样化例子上测试
- 基线: 总是比较基线性能
- 统计严谨性: 使用适当的统计测试进行比较
- 持续评估: 集成到CI/CD管道中
- 人工验证: 结合自动指标与人工判断
- 错误分析: 调查失败以理解弱点
- 版本控制: 随时间跟踪评估结果
常见陷阱
- 单一指标痴迷: 优化一个指标而以其他指标为代价
- 小样本大小: 从太少例子中得出结论
- 数据污染: 在训练数据上测试
- 忽略方差: 不考虑统计不确定性
- 指标不匹配: 使用与业务目标不一致的指标