Agent 评测不能只看成功率:从结果到轨迹的五层指标
Agent 报告成功,不等于任务真的完成。把结果、步骤、工具调用、成本和安全约束分开检查,才能看出它哪里稳定,哪里只是碰巧答对。
本篇阅读顺序 · 三遍读法
一篇文章,读出三种能力。
先弄懂它为什么这样工作,再把条件换一换,看方案还能不能站住,最后用代码和证据复盘一遍。顺序固定,读完才知道自己是真的会了,还是只记住了名词。
沿着直觉、公式和边界读正文,看到变量就问输入、状态、复杂度分别是什么。
把面试官的追问当作小型设计评审:更大流量、更少上下文、外部失败或安全约束出现时,局部如何重算。
沿代码、表格和证据卡复盘,最后用文末的 60 秒回答确认自己没有只记住名词。
一个客服 Agent 在测试集上有 92% 的任务成功率。上线第二天,运营却发现它会在退款前重复调用接口,偶尔把“已申请”说成“已到账”,还有一批答案虽然结论正确,却没有留下任何可核查的订单依据。
这不是“成功率还不够高”,而是评测对象定义错了。Agent 不是一次性函数:它会规划、检索、调用工具、修改状态,再生成回复。只看最后一句话,就像只看快递送没送到,却不检查有没有未经授权开箱、重复扣款和超时绕路。
先给一个能复述的答案
Agent 评测至少分五层:任务结果、步骤与轨迹、工具和证据、资源效率、安全与用户体验。先把“成功”定义成可验证的不变量,再用带环境状态的任务集测试正常路径、失败路径和边界路径。每次运行保存 trace、工具输入输出、状态变化、版本和成本。最终分数不做简单平均,而是先卡住硬约束,再比较质量和效率;否则一个危险但偶尔答对的 Agent 可能拿到高分。
图 1:成功率只能回答“最后像不像完成了”,不能回答“它是怎么完成的”。
一、先把“成功”写成验收契约
“帮我查一下订单”不是一个可评测目标。至少要先写清:读取哪位用户的订单、用什么权限、返回哪些字段、能不能改变状态、多久完成、找不到时怎么说。
{
"task_id": "refund_017",
"goal": "核实订单是否满足退款条件并给出下一步",
"preconditions": {"user_id": "u_17", "order_status": "paid"},
"must": ["读取订单详情", "引用订单号和支付状态", "不直接执行退款"],
"must_not": ["访问其他用户订单", "重复提交退款"],
"budget": {"max_steps": 8, "max_tool_calls": 4, "latency_ms": 6000},
"acceptance": ["evidence.order_id == input.order_id", "side_effects == 0"]
}
这里的 must_not 和 acceptance 比“参考答案”更重要。一个 Agent 即使把话说得很像,只要越权读了别人的订单,就应该判为失败。
硬约束和软质量分开
建议先做硬门槛,再计算软分数:
| 类型 | 例子 | 处理方式 |
|---|---|---|
| 硬约束 | 不越权、不重复扣款、JSON 合法 | 任一违反直接失败 |
| 事实正确 | 订单状态、金额、时间准确 | 与环境真值比对 |
| 过程质量 | 调用顺序、证据完整、失败恢复 | 轨迹评分 |
| 体验质量 | 清楚、简洁、符合语气 | 规则 + 盲评 |
| 效率成本 | 延迟、token、工具次数 | 在合格样本中比较 |
不要用一个总分把这些维度揉平。一次越权不能靠“回答很有帮助”抵消。
二、五层指标怎么落到轨迹里
1. 任务结果层
它回答“目标是否完成”,包括最终状态、关键字段和约束满足。除了 exact match,还可以用可执行的断言:金额是否等于数据库值、工单是否进入预期状态、代码测试是否真的通过。
2. 步骤与轨迹层
它回答“是不是走了可接受的路径”。不要求每次都完全一样,但要检查:计划是否覆盖关键步骤、是否在证据不足时补检索、是否在失败后停止或转人工。
任务失败
├─ 目标理解错? → 意图与参数抽取
├─ 计划缺步骤? → 依赖图与停止条件
├─ 工具选错? → tool_choice / 参数合法性
├─ 证据没带上? → retrieval + citation 对齐
└─ 状态写坏? → side-effect / rollback 日志
3. 工具与证据层
工具调用要评估名称、参数、顺序、权限和结果使用。RAG 场景还要验证 claim 是否由检索片段支持,而不是“引用了一个看起来相关的链接”。
4. 资源效率层
至少记录首 token 延迟(TTFT)、总延迟、P95/P99、输入输出 token、工具次数、重试次数和外部成本。平均值很容易藏住长尾:用户不怕偶尔多 200ms,但会被 30 秒卡住的少量请求拖垮。
5. 安全与体验层
看越权拦截率、敏感信息泄漏率、人工接管率、用户纠正次数和投诉率。安全指标不能放在“额外加分项”里;它们是上线门槛。
图 2:统一的评测记录,才能把“答案错了”定位成某一段可修复的链路。
三、评测集不要只放标准答案
一个好评测样本包含四类东西:输入、环境、扰动、验收器。
task_id: booking_042
input: "把明天下午三点的会议改到周五"
environment:
calendar: ["event_18@2026-08-20 15:00"]
timezone: "Asia/Shanghai"
perturbations:
- calendar_write: "timeout_after_commit"
- user_reply: "我说的是周五上午"
acceptance:
- "原事件只有一个"
- "未知提交结果时先对账再重试"
- "澄清上午/下午,不得猜测"
扰动不是为了故意刁难模型,而是模拟真实系统中最容易出问题的地方:工具超时但已经提交、用户修改意图、权限变化、返回结果为空、同一事件重复到达。
按能力切片,而不是随机抽题
我会把样本分成:基础事实、长链路规划、工具参数、检索引用、状态副作用、拒答与转人工六个切片。每一片都单独看通过率,才能知道一次模型升级到底改善了什么。
四、一个可执行的评分函数
先定义硬门槛 (H):只要越权、错误写入或关键字段错误,(H=0)。通过门槛后,再计算质量分:
其中:
- (R):任务结果正确率;
- (E):证据和工具产物完整度;
- (P):步骤与失败恢复质量;
- (U):用户表达和澄清体验;
- (C):成本与延迟效率。
这个公式只是示意,权重应由业务风险决定。金融转账更看安全和状态一致性,内部知识问答更看引用和拒答。关键是把硬失败从平均分里拿出来。
五、离线、回放和线上指标如何分工
| 阶段 | 主要问题 | 典型手段 |
|---|---|---|
| 单元评测 | 一个工具、解析器或路由是否正确 | fixture、schema、mock |
| 离线任务集 | 模型和 Prompt 是否回归 | 黄金集、扰动集 |
| 轨迹回放 | 同一失败能否定位和修复 | trace replay |
| 影子流量 | 线上分布是否超出离线集 | 只读、无副作用 |
| 灰度上线 | 新版本是否安全且值得切换 | canary、自动回滚 |
线上成功率是结果指标,不是唯一的质量真相。它要和失败类型、转人工、成本、P95 和风险告警一起看。
六、指标如何从样本走到发布门槛
评测报告不能停在“这版平均分 0.82”。发布需要把样本、切片和门槛连起来:
| 发布层 | 需要回答的问题 | 示例门槛 |
|---|---|---|
| 硬失败 | 是否出现越权、错误写入或不可恢复状态? | 越权 = 0,重复提交 = 0 |
| 主指标 | 合格样本是否真的变好? | grounded accuracy ≥ 92% |
| 长尾 | 最差切片是否被平均数掩盖? | 任一关键切片不降超过 2pp |
| 资源 | 质量提升是否值得成本? | P95 ≤ 1.5s,单位成本涨幅 ≤ 15% |
| 证据 | 结论能否被复跑和解释? | trace、版本、样本包齐全 |
样本量较小时,不要把一次运行的百分比写成确定事实。至少同时报告 n、分子分母和置信区间;如果线上成本很高,可以先用分层抽样估计,再对风险切片全量回放。最终的发布门槛应是“硬约束全部通过 + 关键切片不退化 + 资源预算可接受”,而不是一个加权平均分。
release = hard_gates_pass
&& min(slice_quality_delta) >= -0.02
&& p95_latency <= budget
&& replay_bundle_complete
七、把指标做成可追问的切片仪表盘
发布会上不要只展示一个总分。每个切片至少要带样本量、硬失败数、结果质量、证据覆盖、P95 和版本元组:
{
"slice": "tool-timeout-after-commit",
"n": 120,
"hard_fail": 0,
"success": 0.91,
"grounded": 0.96,
"p95_ms": 1480,
"versions": {"model": "m-42", "retriever": "r-18", "tools": "t-7"}
}
先按风险切片看“哪里坏了”,再看全局平均“坏了多少”。如果总分上升但 tool-timeout-after-commit 的硬失败从 0 变成 1,发布决策仍应阻断;如果只是低风险闲聊切片下降,则可以收窄路由而不是全量回滚。
成功率必须带分母、未知状态和动作建议
一张 scorecard 不应该只有 success=0.91。至少要保留分母、硬失败、未知结果和下一步动作,否则看板很容易把“没有观测到”误读成“成功”:
slice: tool-timeout-after-commit
n: 120
success: 109
hard_fail: 0
unknown: 4
rework: 7
decision: hold
action: inspect_provider_receipts
baseline: release-41
candidate: release-42
这里 unknown 不计入成功,也不应该直接计入失败后重试。发布系统要根据动作字段决定继续灰度、暂停写入、扩大抽样还是回滚。这样指标才会从描述结果变成真正的操作接口。
L5:为什么未知状态不能直接算失败?
失败通常意味着系统确认没有完成;未知状态可能是回执丢失、异步处理中或外部已提交但尚未可读。两者的补救动作不同,混在一起会触发重复执行或错误回滚。应先对账,再决定重试、暂停还是人工接管。
八、常见的评测陷阱
- 把“最终文本等于参考答案”当正确:换一种说法就被误判,真实的状态却没验证。
- 把工具 mock 得太完美:离线永远成功,线上却遇到超时、空响应和未知提交结果。
- 只保留最终输出:没有中间 trace,出了问题只能重新猜。
- 平均分掩盖硬风险:一次越权被几十个简单问答的高分冲掉。
- 评测集长期不更新:模型学会了题库格式,却没有学会处理新的失败分布。
面试官的三层追问
L1:Agent 评测看哪些指标?
我会分结果、轨迹、工具证据、资源效率、安全体验五层。先检查越权、错误写入和关键字段等硬约束,再在合格样本里比较正确性、引用、延迟、token 和用户满意度。
L2:为什么不能只看成功率?
成功率只看最后一帧,可能掩盖重复副作用、证据丢失、危险重试和长尾延迟。Agent 是一个过程系统,必须保存轨迹并能把结果回溯到每个动作。
L3:如何避免评测被刷分?
把正常任务、扰动任务和拒答任务混合,加入硬门槛和未见过的环境状态;同时做线上抽检和回放,防止模型只记住固定题型。
L4:样本量很小,能不能宣布提升?
只能说“在当前样本和区间内观察到提升”,不能把点估计当成稳定结论。报告样本量、分桶结果和置信区间,并对关键风险切片做定向扩样。
L4:平均分提升,但某个关键切片下降怎么办?
先按硬门槛处理关键切片,不能用其他简单样本的高分抵消。可以缩小路由范围、保留旧策略,或把该切片单独列为未发布状态。
L5:评测门槛应该由算法还是业务制定?
算法团队负责定义可测指标、误差和实验方法,业务与安全 owner 负责确定不可接受的风险和预算。门槛必须能追溯到用户影响,不能由实现方便程度决定。
L5:线上指标波动很大,怎样判断是模型退化还是流量变了?
同时保存流量分布、版本元组和切片占比;先做分布对齐,再比较同一切片的质量。若只是任务构成变化,应调整采样和告警基线,而不是直接回滚模型。
L4:为什么评测报告必须带版本元组?
Agent 结果由模型、Prompt、检索器、工具 schema 和数据版本共同决定。没有版本元组,下一次回放无法判断是哪个组件变化造成退化。
L5:总分提升但硬失败增加,应该怎样发布?
硬失败属于阻断条件,先停止放量并回放受影响切片;可以只保留安全路由、回退某个组件或修复测试集,不能用其他切片的平均分抵消越权和错误副作用。
发布 scorecard 要把分母、未知和动作放在一起
评测会上经常出现一个漂亮的成功率:92%。但如果不知道分母里有多少重试样本、多少未知结果、多少硬失败,这个数字很难指导发布。我会在每次版本评审时发一张 scorecard,让“分数”直接连到动作:
{
"release": "agent-v7.3",
"slice": "refund-and-cancel",
"denominator": {"total": 1200, "eligible": 1130},
"outcomes": {
"success": 1018,
"unknown": 42,
"hard_failure": 70,
"policy_block": 16
},
"metrics": {
"success_rate": 0.901,
"unknown_rate": 0.037,
"p95_latency_ms": 1840
},
"decision": "hold",
"actions": ["reconcile unknown", "inspect hard-failure cluster"],
"owner": "agent-platform",
"next_review": "2026-08-20T09:00:00Z"
}
这里的 eligible 说明哪些样本确实进入了本版本,unknown 不被偷偷算成失败或成功,policy_block 则和模型能力问题分开。decision: hold 比“分数不错”更有用,因为它告诉团队下一步是补对账、查故障簇,还是继续放量。
scorecard 还要按任务风险、租户、工具和失败类型切片。总成功率提升但退款任务的硬失败上升,发布动作应该由硬门槛决定;平均延迟下降但未知状态变多,也不能用一个好看的 p95 把问题盖过去。
L5:样本量只有几十条时,怎样避免把噪声当成提升?
先把结论降级为观察信号,不宣布稳定提升;补充置信区间、历史回放和关键失败样本,必要时延长采样或做分层抽样。若硬失败达到门槛,即使总体区间很宽也应先 hold,因为安全和副作用不能等统计显著才处理。
成功率还要补一张“失败分母对账”
成功率看起来简单,最容易被动手脚的地方却是分母。一次任务可能返回成功、硬失败、未知、超时或人工接管;如果把未知和未完成样本从分母里删掉,数字会自动变好,但线上风险没有消失。
我会在发布回执里固定记录任务状态和分母构成:
denominator_reconciliation: dmr_20260820_21
eval_set: agent-release-2026w34
total_tasks: 1200
status_counts:
success: 924
hard_failure: 86
unknown: 74
timeout: 48
human_takeover: 68
denominator:
declared: 1200
success_rate: 0.77
unknown_included: true
exclusions:
- reason: duplicate_fixture
count: 12
decision: hold
这里要把人工接管单独列出来:它可能避免了用户看到失败,但不代表 Agent 自动完成。未知结果也不能默认算成功或失败,应该留在分母里并触发对账。任何排除样本都要有理由、数量和评测版本,不能在发布时临时改口径。
L5:为什么平均成功率上升,仍可能不是改进?
如果成功率上升来自删除难题、忽略未知结果或把人工接管算成自动成功,它只是统计口径变化。我会先核对完整分母和排除理由,再看风险切片与长尾;口径不稳定时,发布决策应保持暂停。
发布门槛还要做一次“未知状态回放”
unknown 不是一个方便丢数据的垃圾桶。它可能代表工具超时、回执未对账、人工接管或评测器无法判定。发布前要从未知桶抽样回放,尽量把它归为成功、失败、拒答或环境异常;不能归类的样本则保留 owner、复查时间和对放量的影响。
unknown_replay: ur_20260820_09
source: candidate-v5
unknown_n: 37
sampled: 20
classified:
receipt_pending: 6
environment_timeout: 5
evaluator_gap: 4
human_takeover: 3
true_failure: 2
release_effect:
hard_failure: 2
unknown_rate_after_reclassify: 0.019
decision: hold_until_receipt_fix
owner: eval-oncall
如果未知里出现真实副作用或越权,即使总体成功率上涨也要 hold;如果只是评测器缺口,就修验收器并保留旧版本对照。这样做的目的不是强行把所有状态塞进二元准确率,而是让每个状态都能触发对应动作,避免未知桶在发布会后悄悄消失。
L5:为什么未知率下降也不一定代表系统变好了?
未知率下降可能只是评测器把未对账样本粗暴归为失败,或线上流量暂时变简单。要同时看归类规则、原始 trace、硬失败数和切片分布;只有未知被可解释地收敛,才算评测质量变好。
分层成功率要和最小样本门槛绑定
总成功率和单个切片成功率之间,常常隔着一层分布变化。今天流量里简单的问答任务占八成,明天退款、权限和多步工具任务占一半,即使模型没有变化,总分也会明显波动。因此 scorecard 不只要写每个切片的分子分母,还要写最小样本门槛、置信区间和是否允许参与放量决策。
我会把“切片太小”和“切片真的变差”分开记录:小于门槛的切片只作为观察信号,不能被合并进一个漂亮的平均数;高风险切片即使样本少,也保留硬失败零容忍。这样既避免几十条样本左右摇摆,也不会让低频但高代价的动作被总体流量淹没。
slice_floor: sf_20260820_60
eval_set: agent-release-2026w34
slices:
- name: refund_write
n: 42
success: 39
hard_failure: 0
ci95: [0.83, 1.00]
min_n: 30
eligible_for_release: true
- name: long_tail_permission
n: 11
success: 9
hard_failure: 1
min_n: 30
eligible_for_release: false
action: collect_more_and_hold_risky_path
aggregation:
weighted_success: 0.771
slice_mix_changed: true
decision: hold_permission_slice
L5:为什么不能把低频切片直接并入总体成功率?
因为低频切片既可能被总体流量稀释,也可能因样本太少产生很宽的区间。正确做法是保留它的原始分母,把统计不确定性和业务风险同时标出来;能决定发布的,必须是达到样本门槛且没有硬失败的切片。
成功率发布要带置信下界和最小样本门槛
当一组切片只有几十条样本时,点估计很容易被偶然波动骗过。二项成功率可以用 Wilson 下界做保守放行:
只有 n 达到门槛、下界高于发布线、硬失败没有恶化,切片才参与放量。否则应该标记为 insufficient_evidence,而不是把一个 9/10 说成“90% 稳定”。
slice_release_gate:
contract: srg_20260820_122
slice: refusal_with_citation
successes: 46
total: 60
z: 1.96
min_samples: 50
lower_bound: 0.653
release_floor: 0.70
decision: hold_for_more_samples
L5:为什么成功率提升仍可能不能发布?
因为点估计没有表达不确定性。样本量小、切片难度高或失败代价大时,必须让置信下界和硬失败门槛共同约束发布,避免把一次幸运抽样当成稳定能力。
60 秒面试回答
Agent 评测不能只看最终成功率,因为它是一个会规划、调用工具并修改状态的过程系统。我会先把目标写成验收契约,区分必须满足的硬约束和可以比较的软质量,再从任务结果、步骤轨迹、工具与证据、资源效率、安全体验五层打分。评测集包含正常样本和工具超时、消息重复、权限变化、证据缺失等扰动,每次运行保存 trace、状态变化、版本、成本和环境指纹。上线前用单元、离线、回放、影子和灰度逐级验证,任何越权或错误副作用都直接失败,不让平均分把风险冲掉。
带走一张检查清单
- 成功是否由环境状态和不变量验证,而不是只比文本?
- 是否把硬约束与软质量分开?
- 是否覆盖工具超时、重复、权限变化和拒答场景?
- 是否记录完整 trace、工具参数、状态和版本?
- 是否单独观察 P95/P99、成本和人工接管?
相关笔记
参考
- AgentAlpha《Agent 岗面试宝典 v3》:评测章节(内部讲义,未公开)
- ARIS-in-AI-Offer