本文内容来自《AI Engineering Building Applications with Foundation Models》这本书里面的总结。
什么是评估?
对于评估不是简单的让地让 AI Judge 打个 1-5 分,这样做显然效果会很差,评估体系,评估方法,甚至评估标准都没明确说明, 即使是再牛逼的AI Judge也无法做好整个评估体系。
用一个例子说明。
假设你做一个 RAG 客服机器人,用户问:
我买的耳机用了 20 天,左耳没声音了,可以退货还是只能维修?
知识库里有两条规则:
1. 商品签收后 7 天内可无理由退货。
2. 7 天后、保修期内出现质量问题,可申请维修或换货。
模型回答 A:
你已经使用了 20 天,超过 7 天无理由退货期限。
如果左耳没声音属于质量问题,可以申请维修或换货。
建议你提交售后申请,并提供订单号和故障说明。
模型回答 B:
可以退货。耳机质量有问题的话,一般都可以直接退款。
模型回答 C:
根据政策,你的耳机已经超过 7 天无理由退货期限。
如果左耳没声音属于质量问题,可以申请维修或换货。
另外,我们会补偿你一张 50 元优惠券。
如果只用一个 AI Judge 打分问:
这个回答好不好?
可能会出现主观上觉得 C 不错,安抚了用户,并且有理有据,但是事实上编造了“50 元优惠券”。所以我们应该把这个问题拆细了看。
比如我们可以拆成这几类问题:
这个回答有没有违反硬性规则? → deterministic check
它有没有覆盖标准答案里的关键点? → reference-based evaluation
它有没有编造上下文没有的内容? → faithfulness / groundedness
它整体是否有帮助、清晰、符合语气? → AI judge
它比另一个版本更好吗? → pairwise comparison
它有没有线上真实用户认可? → user feedback / human audit
也就是说:
开放式任务评估 = 硬规则检查 + 事实检查 + 语义覆盖 + 主观质量评分 + 版本对比 + 人工抽检
那么我们再来给上面的回答评价,结果可信度就会高很多:
| 评估维度 | A | B | C |
|---|---|---|---|
| 是否符合政策 | ✅ | ❌ | ✅ |
| 是否覆盖关键事实 | ✅ | ❌ | ✅ |
| 是否有 hallucination | ✅ 无 | ✅ 无 | ❌ 有 |
| 是否回答用户问题 | ✅ | 部分 | ✅ |
| 是否清晰易懂 | ✅ | ✅ | ✅ |
| 是否安全可上线 | ✅ | ❌ | ❌ |
这组体系,主要是回答了什么是好,以及好在哪里。
应该怎么拆指标?
上面也说明了,评估在与怎么定义好与坏,好与坏又是由一系列的指标定义的,所以这一节来讲讲怎么拆指标。
硬性规则评估 deterministic check
先评估能客观验证的部分,这部分可以用代码进行校验。
输出是否是合法 JSON?
是否包含必须字段?
是否调用了正确 tool?
是否调用了禁止 tool?
是否超过 token 限制?
是否包含敏感词?
是否引用了不存在的 source?
是否返回了空答案?
例子:你要求模型输出:
{
"answer": "...",
"citations": ["doc_1", "doc_2"],
"confidence": 0.83
}
那第一步直接校验:
JSON parse 是否成功
answer 是否非空
citations 是否存在
confidence 是否在 0 到 1 之间
citations 是否真的来自检索结果
这个阶段不判断“回答是否优雅”,只判断格式和流程是否合规。
关键点覆盖 Reference-based
这层用于判断模型有没有覆盖标准答案里的关键点。比如可以给每个测试 case 写一个 reference answer,或者更工程化一点,写成 required facts。例如:
{
"query": "用了 20 天耳机坏了可以退吗?",
"required_facts": [
"超过 7 天无理由退货期限",
"质量问题可申请维修或换货",
"需要提交售后申请"
],
"forbidden_claims": [
"可以直接退款",
"一定可以退货",
"补偿优惠券"
]
}
然后评估:
required_facts_coverage = 覆盖了几个必要事实
forbidden_claims_count = 出现了几个禁止说法
比如有这么几个回答:
| 回答 | required facts coverage | forbidden claims |
|---|---|---|
| A | 3/3 | 0 |
| B | 0/3 | 1 |
| C | 3/3 | 1 |
这样你就能区分:
- B 是核心事实错误;
- C 是关键事实正确,但有额外编造。
事实评估 Groundedness / Faithfulness
模型说的每一句事实,是否都能被 context 支持?
还是刚才的回答 C:
根据政策,你的耳机已经超过 7 天无理由退货期限。
如果左耳没声音属于质量问题,可以申请维修或换货。
另外,我们会补偿你一张 50 元优惠券。
前两句有 context 支持,最后一句没有。
你可以让 AI Judge 做 claim-level 检查:
Context:
1. 商品签收后 7 天内可无理由退货。
2. 7 天后、保修期内出现质量问题,可申请维修或换货。
Answer:
根据政策,你的耳机已经超过 7 天无理由退货期限。
如果左耳没声音属于质量问题,可以申请维修或换货。
另外,我们会补偿你一张 50 元优惠券。
请逐条抽取 Answer 中的事实声明,并判断每条是否被 Context 支持。
输出:
- claim
- supported: true/false
- evidence
可能输出:
[
{
"claim": "超过 7 天无理由退货期限",
"supported": true,
"evidence": "商品签收后 7 天内可无理由退货"
},
{
"claim": "质量问题可申请维修或换货",
"supported": true,
"evidence": "7 天后、保修期内出现质量问题,可申请维修或换货"
},
{
"claim": "会补偿 50 元优惠券",
"supported": false,
"evidence": null
}
]
这个比问“回答是否 grounded,打 1-5 分”更稳,因为它把判断拆到了事实声明级别。
主观质量评估 AI judge
有些维度没法完全用代码判断,比如:
是否有帮助?
是否解释清楚?
是否啰嗦?
是否符合品牌语气?
是否安抚了用户情绪?
是否给了下一步行动?
这时候主要靠 AI Judge ,但 judge prompt 必须明确标准。使用 AI judge 时要说明任务、评价标准、评分系统;而且分类式评分通常比连续数值评分更可靠。
例如你可以不要让它打 0.73 分,而是让它分类:
请评估回答是否满足“客服可上线标准”。
评价维度:
1. 是否直接回答用户问题
2. 是否给出明确下一步
3. 是否语气专业、不过度承诺
4. 是否没有多余营销话术
输出:
- pass / fail
- failed_dimensions
- reason
比如回答 A:
{
"pass": true,
"failed_dimensions": [],
"reason": "回答直接说明不能无理由退货,但可申请维修或换货,并给出提交售后申请的下一步。"
}
回答 B:
{
"pass": false,
"failed_dimensions": ["不过度承诺", "政策准确性"],
"reason": "回答承诺可以退货/退款,但知识库只支持维修或换货。"
}
注意:AI Judge 适合判断“软质量”,但不应该替代前面的硬规则和事实检查。
版本对比评估 pairwise comparison
这层不是判断一个回答绝对好不好,而是判断:
Prompt v2 是否比 Prompt v1 更好?
RAG 策略 B 是否比 RAG 策略 A 更好?
模型 B 是否比模型 A 更适合这个场景?
例如你在优化 prompt。
用户问题:
我买的耳机用了 20 天,左耳没声音了,可以退货还是只能维修?
Prompt v1 输出:
超过 7 天一般不能退货,可以联系售后。
Prompt v2 输出:
你已经超过 7 天无理由退货期限,因此通常不能直接退货。
如果左耳没声音属于质量问题,可以申请维修或换货。
建议你提交售后申请,并附上订单号和故障说明。
Pairwise judge:
在不编造政策的前提下,哪个回答更适合作为客服回复?
A: ...
B: ...
输出 winner: A/B/tie,并说明原因。
结果:
{
"winner": "B",
"reason": "B 同时说明了退货限制、质量问题处理方式和下一步操作,比 A 更完整。"
}
但是它有一个限制:
B 比 A 好,不代表 B 一定可以上线。
所以你还需要绝对指标,除了上面所说的指标以外还可以结合 ai agent工程化用到的指标:tool call 成功/准确率、延迟情况、用户差评率等。
设计评估 AI Agent Pipeline
AI 系统评估不能只看最终答案,也不能只靠一个总分。你要把系统拆成组件,把“好回答”拆成明确评价标准和评分标准,再用多套评价数据覆盖真实分布、高风险场景、历史 bad case 和越界输入。
所以评估 AI Agent Pipeline 不是一个“打分脚本”,而是 AI 应用的质量控制系统。可以理解为:
Evaluation Pipeline = AI Agent 的 CI/CD 质量门禁 + 回归测试 + 线上质量监控 + bad case 归因系统
评估所有组件 Evaluate All Components in a System
真实 AI 应用不是一个单模型调用,而是一条链路。比如要做一个简历 PDF 提取当前雇主:
Step 1: 从 PDF 提取文本
Step 2: 从文本中提取当前雇主
如果最终雇主提取错了,原因可能是:
PDF → Text 解析错了
Text → Employer 抽取错了
如果只看最终结果,你不知道系统失败在哪一步。
假设我们 AI Agent 整个流程是这样:
User Query
↓
Intent Detection
↓
Query Rewrite
↓
Retrieval / Tool Selection
↓
Tool Call
↓
Context Assembly
↓
Final Answer Generation
↓
Guardrail / Safety Check
↓
Response
那么应该分别评估:
| 组件 | 要评估什么 |
|---|---|
| Intent Detection | 是否识别对用户意图 |
| Query Rewrite | 改写后是否保留原意,是否更利于检索 |
| Retrieval | 是否召回正确文档,context 是否相关 |
| Rerank | 正确文档是否排在前面 |
| Tool Selection | 是否选择正确工具 |
| Tool Arguments | 参数是否正确、完整、合法 |
| Context Assembly | 是否拼接了必要上下文,是否塞入无关信息 |
| Final Answer | 是否事实正确、完整、有帮助 |
| Guardrail | 是否拦截危险请求或违规输出 |
| End-to-End | 用户任务是否最终完成 |
这样你才能做故障归因。例如用户问:
我的订单 12345 为什么退款失败?
Agent 最终回答错了,你要知道到底是:
没有识别成 refund_failure_query
没有调用 order_refund_status 工具
调用工具时 order_id 参数错了
工具返回了正确结果,但模型解释错了
模型回答正确,但安全策略误拦截了
如果没有组件级评估,你只能看到“最后错了”,无法知道该改 Prompt、改 Retriever、改 Tool Schema,还是改业务逻辑。
评估指南 Create an Evaluation Guideline
创建 guideline ,不仅要定义应用应该做什么,也要定义它不应该做什么。比如客服机器人是否应该回答和产品无关的选举问题?如果不应该,就要定义什么是 out-of-scope,怎么检测,以及应该如何回复。
正确答案不等于好答案
首先我们要明确一点:正确答案不等于好答案。模型回答“你非常不适合这份工作”可能事实上是正确的,但它不是一个好回答,因为它没有帮助用户理解差距,也没有告诉用户如何改进。一个好回答应该解释职位要求和候选人背景之间的差距,并说明候选人可以怎么弥补这些差距。
这句话对 AI 应用评估很关键:
Correct ≠ Good
再来一些例子比如:
事实正确,但语气伤人
事实正确,但没有下一步建议
事实正确,但没有引用依据
事实正确,但太长,用户看不懂
事实正确,但违反业务策略
事实正确,但暴露内部信息
should do 和 shouldn’t do
除此之外还要让模型明白 should do 和 shouldn’t do,guideline 不仅要定义应用应该做什么,也要定义它不应该做什么。比如客服机器人是否应该回答和产品无关的问题;如果不应该,就要定义哪些输入是 out-of-scope、怎么检测、怎么响应。
很多团队只写正向要求:
回答要准确
回答要有帮助
回答要简洁
但没有写负向边界:
不能编造政策
不能承诺退款
不能提供法律建议
不能回答产品无关问题
不能暴露内部 SOP
不能执行高风险写操作
不能在缺少订单号时查询订单
不能把用户引导到不存在的流程
结果模型出了问题之后,团队才补规则。
一个好的 guideline 应该先把边界写清楚:
| 类型 | 应该定义的问题 |
|---|---|
| In-scope | 哪些问题属于应用职责范围 |
| Out-of-scope | 哪些问题不应该回答 |
| Refusal | 不回答时应该怎么说 |
| Escalation | 什么时候转人工 |
| Safety | 哪些内容必须拦截 |
| Business policy | 哪些承诺不能做 |
| Tool boundary | 哪些工具可读,哪些工具可写,什么时候能调用 |
| Privacy | 哪些用户信息不能输出 |
| Source boundary | 回答必须基于哪些上下文,不允许用哪些来源 |
定义评价标准 criteria
比如客服应用的三个常见 criteria:
1. Relevance:回答是否和用户问题相关
2. Factual consistency:回答是否和上下文事实一致
3. Safety:回答是否安全、无毒、有边界
也就是说,一个好回答至少要相关、和上下文事实一致,并且不含有害内容。那么这些标准其实和业务本身有关的。一个比较完整的 Agent evaluation criteria 可以是:
| Criterion | 评价问题 |
|---|---|
| Relevance | 是否回答了用户真正的问题 |
| Faithfulness | 是否严格基于 context / tool result |
| Completeness | 是否覆盖必要信息 |
| Instruction Following | 是否遵守格式、角色、输出约束 |
| Tool Correctness | 是否选择了正确工具 |
| Tool Argument Correctness | 工具参数是否正确、完整、合法 |
| Task Success | 最终是否完成用户任务 |
| Safety / Policy | 是否违反安全或业务规则 |
| Helpfulness | 是否给出有用下一步 |
| Efficiency | 是否用尽量少的轮次、工具和 token 完成任务 |
| User Experience | 语气是否合适,是否减少用户负担 |
为了形成 criteria,可以先拿一些测试 query,最好是真实用户 query;对每个 query 生成多个 response,可以人工写,也可以用 AI 生成,然后判断哪些好、哪些坏。一般可以这么做:
收集真实 query
↓
生成多个候选回答
↓
人工判断好坏
↓
归纳坏回答类型
↓
把坏回答类型变成 criteria
↓
把 criteria 写成 rubric
把评价标准量化成评分 rubric
定义 criteria 还不够,还要定义评分标准,也就是 rubric。每个 criterion 都要选择评分系统,可以是二分类 0/1、1 到 5、0 到 1,或者其他形式。比如评估回答是否和上下文一致,有的团队用 0/1,有的团队用三值:contradiction、entailment、neutral。选择哪种评分方式取决于你的数据和需求。
选择哪种评分体系取决于数据和需求。然后要为每个分数写清楚样例,并让人类验证 rubric 是否容易理解。
例如你要评估客服 Agent 的回答是否忠实于知识库,可以这样定义:
| 分数 | 标准 |
|---|---|
| 5 | 所有事实声明都能被 context 支持,没有额外编造 |
| 4 | 基本正确,有轻微泛化,但不影响用户决策 |
| 3 | 主要结论正确,但有部分不被 context 支持的描述 |
| 2 | 存在关键事实错误,可能误导用户 |
| 1 | 编造关键政策、承诺、赔偿或流程 |
对应例子:
Context:
7 天内可无理由退货。
7 天后质量问题可维修或换货。
Answer A:
你已超过 7 天无理由退货期限。如果属于质量问题,可以申请维修或换货。
Score: 5
Answer B:
你已超过 7 天,但可以直接退款。
Score: 2
Answer C:
你可以直接退款,并获得 50 元补偿券。
Score: 1
准备对应评价数据
最后我们这套体系需要标注的评估数据来评估系统的每个组件和每个 criterion。能用真实生产数据最好;如果应用天然有标签,就直接利用;如果没有,可以用人类或 AI 标注。
评估数据怎么做
数据不是只给最终回答用的,很多人构建 eval set 时只写:
{
"query": "...",
"reference_answer": "..."
}
这对简单问答够用,但对 Agent 不够。因为 Agent 有很多中间组件:
intent detection
query rewrite
retrieval
rerank
tool selection
tool args
planning
final answer
safety check
所以 eval data 也应该包含组件级标注。例如:
{
"case_id": "refund_001",
"user_query": "我的耳机用了 20 天坏了,可以退吗?",
"expected_intent": "after_sales_policy",
"gold_documents": ["return_policy_v3", "warranty_policy_v2"],
"expected_tool_calls": [
{
"tool": "get_order_status",
"required": false
}
],
"required_facts": [
"超过 7 天无理由退货期限",
"质量问题可维修或换货"
],
"forbidden_claims": [
"可以直接退款",
"补偿优惠券",
"一定可以退货"
],
"reference_answer": "超过 7 天无理由退货期限,不能直接无理由退货。如果属于质量问题,可以申请维修或换货,并提交售后申请。",
"tags": ["refund", "after_sales", "high_risk"]
}
这样你就可以分别评估:
intent 是否正确
retrieval 是否命中 policy
tool 是否该调用
最终回答是否覆盖 required facts
是否出现 forbidden claims
不要只看总分
把数据拆成多个 subset,然后分别看系统在每个 subset 上的表现。这样可以避免偏差、帮助 debug、发现改进方向。比如对于某个场景如果你只看整体:
overall task_success_rate = 88%
你可能觉得系统不错,但切开之后可能是:
普通 FAQ:95%
退款政策:72%
多轮订单查询:68%
英文输入:91%
中英混合输入:61%
prompt injection:35%
这时候整体 88% 没意义,因为关键风险场景很差。
评估集需要多大?
引用 OpenAI 的粗略估计:如果你想以 95% 置信度判断一个系统比另一个系统好,能检测到的差异越小,需要的样本越多。大致是:
| 想检测的分数差异 | 需要样本量 |
|---|---|
| 30% | 约 10 |
| 10% | 约 100 |
| 3% | 约 1,000 |
| 1% | 约 10,000 |
作为参考,Eleuther 的 lm-evaluation-harness 里 benchmark 的中位样本数约 1,000,平均约 2,159;Inverse Scaling Prize 组织者建议 300 是绝对最低值,更希望至少 1,000,尤其当样本是合成生成的。
不用一开始就追求 10,000 条 eval case。可以分层:
开发调试集:30-50 条
日常回归集:200-500 条
发布前主评估集:1,000+ 条
核心高风险集:100-300 条,但人工精标
线上抽样评估:持续积累
如果你只是想快速判断 prompt_v2 是否明显比 prompt_v1 好,几十到几百条可能够用。
评估体系 workflow
这一部分主要是我想要把整个评价体系设计成一个 闭环 workflow,分成 5 个阶段:
Stage 0:定义评估标准
Stage 1:离线评估
Stage 2:发布前门禁
Stage 3:线上评估 / A/B Test
Stage 4:线上数据回流到离线评估集
由这 5 个阶段构建成一个循环:
离线评估:用可控数据判断“能不能发”
↓
灰度 / A/B:用真实流量判断“上线后是否真的更好”
↓
线上反馈与日志:发现真实 bad case / good case
↓
人工或 AI 标注:沉淀成新的离线评估集
↓
下一轮 prompt / RAG / agent / model 迭代
Stage 0:先统一评估标准
在离线和线上之前,必须先定义同一套 criteria。比如你做的是 AI Agent / RAG 客服系统,criteria 可以是:
| Criterion | 离线怎么评 | 线上怎么观察 |
|---|---|---|
| Relevance | AI judge / semantic similarity | 用户是否继续追问“你没回答我” |
| Faithfulness | claim-level judge / NLI | 点踩、投诉、人工客服纠错 |
| Tool Correctness | expected tool match | tool error rate、人工介入率 |
| Task Success | 标注任务是否完成 | 用户是否完成退款/查询/下单 |
| Safety / Policy | rule + classifier + judge | 违规拦截、投诉、风控命中 |
| Helpfulness | AI judge / 人工打分 | 点赞率、二次追问率、转人工率 |
| Cost / Latency | telemetry | p95 latency、cost per task |
Stage 1:离线评估 workflow
首先就是和上面提到一样,离线评估数据集的构建,要做到离线数据集分层和细化,比如分成几类:
| 数据集 | 用途 |
|---|---|
dev_eval_set |
日常 prompt / RAG / agent 调试 |
golden_eval_set |
高质量人工标注,用于核心回归 |
production_like_set |
模拟真实线上分布 |
high_risk_set |
退款、账单、赔偿、合规等高风险 |
known_bad_cases_set |
历史 bad case,防止回归 |
tool_required_set |
必须调用工具的问题 |
no_tool_set |
不应该调用工具的问题 |
out_of_scope_set |
越界请求,测试拒答 |
prompt_injection_set |
测试攻击鲁棒性 |
multi_turn_set |
多轮任务完成 |
然后就是离线评估打分 / 分类。
第一层:确定性检查,能用代码判断的,不要交给 LLM。比如 JSON schema 是否合法;
第二层:参考答案 / 必要事实评估,用于判断回答是否覆盖关键点;
第三层:AI Judge / 人工评估,用于开放式质量;
最后就是离线评估输出,并且输出详细的subset结果,而不是一个总分。
Stage 2:发布前 gate
离线评估跑完后,不是看“总分高一点就发”,而是设 release gate。
例如:
必须满足:
- overall task_success_rate >= 85%
- high_risk_policy_pass_rate >= 99%
- forbidden_claim_rate <= 0.5%
- tool_call_correct_rate >= 98%
- faithfulness_avg >= 4.5
- known_bad_cases_pass_rate = 100%
- p95 latency <= 5s
- cost_per_task <= $0.01
这里有一个重点:
known_bad_cases_pass_rate 最好要求 100%。
历史上踩过的坑,不能回归。
如果你是做 prompt 迭代,发布前可以这样比较:
| 指标 | baseline | candidate | 是否通过 |
|---|---|---|---|
| task success | 84% | 87% | ✅ |
| high-risk pass | 99.2% | 98.7% | ❌ |
| faithfulness | 4.4 | 4.6 | ✅ |
| latency p95 | 3.8s | 4.9s | ✅ |
| cost/task | $0.004 | $0.007 | ✅ |
虽然 candidate 总体更好,但 high-risk pass 下降了,所以不能直接上线。
Stage 3:线上评估 workflow
用户反馈
这一部分可以包括线上用户打分:点赞 / 点踩。建议点踩时让用户选择原因:
- 没有回答我的问题
- 回答不准确
- 信息过时
- 编造内容
- 太啰嗦
- 没有给下一步
- 工具结果错误
- 其他
点赞也可以收集轻量原因:
- 解决了我的问题
- 解释清楚
- 推荐有用
- 操作步骤明确
还可以做线上隐式反馈 implicit feedback,比如下面信号:
| 信号 | 可能含义 |
|---|---|
| 用户继续问同一个问题 | 上一轮没解决 |
| 用户改写问题重问 | 回答不相关或不清楚 |
| 用户要求转人工 | Agent 没解决或用户不信任 |
| 用户点击推荐项 | 推荐可能有效 |
| 用户完成操作 | task success |
| 用户退出 | 可能解决了,也可能放弃了 |
| 投诉 / 工单升级 | 高风险失败 |
| 人工客服改写答案 | Agent 输出质量不足 |
A/B Test
A/B test 的价值是判断线上真实效果。比如对于 AI Agent,A/B test 应该这样设计:
Control:当前线上版本
Treatment:新 prompt / 新 model / 新 RAG 策略 / 新 agent planner
一次实验尽量只改一个主要变量,否则无法归因。具体设计应该要根据当前的任务和需求而定。
Stage 4:线上数据回流到离线评估集
因为真实的例子更有利于构建我们的评估体系,并且只收集好的例子不够,评价体系最值钱的通常是 bad cases 和 hard cases,所以总体应该包括:
抽样真实好例子 + 真实坏例子 + 边界例子,经过验证后,构建和更新离线评估数据集。
抽取完这些线上的例子之后,就可以构建数据回流流程,可以是这样:
线上日志采集
↓
自动打标签:点赞/点踩、转人工、投诉、tool error、latency、cost
↓
规则过滤:去 PII、去重、去低质量日志
↓
样本分桶:good / bad / hard / high-risk / out-of-scope
↓
AI 预标注:required facts、错误类型、风险类型
↓
人工复核:重点看 high-risk、bad、ambiguous
↓
写入离线评估集
↓
版本化:eval_dataset_vN
Reference
《AI Engineering Building Applications with Foundation Models》