Eval 自动化与回归测试
Eval 是 evaluation 的简称,意思是评估。对提示词工程来说,Eval 不是“让 AI 自己夸自己好不好”,而是把 AI 输出质量变成可重复测试、可比较、可回归检查的工程流程。
没有 Eval,提示词优化很容易变成凭感觉改来改去:这次看起来更好,下一次换一批输入又坏了。Eval 的目标是让你能回答三个问题:
- 这个 prompt、RAG 或 Agent 到底好不好?
- 新版本是否比旧版本更好?
- 哪些失败样例必须进入长期回归测试?
截至 2026-06-14,OpenAI 官方文档提示旧 Evals 平台有退场时间:现有内容会保留过渡期,平台计划在 2026-10-31 对现有用户变为只读,并在 2026-11-30 关闭。因此,本讲重点不绑定某个平台,而是讲稳定的工程方法:评估集、评分器、运行器、报告、阈值、失败样例和持续回归。
本讲常见术语先按下面理解,详细定义和更多例子见 00.5-术语词典与最小用例。
| 术语 | 直觉解释 | 最小例子 |
|---|---|---|
| Eval | 可重复评估 AI 输出质量的流程 | 50 个样例每次改 prompt 后都跑一遍 |
| Evaluation set | 固定测试样例集合 | 普通、长文档、缺失信息、对抗样例 |
| Rubric | 评分标准 | 忠实性 0-5 分,格式 0-2 分 |
| LLM-as-judge | 用另一个模型按标准评分 | 让评分模型判断回答是否引用充分 |
| Gold set | 人工确认过的高质量标准答案集 | 法务确认过的 30 个合格摘要 |
| Regression test | 防止旧错误复发的测试 | 曾经漏掉金额的案例永久加入测试集 |
一、直觉
传统代码测试像这样:
输入 -> 函数 -> 输出 -> 断言是否等于预期
LLM 评估像这样:
输入样例 -> AI 系统 -> AI 输出
-> 评分器检查输出是否满足标准
-> 汇总分数、失败原因、成本、延迟
-> 决定是否接受新版本
区别在于:AI 输出经常不是唯一正确答案。所以 Eval 不总是检查“是否完全相等”,更多时候检查“是否满足任务标准”。
例如总结任务不应该只问:
输出是否等于参考答案?
更应该问:
是否忠实于原文?
是否覆盖关键事实?
是否遗漏重要数字?
是否把不确定信息说成确定?
是否符合输出格式?
Eval 的本质是:把“好不好”拆成可检查的维度。
二、Eval 系统的基本结构
一个成熟 Eval 系统通常包括:
| 组件 | 作用 |
|---|---|
| 评估目标 | 说明要验证什么能力 |
| 评估集 | 一批固定测试样例 |
| 被测系统 | prompt、RAG、Agent、模型版本或完整应用 |
| 运行器 | 批量执行测试样例 |
| 评分器 | 判断输出质量 |
| 指标 | pass rate、平均分、严重错误数、成本、延迟 |
| 报告 | 比较版本、列出失败样例和原因 |
| 阈值 | 决定是否允许上线 |
| 回归集 | 从历史失败中沉淀的长期测试集 |
可以用一条链路表示:
目标 -> 数据集 -> 运行 -> 评分 -> 报告 -> 错误分析 -> 修改 -> 回归
这条链路比某一个工具更重要。工具会变,但链路应该长期保留。
三、评估集怎么建
评估集不是随便找几条样例。它要代表真实任务。
最小结构:
{
"id": "case_001",
"task": "summarize_document",
"input": "...",
"expected": {
"must_include": ["关键事实A", "金额B"],
"must_not_include": ["原文未出现的结论"],
"format": "markdown_sections"
},
"rubric": "按忠实性、完整性、精确性、格式评分",
"tags": ["normal", "long_document"]
}
评估集至少要覆盖:
- 普通样例:最常见输入。
- 长输入样例:测试上下文管理。
- 信息缺失样例:测试拒答和不确定性。
- 边界样例:测试规则边界。
- 格式混乱样例:测试鲁棒性。
- 对抗样例:测试提示注入和越权请求。
- 历史失败样例:防止同样错误再次出现。
评估集不要只包含“模型容易答对”的样例。真正有价值的是能暴露失败的样例。
四、评分器的层级
评分器越简单、越确定,越应该优先使用。
1. 程序评分
最可靠,适合明确格式和确定答案。
例子:
- JSON 是否可解析。
- 必填字段是否存在。
- 分类结果是否等于标准答案。
- 输出是否包含指定引用编号。
- 数字、日期、ID 是否匹配。
- 工具调用参数是否符合 schema。
优点:快、便宜、稳定。
缺点:不擅长判断语义质量。
2. 规则评分
适合半结构化任务。
例子:
- 输出必须少于 300 字。
- 每个结论必须包含来源标注。
- 不允许出现“根据常识可知”。
- 不能包含外部资料中的提示注入指令。
优点:清楚、可解释。
缺点:规则写不全时会漏判。
3. LLM-as-judge
让另一个模型按评分标准评价输出。
适合:
- 总结质量。
- 语气风格。
- 复杂推理是否合理。
- 回答是否真正解决用户问题。
- 多个答案之间哪个更好。
使用 LLM judge 时要注意:
- 给明确 rubrics,不要只说“评估好坏”。
- 让它输出结构化分数和失败原因。
- 尽量使用二分类、三档或 1-5 分,不要只要长篇评论。
- 用人工标注的小样本校准 judge。
- 对重要任务保留人工复核。
- 不要让 judge 看到候选版本名称,避免偏见。
4. 人工评分
最贵、最慢,但在高风险任务里不可替代。
适合:
- 建立第一版 gold set。
- 校准 LLM judge。
- 复核严重失败。
- 判断业务上真正能不能上线。
五、普通 Prompt 的 Eval
普通 prompt 的评估重点是输出质量和稳定性。
常见指标:
- 忠实性:是否只基于输入材料。
- 完整性:是否覆盖关键要求。
- 精确性:数字、日期、名称是否正确。
- 格式:是否符合结构。
- 拒答:信息不足时是否不编造。
- 风格:语气、长度、专业度是否符合要求。
- 稳定性:多次运行是否大体一致。
最小评估表:
| case_id | 输入类型 | 预期 | 实际输出 | 分数 | 严重错误 | 是否通过 |
|---|---|---|---|---|---|---|
| p001 | 普通 | 覆盖 A/B/C | ||||
| p002 | 信息缺失 | 应标注不足 | ||||
| p003 | 对抗输入 | 不执行注入指令 |
Prompt 改版时,不要只看平均分。必须单独看严重错误数。一个版本平均分提高,但新增了高风险幻觉,仍然不能上线。
六、RAG 的 Eval
RAG 评估要分两层:
检索是否找到了正确资料?
生成是否忠实使用了正确资料?
检索层指标:
- context recall:该找出的关键资料是否被找出。
- context precision:检索结果中噪声多不多。
- rank quality:正确资料是否排在前面。
- metadata filtering:权限、日期、版本过滤是否正确。
生成层指标:
- groundedness:回答是否有资料支持。
- citation accuracy:引用是否真的支持结论。
- answer completeness:是否答全。
- abstention:资料不足时是否拒答。
- conflict handling:来源冲突时是否说明冲突。
RAG 失败分析要先问:
- 正确资料有没有进入检索结果?
- 正确资料有没有进入模型上下文?
- 模型有没有使用正确资料?
- 引用是否支持结论?
- 如果资料不足,模型是否承认不足?
不要一看到答案错就立刻改 prompt。RAG 的错误常常出在 chunk、metadata、召回、重排或上下文打包。
七、工具调用和 Agent 的 Eval
Agent 不能只评最终答案,因为它可能中途做错事。
Agent Eval 要看 trace:
用户目标
-> Agent 计划
-> 工具选择
-> 参数
-> 工具结果
-> 下一步决策
-> 停止条件
-> 最终输出
关键指标:
- 工具选择是否正确。
- 参数是否完整、合法、来自可信上下文。
- 是否优先使用只读工具。
- 高风险操作前是否请求确认。
- 工具失败时是否降级或停止。
- 是否把工具结果忠实解释给用户。
- 是否执行了外部内容中的恶意指令。
- 是否在完成后停止。
Agent 评估样例一定要包含:
- 工具返回空结果。
- 工具报错。
- 用户信息不足。
- 用户要求高风险写操作。
- 外部内容包含提示注入。
- 两个工具名称相似,容易误选。
- 已完成任务但模型可能继续调用工具的场景。
八、回归测试
回归测试的意思是:过去出过的错,以后不能再犯。
每次发现失败,都要判断是否加入回归集:
失败样例 -> 归因 -> 修复 -> 加入回归集 -> 后续每次改动都跑
应该加入回归集的样例:
- 严重幻觉。
- 金额、日期、权限、工具参数错误。
- 格式破坏导致程序无法消费。
- 安全边界被绕过。
- RAG 引用错误。
- Agent 未确认就执行高风险操作。
- 用户明确指出的错误。
回归集不是越大越好。它应该代表真实风险,并保持可维护。
九、自动化运行
一个平台无关的 Eval 自动化流程可以这样设计:
eval_cases.jsonl
-> run_candidate.py
-> outputs.jsonl
-> grade_outputs.py
-> report.md
-> fail / pass
触发时机:
- 修改 prompt。
- 更换模型。
- 调整温度、输出长度、reasoning effort 等参数。
- 修改 RAG chunk、embedding、重排或上下文打包。
- 修改工具定义、参数 schema 或权限。
- 修改 Agent 工作流。
- 上线前。
- 定期从生产日志抽样。
报告至少包含:
- 总通过率。
- 各维度平均分。
- 严重失败数。
- 与上一版本相比的提升和下降。
- 新增失败样例。
- 成本和延迟变化。
- 是否达到上线阈值。
十、上线阈值
不要用“总体 80 分”这种模糊标准上线。应该按风险拆分阈值。
示例:
上线要求:
1. 严重安全失败 = 0
2. JSON 格式通过率 >= 99%
3. 忠实性平均分 >= 4.5 / 5
4. 关键字段准确率 >= 98%
5. RAG 引用准确率 >= 95%
6. P95 延迟 <= 3 秒
7. 单次平均成本不超过旧版本 120%
注意:平均分不能掩盖严重错误。高风险任务中,一次严重失败可能比 100 次小瑕疵更重要。
十一、错误分析
Eval 的价值不只是给分,而是帮助你决定下一步该改哪里。
常见归因:
| 失败类型 | 优先改哪里 |
|---|---|
| 输出格式不稳定 | 结构化输出、schema、少量 prompt |
| 原文没依据却编造 | 资料边界、拒答规则、RAG 引用 |
| 检索不到资料 | chunk、embedding、关键词、metadata、重排 |
| 有资料但没用对 | 上下文打包、回答规则、引用规则 |
| 工具选错 | 工具名、描述、schema、工具数量 |
| 参数填错 | 参数 schema、输入校验、澄清问题 |
| 高风险操作失控 | 权限、确认节点、审批、工具分层 |
| 成本延迟过高 | 模型选择、上下文长度、缓存、批处理 |
这就是 Eval 驱动开发:不是“分数低就继续加提示词”,而是根据失败原因选择正确工程手段。
十二、常见误区
误区 1:人工看几个样例就够了
不够。人工检查可以发现问题,但不能保证每次改动后没有回归。
误区 2:平均分高就能上线
不一定。平均分会掩盖严重失败。高风险任务要单独统计严重错误。
误区 3:LLM judge 一定客观
不对。LLM judge 也会偏、会漏、会受提示词影响。必须用人工标注样例校准。
误区 4:Eval 只评最终答案
不对。RAG 要评检索,Agent 要评工具调用轨迹,结构化输出要评 schema。
误区 5:评估集建好后就不用管
不对。生产中的新失败、新输入分布、新模型行为都要不断进入评估集。
十三、理解检查
请你试着回答:
- 为什么 LLM 评估不能只用“输出是否等于参考答案”?
- 程序评分、LLM judge、人工评分分别适合什么场景?
- RAG 评估为什么要分成检索层和生成层?
- Agent Eval 为什么必须看工具调用 trace?
- 一个 prompt 改版上线前,至少应该看哪些指标?
十四、下一步
下一步可以继续补两个方向:
- 多智能体协作:什么时候需要 subagents、handoff、并行评审和任务分派。
- 成本与延迟优化:Prompt caching、上下文裁剪、批处理、模型分层和监控。