
1. 为什么 AI coding agent 需要“眼睛”和“免疫系统”AI coding agent 这两年从“能补全一行代码”进化到“能独立完成一个模块”但真正把它放进生产流水线的人都会遇到同一个尴尬它跑起来像个黑盒。你给它一个任务它开始调用工具、读写文件、执行命令中间发生了什么、哪一步开始跑偏、为什么最后产出的代码编译不过全靠事后翻日志猜。更麻烦的是很多失败不是“报错”式的失败而是“静默跑偏”——它自信满满地改了一堆文件测试没跑或者跑了个假的测试然后告诉你“已完成”。这就是“可观测”和“自愈”这两个词被反复提起的原因。可观测解决的是“我看得见它在干什么”自愈解决的是“它跑偏了能自己拉回来”。前者是眼睛后者是免疫系统。没有眼睛免疫系统就是瞎打没有免疫系统眼睛只能看着它一路错到底。我自己的体会是给 agent 加可观测收益最大的不是调试阶段而是信任阶段。当你能清楚看到 agent 每一步的决策依据、工具调用参数、中间产物你才敢让它去碰真实仓库而不是只敢在玩具项目里玩。而自愈能力决定了它能不能从“一次性工具”变成“可托付的执行者”。这篇文章不聊某个具体框架的 API 怎么调而是把“可观测 自愈”这套思路拆开讲清楚开源社区里几种被验证过的做法以及我在实际搭建时踩过的坑。适合已经在用 AI coding agent、想把它往生产环境推的工程师也适合想自己造轮子的同学。2. 可观测到底要观测什么从“日志”到“决策轨迹”2.1 传统日志为什么不够用大多数人第一反应是“加日志”。但 agent 的日志和普通服务的日志完全不是一个东西。普通服务是确定性的输入 A走路径 B输出 C。agent 是概率性的同一个任务它这次调了read_file再edit_file下次可能先grep再read_file再edit_file路径不固定。如果你只打print式日志最后得到的是几千行“调用了工具 X参数 Y”根本看不出决策链条。真正有用的是三样东西决策轨迹它在每一步“想”了什么为什么选这个工具而不是那个。工具调用详情参数是什么、返回什么、耗时多少、有没有报错。状态快照每一步之后工作区文件、环境变量、git 状态变成了什么样。这三样合起来才叫“可观测”。缺了状态快照你看到它改了文件但不知道改之前是什么样没法回滚也没法对比。2.2 用结构化事件替代文本日志开源社区比较成熟的做法是把 agent 的每一步输出成结构化事件而不是纯文本。典型的事件类型包括事件类型含义关键字段thought模型的推理片段content, step_idtool_call发起工具调用tool_name, args, call_idtool_result工具返回call_id, output, error, durationstate_change工作区状态变化files_changed, git_diffdecision关键分支选择chosen, alternatives, reason有了结构化事件你就能做很多文本日志做不到的事按call_id把调用和结果配对、统计每个工具的成功率、还原任意一步的完整上下文、甚至把轨迹喂回给模型做自我复盘。我实测下来事件流用 JSONL 落盘是最省事的方案。每行一个事件追加写不阻塞主流程事后用jq或写个脚本就能分析。比直接上数据库轻量得多也比纯文本好解析。2.3 轨迹可视化别小看“看一眼”的价值结构化数据是给机器看的但人需要“看一眼就懂”。开源里常见的做法是做一个轻量的 Web 面板把事件流渲染成时间线左边是步骤序号中间是 thought 和 tool_call右边是状态变化。这里有个反直觉的经验可视化不需要做得很漂亮但一定要能“跳转”。比如你看到第 37 步测试失败了要能一键跳到第 37 步的完整上下文看到它当时读的文件内容、执行的命令、拿到的报错。我早期做过一个只有静态列表的面板排查效率极低因为每次都要手动翻。后来加了“按 call_id 折叠/展开”和“跳到上一步状态”排查时间直接砍半。提示轨迹里最容易被忽略但最有价值的是失败的工具调用。成功的调用大同小异失败的调用才暴露 agent 的认知盲区。建议在面板里把 error 事件高亮并且统计“同一类错误重复出现次数”。3. 自愈的三种层次重试、回滚、重规划3.1 最浅的自愈工具级重试这是最容易实现的也是收益最直接的。agent 调工具失败网络抖动、命令超时、文件被占用自动重试几次。听起来简单但有几个坑不是所有失败都该重试。语法错误、文件不存在这种确定性失败重试一百次也没用只会浪费 token。重试要带退避。连续快速重试容易把外部服务打挂指数退避是基本礼貌。重试要记录。同一个工具连续重试 3 次才成功这本身就是个信号说明环境不稳定值得告警。我的做法是给每个工具配一个retry_policy可重试错误类型、最大次数、退避策略。默认只对“瞬时错误”超时、连接重置重试确定性错误直接上报。3.2 中层的自愈状态回滚工具级重试解决不了“agent 改错了文件”这种问题。这时候需要状态回滚在每一步关键操作前打快照出错时回退到上一个干净状态。开源里常见的实现是基于 git 的快照。每完成一个“逻辑步骤”比如改完一个文件、跑完一次测试就git stash或git commit一次。出错时git reset --hard回到上一个快照。好处是天然有 diff、有历史坏处是频繁 commit 会污染仓库历史。更干净的做法是用独立的工作区快照把工作目录复制一份到临时区或者用 overlay 文件系统。但实现复杂度高不少。我自己的项目里用的是“轻量 git 分支”方案agent 在独立分支上工作每个逻辑步骤 commit 一次出错就 reset任务完成后再决定要不要合并。这样既不污染主分支又能享受 git 的 diff 和回滚能力。3.3 深层的自愈重规划回滚只能回到过去重规划才能走向未来。当 agent 发现“当前路径走不通”时能不能自己换一条路这需要 agent 具备自我评估能力在关键节点比如测试失败、连续两次工具调用无进展触发一次“复盘”让模型基于当前轨迹重新判断下一步。开源里比较务实的做法是设置触发条件而不是让模型每步都复盘那样 token 烧不起。常见的触发条件同一个错误连续出现 2 次以上连续 N 步没有产生任何文件变更测试从通过变成失败工具调用成功率低于阈值触发后把最近的轨迹摘要 当前状态喂给模型让它输出“继续 / 换方案 / 放弃”的决策。这里的关键是摘要要精炼不能把完整轨迹塞进去否则上下文爆炸。我一般只保留最近 10 步的 thought 和 tool_result 的摘要。注意重规划很容易变成“无限循环”——模型换个说法又走回老路。一定要设最大重规划次数超过就上报人工别让它自己耗到天荒地老。4. 开源思路拆解几种被验证过的架构模式4.1 事件总线模式解耦观测与执行这是目前最主流的思路。agent 核心只负责“决策 执行”所有观测数据通过事件总线可以是内存队列、Redis Stream、甚至简单的文件追加发出去由独立的消费者处理落盘、可视化、告警、触发自愈。好处是观测逻辑不侵入 agent 核心。你可以随时加一个新的消费者比如“统计 token 消耗”不用改 agent 代码。坏处是引入了额外组件对小型项目可能过重。我自己的项目里用的是“轻量事件总线”一个进程内的发布订阅 异步落盘。够用且没有外部依赖。等规模上来了再换 Redis 也不迟。4.2 检查点模式把“状态”当一等公民这个思路的核心是每一步都显式保存状态而不是依赖 agent 自己记住。状态包括工作区文件、环境变量、已执行命令的历史、当前任务进度。开源里常见的实现是定义一个Checkpoint结构包含files、env、history、progress四个字段每步序列化落盘。恢复时反序列化agent 从检查点继续。这个模式最大的价值是支持断点续跑。agent 跑到一半挂了进程崩溃、超时、人工中断下次能从检查点继续而不是从头再来。对于长任务比如重构一个模块这能省大量时间和 token。4.3 反馈闭环模式让 agent 自己“照镜子”这个思路更激进agent 不仅执行任务还要评估自己的执行结果并把评估结果作为下一步的输入。具体做法是引入一个独立的“评估器”可以是另一个模型调用也可以是一组规则在关键节点对 agent 的产出打分。比如代码改完后跑 lint 和测试把结果作为反馈文档写完后检查是否覆盖了所有要求点命令执行后检查退出码和输出是否符合预期评估结果如果不及格就触发重规划或回滚。这个模式的关键是评估标准要明确不能是“你觉得好不好”这种主观判断。最好是可执行的检查测试、lint、schema 校验。我踩过的一个坑是评估器太严格导致 agent 反复重试一个其实已经达标的结果。后来改成“分级评估”——硬性检查编译、测试必须过软性检查代码风格只警告不阻塞才稳定下来。5. 落地时的几个真实坑与应对5.1 观测数据本身把磁盘写爆这是最容易被忽略的坑。agent 跑一个长任务事件流可能几百 MB加上状态快照尤其是文件快照磁盘很快就满了。我见过一个项目因为没做清理跑了一晚上把磁盘写满导致整个流水线挂掉。应对方案事件流按天/按任务分文件设置保留天数状态快照只保留最近 N 个旧的压缩或删除大文件比如二进制产物不存快照只存 hash 和路径5.2 自愈逻辑自己出 bug自愈逻辑本身也是代码也会出 bug。最危险的是“回滚逻辑把不该回滚的东西回滚了”。我遇到过一次回滚时误删了 agent 刚生成但还没提交的产物导致任务永远无法完成。应对方案回滚前先 dry-run打印将要回滚的文件列表回滚操作本身也要记事件可追溯关键目录比如用户数据加入“禁止回滚”白名单5.3 观测带来的性能开销每步都落盘、都发事件会拖慢 agent。尤其是状态快照如果每步都全量复制文件开销巨大。应对方案事件落盘异步化不阻塞主流程状态快照用增量只存变化的文件而不是全量高频事件比如 thought可以采样低频关键事件tool_result、state_change全量5.4 轨迹太长模型复盘时上下文不够重规划需要把轨迹喂回模型但轨迹太长会超上下文。我试过直接截断结果模型看不到关键信息复盘质量很差。后来改成分层摘要最近 5 步保留完整 thought 和 tool_result5-20 步只保留 tool_name 和结果摘要20 步以上只保留“做了什么”的一句话。这样既控制了长度又保留了关键信息。6. 从“能跑”到“敢用”我的实践顺序建议如果你现在手上有一个能跑的 agent想加可观测和自愈我建议按这个顺序来别一上来就搞全套第一步先加结构化事件流。不用做可视化先保证每步都有 JSONL 落盘。这一步成本最低收益最直接——至少你能事后分析了。第二步加工具级重试。给每个工具配重试策略处理瞬时错误。这一步能解决大部分“偶发失败”。第三步加状态快照和回滚。用 git 分支或轻量快照保证出错能回到干净状态。这一步是自愈的基础。第四步加轨迹可视化。做一个能跳转的轻量面板排查效率会质变。第五步加重规划。这是最复杂的一步需要触发条件、摘要策略、最大次数限制都调好。建议前四步稳定运行一段时间后再上。第六步加评估闭环。引入独立的评估器让 agent 能自我判断。这一步对任务类型有要求不是所有场景都适合。这个顺序的逻辑是先能看见再能恢复最后能自主。跳过前面直接搞自主大概率是灾难。7. 一个容易被忽视的点可观测数据本身就是资产大多数人把可观测数据当“调试用的临时产物”用完就删。但我发现这些轨迹数据本身是很有价值的资产。比如训练数据成功的轨迹可以用来微调模型让它学会更好的决策路径评测集失败的轨迹可以整理成回归测试集验证新版本有没有修复老问题模式发现统计大量轨迹能发现 agent 的常见错误模式指导 prompt 优化我自己的项目里会把“成功完成且评估通过”的轨迹单独归档定期拿出来分析。有一次发现 agent 在“读文件”这一步平均要调 3 次才拿到想要的内容后来优化了工具描述直接降到 1.2 次。这种优化靠拍脑袋是想不出来的必须靠数据。所以别把可观测当负担它其实是在给你的 agent 攒“经验值”。跑得越多数据越厚后续优化的空间越大。8. 关于开源选型的几句实在话最后聊几句选型。开源社区里做 agent 可观测的项目不少但选的时候别只看 star 数。我的判断标准是三条第一事件模型是不是开放的。如果它把事件格式锁死在自己的 SDK 里你后续想接自己的分析工具就很痛苦。优先选事件格式简单、可扩展的。第二自愈逻辑是不是可插拔的。重试、回滚、重规划应该是独立模块能单独开关、单独替换。如果全揉在一起调起来很累。第三有没有“最小可用”的示例。很多项目文档写得很全但跑起来一堆依赖。优先选那种“clone 下来改两行就能跑”的学习成本低。至于具体用哪个我的建议是先自己写一个最小版本。事件流 简单重试 git 回滚加起来可能就几百行。跑通了再考虑要不要换成熟框架。因为只有自己写过才知道哪些抽象是必要的哪些是过度设计。直接上框架很容易被它的设计带着走反而看不清自己真正需要什么。这套东西我断断续续搭了小半年最大的感受是可观测和自愈不是“加个功能”而是改变你和 agent 的关系。从“我盯着它干活”变成“我信任它干活出问题能查、能恢复”。这个转变一旦完成agent 才真正从玩具变成工具。