☰
Tessary:让AI agent评估从“打分”变成“找失败”的故障探测器
2026/10/14 8:02:00 网站建设 项目流程

做 AI agent 评估的朋友,八成有这种体验:评测集里塞了几百条样本,跑下来通过率 96% 以上,心里觉得稳了;结果一上线,用户随手两步就翻车。问题出在哪儿?我们太把评估当成打分,而不是当成破案了。Tessary 就是干这个的:它专门盯着采样评估(sampled evals)会漏掉的那批 AI agent 失败,把隐性问题挖出来。这篇文章我会从评估盲区的成因、Tessary 的解决思路、实际接入方式和几个我亲测过的失败案例展开,适合正在做 agent 可靠性、准备搭评估体系,或者已经在跑评测但总觉得“指标好看、心里没底”的团队参考。

1. 先把自己当成事故调查员,而不是考官

1.1 一段让我彻底改变的评估翻车现场

去年我帮某团队复盘过一起典型事故。他们的客服 agent 在评测环境里跑了 500 条已标注样本,通过率 97.6%,管理层非常满意。上线第三天,用户投诉开始涌进来,说“同一个问题问两遍答案不一样”“让它查订单它跑去改备注”。团队当时的第一反应是“线上流量太大,模型扛不住”,后来把 trace 全部拉出来逐条看才发现,真正的翻车点集中在工具调用参数格式的歧义上——用户输入“退回这件衣服”,agent 分不清该调用退货接口还是退款接口,而 500 条样本里退货场景只有 3 条,失败 1 条,对总通过率的影响只有 0.2%。

这事让我意识到,采样评估不是“测不准”,而是它根本就不是为找失败设计的。它是为“估计整体质量”设计的,而估计整体质量这件事,天然会牺牲对边缘失败的敏感度。

1.2 采样评估的三个天然盲区

第一个盲区是覆盖偏差。你抽样的时候,热门路径会反复被抽到,长尾路径则几乎为零。拿客服 agent 举例,“查余额”“改地址”这类高频意图可能占了样本的 60%,但真实线上流量里,反而是“合并订单”“拆分发票”这类低频操作更复杂、更容易出错。更麻烦的是,商业 agent 的输入空间是组合爆炸级别的,你不可能靠手写几百条样本把状态空间铺满。

第二个盲区更阴险:平均指标掩盖了失败聚类。假设你的 agent 在 100 个任务里通过了 97 个,通过率 97%。看着不错,但如果那 3 个失败全部指向同一个根因,比如“系统提示里工具描述格式与真实 API 不一致”,那说明你的 agent 大概率还有一批类似场景会在线上挂掉。只不过它们在样本集里恰好没被抽到,或者被抽到了但失败数太少,淹没在平均值里。

第三个盲区是失败相关性。很多 agent 的失败不是独立随机事件,而是一根链条上的不同出口。同一个根因,可能在一个任务里表现为“超时”,在另一个任务里表现为“回答错误”,在第三个任务里表现为“拒绝执行”。如果你只按任务维度看通过率,这三个失败会被当成三种互不相干的问题,你就永远找不到真正的病灶。

1.3 为什么 agent 比普通模型更容易摔在长尾上

纯粹的问答模型,失败往往局限于“理解错了”或“生成错了”,结果空间相对可控。但 agent 是多环节决策系统,它要消化用户输入、决定调用哪个工具、解析返回结果、维护中间状态、决定下一步动作。任何一个环节产生微小偏差,都会在后续环节被放大。换句话说,agent 的错误是“复合型错误”,状态空间比单轮模型高出几个量级。

我以前做过一个比喻:评估 agent 就像在漆黑走廊里用手电筒找人。采样评估相当于拿手电筒照了几个固定的点,看到那里没人,就以为整个走廊都是安全的。但 agent 的失败往往发生在你根本没照到的拐角,而且它摔倒了还会自己爬起来接着走,表面上好像还在响应,其实已经脱离正确轨道了。

Tessary 的思路恰恰是把手电筒换成探照灯,并且把“照过哪里”记录下来:它看的不只是结果的过与不过,而是 agent 每一步的决策轨迹,再通过轨迹分析找出你没抽到的那些失败模式。

2. Tessary 的核心设计与技术拆解

2.1 一句话理解 Tessary

Tessary 的定位不是又一套评估框架,而是评估框架的“故障探测器”。它接收你的 agent 和任务集,运行后输出四类东西:覆盖率报告、失败聚类、最小化复现样本、修复建议。它不是告诉你“你的 agent 通过率是多少”,而是告诉你“你的 agent 在哪些地方、以什么方式、因为什么根因会失败”。

这听起来简单,但实现起来有几个关键设计,值得逐个展开。

2.2 从“结果日志”升级到“足迹追踪”

传统评估只记录最终答案与预期是否一致,最多再记个耗时。Tessary 的做法是给被测 agent 包一层 trace 记录器,把每次运行的完整状态机快照都留下:用户原始输入、模型每次输出的完整消息、工具调用的函数名与参数、工具返回值、当前 token 消耗、当前步数、agent 从哪一步开始偏离预期。

这个设计我一开始觉得有点小题大做,直到自己排查过一个诡异问题才服气。那个 agent 在特定任务上偶尔会返回一个“看起来合理但多了一步操作”的结果,如果只看最终输出,它被判为通过。但 trace 显示,它其实先调错了工具,再用另一个工具“补救”回来了。这种依赖运气的成功非常危险,因为环境稍微一变,补救路径就断了。足迹追踪的核心价值在于,它能让你看到“成功背后的侥幸”和“失败背后的必然”。

2.3 失败聚类:把不同任务里的同类毛病归到一起

有了 trace,下一步就是从海量轨迹里提炼失败模式。Tessary 的失败聚类大致分两层。第一层按“失败特征”粗分,比如超时退出、解析错误、安全拒绝、达到最大步数、工具调用序列异常、上下文溢出等。第二层再做根因归并,把特征相似、发生位置接近、触发条件相近的失败合并为一个聚类。

举个例子,两个任务表面上看完全不同——一个让 agent 查询天气,一个让 agent 预订会议室——但它们的 trace 都在“解析工具返回的 JSON 数组”这一步爆了,原因是系统提示里给出的工具返回示例与实际 API 格式存在细微差异。传统评估会把这两个失败记为两条独立的失败记录,而聚类会告诉你:别管任务了,你有一个共性 bug,出现在工具返回解析层。

聚类质量的好坏,直接决定工具的实用性。聚类太粗,一个大类里什么都有,等于没分;聚类太细,每个失败单独成簇,你也看不出共性。Tessary 的做法是先以“失败特征 + 工具调用序列的编辑距离”做初步分组,再用 trace 中的关键字段(比如报错信息、特定 tool call 的参数)辅助二次归并。实操中我会建议把聚类数量控制在 3~10 个之间,如果超过 10 个,说明你的评估任务集太杂,或者 agent 处于极不稳定状态,先修基础问题再说。

2.4 最小化复现:把 300 步的复杂轨迹缩成 30 步

发现一个失败聚类之后,你面对的可能是一段几百步的超长 trace,里面交织着大量无关信息。Tessary 内置的 minimizer 会用类似 delta debugging 的策略,逐步剔除 trace 中与失败无关的步骤,最终产出一个能稳定复现该失败的最小任务描述。

这里有个技术点值得细说:对于 agent 这类有外部副作用和随机性的系统,最小化不能简单地把 prompt 里的句子删掉就完事,还要考虑工具响应、上下文长度、随机种子等因素。Tessary 在实际执行时,会把完整运行环境镜像化,对工具 Mock、固定随机种子,然后在这个可复现的环境里做缩减。这一步很关键,否则你拿到的最小化样本可能在本地跑三遍三次结果都不一样,那就没法修 bug 了。

最小化样本的价值不只在修复阶段。它还是沟通工具,你可以直接把 12 行的最小输入发给同事,说“跑这个,就挂了”,比发一个 300 步的 trace 截图高效得多。

2.5 扰动机制:主动找盲区,而不是被动等样本

Tessary 区别于普通 trace 分析工具的最大不同,是它不满足于分析你喂给它的样本,它还会对你给出的任务主动做扰动。比如把用户输入从一个长句改成一个短句、把工具返回的结构体字段顺序打乱、在上下文里插入一段无关历史消息、把外部 API 的响应延迟从 200ms 调到 2s,然后看 agent 在这些微小的变化下会不会触发新的失败聚类。

这个机制有点像我以前做测试时的“变异测试”思路,但放到 agent 上更有意思。因为 agent 的失败往往对初始条件极其敏感,一条指令里换一个词、工具返回里多一个额外字段,都可能让 agent 从正确路径滑向错误路径。扰动机制能帮你在没有真实用户反馈的情况下,提前暴露这类脆弱性。

我实测下来,一个设计良好的扰动集能把这类的发现量提升一倍以上,尤其是工具返回结构的健壮性问题,几乎一扰一个准。

3. 实操过程与关键配置

3.1 接入方式与最小运行流程

Tessary 的接入方式非常轻量。假设你的 agent 入口是一个run_agent(task)函数,你只需要给它包一层 trace 装饰器,然后交给 Tessary 的评估器去跑。我把它的常见用法用示意代码整理一下,具体函数名和参数以你实际使用的版本为准,但结构大同小异:

import tessary from tessary import TracingEval @tessary.trace() def run_agent(task): return agent.run(task) eval_runner = TracingEval( tasks=task_sampler.load(seed=42), suite="regression", max_steps=15, sampling_ratio=1.0, perturbation_level=2, ) report = eval_runner.run() report.clusters().print_summary() report.reproduce_minimized(cluster_id=3, out_dir="./repro/")

这份代码做的事情很简单:加载任务集,对每个任务完整运行 agent 并记录 trace,开启中等强度的扰动,跑完以后输出聚类摘要,还可以把指定聚类的最小化复现样本输出到目录。

3.2 几个直接影响结果质量的关键参数

第一个是max_steps,也就是允许 agent 执行的最大步骤数。这个值不是越大越好。设得太小,很多正常任务会因未完成而误报失败;设得太大,失败聚类里会混入大量“本来能成功但拖到了超时”的噪声。我建议你先拿 5~10 个已知通过的任务试跑,选择一个能让它们全部顺利完成的阈值,再往上加 20% 作为余量。

第二个是sampling_ratio。这个参数控制你是跑全部任务还是跑子采样。听起来有点矛盾——Tessary 不是要解决采样漏检吗,怎么自己还要采样?实际上,对超大规模任务集,全量跑可能非常耗时。这时候可以用两段式策略:先用较小的sampling_ratio(比如 20%)快速跑一遍,找出可疑失败聚类,再针对这些聚类对应的任务领域做全量放大验证。这和传统评估是互补的,传统评估采样是为了估计整体水平,Tessary 采样是为了快速锁定需要细查的区域。

第三个是perturbation_level,扰动等级。等级越高,生成的扰动变体越多,发现盲区的概率越大,但耗时也越长。我建议第一次跑设成 1,只做基础输入扰动,先看整体失败画像;确认跑得通之后,再开到 2 或 3 做更深度的探索。

第四个是聚类阈值cluster_threshold。这个参数控制失败轨迹被归为同一聚类的相似度门槛。调高阈值会得到更多的小聚类,更精细,但更容易被噪声干扰;调低阈值会得到更少的大聚类,更宏观,但可能把不同根因混在一起。通常我用一个经验法则:先看聚类的 数量,目标在 3~10 个之间,如果远远超出,就逐步调低阈值,让结果收敛。

3.3 结果怎么读:一份报告的五段信息

Tessary 聚类报告的输出结构大致是这样的:每个聚类包含失败样本数、失败特征标签、共同触发的工具调用链片段、可能根因提示,以及一个指向最小化复现样本的路径。我建议你按下面顺序来读:

先看聚类数量和每个聚类的样本占比。如果某个聚类占比超过 30%,恭喜你,找到一个主要矛盾,优先修。然后逐个聚类看“共同工具调用链片段”,重点观察在哪一步开始与正常轨迹分叉。接着看根因提示,但不要全信,提示只是基于统计的猜测,最终还是要结合最小化复现样本做人工确认。最后一定要去./repro/目录里实际跑一遍最小化样本,眼见为实。

3.4 接入 CI 的正确姿势:别只卡通过率这条线

很多团队把评估接入 CI 以后,只是设了一条“通过率低于 95% 就失败”的门禁。这样做最大的问题是,修复一个小 bug 导致通过率从 94% 跳到 96%,门禁变绿了,但你可能根本不知道哪个聚类消失了、哪个新聚类出现了。

我的建议是增加两条附加门禁。第一条是“新增失败聚类阻断”:如果本次运行的聚类集合与上次相比,出现了此前从未见过的聚类,则触发告警,人工确认是否引入回归。第二条是“已知聚类放大阻断”:如果某个已知聚类的失败样本数比上次增长了超过 20%,就算总通过率没变,也要拉出来查一查。

这两条门禁的思路是,把评估的颗粒度从“整体分数”下沉到“具体失败模式”,让 CI 不仅能告诉你系统坏了,还能告诉你哪里坏了、是不是老问题反弹了。

4. 三个真实案例:这些失败为什么集体隐身

4.1 案例一:在同一个坑里反复横跳的重试循环

某团队做的是一个信息检索 agent,评测通过率一直稳定在 96% 左右。Tessary 跑出来一个聚类特别醒目:样本量不大,共 7 个失败,但根因高度一致——agent 在调用同一个检索工具时连续重试 11 次,最后因为达到最大步数被强制截断。

正常评估里,这 7 个任务分散在 500 个样本中,失败的代价就是 1.4 个百分点的损失,很容易被当成“偶发超时”忽略。但聚类把 7 次重试的轨迹放在一起后,问题清晰了:这个检索工具在结果为空时返回一个空结构体,agent 无法区分“没搜到东西”和“工具出错了”,于是反复重试同一个查询。真正的修复不是在 prompt 里加一句“不要重试”,而是在工具返回协议里增加一个明确的“no_result”状态字段,让 agent 能识别空结果的语义。

这类失败就是典型的“聚众隐身”:单个出现都像零星事故,聚类之后就暴露出了协议语义缺陷。

4.2 案例二:上下文窗口被压扁之后的决策退化

另一个案例来自一个长对话场景的 agent。它的任务平均需要 20 到 30 轮交互,每轮都要携带历史摘要。传统评估只报告“最终任务完成度 98%”,但 Tessary 的 trace 显示,几乎所有失败都在第 18 轮左右开始出现:agent 的回复开始变得简短、丢失了用户早期给出的关键偏好、重复询问已经确认过的信息。

继续挖 trace 才发现,这个 agent 的实现里没有对上下文做压缩管理,一旦累积 token 超过模型上下文限制,系统会自动截断早期对话。用户在第 3 轮说过的偏好,到第 18 轮已经被截掉了,agent 根本“看不见”,后续决策自然退化。这个失败模式如果只看最终结果,会表现为“agent 态度变差”或“回答质量下降”,很难归因到上下文管理。只有把 trace 里的 token 消耗曲线画出来,才能看到失败和截断之间的强相关关系。

这个案例给我的启发是:agent 的失败有时不是模型的错,而是状态管理基础设施的错,而这类错误在纯结果评估里几乎不可见。

4.3 案例三:改一个参数顺序,行为就全变了

第三个案例特别有意思。某团队开发一个调度 agent,负责根据用户指令安排会议。测试用例的构成大多是“明天下午三点和项目组开会”这种完整表述。Tessary 的扰动机制自动生成了几个变体:把时间参数放在句子末尾、把会议室地点提前到我说的第一位、加了一句无关的寒暄。结果发现,agent 在时间出现在句首时表现正常,把时间放到句尾后,就开始频繁跳过会议时长的确认。

这个问题的根源让人哭笑不得:prompt 里给了工具一个“按用户表述顺序提取参数”的暗示,导致 agent 对输入顺序产生了强烈依赖。你可以让 agent 把参数按固定优先级解析,而不是依赖用户在自然语言里的表述顺序。这类 bug,如果只靠人工手写测试用例,几乎不可能覆盖到,因为人在构造用例时会不自觉地按“标准表达”来写,真正的用户输入是最不标准的。

4.4 这些失败为什么会集体隐身

三个案例放在一起,能清晰地看到采样评估漏掉失败的三种机制。第一种是概率稀释:失败比例太低,淹没在通过率里。第二种是维度过高:失败发生在你不知道该监控的维度上,比如上下文 token 曲线、重试次数、调用序列顺序。第三种是分布偏移:你的测试样本分布和真实输入分布存在系统性的偏差,而抽样逻辑本身不会纠正这个偏差。

Tessary 的处理策略,本质上是把这三个盲区逐个补齐:用聚类对抗概率稀释,用足迹追踪覆盖隐藏维度,用主动扰动缓解分布偏差。它不一定能发现所有失败,但它能显著提高你看到失败的概率。

5. 常见问题与排查技巧实录

5.1 trace 数据量太大,跑一次要一小时,怎么办

这是我最常被问到的问题。agent 的 trace 是普通评估日志的几十倍,动辄几百 MB。三个有效手段:第一,开启 trace 抽样,对同一个任务只保留前 N 次运行结果,N 建议取 3~5;第二,对 trace 做“关键事件截取”,也就是只保留工具调用、模型回复、错误信息和 token 统计,把中间过程的调试细节丢弃;第三,把外部调用 Mock 成本地响应,省去网络等待时间。Mock 之后还能顺便提升复现稳定性,一举两得。

5.2 聚类结果噪声很大,一个聚类里混了好几种问题

这种情况通常发生在cluster_threshold设得太低,或者任务集本身太杂。我一般先把阈值调高,让聚类更精细,看小聚类能不能浮现出来。如果还是混在一起,就按领域或工具类型把任务集切成几个子集,分别跑 Tessary。一个客服 agent 的“退货”和“订单查询”看似都是客服任务,但工具调用链完全不同,混在一起聚类时容易相互干扰。

5.3 最小化复现跑了三次,只有一次成功,怎么排查

先固定随机种子,再检查是否有外部依赖。很多 agent 的最小化复现不稳定,是因为真实环境里调用了外部 API,而外部 API 的响应不可控。把外部工具全部 Mock 成固定响应的假实现,然后再跑最小化样本。如果 Mock 之后稳定复现,说明问题出在环境依赖,而不是 agent 逻辑;如果 Mock 之后反而不复现了,那可能是真实环境里的某个特定响应触发了失败路径,这时需要把那个特定响应固化到 Mock 里,反复逼近。

5.4 Tessary 和现有评估平台的关系是什么

它不是替代关系,而是互补关系。评估平台解决的是规模化和持续回归问题,适合每天跑几百上千条用例,生成趋势报告。Tessary 解决的是深度诊断问题,适合在评估平台发现可疑信号后,做多轮迭代式排查。我建议的用法是:每次模型或 prompt 更新后,先跑一遍常规评估确认没有大回归,再用 Tessary 做一次深度扫描,看旧失败聚类是否修复、新失败聚类是否产生。两条路径并行,既保规模又保精度。

注意:如果你的 agent 还没有接入任何 trace 记录机制,建议先补这一课。没有 trace 的评估,就像没有录音的会议纪要,出了事只能靠回忆。

我个人在实际操作中的体会是,评估体系建设的重心早晚会从“证明它没坏”转向“找到它什么时候会坏”。Tessary 把我从“盯着单一通过率焦虑”里解放出来,让我能直接看到失败的形状、位置和规律。我现在每跑一轮评估,都会把聚类的输出存档,下一轮对比时,旧聚类是否消失、新聚类来自哪里,一目了然。最后再分享一个小技巧:在往测试集里加新样本时,优先从 Tessary 报告里那些高失败聚类覆盖的场景里挑,这样样本集的“味觉”才会越来越灵敏。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询