Agent 调试与止损:卡住了怎么办
前言
Agent 基座系列番外第五篇。番外二讲怎么「看清」(可观测),这篇讲怎么「出手」:Agent 卡住了、越改越糟了、开始一本正经地胡说八道了——识别五种失败模式,判断救还是重启,以及怎么重启才不白干。案例全部来自真实的浏览器自动化调试现场。
一、五种失败模式:先认出来,再谈处置
| 模式 | 第一信号 | 根因 | 处置 |
|---|---|---|---|
| 循环打转 | 连续几轮调用同一个工具、参数几乎不变 | 状态没被确认,Agent 以为没成功 | 换确认手段,别让它重试 |
| 幻觉工具 | 调用了不存在的参数/接口,报错后换个姿势再编 | 记忆里的 API 形态过时或臆造 | 喂真实报错原文,纠正认知 |
| 上下文毒化 | 越改越糟,早先好的部分开始变坏 | 错误结论进了上下文,后续推理全部基于它 | 立即止损,开新会话 |
| 静默偏题 | 任务「成功」完成,但交付物不是要的 | 需求理解从某轮开始漂移 | 对照原始需求逐项核对 |
| 挤牙膏返工 | 每轮只修一小点,修完又冒新问题 | 需求没说清,Agent 在猜 | 停下,重写任务说明(番外四第六节) |
前三种是执行层故障,后两种是理解层故障。处置原则相反:执行层故障可以救(给信息、换手段),理解层故障救的成本通常高于重启。
二、循环打转:别让它重试,给它换眼睛
真实案例:往编辑器注入一段文本,脚本执行了,但界面几秒不刷新。Agent 的反应是再执行一次——而注入其实已经成功,第二次执行变成重复插入。
循环打转的根因几乎都是确认手段失效:Agent 用「看结果」确认动作,而结果恰恰看不清。解法不是禁止重试,是换一个可观测的信号:
动作后确认不要依赖"界面变化",改查状态本身: - 写入后读回来比对(内容在不在) - 命令后查退出码和产物文件(文件生成了没) - 请求后查返回体字段(而不是查界面显示)一句话:动作是否成功,用状态回答,不用表象回答。给 Agent 的工具设计里就该内置回读——这是工具层该还的债,不是 Agent 该猜的谜语。
三、超时不等于失败:最危险的操作是重发
真实案例:一段长脚本在浏览器里执行,15 秒没返回结果,工具层报超时。直觉反应是再跑一次——但脚本其实还在跑,重发等于让两个实例同时操作同一个页面,数据直接写坏。
超时的三种真相,处置完全不同:
- 脚本还在跑,只是慢→ 不动它,等。用轻量查询确认状态(查产物在不在、查页面状态位),而不是重发操作;
- 脚本死了,没执行→ 安全重发;
- 脚本执行了一半,停在中间态→ 最麻烦:先清中间态再重发,否则重发叠加半成品。
分不清时永远选等待 + 观察状态。可重入的操作才配得上自动重试——设计工具时就把「重复执行两次结果不变」当验收标准,这个性质有个正式名字:幂等,第十篇在无人值守场景讲过它救场的样子。
四、上下文毒化:止损点在哪
毒化的传播路径:一个错误判断(比如「这个接口不存在」)进入上下文 → Agent 基于它绕路 → 绕路产生更多失败 → 失败被解释成「环境有问题」→ 彻底放弃正确路径。每多一轮,毒化深一层。
判断该不该立刻开新会话的三问:
- 前几轮里有没有一个「当时看起来对、现在看是错」的结论被反复引用?有 → 毒化实锤;
- 让 Agent 复述当前思路,它的解释和原始任务还对得上吗?对不上 → 漂移已深;
- 继续救的预期轮数,超过重开重来吗?超过 → 别救了。
开新会话不等于从头再来——重启的艺术在于交接:
新会话第一句话不是重述任务,是给它交接文档: 1. 任务原始目标(原话粘贴) 2. 已确认的事实(哪些路走通了、哪些结论验证过) 3. 已证伪的路(别再试,上次为什么失败) 4. 当前状态(做到第几步、产物在哪)一份好交接让新会话从 80% 处起步。第五篇的记忆设计在这里再次生效:会话是易失的,落盘的才是资产。
五、人工介入点:什么时候把方向盘拿回来
Agent 时代的新技能不是 prompt 技巧,是判断「这轮我该不该插手」。三个该插手的信号:
- 同一问题第三次出现:两次可以怪运气,第三次就是系统性问题,Agent 自己修不动,人介入重新定义问题;
- 要动不可逆的东西:删除、发布、对外发送——第一篇到番外三反复立的红线,权限模型管底线,人管例外;
- Agent 开始解释而不是行动:大段输出「可能是因为……或许可以尝试……」时,它在用语言代替进展。这时候往往缺一个关键信息,问它「你现在最不确定的是什么」,一句话就能解锁。
反过来,两个不该插手的时刻:进展正常只是慢(插手打断缓存和节奏);失败在可接受范围(让它自己从报错里学,比人肉纠正便宜)。
六、调试工具箱:让故障可复现
- 截图留档关键节点:出问题时不用复现,直接看当时界面(第九篇的稳定性设计,调试时是第一手证据);
- 最小复现优先:大任务卡住,把出问题的那一步抽出来单独跑——上下文小、变量少、定位快;
- 报错原文永远优于转述:给 Agent 的纠错信息必须是原始报错,不是人的转述——转述丢掉的细节常常正是病根;
- 一次只改一个变量:同时改三处再跑,好了不知道谁的功,坏了不知道谁的锅。这条传统工程纪律在 Agent 调试里同样成立,且更容易被违反——因为改提示词太轻松了。
踩坑清单
- 超时重发写坏数据:见第三节。把「超时 ≠ 失败」刻进肌肉记忆,重发前先查状态;
- 和毒化上下文讲道理:试图用更多对话纠正错误结论,结果错误结论成了对话的一部分越埋越深。毒化只认重启,不认解释;
- 拿转述喂 Agent:「报错了,好像是权限问题」——「好像」两个字让它往错误方向排查半小时。贴原文,一字不差;
- 调试信息不落盘:排查过程全在会话里,会话一关全丢。每个 bad case 的结论写进 FAQ 或 skill——人肉回答只允许一次,第七篇的纪律在调试场景复用。
参考资料
- 本系列第九篇:《浏览器自动化 Agent 详解》—— 等待、重扫、截图的稳定性三件套
- 本系列第十篇:《无人值守 Agent 详解》—— 幂等与失败分级
- 本系列第五篇:《Agent 上下文管理详解》—— 会话交接与记忆落盘
- 本系列番外二:《Agent 可观测性》—— 看清失败的第一步
- 本系列番外四:《Token 成本优化实战》—— 挤牙膏式对话的账单代价