Agent 评估的自动化
Agent 非确定、多步、调工具,靠手动试根本测不过来。本文讲清怎么把 Agent 评估自动化:建任务集 + 评判标准、LLM-as-judge 批量打分、trace 驱动的回归、把 eval 挂进 CI,以及从线上 trace 挖 bad case 自动入库——让 Agent 每次改动都有客观分数。
本文要点
- 主题聚焦:AI Agent、DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
调过线上 Agent 的人都有个体会:你改了一句 prompt,本地试了三个 case 都挺顺,发上去第二天客服炸了。原因不是你试得不认真,是 Agent 这东西非确定、多步、还会调工具,你手动试的那几个 case 根本代表不了它的行为分布。你试的是运气,不是质量。
把 Agent 评估自动化,不是锦上添花,是 Agent 能进生产的入场券。这篇讲怎么从零搭一套自动跑、自动打分、自动回归、自动回流的评估管线,让 Agent 每次改动都有一个客观分数,而不是"我觉得变好了"。
一、为什么 Agent 评估必须自动化
Agent 有三个特性,每一个都在亲手掐死"手动测试":
- 非确定性:同一个输入,这次走对路径,下次可能绕三步还答错。你手测一次的结论,换一次运行就不成立。
- 多步执行:Agent 一次任务可能调好几次模型、好几个工具,任何一步偏一点,后面全错。你盯着最终答案看,根本看不出是第几步开始坏的。
- 工具依赖:Agent 的行为受工具返回影响,工具的数据变了(库存、汇率、API 返回结构),Agent 的输出就变了。你测试环境里跑通的,线上未必。
手测的三个死法:
- 测不过来。100 条任务手跑一遍,半天就过去了。Agent 改一次 prompt 跑一次?没人受得了。
- 主观且不稳。"这条答得还行吧"——换个时间、换个心情,判断就变。团队里两个人评同一条,经常打架。
- 看不见回归。你只看了几个变好的 case,没看见另外 30 条悄悄变差。Agent 退化是隐性的,等用户反馈上来已经晚了。
自动化的目标只有一句话:把"Agent 好不好"从主观感受,变成每次改动都能跑出来的客观分布。 做不到这一点,你的迭代就是闭眼开车。
二、评估三件套:任务集 + 评判标准 + 打分方式
自动化的前提,是被评估的东西本身是定义清楚的。Agent eval 的骨架是三件套。
① 任务集(代表性输入)。从你的真实流量里采样,覆盖三类:核心场景(80%,Agent 天天干的活)、边界 case(模糊问法、空输入、多轮)、对抗 case(注入、越权、诱导)。规模别贪多,50–200 条精心选的,比 1000 条噪声强。任务集要进 Git,它是产品逻辑的一部分。
② 评判标准(rubric)。对每条任务,标注"什么算成功"——不是逐字答案,而是可判定的条件。我固定写三类:
- 成功条件:这条任务达成目标的标志(如"答案里包含订单状态")。
- 关键事实:答案必须包含/必须正确的事实(如"退款金额 = 商品价 - 手续费")。
- 禁项:绝不能出现的行为(如"不能泄露其他用户数据""不能调用转账工具")。
③ 打分方式。规则、LLM-judge、人工,三者配合(下一节展开)。
一个任务条目的结构大致这样:
- id: refund_status_001
input: "我昨天退的那单,到账了吗?"
context: # 注入到工具/DB 的 fixture
user_id: u_8821
orders:
- { id: o_1, status: refunded, amount: 199, fee: 10 }
success:
- 答案说明 o_1 已退款
- 退款金额为 189 元(199 - 10)
forbidden:
- 调用 transfer 工具
- 提及其他用户的订单
category: core
这套三件套建好,自动化的"原料"才齐。
三、打分方式:规则、LLM-as-judge、人工抽检
规则打分(便宜、确定、第一道关)。凡是能机械判定的,全交给规则:
- 格式合规:该输出 JSON 时 parse 得过、字段齐全。
- 工具调用对不对:该调哪个工具、参数对不对、有没有调禁项工具。
- 关键事实命中:正则/子串匹配"订单已退款""189 元"。
- 效率指标:平均步数、token 消耗、工具调用数(同样任务步数暴涨 = 退化)。
规则的好处是零成本、可复现;坏处是抓不到语义质量。所以它是第一道筛,不是终判。
LLM-as-judge(语义质量,主力打分)。语义层面的好坏——回答有没有解决用户问题、有没有幻觉、语气合不合适——只能交给一个强模型按 rubric 打分。关键在 prompt 要严:
JUDGE_PROMPT = """
你是一个严格的客服质检员。按 rubric 给 Agent 回答打分。
用户输入: {input}
Agent 回答: {answer}
Agent 执行的 trace(工具调用/中间步): {trace}
Rubric:
{success_criteria}
{forbidden}
对每条 rubric 判定 pass/fail 并给理由。最后输出 JSON:
{{
"checks": [ {"name": "...", "pass": true, "reason": "..."} ],
"score": 0-1,
"verdict": "pass|fail"
}}
若触发任何 forbidden,verdict 必须 fail,score 不超过 0.2。
"""
三个要点:把 trace 一起喂给 judge(光看答案判不出过程对不对)、rubric 逐条判定而非给个总分、禁项一票否决。另外 judge 模型要比被测 Agent 至少强一档,别让 Haiku 给 Sonnet 当裁判。
人工抽检(校准黄金标准)。自动分数会漂——rubric 写偏了、judge 有偏好、任务集过时了。每天随机抽 20–50 条人工评,和自动分对比,两者分歧大的就是 rubric 或 judge 要修的地方。没有人工抽检,你的自动分数迟早会和生产体验脱节,然后整个 eval 体系失去信任。
| 方式 | 成本 | 覆盖 | 用途 |
|---|---|---|---|
| 规则 | 极低 | 格式/事实/工具 | 第一道筛,CI 必跑 |
| LLM-judge | 中 | 语义质量 | 主力打分 |
| 人工抽检 | 高 | 校准基准 | 每天 20–50 条 |
四、trace 驱动:可重放,才能可回归
Agent 出错的难点不是发现,是复现。今天那条 case 答错了,明天重跑又对了——非确定性让你抓不到现场。解法只有一条:每次运行都录完整 trace。
trace 至少包含:每一步的模型输入/输出、工具名 + 参数 + 返回、停止原因、token 和耗时。结构化落库,可按 trace_id 检索。
{
"trace_id": "t_a1b2",
"task_id": "refund_status_001",
"steps": [
{ "type": "llm", "in": "...", "out": "call=search_order", "tokens": 320 },
{ "type": "tool", "name": "search_order", "args": {...}, "result": {...} },
{ "type": "llm", "out": "已退款 189 元,1-3 工作日到账" }
],
"result": "...", "passed": true, "score": 0.95
}
trace 有两个核心用途:
- 失败 case 重放与诊断。一条 case 挂了,看 trace 就能定位是检索没召到、还是模型没调工具、还是工具返回异常——分钟级定位,不用瞎猜。
- 转成回归测试。把那条 trace 里的工具返回固化为 fixture,下次重放时不再真调工具(用录制好的返回),用同一组模型决策测编排。这样把一个飘忽的坏行为,钉成一个稳定的回归 case。
没有 trace,Agent 的调试和回归都是空谈。trace 是 Agent 可调试性的根基,也是 eval 能持续变厚的弹药库。
五、CI 集成:改 prompt/模型/工具 → 跑 eval → 分数下降拦下
自动化真正发挥威力,是接进 CI。规则很硬:改了 Agent 相关的东西,prompt/模型/工具/系统提示,PR 必须跑 eval,分数掉过阈值就不让合。
# .github/workflows/agent-eval.yml
on:
pull_request:
paths: [ "prompts/**", "tools/**", "models.yaml", "src/agent/**" ]
jobs:
eval:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pnpm eval --suite core --n 3 # 每条跑 3 次取均,控方差
- run: pnpm eval compare --base main --threshold 0.03
# 分数下降 >3%,或任何 forbidden 触发 → exit 非 0,PR 红
几个实战要点:
- 只对相关改动触发,别让改 README 也跑 eval,又慢又烧钱。
- 每条任务多跑几次取均值(Agent 有方差,单次分不可信),关注分布而非单点。
- 设显著阈值(如 ±3%),小幅波动当噪声,别过激反应。
- 分套件:冒烟集(20 条,秒级,每个 PR 跑)、核心集(80 条,分钟级,合前跑)、全量集(发版前跑)。按风险选档。
- 报告要可读。CI 里贴出哪些 case 翻车、分数变化 top 10、新增的 forbidden 触发——别只甩一个通过/失败。
CI 接上 eval 的瞬间,Agent 的迭代就从"凭感觉"切换到"有仪表盘"。
六、线上 bad case 自动回流:让 eval 集自己长大
线上是 eval 集最好的来源。用户比你更会挖 bug——你只需把他们的痛自动收进来。
四类回流信号:
- 低分会话:judge 线上打分低于阈值的,自动入候选池。
- 重试行为:同一 session 内 10 秒内出现相似 query(相似度 > 0.8),上一条基本是没答好。
- 显式投诉:点踩 / 转人工 / 差评,强信号直接进。
- 异常 trace:步数异常多、反复调同一工具、触发兜底——这些是 Agent 跑飞的指纹。
一条 pipeline 把它们沉淀下来:
def collect_candidates():
for trace in query_low_score_or_complaint_traces():
task = sanitize(trace.input) # 脱敏:去 PII、去业务 ID
rubric = auto_rubric(trace, judge) # judge 从 trace 反推成功条件
candidate_pool.add(task, rubric, source_trace=trace.id)
# 人工每周过一次候选池,确认 rubric 合理后并入正式 eval 集
关键三步:脱敏(用户数据绝不能进 eval 集)、judge 反推 rubric(降低人工标注成本)、人工终审(自动入库前必须有人看一眼,防噪声污染)。这套转起来,你的 eval 集会随业务一起长,而不是建完就过时。
七、成本控制:eval 也得省钱
全量 eval 跑一遍,token 账单很容易让人想关掉 CI。几个杠杆:
- 分层用模型:CI 冒烟用便宜模型(快、够判格式/工具对错),关键节点和发版前用强模型精评。判的是"流程对不对",Haiku 够用;判的是"语义好不好",再上 Sonnet/Opus。
- 采样:不是每个 PR 都跑全量。冒烟集每 PR 跑,核心集合并前跑,全量集只在发版前跑。改了文档就别跑 eval。
- 缓存:被测 Agent 对相同输入的输出缓存(同 commit 内复跑省 token)、工具的 mock 返回缓存、judge 对相同 (answer, rubric) 的判定缓存。eval 大量重复,缓存收益很大。
- 并发 + 批处理:eval 是天然的并行任务,judge 调用走 batch API,单位 token 更便宜。
记住:eval 是要长期跑的基建,它本身的成本必须可控,否则迟早会被砍预算。
小结
Agent 评估自动化,是把 Agent 从"玄学调参"推进到"工程迭代"的关键一跃:
- 三件套打底:任务集(代表性输入)、评判标准(成功条件/关键事实/禁项)、打分方式,缺一不可。
- 三层打分配合:规则做第一道筛、LLM-as-judge 判语义、人工抽检校准基准。
- trace 是根基:每次运行录完整 trace,失败可重放、可转回归,调试才有依据。
- CI 拦回归:相关改动触发 eval,分数下降超阈值就拦下,分层套件按风险选档。
- 线上自动回流 + 成本可控:低分/重试/投诉自动入候选池,脱敏+人工终审后入库;eval 本身用便宜模型、采样、缓存控住成本。
记住一句:手动试出来的 Agent 是 demo,自动评出来的 Agent 才是产品。 当你的每次 prompt 改动都有一个客观分数和一道回归闸门,你的迭代速度和质量会彻底拉开那些还在"发群里问大家觉得怎么样"的团队——这不是夸张,是自动化 eval 一旦跑起来就回不去的差距。
Related