评估多轮智能体

10 分钟读完

E13
深入解析 · 评估智能体

评估多轮智能体。

一段录下来的对话,在智能体说出与录音不同的话的那一轮,就不再是一个有效的测试用例了——因为第三轮的期望答案,是假定了第二轮的回复才写出来的,而你手上每一个多轮测试集里都塞满了「第三轮」。出路是把用户生成出来,而不是回放他;而这件事有一个大多数团队从不汇报的后果:用户模拟器现在进到了被测系统里面,于是一个多轮分数是「智能体+模拟器+评测框架」三者共同的属性。已发表的数字,光是一个框架开关就能让它移动 3 到 5 分。

步骤 1固定的轨迹在第一次分叉处就过期了。

单轮评测之所以行得通,是因为输入与输出互相独立:你把提示词固定住,变动系统,再比较答案。多轮把这一点打破了——第 n 轮的用户消息,是对第 n−1 轮智能体消息的回应,所以一旦你的智能体的回复与录音里的那句不同,后面每一条用户发言都成了答非所问,而每一个期望答案所评的,都是一场并未发生过的对话。

# a recorded case, and what happens when the agent improves

RECORDED                          YOUR AGENT
u: my router is offline           u: my router is offline
a: have you tried rebooting?      a: I see line sync is down
                                     upstream — this is an
                                     outage in your area
u: yes, still nothing             u: yes, still nothing     <- nonsense
a: I'll dispatch a technician
   [expected: dispatch=true]                                <- ungradeable

# the agent did BETTER and scores worse. the test set
# encodes one path through the conversation as the only path.

这不是边缘情况,而是常态,而且它的偏置有明确方向。固定轨迹奖励的是「复现录音轨迹」的那个智能体,而那通常就是与「生成这份录音的系统」最相似的那个智能体。那些能把对话变短的改进——用一轮就诊断出录音里花了四轮才搞清的事——看起来反而像失败,因为脚本还有三轮没发完。

你恰好有三个诚实的选项,而它们测的是三件不同的事。

步骤 2回放前缀、模拟用户,或者只评最终状态。

  • 回放,并且只评到分叉为止。便宜、确定、可复现,而它测的是一件很窄的事:智能体是否走在一条已知良好的路上。作为回归检测器它有用——如果昨天的构建在第二轮是这么处理的而今天的不是,你会想知道。作为能力度量它没用,因为分数是「智能体与录音保持一致了多久」的函数,而分叉并不等于失败。请把它汇报为「分叉前匹配的轮数」,永远不要当成通过率。
  • 用一个模型来模拟用户。这是唯一能评估「由智能体来掌舵的对话」的设计。你给模拟器一个人物设定和一个目标,让它与智能体对话,然后给结果打分。τ-bench 及其后继者做的就是这件事,而对任何对话式系统来说,这是正确的默认选项。代价是:你的测量里现在含着第二个你并不打算评估的模型——见 STEP 3。
  • 只评最终状态,不管对话。查数据库,而不是查对白:预订改了没有、退款金额对不对、工单有没有升级到正确的队列。这恰恰因为「不在乎对话过程如何」而成为多轮评测里最稳健的信号,也是最能迁移到生产的那一个。它的局限是:它分不出一场好的对话和一场「过程难受但恰好结局正确」的对话,而且对那些「正确结果就是不要写入」的用例,它什么也说不出来。

三个都用,各司其职,并且把它们放在分开的列里。常见的错误是把回放分数与最终状态分数平均成一个头条数字,那会造出一个会为两个互不相关的原因而移动的指标。「把路径与结果分开打分」的更一般论证在轨迹与过程评测里;多轮额外添上的一点是:路径现在是共同署名的,所以路径匹配类指标的退化速度,远快于它们在单轮工具调用任务上的表现。

步骤 3模拟器在被测系统里面,而没人汇报它。

一旦有个模型扮演用户,轨迹就是从两个策略里联合抽出的样本。一个不用问就主动报出账号的弱模拟器,会让每个智能体都显得称职,因为任务里最难的那部分——把信息套出来——根本就没发生。一个过于对抗、或者会回答真实用户答不出的问题的模拟器,会让每个智能体都显得不称职。这两件事都不会出现在头条数字里,而换掉模拟器模型会悄悄地把你手上全部历史分数重新标定一遍——与评判器校准里换评判器的效果一模一样。

τ²-bench 把这个结构摆到了明面上:它把这种设定建模为一个去中心化的部分可观测马尔可夫决策过程,其中双方都能说话、调用工具并接收观测——是一个双控环境,而不是一个只会吐文本的用户。这个框架之所以重要,是因为它点明了被测量的东西:不是智能体的策略,而是在双向部分可观测下这一对的联合行为。它的 telecom 领域——用户手里握着智能体碰不到的工具,必须被一步步说着话引导去用——被报告为明显最难的那个;论文中当时某个前沿模型的数字,retail 约 74%、airline 约 56%,而 telecom 约 34%。这道落差与其说是任务更难,不如说是「必须透过另一个人去行动」的代价。

然后是评测框架,而最安静的那部分方差就住在这里。官方的 τ²-bench 评测施加了一条「不携带思维」策略:先前的推理内容在轮次之间被剥掉。一篇 2026 年针对同一基准的论文指出,相对于把最近一轮的推理带下去,这种设置稳定地让分数低了 3 到 5 分。那是一个框架开关,不是模型属性,而它比团队们宣布的大多数模型间差距都要大。

两个多轮分数可比,仅当模拟器模型、模拟器的提示词与人物设定集合、推理携带策略、以及轮数上限这四项全都一致。请把这四项与数字一起记录下来,就像你在预算对齐的评测里记录预算那样。一个不带模拟器就被引用的多轮数字,不是一次微弱的测量——它是一次未识别的测量,而你连它偏在哪个方向都说不出来。

步骤 4每轮可靠性会复利,所以能力与可依赖性每多一轮就分得更开。

多轮正是「做得到」与「每次都做到」之间的落差变成全部故事的地方,因为一场对话只有在没有任何一轮把它搞坏时才算成功。如果各轮以速率 p 大致独立地失败,那么一场 t 轮的对话以 (1−p)t 的概率走完,而这道算术并不友善。

# probability a whole conversation survives

per-turn   3 turns   5 turns   8 turns   12 turns
0.99        0.970     0.951     0.923     0.886
0.97        0.913     0.859     0.784     0.694
0.95        0.857     0.774     0.663     0.540
0.90        0.729     0.590     0.430     0.282

# a 2-point per-turn improvement (0.95 -> 0.97) is worth
# 15 points of completion at 8 turns. the lever is turns,
# then per-turn reliability -- never the headline average.

这就是为什么 pass^k——k 次独立尝试全部成功的概率——才是真正描述一个已部署对话式智能体的指标,也是为什么它坍缩得远比 pass@k 所美化的要快。一个智能体可以拿到一个体面的单次分数,却在同一个任务重复跑时是枚硬币;而抛硬币的那一段,正是会上线的那一段。这件事的统计学——包括为什么任务间方差意味着「加任务胜过加重复」——在评测方差与统计功效里推完了。

关于独立性假设,还有一条多轮特有的告诫:它在错误的地方过于乐观。各轮的失败是相关的,因为一个在第二轮就误解了用户的智能体会把这份误解带着走——误解现在在上下文里了。所以上面那张表是个上限,而真实分布比它暗示的更双峰:顺的对话会一路顺下去,而歪了的对话很少能救回来。那个形状才是值得画出来的东西,而平均值把它彻底藏住了。

步骤 5现实中真正难的,是用户改主意。

大多数多轮测试集只给模拟用户一个固定不变的目标,而那是对话的简单版本。真实用户会推翻决定、中途加约束、为了另一件事放弃手头这件——而固定脚本在结构上就表达不了这些,因为目标切换只有相对于「智能体已经做了什么」才有意义。

AgentChangeBench 是一个 2025 年专为此而建的基准,它值得一读的不是排行榜,而是它的仪表盘:它把一个单一成功率混在一起的四件事分了开——任务成功率、工具使用效率、工具调用冗余率,以及目标切换恢复时间,也就是在用户改变目标之后,智能体要花几轮才开始按新目标行动。恢复时间正是团队们缺的那个测量。一个智能体完全可以在最终任务成功率上拿到好分数,却花了六轮才注意到用户已经不要原来那个东西了——而那六轮就是全部的用户体验。

冗余是另一个值得偷走的指标。目标切换之后,典型的失败不是拒绝,而是重新折腾:智能体重复调用它已经调过的工具、重复索要它已经拿到的信息,或者两个目标各服务一半。按对话统计冗余工具调用能直接检测到这件事,而它是个便宜的计数器,不是一个评判器。这两种失败都是从评测这一侧看过去的目标漂移,而恢复时间这个指标,正是让一个澄清性提问显出它通常就是那步便宜招数的东西。

请刻意地设计这次切换,而不是指望模拟器临场即兴:给人物设定一个在明确触发点上的剧本化改主意——在第一次成功写入之后,或者在第四轮——这样测量才可复现。一次由模拟器随机发明出来的切换是方差来源,不是测试。

步骤 6先把小的那版建起来。

你并不需要一个已发表的基准就能拿到这里的大部分东西,而且你不该把它当作门禁:公开多轮集不是你的领域,而你的政策才是你的智能体会搞错的东西。二十场你自己的、建得扎实的对话,胜过一张排行榜。

  • 写人物设定与目标,不要写轨迹。一份人物设定是:用户知道的几个事实、他不知道的几个事实、一个目标、一种语气。用户不说出来的那些信息才是设计面——智能体的工作通常就是把它们套出来,所以一个什么都主动交代的人物设定什么也测不到。
  • 把模拟器钉死,并像代码一样给它版本。一个模型、一段提示词,放在仓库里,只在刻意的时候改。而当你真的改了它,请重跑历史,并预期每个数字都会移动。
  • 在数据库里评最终状态。对写入、金额与队列做断言——而不是对措辞。这是在模拟器更换之后还能存活下来的那部分。
  • 加入「不该写入」的期望。至少四分之一的用例,正确结果应当是「什么都没发生」——那笔不符合条件的退款、那次违反政策的变更。一个每个用例都以成功写入收场的测试集,奖励的是一个永远会写入的智能体。
  • 重复,并且把重复汇报出来。每个用例跑五次,报「五次全通」率,而不是五次里最好的那次。如果你只能在一个方向上花钱,加用例胜过加重复。
  • 每次运行都记录恢复时间与冗余调用,哪怕你还没有目标切换用例。它们是计数器,不花什么钱,而且是当某次提示词改动让智能体变固执时最先移动的那两个数字。

如果你根本没法给智能体装仪器——一个藏在 API 后面的厂商产品——这些技法会收窄但不会消失;评估一个你只能调用的智能体讲了重复 n 次与副作用断言仍然能给你买到什么。而无论你测什么,一个分数在你知道「一个称职的人在同样这些对话上能得多少」之前都是没有分母的,这是人类基线的主题。

别再把轨迹回放当成通过/失败——只把它们留作分叉检测器。从人物设定与目标把用户生成出来,然后钉死模拟器模型、它的提示词、推理携带策略与轮数上限,并把这四项公布在每个数字旁边;光是第三项里就住着 3 到 5 分的摆动。在数据库里评最终状态,让四分之一的用例以「不该写入」收场,并汇报「n 次全通」率而不是单次运行。然后在一个固定触发点加入一次剧本化的改主意,并记录恢复时间与冗余工具调用。最后那一对是这里最便宜的诊断,也是没有任何排行榜会递给你的那一对。