综合案例

全程拆解D|一次“变慢且变差”的Agent回归怎样查到根因

综合案例约 4.6 千字1 组分步图解

本例是完整的系统诊断题,数据为作者构造。它不是某家公司事故复盘,也不是对任何模型版本的实测评价。目标是练习在多种解释竞争时,逐层排除,而不是凭直觉把一切归因于模型变笨。[EVALS][SRE][HARNESS]

场景:团队更新了上下文策略后,用户反馈同类修复任务更慢,且偶尔重复修改已改好的文件。有人建议换更强模型;有人建议加一个Review Agent;有人建议把上下文加倍。应该先做什么?

本章目录

沿着对象与状态理解本章

从失败发生的位置选择组件:信息没取到先改检索,已有证据却读错再看上下文与模型,执行未知先查状态。不要同时加Memory、多Agent和Review后再猜是哪一项有效。

下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。

动态图解 · F40

先找错误发生在哪层,再谈换模型

什么时候该改Prompt、检索、记忆或模型?

一个错误答案可以来自不同原因。模型根本没拿到新版本时,增加推理时间不能补出缺失事实;检索已经拿到新版本却被旧记忆覆盖时,需要修上下文与记忆使用规则。选择修复层应跟随证据,而不是看到失败就再加一个Agent。

归因用证据判断导致现象的环节。
消融改变或移除一个因素,看现象如何变化。
最小有效修复能处理已确认问题而不扩大无关复杂度的改动。

输入与适用条件:构造“旧配置被当成当前配置”的诊断案例;不以单次观察就宣称确定因果。

1 / 6 · 现象

第1步,共6步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

先找错误发生在哪层,再谈换模型:现象现象回答引用了旧配置定位输入新资料是否进入索引/请求定位检索候选是不是旧版本优先定位状态长期记忆是否覆盖了新证据最小修复修版本过滤或失效条件配对验收同题集比较正确性、成本与退化教学流程;高亮表示当前步骤,不表示真实耗时比例。

先写清楚哪句话错、正确证据是什么,避免只说“感觉变差”。

本步状态由图形与说明共同给出。

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

避免无目的地叠Prompt、规则、模型和审查环节。

怎样实现

按原文→索引→检索→上下文→推理→行动→核验逐段定位。

可能的代价与误解

同时改变多个因素后只看总成功率,无法解释哪项改动起作用。

如何判断是否做对

同任务、同版本、同预算对照,保留失败样本与可复查轨迹。

D.1|把主观反馈变成可观察的目标

先定义三个症状:任务完成时间变长、同一逻辑动作重复执行、最终结果是否真的变差。不要只看用户体感,也不要因平均Token减少就断言优化成功。

收集同一组代表性任务的旧版本与新版本轨迹,并记录模型、提示、工具、索引、压缩和运行器版本。若模型也同时变化,就先承认实验混杂,不能把差异全部归给压缩。

本例假设模型和工具执行器未变,改动包括:更早压缩历史、摘要模板精简、默认加入更多专业技能。三个变化并不是一个变量。接下来需要分别检查。

D.2|先看一条失败任务的时间线

事件 开始秒 结束秒 观察
检索 0 2 命中正确源码r42
模型M1 2 12 正确提出补丁p1
apply c19 12 13 文件已变r43,响应丢失
自动压缩 13 20 摘要把超时写成“修复失败”
模型M2 20 31 根据摘要再次提出同类修改
apply c22 31 32 部分重复修改
测试与返工 32 50 新错误,继续修复

这里已经有强线索:原始模型能定位并提出正确补丁,问题发生在外部结果与压缩摘要之间。立即更换模型不一定解决状态语义错误;增加Review可能只是延后发现重复修改。

还要确认表中的“文件已变r43”来自磁盘或操作日志,不是模型自己说的。如果这一项只是猜测,必须先核验,不能用假设构造一个看似完整的根因故事。

D.3|比较三个状态:聊天、运行器、外部世界

外部文件:p1已经应用,版本r43
运行器账本:c19超时,结果尚未确认
摘要文本:修复失败,需要重试

矛盾发生在摘要把unknown转换为failed。unknown表示不知道是否生效;failed通常诱导重试。两者文字只差几个字,执行后果完全不同。

即使模型本身完全遵守摘要,它也会做错。因此根因不是简单的“模型没听话”,而是它获得了错误状态。系统需要保留未确认操作的结构化状态,压缩不得把其语义改写,并在下一步前核验实际效果。

再追问:为什么c19响应丢失?可能是网络或进程问题,仍应修复,但分布式环境不可能靠“确保永不超时”消灭所有窗口。可靠设计必须处理响应丢失,而不只祈祷它少发生。

D.4|设计能区分假设的最小实验

候选H1:新模型能力下降;H2:摘要丢失状态;H3:技能过载;H4:测试环境噪声。

针对同一个已知故障轨迹,构造四个受控输入:原始历史、当前错误摘要、保留unknown的修正摘要、修正摘要加原始操作核验结果。保持模型、工具可见集合和任务不变,观察下一步动作选择。若错误主要随摘要状态变化,而非随模型版本变化,H2更有支持。

还要测试运行器本身:对unknown直接start应拒绝,只有verified_not_applied才允许进入适当重试路径;verified_applied应进入验证而不是再次修改。包内状态机见证测试覆盖这个局部规则,不声称它已经证明商业模型会正确选择动作。

实验不能只挑一个成功案例。至少覆盖“操作确实已生效”“操作完全未生效”“部分生效”“核验也失败”四类情况。否则修复可能只是把所有unknown都猜成成功,从一种错误跳到另一种错误。

D.5|为什么多加载技能可能让成本下降指标产生错觉

假设新策略把原先40K未缓存输入改为20K摘要,但额外常驻技能使每轮又加10K。单次输入仍略降,然而压缩多一次模型调用,重复动作又多两轮,总延迟和总成本可能上升。

真实成本需要累加每轮未缓存、缓存与输出费用,并包括失败返工。不能比较“压缩前最后一轮”和“压缩后第一轮”的Token就下结论。缓存前缀是否稳定、工具输出是否被裁剪,也会影响实际账单。

技能加载过多还可能改变任务解释或增加冲突。要看最终请求manifest:哪些技能因何选择、是否互相重叠、有没有本应局部按需读取的长指南。把技能描述改窄之前先收集误加载正例和漏加载反例,防止修一个方向却损害专业召回。

D.6|把时间拆成关键路径,而不是把所有耗时相加

若两个只读检索分别耗时3秒和4秒并行执行,用户等的可能约4秒;若它们先后串行就是7秒。任务Trace应记录实际依赖,而不是仅按操作类别求和。

本例的压缩13到20秒在关键路径上,无法被后续模型计算隐藏。若压缩后节省的Prefill时间小于这7秒,并且任务本来只剩一轮,压缩可能得不偿失。但在更长任务中,压缩可以降低后续上下文成本;是否值得要看剩余工作,而不是所有任务统一在某占用率触发。

再看M2的20到31秒:其中可能包含排队、Prefill、内部推理和输出传输。没有服务端细分指标时,不应凭11秒猜具体每项。能确认的是端到端调用耗时,其他只能列为待验证原因。

D.7|修复方案应对应根因,不扩大成平台重构

最低必要改动可以是:保留结构化pending/unknown操作;压缩摘要把这些状态作为不可丢失事实;恢复时先核验;对修改加版本前提;测试结果绑定最终版本。它们直接对应观察到的失败窗口。

并不必然需要新增大型记忆数据库、多层合同、每步签名或更多Agent。若系统已有任务状态存储,可以在现有结构上修正。是否增加数据库事务或远程幂等,需要依据真实副作用边界决定,而不是从一个例子推出所有项目必须统一架构。

对于技能过载,优先减少无关常驻内容,保持必要技能召回;对于过早压缩,考虑任务阶段和近期工具输出,而不只调整阈值数字。每一项优化都应能独立开关,以便定位退化。

D.8|怎样证明修复改善了质量,而不是碰巧多成功几次

用固定代表任务做配对比较,同一任务在旧新版本中都运行,控制环境与预算。对于随机执行,增加合理重复并按任务聚类分析,不能把同一任务多次试验当成完全独立的新任务。

教学二乘二表:100个任务中旧新都成功70个、仅旧成功5个、仅新成功10个、都失败15个。旧成功75,新成功80,表面提升5个百分点;但真正决定配对差异的是5与10这15个不一致任务。样本有限,不能仅凭5个百分点宣称稳定重大提升。

成本也看全部尝试。若新版本只完成简单任务、放弃复杂任务,成功样本平均耗时可能变短,但用户目标未改善。应同时报告覆盖、成功、失败类型和不同复杂度分层。基础设施异常也要单独标记,避免将机器资源不足归给模型能力。

D.9|上线与回滚:历史状态会不会带着错误继续运行

新运行器上线后,旧checkpoint里可能仍有“失败”但实际unknown的记录。只修摘要模板不能自动修复这些存量任务。需要识别相关版本和状态,按受控策略核验或暂停,不能批量盲目重试所有失败操作。

回滚也不能只切回旧提示。如果新状态schema包含unknown而旧版不理解,回退可能重新引入危险重复。兼容读取、状态迁移与明确停止,是比“回滚按钮存在”更实在的恢复能力。

灰度期间监测未知操作核验率、重复动作、任务成功、总成本和延迟,而不是只盯API报错数。异常应触发有针对性的降级,例如暂时关闭写操作而保留只读诊断,而不是让系统在不明状态下继续自主推进。

D.10|六个继续追问,以及完整回答方向

问:压缩后为什么不直接重读所有文件? 重读可以恢复部分当前事实,但成本高,也无法重建已经发生却没有落在当前源码里的外部副作用。应优先恢复与下一步有关的证据和待核验操作;当前源码不等于完整历史。

问:能否让更强模型自动发现摘要错误? 只有摘要本身或其他证据暴露矛盾时才有机会。如果输入一致地写“失败”,再强模型也无法可靠知道文件已修改。能力不能代替不存在的观察。

问:给所有工具加重试是否更可靠? 只读且幂等操作与有副作用操作应区分;超时不代表未执行。需要动作语义、幂等键或结果查询,重试次数本身不创造可靠性。

问:测试通过是否可以忽略重复动作? 不能。重复修改可能偶然无害,也可能导致额外外部作用、历史混乱或未来隐患。要分别评估代码结果与执行副作用,不能用一个绿色状态覆盖全部。

问:为什么不让Reviewer决定unknown是什么? 它也需要实际证据。Reviewer可以提出核验路径,不能凭角色名称获得外部事实。把状态判定交给另一个模型并不消除信息缺口。

问:最终真正改进了哪一层? 主修复是执行状态与上下文交接,辅修复是选择性加载和压缩时机。没有证据表明需要改变模型参数。能够把措施定位到层,才避免了昂贵而无关的优化。

D.11|把系统诊断答案压缩成一段面试陈述

先固定任务和版本,把失败定义为可验证现象;用Trace对照模型输入、输出、工具账本与外部状态,找到最早出现事实不一致的位置。再用受控反例区分候选原因,修复必要状态和验证边界,最后做配对回归与灰度。模型、上下文、工具、记忆和工作流都是可调整对象,但不是每次失败都要全部重构。

这段陈述背后应能展开本例每一个中间对象、时间点与分支。只背最后一段不够;真正理解体现在追问“响应丢了但文件改了怎么办”时,能继续讲出unknown、核验、幂等边界、压缩保留和最终版本验收。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。