Agent 出错以后:四次复盘
实战手记第 05 篇
前几篇讲了规则和证据,听起来像是只要准备充分,Agent 就不会出错。实际不是这样。这一篇复盘四次真实发生的问题:一次线上中断,几次没有证据支持的“已完成”,一道 AI 代码审查门禁从启用到移除,以及一次差点把客户信息发布到公开页面。
每一次都按同样的顺序讲:发生了什么,错误怎样传播,之后改了什么。读完你应该能在自己的流程里找到类似的薄弱点:哪里是 Agent 的判断条件,哪里是它的执行范围,哪里需要人的眼睛。
一、验收脚本误判,引发约 13 分钟中断
全双工语音服务部署在一台 GPU 服务器上,网关和模型分别作为系统服务运行。一次发布由 Agent 编写验收脚本并执行:先停旧服务,启动新版本,然后检查健康状态,检查失败就自动回滚。
问题出在第一步的判断条件。模型服务刚启动时,就绪状态字段是 ready=None,意思是“还在加载”。脚本把它当成了失败,触发回滚。回滚的范围又太大:网关检查失败,模型也跟着一起回滚。连续的停止和启动让 systemd 判定服务启动过于频繁(StartLimitBurst),拒绝再启动。服务因此中断约 13 分钟。
每一步单独看都在“按规则执行”:检查失败就回滚,这本身是对的。错在判断条件写得不对,回滚范围定得太宽,以及没有考虑 systemd 的启动保护。
之后改了三处,都写进了项目的交接文档:
- 停任何服务之前,先对线上只读地跑一遍验收脚本,确认判断条件在当前状态下给出预期结果。
- 回滚只动出错的部分:网关检查失败只回滚网关,模型保持不动。
- 每次启动前先执行
reset-failed清除启动计数,并同时检查is-active和ready两个状态。
这件事的教训是:Agent 写的自动化脚本也是代码,它会在你看不到的地方执行。脚本里的判断条件,和业务代码一样需要先在真实状态下验证一遍。
二、没有证据的“已完成”
这类问题最常见,也最隐蔽,因为报告读起来完全合理。
移动端 SDK 项目的一份记录写着“某 PR 已合并”。实际上那个 PR 被关闭了,修改由另一个替代 PR 合并。同一个项目里,语音端点检测的配置值 800 毫秒被写成了“延迟指标”,而真机实测的端点耗时约 1.6 秒。配置值是输入参数,实测值才是结果。
云平台项目里,一份记录写着前端构建“已通过验收”。复查发现,依据只是流水线状态为成功,没有人打开页面检查。记录被改为“推断不成立”。同一个项目还有一条:构建时传入了国内区域的参数,不能说明 Dockerfile 真的用上了这些参数,要看构建产物。
反过来的例子也有。飞书工作流服务发布新版本时,我已经同意发布,但 Agent 在发布前自己检查了卡片回调的订阅配置,发现订阅列表是空的:此前卡片回调一直没有被真正验证过。它把这个问题报告出来,而不是拿“已经同意发布”当作完成。
这几次之后,报告里的结论都要附上证据所在的位置和级别(见上一篇),我检查报告时也优先看“依据是什么”,而不是“结论是什么”。
三、AI 代码审查门禁:从严格启用到移除
公司的 GitLab CI 曾经有一道 AI 代码审查门禁。它的设计相当严格:
- 审查完整的 diff,不截断;
- 发现中等及以上问题就阻止合并;
- 模型服务失败、输出不完整或审查结果过期,同样阻止合并;
- 确认是误报的问题,只能通过一份受保护、与问题哈希绑定的说明文件豁免,业务合并请求不能给自己豁免;
- 绕过门禁的权限只给维护者。
上线前用一个故意写了除零错误的合并请求测试过,门禁能拦住。规则里还有一句后来被反复引用的话:不要反复重试,直到模型恰好同意。
运行期间记录下来的代价主要有两类:模型服务超时或失败时,合并被卡住;误报需要走正式的豁免记录,比如测试代码里的一段哈希值被当成了密钥。10 月 8 日,这道门禁从所有项目的流程中移除,六个项目切换到不含 AI 任务的流水线模板,历史审查报告保留备查。
移除的只是 AI 审查这一项。单元测试、密钥扫描、受保护分支、生产环境手动发布和 Runner 隔离全部保留。它们的共同点是确定性:同样的输入总是得到同样的结论,失败时原因明确。
这件事让我对“用 AI 检查 AI”更谨慎:模型审查的结论本身也需要证据,它更适合作为提示,放在人审查之前,而不是作为阻止合并的硬门禁。
四、差点发布到公开页面的客户信息
作品集里的项目案例由多个会话维护。有一次,另一台电脑上的会话新增了两个案例并提交到博客仓库,其中一页的部署说明里写进了客户的生产域名,服务名里也带着客户名称的缩写。页面已经发布到线上。
作品集的源头仓库里有一份事实与表达规则,明确列出了不能出现在公开页面上的内容:客户名称、人员、服务器地址、域名、账号。但那个会话直接改了博客仓库,没有经过源头仓库,也就没有读到这份规则。
问题是在下一个会话更新这两个案例时发现的:它读完提交内容,在改写之前先做了一遍敏感信息扫描。修复包括改写文案、重命名页面地址、重画架构图、从服务器上移走旧页面文件,并把规则补充到源头仓库的记录里。
这件事说明规则写在哪里同样重要:只放在一个仓库里的规则,管不到绕过这个仓库的会话。公开内容的检查最好落在发布环节,而不是依赖每个会话都记得读某份文件。
还有几次小事
- 一次发布用的是带着未提交改动的工作区快照,导致线上版本和仓库里任何一个提交都对不上。从固定提交构建可以避免这种情况,博客现在的发布流程就是这样做的。
- 模型接入网关启用新模型时,SSH 中途断开触发了完整回滚;第二次尝试时,计费核对用错了字段,又触发一次回滚。两次回滚都按设计生效,修好原因以后再重试。回滚能正常工作,本身就是验证的一部分。
总结
四次问题里,Agent 都没有“违反规则”。它们出在判断条件写错、执行范围过宽、把弱信号当成结论,以及规则没有覆盖到所有入口。对应的改进也都不是更长的提示词,而是:先在真实状态下验证脚本的判断条件,缩小回滚和授权的范围,要求结论附带证据,把检查放在所有路径都必经的环节。
最后一篇回到最初的问题:哪些活该交给 Agent,哪些不该。
