Agent 评测与持续优化
「你改了 Prompt,怎么知道变好了?」——这是 AI 应用面试最容易被问倒的一句话。 答不上来,说明你只有「感觉」,没有度量。这篇讲怎么把感觉变成数字。
一、为什么必须做评测
| 没有评测 | 有评测 |
|---|---|
| 改 Prompt 靠感觉,A 说好 B 说差 | 有 30 条固定用例,改完跑一遍看通过率 |
| 上线后靠用户投诉发现问题 | 回归集能在发布前拦住退化 |
| 说不清「准确率多少」 | 能给出 82% → 91% 的对比 |
| 优化方向靠猜 | badcase 归类后知道瓶颈在检索还是生成 |
一句话:评测不是为了刷分,是为了在改动前后有可比性。
二、评测的三个层次
L1 单点评测(组件级) 检索质量、生成质量、工具调用正确性
L2 链路评测(端到端) 一条完整任务是否成功
L3 线上评测(真实流量) 灰度、A/B、用户反馈L1 单点评测(组件级) 检索质量、生成质量、工具调用正确性
L2 链路评测(端到端) 一条完整任务是否成功
L3 线上评测(真实流量) 灰度、A/B、用户反馈大多数团队只做 L1 就上线了,结果「组件都变好了,端到端反而差了」—— 因为链路里的取舍是此消彼长的。
三、建评测集(最费工但最值钱)
三条来源
| 来源 | 说明 | 规模建议 |
|---|---|---|
| 真实日志 | 从线上挑高频问题 + 失败案例 | 50~200 条起步 |
| 专家构造 | 覆盖业务边界、长尾、对抗样本 | 50~100 条 |
| 合成数据 | 用强模型按场景生成再人工筛 | 补充长尾 |
关键原则:
- 从真实问题里来,不要自己拍脑袋编;
- 每条用例要有参考答案或判定标准(否则只能人工看);
- 按场景分层(简单/中等/困难),否则一堆简单题会掩盖退化;
- 评测集要冻结版本,改动要记 changelog —— 换了题集,历史分数就不可比。
用例长什么样
json
{
"id": "refund-003",
"scene": "售后退款",
"difficulty": "medium",
"input": "我上周买的耳机坏了,能退吗?",
"context": ["退换货政策:7 天内非人为损坏可退……"],
"expected": {
"must_contain": ["7 天", "非人为损坏"],
"must_not_contain": ["一定能退"],
"tool_calls": [{ "name": "queryOrder", "args": { "orderId": "*" } }],
"max_latency_ms": 5000
}
}{
"id": "refund-003",
"scene": "售后退款",
"difficulty": "medium",
"input": "我上周买的耳机坏了,能退吗?",
"context": ["退换货政策:7 天内非人为损坏可退……"],
"expected": {
"must_contain": ["7 天", "非人为损坏"],
"must_not_contain": ["一定能退"],
"tool_calls": [{ "name": "queryOrder", "args": { "orderId": "*" } }],
"max_latency_ms": 5000
}
}注意 must_not_contain:很多评测只检查「有没有答对」,不检查「有没有瞎承诺」,而后者才是线上事故来源。
四、怎么打分:三种手段
| 手段 | 成本 | 适用 | 局限 |
|---|---|---|---|
| 规则/断言 | 极低 | 格式、关键词、工具调用参数、JSON 合法 | 无法判断语义质量 |
| LLM-as-judge | 低(按次计费) | 开放性回答、忠实度判断 | 有偏好偏差,需校准 |
| 人工标注 | 高 | 建立基准、校准 judge | 慢、贵,只用于抽样 |
LLM-as-judge 的四个坑
- 位置偏差:倾向选第一个答案 → 评测时交换顺序各评一次;
- 长度偏差:倾向更长的回答 → 明确要求「只看正确性,不看长度」;
- 自偏好:用 GPT 评 GPT 会偏高 → 用不同家族的模型做 judge;
- 无标定:先人工标 50 条,算出 judge 与人工的一致率(Kappa 或简单吻合率),一致率 < 80% 就别用。
js
// judge prompt 的核心结构
`你是评审。只依据【参考资料】判断【回答】是否正确。
输出 JSON:{"score": 0-2, "reason": "一句话"}
【问题】${q}
【参考资料】${ctx}
【回答】${answer}
评分标准:
2 = 完全正确且无编造
1 = 部分正确,或有轻微过度承诺
0 = 错误、编造,或答非所问`// judge prompt 的核心结构
`你是评审。只依据【参考资料】判断【回答】是否正确。
输出 JSON:{"score": 0-2, "reason": "一句话"}
【问题】${q}
【参考资料】${ctx}
【回答】${answer}
评分标准:
2 = 完全正确且无编造
1 = 部分正确,或有轻微过度承诺
0 = 错误、编造,或答非所问`五、RAG 的四个核心指标
| 指标 | 衡量 | 怎么算 |
|---|---|---|
| Context Recall(召回率) | 该找到的文档找到了吗 | 标注的「必须命中文档」出现在 topK 里的比例 |
| Context Precision(精确率/信噪比) | 找到的有多少是无关的 | 相关内容在 topK 中的排名加权占比 |
| Faithfulness(忠实度) | 回答是否只依据检索内容 | 回答中的每个断言能否在 context 里找到依据 |
| Answer Relevancy(相关性) | 回答是否切题 | judge 判断「回答是否解答了问题」 |
排查顺序:先看 Recall(找不到就全完),再看 Precision(噪音多会误导模型),最后看 Faithfulness(有依据但瞎写)。
六、Agent 的评测更麻烦
Agent 是多步 + 有副作用的,不能只看最终答案。
| 维度 | 看什么 |
|---|---|
| 任务完成率 | 端到端是否达成目标(最关键) |
| 工具调用正确性 | 选对工具、参数对、没多余调用 |
| 步数 / 轮次 | 是否绕远路(效率) |
| 轨迹合理性 | 中间步骤是否可解释、有没有死循环 |
| 副作用安全 | 有没有越权写操作、重复提交 |
| 兜底能力 | 信息不足时是否主动追问而不是编 |
js
// 端到端评测的骨架
for (const c of testCases) {
const trace = await runAgent(c.input) // 记录全部工具调用
const okTool = matchToolCalls(trace.calls, c.expected.tool_calls)
const okAnswer = await judge(trace.answer, c.expected)
const okSafe = !trace.calls.some(isDangerous)
results.push({ id: c.id, okTool, okAnswer, okSafe })
}// 端到端评测的骨架
for (const c of testCases) {
const trace = await runAgent(c.input) // 记录全部工具调用
const okTool = matchToolCalls(trace.calls, c.expected.tool_calls)
const okAnswer = await judge(trace.answer, c.expected)
const okSafe = !trace.calls.some(isDangerous)
results.push({ id: c.id, okTool, okAnswer, okSafe })
}建议:把每次运行的 trace 存下来(输入、每步工具调用、返回、耗时、token),出问题才能复盘。
七、上线:灰度与 A/B
新版本 → 5% 流量 → 观察 24h(错误率、延迟、成本、用户反馈)
→ 20% → 50% → 100%,每一步都可一键回滚新版本 → 5% 流量 → 观察 24h(错误率、延迟、成本、用户反馈)
→ 20% → 50% → 100%,每一步都可一键回滚| 指标 | 关注点 |
|---|---|
| 业务指标 | 任务完成率、转人工率、差评率 |
| 技术指标 | P99 延迟、超时率、token 成本 |
| 安全指标 | 越权拦截数、内容审核命中率、注入尝试数 |
A/B 的坑:AI 输出差异大,样本量要比传统 A/B 更大;只看「满意度」容易被一次坏体验带偏,要结合任务完成率。
八、badcase 闭环(持续优化的核心)
线上坏案例 → 归类(检索错 / 生成错 / 工具错 / 理解错)
→ 归因(是数据问题、Prompt 问题、还是模型能力问题)
→ 修复(补文档 / 改 Prompt / 加规则 / 换模型)
→ **加入回归集**(防止再犯)
→ 下一轮评测验证线上坏案例 → 归类(检索错 / 生成错 / 工具错 / 理解错)
→ 归因(是数据问题、Prompt 问题、还是模型能力问题)
→ 修复(补文档 / 改 Prompt / 加规则 / 换模型)
→ **加入回归集**(防止再犯)
→ 下一轮评测验证关键动作:每个修好的 badcase 必须进回归集。否则三个月后同一个坑会再踩一次 —— 这是团队级经验沉淀的唯一方式。
九、工具与自建
| 工具 | 定位 |
|---|---|
| LangSmith / Langfuse | trace + 数据集 + 评测编排(最省事) |
| RAGAS | RAG 指标现成实现(faithfulness 等) |
| 自建脚本 | 用例不多、需要接内部系统时更灵活 |
自建最小可用版:一个 JSON 存用例 + 一个跑批脚本 + 一个 HTML 报表(通过/失败/耗时/成本)。不用一上来就上平台。
十、速查
| 问题 | 答案 |
|---|---|
| 怎么证明「改好了」 | 固定评测集 + 改动前后跑分对比 |
| 评测集怎么来 | 真实日志 + 专家构造 + 合成补充,50~200 条起步 |
| 怎么打分 | 规则断言 + LLM-as-judge(需校准)+ 人工抽样 |
| LLM-as-judge 最大坑 | 位置偏差、长度偏差、自偏好、未标定 |
| RAG 看哪四个指标 | Recall、Precision、Faithfulness、Relevancy |
| 排查顺序 | 先 Recall,再 Precision,最后 Faithfulness |
| Agent 评测看什么 | 任务完成率 + 工具调用正确性 + 步数 + 副作用安全 |
| 上线怎么做 | 灰度 5%→20%→50%→100%,每步可回滚 |
| 怎么持续变好 | badcase 归类 → 归因 → 修复 → 进回归集 |
Cao Note