Skip to content

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 条
合成数据用强模型按场景生成再人工筛补充长尾

关键原则:

  1. 从真实问题里来,不要自己拍脑袋编;
  2. 每条用例要有参考答案或判定标准(否则只能人工看);
  3. 按场景分层(简单/中等/困难),否则一堆简单题会掩盖退化;
  4. 评测集要冻结版本,改动要记 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 的四个坑 ​

  1. 位置偏差:倾向选第一个答案 → 评测时交换顺序各评一次;
  2. 长度偏差:倾向更长的回答 → 明确要求「只看正确性,不看长度」;
  3. 自偏好:用 GPT 评 GPT 会偏高 → 用不同家族的模型做 judge;
  4. 无标定:先人工标 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 / Langfusetrace + 数据集 + 评测编排(最省事)
RAGASRAG 指标现成实现(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 归类 → 归因 → 修复 → 进回归集