Agent 评测:怎么知道它真的变好了
这个系列里,评测已经出现过好几次。在 搭建 Agent 的基础知识 里,我列了几条基本做法:尽早建评估集、能用代码判断就用代码、认真读轨迹;工具 那篇讲了怎么从调用记录里看出工具设计的问题;记忆 那篇讲了怎么写跨会话的测试。
但这些都是某个具体问题下的评测。这篇想把评测本身当成主角:一套 Agent 评测到底由什么组成,怎么搭起来,怎么让它的结论可信。
之所以值得单独写一篇,是因为我越来越觉得,评测是 Agent 开发里杠杆最大、也最常被拖延的那部分。没有评测的时候,每次改动都只能靠“我试了几个例子,感觉好一点”来判断,而 Agent 的随机性足够大,让这种感觉经常是错的。更麻烦的是,模型每隔几个月就换一代,没有评测的团队每次都要花几周手动摸索新模型行不行;有评测的团队跑一遍就知道了。
为什么 Agent 评测比模型评测难
传统的模型评测很简单:给一个输入,拿到一个输出,和标准答案比一下。Agent 不一样,至少有四个地方变复杂了:
- 多步。一个任务可能要几十轮调用,中间任何一步走偏,后面都会跟着偏。最终结果错了,你还得知道是哪一步错的;
- 有环境。Agent 会改文件、写数据库、发请求。要判断它做没做对,常常不是看它说了什么,而是看环境最后变成了什么样;
- 路径不唯一。修一个 bug 可以有十种写法,查一个问题可以走五条路。如果评分时死盯着“应该先调 A 再调 B”,就会把很多聪明的解法判成错;
- 非确定性。同一个任务跑两次,可能一次成功一次失败。一次的结果说明不了什么。
这四点决定了 Agent 评测不能只是一个“输入、输出、比对”的表格,而是一套带环境、带多次试验、带多种评分方式的系统。
一次评测由什么组成
先把术语对齐。我习惯这样拆:
- 任务:一条指令加上它的初始状态,比如“修复这个 issue”加上某个提交时的代码仓库;
- 试验(trial):让 Agent 在一个干净的环境里完整地做一遍这个任务。因为有随机性,同一个任务通常要跑多次;
- 轨迹(transcript / trajectory):这次试验里的全部记录,包括模型的输出、每次工具调用和返回;
- 最终状态:试验结束时环境的样子。Agent 说“我已经订好了机票”不算数,数据库里真的有这条订单才算;
- 评分器(grader):看轨迹或最终状态,给出分数的那段逻辑。一个任务可以有多个评分器;
- 评测集(suite):一组为了衡量某种能力而放在一起的任务。
把这些拆清楚的好处是,出问题时你知道该看哪一层:是任务写得有歧义,环境没清干净,评分器判错了,还是 Agent 真的不行。
任务从哪里来
从真实失败开始
最好的任务来源,是已经发生过的失败。用户报过的 bug、你在开发中手动测出来的问题、线上日志里被用户纠正的对话,每一条都可以变成一个任务。它们天然代表了真实分布,而且你已经知道“对”长什么样。
很多团队拖着不做评测,是因为觉得要先攒几百条任务才有意义。其实不用。二三十条从真实失败里来的任务,就足够在早期发现大部分问题。早期每次改动的效果往往很明显,小样本就看得出来;等 Agent 成熟了、改动的效果变小了,再扩充评测集。
还有一个现实的理由:越晚开始,越难开始。一开始,“该做什么”写在产品需求里,可以直接翻译成任务;等产品上线一段时间,“该做什么”就散落在各种线上问题和口头约定里了,要从中反推出评测标准会困难得多。
写一个好任务
一个好任务的标准是:两个懂行的人各自看一遍,会对“做没做对”给出同样的判断。做不到这一点的任务,评分器也判不准,它的失败率里混着大量噪声。
几个具体的检查点:
- 指令里给出了完成任务需要的全部信息。如果评分器检查的是某个文件路径,指令里就要说清楚是哪个路径,否则 Agent 失败只是因为没猜中;
- 评分器检查的就是指令要求的。指令说“修复 bug”,评分器却还检查了代码风格,这是在考一道没出的题;
- 每个任务都有一个参考解。自己或让人实际做一遍,确认这个任务在当前环境里能做出来、能通过所有评分器。如果一个任务在很多次试验里通过率都是 0,先怀疑任务本身,而不是 Agent;
- 正反两面都要有。只测“该做的时候做了”,Agent 就会被优化成什么都做。比如测搜索时,既要有该搜的问题,也要有不该搜、直接回答就好的问题;测权限时,既要有该执行的操作,也要有该拒绝或该先确认的操作。
别忘了“不该做的事”
最后一点值得单独说。Agent 的失败有两种:没做成该做的事,和做了不该做的事。前者容易测,后者容易漏。
后者包括:删了不该删的文件、改了任务范围之外的代码、在没确认的情况下发了消息、为了让测试通过直接改测试。这些在只看“任务完成没有”的评测里,可能都算成功。所以除了检查目标状态,还要检查不该变的东西没变。
评分器:代码、模型和人
评分器有三类,各有长处:
| 类型 | 例子 | 优点 | 缺点 |
|---|---|---|---|
| 代码 | 跑测试、比对数据库状态、检查输出格式、正则匹配 | 快、便宜、可复现、好调试 | 只能判断能写成规则的东西,容易判错合理的变体 |
| 模型 | 按评分标准给回答打分、两两比较 | 能处理开放式输出和细微差别 | 有随机性、有偏差,需要和人对齐 |
| 人 | 专家打分、抽查轨迹 | 标准最可靠 | 慢、贵、难规模化 |
原则还是那句话:能用代码判断的就用代码。代码评分器的结论最稳定,出了问题也最好查。模型评分器用在代码判断不了的地方,比如回答的语气是否合适、调研报告有没有抓住重点。人主要用来校准前两者。
一个任务往往会组合多个评分器。以一个编程任务为例,写成配置大概是这样:
id: fix-empty-password-login
prompt: |
用户反馈:密码为空时也能登录成功。请修复这个问题,并补上测试。
environment:
image: repo-snapshot:2026-10-01 # 固定的初始状态
reset: per_trial # 每次试验都从头开始
graders:
- type: tests # 隐藏测试,Agent 看不到
run: pytest tests/hidden/test_auth.py
weight: 0.6
- type: state_check # 不该动的东西没动
forbid_changes: ["migrations/**", "tests/hidden/**"]
weight: 0.2
- type: llm_rubric # 代码质量交给模型评审
rubric: rubrics/code_quality.md
weight: 0.2
trials: 5
metrics: [turns, tokens, latency]
注意隐藏测试和 forbid_changes:前者防止 Agent 只对着可见测试写代码,后者防止它通过修改测试来“通过”测试。
评结果,而不是评路径
一个很自然的冲动,是去检查 Agent 是不是按“正确的步骤”做的:先读了配置文件,再调了查询工具,最后才改代码。这种评分器写起来很直观,但通常是个坏主意。
原因是 Agent 经常会找到你没想到的路径,而且其中不少是更好的。一个只认固定步骤的评分器,会惩罚这种创造性,也会让评测变得非常脆弱:换一个模型,步骤顺序稍有不同,分数就掉了,但实际上任务完成得一样好。
所以大多数情况下,评分应该看结果:最终状态对不对,回答对不对。路径相关的东西,比如用了多少轮、多少 token、有没有调用危险工具,作为指标记录下来,而不是作为通过与否的条件。例外是那些路径本身就是要求的场景,比如“退款前必须先核实身份”,这时检查路径是对的,因为跳过核实本身就是错误。
另一个相关的做法是给部分分。一个任务包含三个子目标,Agent 做对了两个,和一个都没做对,是很不一样的。全有全无的打分会把这种差异抹掉,让你看不出改动是不是在往对的方向走。
用好模型评审
模型评审最常见的问题是:评分标准太笼统。“请给这个回答的质量打 1 到 10 分”,得到的分数几乎没有信息量,同一个回答跑两次可能差两三分。
几条让模型评审更可靠的经验:
- 一个评审只看一个维度。“准确性”、“是否切题”、“语气”分开评,比一起打一个总分稳定得多;
- 用二元或少档位。“是否引用了至少一个来源:是 / 否”,比“引用质量 1 到 10 分”可靠;
- 给出判断标准和例子。写清楚什么样算通过、什么样算不通过,最好各附一个例子;
- 允许它说“无法判断”。不给这个出口,它就会编一个分数出来;
- 先说理由,再给结论。让评审先写分析再给分,比直接给分更稳定,也方便你回头检查它为什么这么判;
- 定期和人对齐。拿一批人工打过分的样本跑一遍评审模型,看一致率。一致率低,就改评分标准,而不是直接相信它。
一个评分标准大概长这样:
你在评估一个客服 Agent 的回复。只判断一件事:回复中的退款政策是否与下面的政策文档一致。
政策文档:
{policy}
Agent 的回复:
{response}
先逐条列出回复中提到的政策要点,并指出每一条在文档中的依据。
然后给出结论,只能是以下之一:
- CONSISTENT:所有要点都能在文档中找到依据
- INCONSISTENT:至少有一条与文档矛盾或文档中没有
- NOT_APPLICABLE:回复中没有涉及退款政策
非确定性:跑一次不算数
pass@k 和 pass^k
同一个任务跑 k 次,有两种常用的汇总方式,它们回答的是完全不同的问题:
- pass@k:k 次里至少一次成功的概率。它回答的是“给它几次机会,能不能做出来”;
- pass^k:k 次全部成功的概率。它回答的是“它是不是每次都能做对”。
如果单次成功率是 p,并且各次独立,那么 pass@k = 1 − (1 − p)^k,pass^k = p^k。随着 k 增大,两者会朝相反的方向走:
该看哪一个,取决于产品形态:
- 如果用户可以多次尝试并自己验证,比如编程助手生成几个方案让人挑,或者有测试能自动验证再重试,pass@k 更贴近真实体验;
- 如果用户期望每次都对,比如客服 Agent 处理退款,一次出错就是一次事故,那就要看 pass^k。
pass^k 这个指标是 τ-bench 提出来的,它的发现很能说明问题:一些单次成功率看起来不错的 Agent,pass^8 会掉到很低。对面向用户的 Agent 来说,“平均做得不错”和“稳定地做得不错”是两回事,后者往往才是能不能上线的门槛。
样本太少,差异就是噪声
另一个常被忽略的问题是统计显著性。假设你的评测集有 50 个任务,旧版本通过率 60%,新版本 65%,这是变好了吗?
粗略算一下:通过率的标准误差大约是 √(p(1−p)/n),p = 0.6、n = 50 时约等于 7 个百分点,95% 置信区间大概是正负 14 个百分点。也就是说,5 个百分点的差异完全在噪声范围内。
几个缓解办法:
- 每个任务跑多次,用平均成功率代替单次的成败,能降低任务内部的随机性;
- 做配对比较。新旧版本跑同一批任务,逐个任务看谁赢谁输,比只比较两个总分敏感得多;
- 看差异落在哪里。如果新版本多通过的任务都集中在你改动针对的那一类,这比总分的变化更有说服力;
- 别为了一两个点的变化做决策。小改动的效果,往往要靠更大的评测集或线上数据才能确认。
环境:让每次试验都干净
Agent 评测和模型评测的另一个大区别是环境。环境出问题,评测结果就不可信,而环境的问题往往很隐蔽。
试验之间要隔离。每次试验都应该从同一个干净的初始状态开始。如果上一次试验留下的文件、缓存、数据库记录被下一次看到了,结果就会互相污染:可能是失败被传染,也可能是 Agent 直接捡到了上一次的答案。这和 沙箱 那篇说的“沙箱应该是一次性的”是同一个道理。
小心答案泄露。比如用某个历史提交作为编程任务的初始状态,如果没有把后续的 Git 历史清掉,Agent 完全可以 git log 一下,直接找到当时的修复提交。Agent 在这种事情上非常有创造力,它不是在“作弊”,它只是在用手边一切可用的信息完成任务。
基础设施本身也会产生噪声。超时设置、并发限制、外部 API 的限流、容器的 CPU 和内存配额,都会影响通过率。同一个 Agent,在资源宽松的机器上和资源紧张的机器上跑,分数可能差好几个点。比较两个版本时,要确保它们是在同样的环境配置下跑的;看公开基准的排行榜时,也要知道不同提交之间的环境未必一致。
外部依赖尽量固定。依赖真实的网页、真实的 API,结果会随时间漂移,今天能过的任务下个月可能因为网页改版而过不了。能用快照、录制的响应或本地模拟服务替代的,就替代掉;不能替代的,至少记录下来,在分析失败时把它们单独拎出来。
需要用户参与的任务,用模拟用户。客服、助理这类多轮对话的 Agent,任务的推进依赖用户的回应。常见做法是让另一个模型扮演用户,给它一份设定(它想要什么、知道什么、不知道什么),让它和 Agent 对话。τ-bench 就是这么做的。模拟用户的质量直接决定评测的质量,它也需要像评分器一样被检查:是不是太配合了,是不是泄露了本该由 Agent 去问出来的信息。
能力评测与回归评测
评测集通常有两种用途,它们的期望通过率完全不同,最好分开管理。
能力评测回答的是“它能做到什么”。这类评测集应该从低通过率开始,里面是 Agent 现在还做不好的任务,给团队一个可以往上爬的坡。如果一个能力评测集一开始就是 90%,它能告诉你的东西就很少了。
回归评测回答的是“它还能不能做到以前能做到的”。这类评测集的通过率应该接近 100%,每次改动都跑,掉了就要查。它的作用是守住底线,防止修一个问题的同时弄坏另一个。
两者之间有一条自然的流动路径:
当一个能力评测集的通过率爬到很高、并且稳定之后,它就饱和了:分数已经没有上升空间,再好的改动也看不出差别。这时可以把其中的任务移进回归集,再从新的失败里补充更难的任务。一个长期不更新的评测集,最终只会告诉你“一切都好”。
去读轨迹
前面讲了很多指标和统计,但我想把最重要的一条放在这里:定期去读轨迹。
分数告诉你哪里有问题,轨迹告诉你为什么。而且,你经常会在轨迹里发现评测本身的问题,而不是 Agent 的问题:
- Agent 其实做对了,但评分器只认一种写法,把它判错了;
- 任务描述有歧义,Agent 按另一种合理的理解做了;
- 环境里缺了某个依赖,Agent 花了二十轮在跟环境搏斗;
- Agent 通过了,但用的是你没想到的捷径,比如改了测试、读了不该读的文件。
最后一种尤其要警惕。当分数突然大幅上升时,先别高兴,去读几条通过的轨迹,确认它是真的变强了,而不是找到了评测的漏洞。
读轨迹不需要全读。我的习惯是每次改动之后,抽几条新失败的、几条新通过的,再随机抽几条,各看一遍。重点看这几件事:
| 看什么 | 可能说明 |
|---|---|
| 在哪一步开始偏离 | 提示词或工具描述在那里有歧义 |
| 有没有反复做同一件事 | 工具返回不够清楚,或者缺少停止条件 |
| 有没有忽略已经拿到的信息 | 上下文太长,或者关键信息被埋了 |
| 失败时是怎么收尾的 | 是坦白说做不到,还是假装完成了 |
| 通过时用了什么方法 | 是真的解决了,还是钻了评测的空子 |
工具层面的症状(选错工具、参数填错、冗余调用)在 工具 那篇有一张更细的对照表,这里就不重复了。
读轨迹还有一个附带的好处:它会逼着你对“好”形成具体的判断。看了几十条轨迹之后,你会知道这个 Agent 的典型失败模式是什么,这比任何汇总指标都更能指导下一步的改进方向。
不同类型的 Agent,评测侧重点不同
上面讲的是通用的框架,落到具体类型的 Agent 上,评分方式和关注点会有不少差别:
| 类型 | 主要评分方式 | 要特别注意的 | 可参考的公开基准 |
|---|---|---|---|
| 编程 | 跑测试、静态检查 | 隐藏测试防过拟合;检查有没有改测试、改了范围外的代码 | SWE-bench Verified、Terminal-Bench |
| 对话 / 客服 | 检查最终状态,模型评审语气和政策一致性 | 需要模拟用户;关注 pass^k;路径约束(如先核实身份) | τ-bench |
| 调研 | 模型评审,结合事实核查 | 结论有没有来源支撑;来源本身是否可靠;覆盖面 | GAIA、BrowseComp |
| 操作电脑 / 浏览器 | 检查应用或系统的最终状态 | 环境快照和重置成本高;网页改版导致漂移 | OSWorld、WebArena |
公开基准适合用来选模型、了解大致水平,但不能代替你自己的评测集。原因很简单:它们测的不是你的任务、你的工具、你的用户。一个在公开基准上领先几个点的模型,在你的场景里未必更好。另外,越是热门的基准,越要考虑数据污染和“针对基准优化”的可能。
如果你的系统里用到了多个 Agent 或子 Agent,评测的原则是一样的:先评最终结果,再在轨迹里看是哪一个环节出了问题。具体怎么拆分任务、怎么设计 Agent 之间的交接,是另一个话题了。
离线评测之外
离线评测再完善,也只是用一组固定的任务去近似真实世界。上线之后,还需要其他几层来补位:
- 线上监控:成功率、轮数、token、耗时、报错率的变化趋势,以及用户中途放弃的比例;
- 用户反馈:显式的点赞点踩,以及隐式的信号,比如用户是否重新提问、是否手动撤销了 Agent 的改动;
- A/B 测试:重大改动在小流量上对比,用真实结果说话;
- 抽样人工审查:定期从线上随机抽一批轨迹,像读离线轨迹一样读一遍。
这几层各有盲区:离线评测覆盖不到没想到的场景,线上监控只能看到结果、看不到原因,用户反馈稀疏而且有偏,A/B 测试慢。把它们叠在一起用,才能比较放心。而最重要的是让它们形成闭环:线上发现的每一个新失败,都应该变成离线评测集里的一个新任务。
动手时的几条建议
- 现在就开始,从二三十个真实失败开始,不用等攒够几百条;
- 每个任务都要有参考解,先确认任务能做、评分器判得对;
- 正反两面都测,“该做的做了”和“不该做的没做”都要有;
- 评结果,不评路径,路径相关的东西记成指标,必要时给部分分;
- 能用代码判断就用代码,模型评审一次只看一个维度,并定期和人对齐;
- 每个任务跑多次,按产品形态选 pass@k 或 pass^k,别为了噪声范围内的差异做决策;
- 每次试验都从干净的环境开始,小心答案泄露和基础设施噪声;
- 区分能力评测和回归评测,饱和的评测集要及时更新;
- 定期读轨迹,分数突然大涨时尤其要读。
小结
- Agent 评测比模型评测难:多步、有环境、路径不唯一、结果不确定,所以它是一套系统,而不是一张表;
- 把一次评测拆成任务、试验、轨迹、最终状态和评分器,出了问题才知道该查哪一层;
- 最好的任务来自真实失败,好任务的标准是两个懂行的人会给出同样的判断,并且要有参考解;
- 评分优先用代码,模型评审要有明确、单一维度的标准,评结果而不是评路径;
- 一次不算数:pass@k 衡量能不能做出来,pass^k 衡量是不是每次都能做对,小样本上的小差异多半是噪声;
- 环境要隔离、要固定,环境的问题会伪装成 Agent 的问题;
- 能力评测用来爬坡,回归评测用来守底线,任务在两者之间流动,评测集需要持续更新;
- 读轨迹是最重要的一步,它既能发现 Agent 的问题,也能发现评测本身的问题。
写到这里,这个系列从循环、上下文、工具、记忆一路讲下来,每一篇最后都绕回到同一个问题:你怎么知道这样改是对的?评测就是这个问题的答案。它不会让 Agent 自己变好,但它让你每一次改动都有据可依,而不是在凭感觉。