☰
Agent失败诊断与归因:ReAG、DuoTrace、EDGE工程落地实践
2026/9/26 7:23:14 网站建设 项目流程

1. 从一次线上事故说起:Agent 失败为什么这么难查

凌晨两点被告警叫醒,某个跑在客服系统里的 Agent 连续返回空结果,用户侧看到的是"抱歉,我暂时无法处理"。翻日志,模型调用成功、工具调用成功、返回码 200,链路每一环看起来都"绿"的,但最终答案就是错的。这种场景做 Agent 的人应该都不陌生——Agent 失败最麻烦的地方,不是它挂了,而是它没挂但结果不对。

传统后端服务的失败是显式的:抛异常、超时、5xx,堆栈一拉就知道哪行代码出问题。但 Agent 是一个由 LLM 驱动的多步决策系统,它的"失败"藏在语义层:可能是规划阶段选错了工具,可能是检索阶段召回了一堆无关文档,可能是工具返回的 JSON 被模型误读,也可能是多轮对话里上下文被截断导致它"忘了"用户前面说过什么。你拿到的只是一个错误的最终输出,中间发生了什么,全靠猜。

这就是"诊断与归因"要解决的问题。所谓诊断(Diagnosis),是判断这次 Agent 执行到底哪里出了问题;所谓归因(Attribution),是把最终的错误结果,追溯到具体的步骤、具体的组件、甚至具体的 token 上。这两件事合起来,才构成一条完整的可观测链路。

我最近系统梳理了这个方向上的几篇代表性工作,包括ReAG、DuoTrace、EDGE这几条思路,它们各自解决链路中的一段,拼起来刚好覆盖"Agent 失败了怎么办"的完整流程。这篇就把这条链路拆开讲清楚:每一步在做什么、为什么这么设计、实际落地时怎么抄、以及我踩过的坑。

先说清楚适合谁看:如果你正在做 Agent 开发,已经被"结果不对但查不出来"折磨过,或者正准备给 Agent 加监控和评测体系,这篇会对你有直接帮助。如果你还在纠结 Agent 和 LLM 的区别、Agent 框架怎么选,建议先把基础跑通再回来看,因为诊断的前提是你已经有一个能跑起来的 Agent。

2. 先搞清楚 Agent 失败到底分几类

在讲论文之前,得先把"失败"这件事本身分类。不然你拿着一堆 trace 数据也不知道该看什么。根据我实际排查的经验,Agent 失败大致可以归到下面几类,这个分类也基本对应了后面几篇论文各自盯住的问题域。

2.1 规划失败:方向从一开始就错了

规划失败是最致命的一类。Agent 拿到任务后,第一步的推理就偏了,后面所有步骤都在错误的方向上努力。典型表现是:用户问"帮我对比一下 A 和 B 两个方案的报价",Agent 却去调了一个"查询单个方案详情"的工具,然后基于单方案信息硬编了一个对比。

这类失败的根因通常在任务分解环节。LLM 把复杂任务拆成子任务时,如果拆解粒度和工具能力不匹配,就会选错工具。比如工具库里只有"按 ID 查订单"和"按用户查订单列表",但任务需要的是"按时间范围聚合订单金额",模型很可能强行用前两个工具拼凑,结果就是错的。

排查这类问题,核心是看第一步的推理链。我一般会把 Agent 的 planning 输出单独打日志,重点看它选了哪个工具、理由是什么。如果理由本身就站不住,那后面不用看了,直接改 prompt 或者改工具描述。

2.2 检索失败:喂给模型的东西就是错的

RAG 类 Agent 的失败,很大一部分出在检索环节。模型本身没问题,但你给它的上下文里全是无关内容,它只能基于垃圾进垃圾出。这类失败有个很隐蔽的特点:模型会非常自信地基于错误上下文给出答案,因为它不知道检索结果本身是错的。

检索失败又分几种:召回为空(知识库里根本没有)、召回噪声大(返回了一堆不相关文档)、召回顺序错(最相关的排在了后面被截断)。这三种的处理方式完全不同,所以诊断时必须区分开。

2.3 工具调用失败:参数错了但没报错

工具调用失败不一定是接口报错。更常见的是参数语义错误:模型传了一个格式正确但语义错误的参数。比如查订单,模型把"用户 ID"填成了"订单 ID",接口正常返回,但返回的是别人的订单或者空结果。

还有一种情况是工具返回结果被误读。工具返回了一个嵌套 JSON,模型在解析时把字段理解错了,或者把多个结果当成一个。这类问题在工具返回结构复杂时特别常见。

2.4 上下文与记忆失败:它"忘了"

多轮 Agent 里,上下文管理是个大坑。对话轮次一多,早期信息被挤出窗口,或者摘要时丢了关键约束。表现就是 Agent 突然"忘了"用户前面强调过的限制条件,比如"预算不超过 5000"。

这类失败最难查,因为单看某一轮的执行都是对的,问题出在跨轮的信息传递上。

2.5 失败分类速查表

失败类型典型表现根因位置排查入口
规划失败方向错、工具选错Planning 阶段第一步推理链
检索失败答案基于无关内容Retrieval 阶段召回结果与 query 相关性
工具调用失败参数语义错、结果误读Tool 调用阶段入参出参对照
上下文失败忘记约束、前后矛盾Memory 管理跨轮信息传递

把这张表记住,后面看论文思路时你会更容易对上号——每篇论文其实都在强化其中某一环的诊断能力。

3. ReAG:把检索过程本身变成可诊断的对象

ReAG 这条思路的核心,是把 RAG 里最黑盒的"检索"环节打开,让检索过程本身产生可诊断的信号。传统 RAG 你只能看到"召回了哪些文档",但看不到"为什么召回这些""检索是否真的支撑了最终答案"。ReAG 要解决的就是这个。

3.1 为什么检索需要单独归因

先说个我实际遇到的例子。一个做技术文档问答的 Agent,用户问"如何配置超时重试",Agent 给出的答案里混进了一段关于"数据库连接池"的内容。查召回结果,发现检索确实返回了一篇讲连接池的文档,因为那篇文档里也出现了"超时""重试"这些词。模型看到这段内容,就把它揉进答案了。

问题在于:检索的相关性和答案的正确性之间,存在一个归因断层。你知道召回了什么,但不知道召回内容对最终答案贡献了多少、哪一段是噪声。ReAG 的价值就在于,它让检索结果和最终答案之间建立起可追溯的对应关系。

3.2 ReAG 的核心机制拆解

ReAG 的做法,简单说就是在检索和生成之间插入一层显式的推理与验证。它不直接把召回文档丢给模型生成,而是先让模型对召回内容做一次"相关性判断和证据提取",把真正支撑答案的证据片段挑出来,再基于证据生成。

这个设计背后有个很实在的考量:LLM 在生成时,对上下文里所有内容是一视同仁的,它不会主动区分"这段是核心证据"和"这段是碰巧出现的噪声"。ReAG 通过显式的证据提取步骤,强制模型先做一次筛选,相当于给检索结果加了一道质检。

从诊断角度看,这一步产生的中间产物极其有价值:证据片段列表。当最终答案出错时,你可以直接看证据列表——如果证据本身就是错的,那是检索问题;如果证据对但答案错,那是生成问题。归因路径一下就清晰了。

3.3 实操:怎么把 ReAG 思路落到自己的 Agent 里

你不需要完整复现论文,抓住核心思想就能改造自己的链路。我一般这么做:

第一步,在检索之后、生成之前,加一个证据提取节点。prompt 大致是让模型从召回文档中,逐条列出"与问题直接相关的原文片段",并标注来源文档 ID。这一步的输出是结构化的,方便后续追踪。

第二步,生成阶段只喂证据片段,不喂原始召回文档。这样能大幅降低噪声干扰,同时让生成阶段的输入变得可控可查。

第三步,把证据片段和最终答案一起存进 trace。出问题时,先看证据对不对,再看答案对不对,两步定位。

注意:证据提取这一步会增加一次模型调用,成本和延迟都会上升。如果 QPS 高,建议只对"答案置信度低"或"用户反馈差"的请求做完整证据提取,正常请求走轻量路径。

3.4 我踩过的坑

第一个坑是证据提取过度。一开始我让模型提取所有相关片段,结果它把整篇文档都标成相关,等于没筛。后来改成限制条数(比如最多 5 条)并强制标注"为什么相关",效果才好。

第二个坑是证据和答案的对应关系丢失。早期我没存证据 ID,出问题时只能看到答案,没法回溯到具体证据。后来强制每条证据带唯一 ID,答案里引用证据时带上 ID,归因才真正闭环。

4. DuoTrace:双通道追踪,把执行链路和语义链路对齐

如果说 ReAG 解决的是检索环节的归因,那 DuoTrace 盯的是更全局的问题:Agent 的执行链路(execution trace)和语义链路(semantic trace)是两条线,出问题时对不上。

4.1 执行链路和语义链路为什么会脱节

执行链路是你代码层面能看到的东西:调了哪个函数、传了什么参数、返回了什么。语义链路是模型层面的推理过程:它为什么这么想、每一步的意图是什么。这两条线在传统日志里是分开的,而且粒度对不上。

举个例子:执行日志显示"调用了 search 工具,参数 query='退款政策',返回 3 条结果"。但语义层面,模型当时其实是想查"退款时限",只是它把意图表达成了"退款政策"。执行链路看起来完全正常,语义链路却已经偏了。你只看执行日志,永远发现不了这个问题。

DuoTrace 的核心贡献,就是把这两条链路在时间轴上对齐,让每一步执行都能对应到当时的推理意图。

4.2 双通道追踪的实现思路

DuoTrace 的做法是在 Agent 每一步执行时,同时记录两类信息:一类是执行侧的结构化数据(工具名、参数、返回值、耗时),另一类是语义侧的推理数据(当前步骤的意图、依据、预期结果)。然后通过步骤 ID 把两者关联起来。

关键在于语义侧数据的采集方式。你不能指望模型主动汇报意图,得在 prompt 里显式要求它在每次工具调用前输出一段"意图说明",格式固定,比如"我准备调用 X 工具,目的是 Y,预期得到 Z"。这段说明和执行数据一起入库,就形成了对齐的双通道。

从诊断角度,这个设计的价值在于:当某一步执行结果不符合预期时,你可以立刻对照语义侧的"预期结果",判断是模型预期错了(规划问题)还是执行没达到预期(工具问题)。这个判断在单通道日志下是做不出来的。

4.3 落地时的数据结构设计

我实际落地时,trace 表大概长这样:

字段含义来源
step_id步骤唯一标识系统生成
intent本步意图说明模型输出
expected预期结果模型输出
tool_name调用的工具执行侧
params调用参数执行侧
result返回结果执行侧
latency耗时执行侧
status成功/失败执行侧

有了这张表,排查时就能做很多以前做不了的分析。比如筛出所有"intent 和 tool_name 明显不匹配"的步骤,这些就是潜在的规划失败点;再比如筛出"expected 和 result 语义差距大"的步骤,这些是工具或参数问题。

4.4 实操心得与注意事项

第一个心得是意图说明要短。一开始我让模型写详细意图,结果它写了一大段,反而拖慢速度还容易跑偏。后来限制在 30 字以内,只写"做什么、为什么",信息密度反而更高。

第二个心得是对齐要按 step_id,不能按时间戳。并发场景下时间戳会乱,必须用显式的步骤 ID 关联两条链路。

注意:双通道追踪会让每次调用的 token 消耗上升 15% 到 30%,因为多了意图说明的输出。如果成本敏感,可以对意图说明做采样,比如只对 10% 的请求做完整双通道记录,其余走轻量模式。

5. EDGE:从失败样本里自动挖出归因规则

前面两篇更多是"记录"和"对齐",EDGE 走的是另一条路:从大量失败样本里,自动归纳出归因规则。这解决的是一个很现实的问题——你不可能靠人工一条条看 trace,样本量一大就崩了。

5.1 为什么需要自动归因

假设你的 Agent 每天处理 10 万次请求,失败率 3%,那就是 3000 条失败样本。人工看 3000 条 trace,一条 2 分钟,就是 100 小时。这显然不现实。你需要的是让系统自己告诉你:"这 3000 条失败里,60% 是检索召回为空,25% 是工具参数错误,15% 是上下文截断。"

EDGE 的思路就是做这件事:把失败样本聚类,然后为每一类生成可解释的归因描述。

5.2 EDGE 的归因逻辑

EDGE 的核心是基于失败特征的聚类 + 规则提取。它先从每条失败 trace 里抽取一组特征(比如:是否调用了工具、召回文档数、上下文长度、模型置信度、错误类型等),然后对这些特征做聚类,把相似的失败归到一起。对每一类,再提取出区分度最高的特征组合,形成一条归因规则。

举个具体的:聚类后发现有一类失败样本,共同特征是"召回文档数=0 且 模型置信度>0.8"。这条规则翻译成人话就是:"检索没召回任何内容,但模型还是自信地编了答案。"这就是典型的检索失败导致的幻觉,归因规则直接指向了检索环节。

5.3 特征工程:归因质量的关键

EDGE 效果好不好,八成取决于特征选得对不对。我实际用下来,下面这些特征区分度最高:

  • 检索侧:召回数量、最高相似度分数、召回文档平均长度
  • 工具侧:调用次数、参数类型分布、返回结果大小、是否有空返回
  • 模型侧:输出置信度(如果有)、输出长度、是否包含"无法回答"类话术
  • 上下文侧:当前上下文 token 数、是否触发截断、跨轮引用次数

把这些特征拼成向量做聚类,基本能把大部分失败模式分出来。我实测下来,5 到 8 个簇就能覆盖 90% 以上的失败样本。

5.4 从归因规则到修复动作

归因的终点是修复。EDGE 给出的规则要能直接对应到动作,否则就是纸上谈兵。我一般会建一张映射表:

归因规则对应修复动作
召回为空 + 高置信度加检索兜底,召回为空时强制走"无法回答"
参数类型错误集中在工具描述里加参数示例
上下文截断频繁优化摘要策略或扩大窗口
单工具调用占比过高检查工具描述是否误导模型

这张表是活的,每次归因出新规则就往里加。跑一段时间后,你会发现失败率在稳步下降,因为每一条规则都对应一个被堵住的漏洞。

6. 把三篇拼成一条完整链路:诊断与归因的工程落地

单独看每篇论文都有价值,但真正有用的是把它们拼成一条能跑的链路。我现在的做法是分四层:采集层、对齐层、归因层、修复层。

6.1 采集层:全量记录,重点采样

采集层负责把 Agent 每一步的执行数据和语义数据都记下来。执行数据全量记,语义数据(意图说明、证据提取)按采样率记。采样策略我一般这么定:正常请求 10%,失败请求 100%,用户负反馈请求 100%。这样既控制成本,又保证关键样本不丢。

6.2 对齐层:用 step_id 串起双通道

对齐层就是 DuoTrace 那套,用 step_id 把执行链路和语义链路关联起来。这一层的产出是一张结构化的 trace 表,后面所有分析都基于它。

6.3 归因层:ReAG 证据 + EDGE 聚类

归因层做两件事:一是用 ReAG 的思路,对每条失败 trace 提取证据片段,判断是检索问题还是生成问题;二是用 EDGE 的思路,对失败样本做聚类,归纳出批量归因规则。前者解决单条归因,后者解决批量归因。

6.4 修复层:规则到动作的闭环

修复层把归因规则转成具体动作,落到代码或配置里。这一步必须有人参与,因为有些规则需要判断是改 prompt、改工具还是改检索策略。但有了前面的归因,人的判断成本大幅降低。

6.5 一个完整的排查实例

说个真实案例。某天发现 Agent 的"订单查询"类问题失败率突然从 2% 涨到 8%。走一遍链路:

采集层显示失败请求的 trace 都完整。对齐层一看,失败步骤集中在工具调用后,intent 是"查询订单状态",但 result 返回的是空列表。归因层用 ReAG 思路提取证据,发现检索没问题,问题在工具参数——模型把"订单号"填成了"用户 ID"。再用 EDGE 聚类,发现这类失败集中在"用户输入包含多个数字"的场景,模型分不清哪个是订单号。

修复动作很明确:在工具描述里加参数示例,明确"订单号是 16 位纯数字,用户 ID 是 8 位"。改完第二天失败率回落到 2.5%。

这个案例里,如果没有双通道对齐,你只会看到"工具返回空",根本不知道是参数错了;如果没有自动归因,你得一条条看才能发现"多个数字"这个共性。链路的价值就在这。

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

这一节把我实际踩过的坑和常见问题整理一下,都是文档里不会写的。

7.1 常见问题速查表

问题现象可能原因排查动作
trace 缺失关键步骤采样率配置错误检查失败请求是否 100% 采样
意图说明和实际调用不符prompt 约束不够加格式校验,不符则重试
归因规则太泛无法落地特征区分度低增加检索/工具侧细粒度特征
修复后失败率反弹规则覆盖不全重新聚类,看是否出现新簇
成本超预算语义采集过多降低正常请求采样率

7.2 独家避坑技巧

技巧一:先跑通单条归因,再上批量。很多人一上来就想做自动聚类,结果特征没调好,聚出来的簇毫无意义。正确顺序是先手工归因几十条,搞清楚失败模式长什么样,再让机器去学。

技巧二:意图说明用固定模板。别让模型自由发挥,给它一个模板:"我准备调用 [工具名],目的是 [一句话],预期得到 [结果类型]。"固定格式解析起来才稳。

技巧三:证据提取限制条数。前面提过,不限制条数模型会偷懒全标相关。限制 3 到 5 条,并强制说明理由,筛选效果最好。

技巧四:归因规则要定期清理。规则会过时,尤其是业务变化后。我一般每月 review 一次,把不再触发的规则归档,避免规则库膨胀。

技巧五:修复动作要可回滚。改 prompt 或工具描述可能引入新问题,所有修复动作都要能一键回滚,并保留修改前后的失败率对比。

7.3 关于成本和收益的权衡

这套链路不是免费的。语义采集、证据提取、聚类分析,都会增加成本和工程复杂度。我的建议是分阶段上:先上采集和对齐(成本最低,收益最直接),跑一两个月积累样本后,再上自动归因。如果 Agent 请求量不大(比如每天几千次),甚至可以跳过自动归因,人工看 trace 就够了。

注意:不要为了"完整"而过度工程化。诊断链路的目的是解决问题,不是炫技。能定位问题的最小方案就是好方案。

8. 后续可以怎么扩展

这套链路跑通后,还有几个方向可以继续挖。一是把归因结果反哺到 prompt 优化,让模型在生成时就知道哪些坑不能踩;二是做在线诊断,不等失败发生,而是在执行过程中实时检测异常信号并干预;三是跨 Agent 的归因规则共享,把一类 Agent 的失败模式迁移到相似场景。

我自己目前在做的是第二点,在线诊断的难点在于如何在不增加太多延迟的前提下做实时判断。初步想法是用轻量特征做快速筛查,可疑的再走完整归因。这块还在试,有结果再单独写一篇。

最后分享一个我自己的体会:Agent 诊断这件事,工具和论文都只是辅助,真正决定效果的是你对业务失败模式的理解深度。你越清楚自己的 Agent 在什么场景下容易出错,归因规则就写得越准。论文给的是方法论,业务理解才是那个不可替代的部分。

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

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

立即咨询