外观
评估实战
评估是 LLM 工程的度量衡:没有评估,提示、微调、RAG 的一切优化都是自我感觉;有了评估,你才拥有"改进可归因、回归可发现、上线有把握"的工程能力。
为什么 LLM 评估难?因为它的输出是开放的文本而非固定标签,且事实性、安全性、风格等维度无法用单一分数概括。本文给出一个分层的落地体系:公开基准回答"模型绝对水平如何",自建集回答"你的业务场景如何",judge 与人工回答"质量与安全如何",回归测试回答"改动是否破坏旧能力"。理论基础见评测与基准。
一、评估的四层架构
| 层 | 回答的问题 | 手段 | 成本 | 频率 |
|---|---|---|---|---|
| ① 内在指标 | 模型"流畅度/确定性"如何 | perplexity、loss | 低 | 训练中实时 |
| ② 任务基准 | 通用能力如何(知识/数学/代码) | MMLU / GSM8K / HumanEval 等 | 中 | 每版模型 |
| ③ 自建集 + judge/人工 | 业务任务表现如何 | golden set + 打分 | 中~高 | 每次改动 |
| ④ 线上评估 | 真实用户感受如何 | A/B、反馈、埋点 | 高 | 持续 |
绝大多数"该上线的评估体系"指 ②③④。本文聚焦后三层。
评估的度量口径:先定"用什么数说话"
在搭评估之前,先把"怎么数数"固定下来——不同口径会得出不同结论:
| 口径 | 定义 | 适合回答的问题 |
|---|---|---|
| 准确率(exact match) | 输出与标准答案逐字一致的比例 | 有标准答案的任务(分类/抽取) |
| 部分匹配 / 包含匹配 | 标准答案的关键词或子串出现在输出中 | 摘要、开放性问答 |
| pass@k | 生成 k 次内至少一次通过测试的比例 | 代码生成 |
| 人工打分(1~5) | 标注员按 rubric 打分 | 质量、风格、安全 |
| judge 打分 | LLM 按 rubric 打分 | 同上但可自动化 |
| 胜率(pairwise win-rate) | 两模型对比中胜出的比例 | 排序、选型 |
固定口径的纪律:一个指标一旦定下来,跨版本比较时必须用同一口径。从准确率换到 judge 打分等于换了尺子,前后的数字没有可比性——这也是回归测试能成立的前提。
二、基准集 + 自建集:两条腿走路
1. 公开基准:选有意义的子集
公开基准(MMLU、GSM8K、HumanEval、BBH、HELM 等,全档案见数据集与基准档案)适合横向对比与回归,但直接用全量集成本高。工程建议:
| 基准 | 测什么 | 常用做法 |
|---|---|---|
| MMLU | 多学科知识 | 按学科抽子集(如 10 个学科各 20 题)做快速回归 |
| GSM8K | 数学推理 | 抽 100~200 题(答案可自动比对,适合 CI) |
| HumanEval | 代码生成 | 全量 164 题即可,pass@1 自动判分 |
| 自建 golden set | 你的业务 | 见下文 |
bash
# 用 lm-evaluation-harness 跑模型(开箱即用,注意网络可访问 HF)
pip install lm_eval
lm_eval --model hf \
--model_args pretrained=Qwen/Qwen2.5-7B-Instruct \
--tasks mmlu,gsm8k \
--batch_size 4 \
--output_path results/ \
--log_samples榜单分数 ≠ 你的分数
基准分数受实现细节影响巨大(few-shot 数量、提示模板、解码参数、分词器版本),同一模型在不同 harness 下的分数可能差好几个点。固定你的评测配置并在记录中写明,否则"我们 0.73,别人 0.75"这种比较毫无意义。榜单迷信的更多坑见常见陷阱与反模式。
2. 自建集:golden set 是评估体系的核心
golden set(金标集)是从真实业务场景采集、带标准答案/评判标准的固定数据集。构建三条纪律:
| 纪律 | 说明 |
|---|---|
| 来源真实 | 从线上日志、客服记录、真实查询中采集,不要自己凭空编 |
| 答案权威 | 由领域专家标注标准答案,或给出"正确/错误"的判定标准 |
| 只增不改 | golden set 追加新用例,不删改旧用例(否则回归测试失真) |
json
// golden set 条目示例(任务:客服意图分类)
[
{
"id": "G-0001",
"input": "你们的 App 又闪退了,气死我了!",
"expected": {"intent": "complaint", "label": "投诉"},
"note": "边界:语气激烈但仍是投诉而非退款咨询"
},
{
"id": "G-0002",
"input": "请问会员卡过期了还能用吗?",
"expected": {"intent": "inquiry", "label": "咨询"}
}
]三、LLM-as-a-judge:实现与偏差
1. 什么时候用 judge,什么时候用人工
| 场景 | 首选 |
|---|---|
| 有标准答案(分类、抽取、代码、数学) | 规则比对/自动判分,不需要 judge |
| 开放式质量(摘要质量、回答相关性、礼貌度) | LLM-as-a-judge |
| 高风险内容(安全性、事实性争议、法律/医疗) | 人工标注(judge 可辅助筛选) |
2. judge 的实现
judge 的三种范式(按可靠性从低到高):直接打分 → 评分标准(rubric)打分 → 双模型对比(pairwise)。pairwise 对比通常最稳定。
python
# judge 打分示例:rubric 模式(比"给 1~10 分"可靠得多)
JUDGE_PROMPT = """你是评测员。根据以下标准给回答打分(1~5):
- 5:完全针对问题,信息准确,条理清晰
- 3:部分相关,有少量冗余或偏差
- 1:答非所问或明显错误
只输出一个数字。
【问题】{question}
【参考回答】{reference}
【待评回答】{candidate}
分数:"""
def judge_score(question, reference, candidate):
prompt = JUDGE_PROMPT.format(question=question, reference=reference, candidate=candidate)
out = call_judge_model(prompt) # judge 建议用更强的模型
return int(out.strip()[:1])python
# pairwise 对比:让 judge 二选一,统计胜率(最稳健的排序信号)
def judge_compare(question, answer_a, answer_b):
prompt = f"""根据有用性、准确性、完整性,比较下面两个回答哪个更好。
【问题】{question}
【回答 A】{answer_a}
【回答 B】{answer_b}
只输出 "A" 或 "B":"""
return call_judge_model(prompt).strip()3. judge 的偏差与缓解
| 偏差 | 现象 | 缓解 |
|---|---|---|
| 位置偏差 | 排在前面的回答总被偏好 | 交换 A/B 顺序各评一次,不一致时标记需人工 |
| 自我偏好 | judge 偏爱"像自己"(同门模型的)回答 | 换不同家族模型当 judge;或对敏感样本人工复核 |
| 长度偏差 | 更长的回答得分更高 | rubric 中加入"冗余扣分";控制对比长度相近 |
| 过度放水 | judge 给分普遍偏高 | 用对比模式 + 定期人工校准抽样 |
judge 不能替代人工的地方
事实性错误是 judge 最容易漏的——它可能和被测模型共享同样的训练数据与幻觉模式。事实类评估要么用带答案的 golden set,要么对 judge 判定"优秀"的样本做人工抽检。幻觉的机制与评测见幻觉:成因与缓解。
四、离线批量评估:一个可复用的流水线
把评估做成脚本化的批处理,而不是"逐条手测":
python
import json, random
from concurrent.futures import ThreadPoolExecutor
def evaluate(model_fn, golden_set, judge_fn=None, n=50):
"""对 golden set 抽样跑模型,支持规则比对或 judge 打分"""
random.seed(42)
sample = random.sample(golden_set, min(n, len(golden_set)))
results = []
for case in sample:
out = model_fn(case["input"])
verdict = rule_check(out, case["expected"]) # 规则比对
# 或 verdict = judge_fn(case["input"], case.get("reference"), out) # judge 打分
results.append({**case, "output": out, "verdict": verdict})
return results
def summarize(results):
"""输出汇总:正确率 + 分错误样本(用于错误分析)"""
ok = [r for r in results if r["verdict"] is True]
errors = [r for r in results if r["verdict"] is not True]
print(f"通过率: {len(ok)/len(results):.1%} ({len(ok)}/{len(results)})")
return errors
# 使用:每次改动跑同一函数,对比两次 summarize 输出
r1 = evaluate(my_model_v1, golden_set)
r2 = evaluate(my_model_v2, golden_set)三条工程纪律:
- 固定随机种子与模型调用配置(温度=0 时结果可复现)。
- 错误样本单独输出:评估的价值一半在"错误分析"——看模型在哪些输入上错、错法是否成模式。
- 结果入库:每次评估的时间、版本、分数记录到表格/数据库,形成趋势曲线。
错误分析:把分数变成行动
评估的价值一半在"错误分析"。拿到失败样本后,按下面的清单系统过一遍,而不是"看一眼就完":
| 观察 | 可能的结论 | 下一步动作 |
|---|---|---|
| 错误集中在某个输入类型 | 该类型的提示/数据有系统性问题 | 针对该类写专门用例与修复 |
| 几乎都是格式错误 | 输出约束不足 | 上 JSON mode / 约束解码 |
| 几乎都是事实错误 | 知识不足或幻觉 | 检索增强(RAG)、加事实校验 |
| 随机分布、无规律 | 概率噪声或样本量太小 | 加大采样次数、增大评测集 |
| 与模型版本强相关 | 某版本模型行为漂移 | 定位改动、回滚或补偿 |
错误分析的产出是一份**"已知问题清单"**(问题类型 → 影响面 → 修复方向),它既是研发排期的输入,也是上线前"已知限制"的披露材料。
五、回归测试与 golden set
回归测试 = 用固定的 golden set + 固定的 judge/规则,每次改动自动重跑,防止"改 A 坏 B"。这是 LLM 应用工程化的关键一环:
yaml
# 伪代码:CI 中的回归门禁
# 1. 代码/提示/模型权重有变更 → 触发回归
# 2. 跑三类测试:
# - 单测:结构化输出合法(JSON schema 校验)
# - golden 回归:业务正确率不低于基线(如 95% 基线)
# - 安全回归:危险/违规输入不通过率达标
# 3. 全部通过 → 允许合并/上线回归测试的三个层次
单测(格式/字段合法性,成本最低)→ golden 回归(业务正确率,成本中)→ 安全/事实抽检(高风险,成本高)。先保证第一层全绿,再逐步加第二、三层。回归门禁一旦建立,你就能放心地"不断改提示",而不是战战兢兢怕改坏。
多模型横向对比:选型评估的标准动作
"该选哪个模型"是评估最常被问到的问题。标准做法是把选型变成一次评估实验:
候选模型清单(含基座、量化版本、蒸馏版本)
│
▼
同一份 golden set + 同一套 prompt + 同一解码参数
│
▼
跑出各模型指标 + 成本(token 价格 × 平均输出长度)
│
▼
综合"质量 / 延迟 / 成本"三维度决策关键纪律:对比时 prompt 和解码参数必须一致,否则测的是提示而不是模型。成本与延迟维度的加入见部署与服务化的算账方法。
选型评估要测"量化版本"而不是只看全精度
生产往往用 INT4 量化模型。如果选型只测 fp16、上线用 AWQ,你的评估结果与线上行为就对不上。选型评估直接测你打算上线的那一档(量化、上下文长度、批处理参数都对齐)。
评估报告:数字要能被复述
一次评估的产出应当是一份可复述的报告,而不是一屏 log:
| 字段 | 内容 |
|---|---|
| 版本 | 模型/提示/数据版本号(git commit 级) |
| 配置 | 评测集、judge 模型、解码参数 |
| 结果 | 各指标分数 + 样本量 |
| 趋势 | 与上次运行/基线的对比 |
| 错误分析 | 失败类型分布与典型案例 |
| 结论 | 是否切换、下一步动作 |
报告落成 markdown 或表格入库,让团队任何人都能复述"为什么是现在这个版本"——这是评估体系能被信任的最终检验。
六、线上评估:最后的裁判是用户
离线评估无法覆盖真实输入的多样性。线上评估四件套:
| 手段 | 做法 | 指标 |
|---|---|---|
| A/B 测试 | 新版本只对 5~10% 流量开放,与旧版对比 | 任务完成率、点击、转化 |
| 人工抽检 | 抽 1%~5% 会话由标注员打分 | 满意度、错误率 |
| 用户反馈 | 点赞/点踩按钮、"报告问题"入口 | 负面反馈率 |
| 指标埋点 | 响应延迟、失败率、重试率 | 稳定性 |
线上评估的伦理与合规
涉及真实用户数据的线上评估(尤其生成内容被展示给用户)需要遵守数据合规与产品伦理;高风险输出场景(法律、医疗、金融)必须有人工审核兜底,相关讨论见安全与风险。
七、评估成本控制
评估也是"算力开销",需要预算管理:
| 手段 | 说明 |
|---|---|
| 分层抽样 | golden 集大时每次只跑随机 30~50 条;全量留给发布前 |
| 级联策略 | 先规则比对(免费),不过关的才上 judge(花钱),再不过关的才人工 |
| 复用结果 | 输入-输出-评分缓存;同输入不重复调用 |
| 选便宜 judge | 常规任务用 mini 级模型当 judge,高危样本用强模型复核 |
| 评估频率分级 | 单测每次跑、golden 每天跑、全量基准每周跑 |
评估与成本的正循环
评估看似"额外开销",实际上防止的是更贵的错误:一次没被发现的回归事故导致的客服/舆情成本,远高于跑几千条评测的算力成本。把评估预算当作保险,而不是成本中心。
延伸阅读
- 评测与基准 —— 三类评测、基准污染、榜单读法的理论版
- 幻觉:成因与缓解 —— judge 评测中最容易漏掉的事实性维度
- 微调实战:LoRA 全流程 —— 微调前后对比评估的具体案例
- 提示工程实践 —— 提示优化的基线→假设→回归方法论
- 数据集与基准档案 —— MMLU/GSM8K/HumanEval 等基准的完整档案
- 常见陷阱与反模式 —— 榜单迷信、评估过拟合、数据污染等评估陷阱
- 术语表 —— golden set、judge、pass@k 等术语速查
参考资料
- Measuring Massive Multitask Language Understanding(MMLU, arXiv:2009.03300) —— MMLU 原始论文
- Training Verifiers to Solve Math Word Problems(GSM8K, arXiv:2110.14168) —— GSM8K 原始论文
- Evaluating Large Language Models Trained on Code(HumanEval, arXiv:2107.03374) —— HumanEval 原始论文
- Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena(arXiv:2306.05685) —— LLM-as-a-judge 偏差的系统研究
- lm-evaluation-harness(GitHub) —— EleutherAI 开源评测框架
- OpenCompass(GitHub) —— 上海 AI Lab 开源评测平台
- OpenAI Evals(GitHub) —— OpenAI 开源评估框架