当 Agent 跑了 120 步后崩溃:航空事故调查员如何教我们抓到那一步致命错
当 Agent 跑了 120 步后崩溃:航空事故调查员如何教我们抓到那一步致命错
一架飞机坠毁了,黑匣子里有 120 条记录
想象你是一名航空事故调查员。一架航班坠毁,黑匣子记录了 120 个操作步骤。你逐帧查看,发现飞行员在第 18 步按错了一个按钮,第 47 步读错了高度表,第 73 步和塔台沟通时漏了一个词,第 95 步忘了放下起落架,第 112 步拉杆太猛。
五个错误,飞机只坠毁了一次。哪个才是真凶?
你不能把五个都列为"原因"——那等于没有答案。你必须找到那个最早的决定性错误:它引发了后续连锁反应,即使中间步骤看起来"修正"了,最终仍然导致了坠毁。
这是 LLM Agent 调试面临的同一个困境。清华大学 KEG 实验室和腾讯混元团队 2026 年 8 月发布的论文 TrajDebug 给出了一个系统化答案:追踪错误的整个生命周期,而不是只看错误本身。
Agent 的崩溃现场:平均 7.62 个错误,只有 1 个是致命的
研究者先做了一个让人坐直的先导实验。他们收集了 50 条失败轨迹(来自 τ²-Bench 和 SWE-Bench Pro 两个主流 Agent 评测基准),人工标注每一步是否出错。结果:
- 50 条失败轨迹共 381 个局部错误,平均每条 7.62 个
- 每条轨迹只有 1 个关键错误(critical error)真正导致了最终失败
- 剩下的 331 个非关键错误里:
- 205 个(61.9%)后来被自己修复了
- 104 个(31.4%)一直存在但没导致失败
- 22 个(6.6%)处于休眠状态——既没修复也没造成影响
更麻烦的是,检测准确率随轨迹长度递减。研究者评估了 7 个主流大模型(包括 GPT、Claude、DeepSeek 等),在短轨迹上还能勉强找到关键错误,但轨迹一长,准确率断崖式下跌。原因很简单:判断第 47 步是否出错,可能需要回看第 3 步的指令、第 28 步的观察、第 35 步自己的推理——证据散落在整个上下文里,模型读到后面就忘了前面。
TrajDebug 的三段式调查:从"找错误"到"追生命周期"
TrajDebug 的核心洞察是:错误不是孤立事件,它有生命周期。一个错误从触发、到发展、到被修复或持续影响,是一个完整过程。只看错误本身等于只看案发现场,不看后续发展。
框架分三阶段,每阶段都产出可审计的证据:
阶段一:错误触发检测——多粒度历史压缩
长轨迹的挑战是:判断第 47 步是否出错,需要同时看局部细节(这步的动作)和全局上下文(之前的指令和观察)。TrajDebug 构建了三个粒度的历史视图:
- 高粒度:保留最近几步的完整细节(看当前动作的上下文)
- 中粒度:中等长度的摘要(看近期发展脉络)
- 低粒度:整条轨迹的高度压缩(看全局走向)
在三个视图上,TrajDebug 检测"错误承诺"(wrong commitment)——Agent 在推理、规划、行动、观察或验证阶段做出的与某个参考冲突的判断。参考分四类:
- 任务冲突:与原始任务指令矛盾
- 历史冲突:与自己之前的推理或行动矛盾
- 步骤内冲突:同一步内前后矛盾
- 环境异常:与环境反馈矛盾
阶段二:错误状态分类——四种命运
找到错误触发后,TrajDebug 不急着下结论。它把同一对象相关的触发聚合成"错误实例",然后追踪每个实例的后续发展,分到四个状态:
- Clean Resolution(干净修复):错误被纠正,没留下任何影响
- Costly Resolution(代价修复):错误被纠正了,但消耗了资源或绕了远路
- Manifest Active(显性持续):错误一直存在,且在最终失败中留下痕迹
- Latent Active(隐性持续):错误一直存在,但没在最终失败中直接表现
阶段三:候选集引导的因果归因
最后一步,TrajDebug 把所有"Manifest Active"和"Costly Resolution"状态的错误实例交给 LLM 做最终归因。但关键是:LLM 不再面对整条轨迹,只面对一个精筛过的候选集。
这把任务从"在 120 步里找关键错误"降维成"在 3-5 个候选里选最关键的一个"。候选集已经附带完整证据链(触发位置、违反的参考、后续发展),LLM 只需要做因果判断。
TrajErrBench:486 份"事故档案"
为了让同行能复现和比较,研究团队构建了 TrajErrBench——第一个大规模人工标注的 Agent 失败轨迹基准:
- 486 条失败轨迹:400 条来自 τ²-Bench(客服工具使用场景),86 条来自 SWE-Bench Pro(软件工程场景)
- 平均长度:τ²-Bench 29.3 步,SWE-Bench Pro 119.7 步
- 标注内容:每条轨迹的所有局部错误、错误类型、执行阶段、是否关键
| 维度 | τ²-Bench | SWE-Bench Pro |
|---|---|---|
| 任务冲突 | 52.4% | 73.4% |
| 历史冲突 | 46.3% | 24.1% |
| 推理阶段失败 | 60.7% | 57.1% |
实验结果:诊断即生产力
TrajDebug 在 TrajErrBench 上超越了所有基线方法,尤其在长轨迹上优势更明显。但更有说服力的是两个应用实验:
应用一:诊断引导重跑,+10.80% 成功率提升 用 TrajDebug 诊断失败轨迹,把"关键错误在哪一步、违反了什么、为什么导致失败"作为反馈喂给 Agent,让它重新执行同一任务。平均成功率提升 10.80 个百分点。
应用二:失败记忆迁移,+5.70% 成功率提升 把少量历史失败的诊断聚合为"失败记忆库"(failure memory),迁移到完全没见过的任务上。成功率提升 5.70 个百分点。
第二个结果尤其重要。它证明 TrajDebug 的诊断不只是"事后诸葛亮",而是可迁移的结构化知识。失败模式可以抽象出来,变成 Agent 的免疫力。
工程洞察:错误有生命周期,调试需要时间维度
TrajDebug 给 Agent 工程师带来三个实操启示:
1. 不要只看最终失败点,要追错误源头 Agent 在第 95 步失败,根因可能在第 18 步。直接修第 95 步是治标不治本。TrajDebug 的"错误生命周期"视角让你看到错误的传播链。
2. 不是所有错误都需要修 61.9% 的局部错误被 Agent 自己修复了。如果你花精力修每一个错误,你在浪费 60% 的工程量。先分类,再决定修哪些——这是 TrajDebug 四状态分类的价值。
3. 失败轨迹是金矿,不是垃圾 大多数团队把失败轨迹扔掉。TrajDebug 证明:486 条失败轨迹可以训练出可迁移的失败记忆,让新任务成功率提升 5.70%。失败是结构化知识来源,前提是你有工具把它诊断清楚。
概念连接:颗粒度对齐与"换层面解决问题"
TrajDebug 契合两个我一直在追踪的跨论文共识:
"颗粒度同构"原理:优化颗粒度应该和被优化对象的颗粒度一致。Agent 的失败不是"整条轨迹失败",是"某个错误实例在生命周期中某个状态导致失败"。TrajDebug 把调试颗粒度从"轨迹级"或"步级"细化到"错误实例级",和 Heddle、CodeRescue 把决策颗粒度从"单次调用"升级到"轨迹/恢复动作"是同一个原则。
"换层面解决问题":传统方法让 LLM 在整条轨迹上找关键错误,TrajDebug 换了个层面——先做错误生命周期追踪,把 LLM 的任务从"多步推理"降级为"在候选集里做因果判断"。这和 Euclid-MCP 把推理外包给 Prolog、章鱼用 RNA 编辑绕过 DNA 重写是同一个策略:承认模型在某些任务上不可靠,换一个层面绕过去。
代码与数据
- 论文:https://arxiv.org/abs/2608.06346
- HTML 全文:https://arxiv.org/html/2608.06346v1
- 代码仓库:https://github.com/THU-KEG/TrajDebug(代码和数据在内审中,即将开源)
- 作者团队:清华大学 KEG 实验室 + 腾讯混元
个人思考:从"找 bug"到"理解 bug 的一生"
最让我触动的是 TrajDebug 对"错误"概念的重新定义。我们习惯了把错误当作离散事件——"第 47 步出错了"。但 TrajDebug 告诉我们:错误是一个有生命周期的实体,它有诞生(触发)、有发展(状态变化)、有结局(修复或持续)。
这和医学的演进惊人相似。19 世纪的医生把疾病当作"某个器官坏了",20 世纪转向"疾病是一个过程,有潜伏期、发作期、恢复期"。TrajDebug 把 Agent 调试从"找坏步骤"推向"理解错误的发展史"。
更深一层:TrajDebug 的"失败记忆迁移"实验暗示了一个可能性——Agent 的经验不只是"成功案例库",还应该有"失败模式库"。人类专家之所以厉害,不只因为他见过很多成功,更因为他踩过很多坑。TrajDebug 给 Agent 踩坑经验提供了一种结构化编码方式。
当 Agent 系统越来越复杂、轨迹越来越长,"如何从失败中学习"会比"如何成功"更重要。TrajDebug 做了一个扎实的起点:先得能诊断,才能谈学习。