本文是「AI 效能」系列的第七篇。前面几篇分别讨论了流程边界、工作区初始化、自动链编排与代理记忆;这一篇讨论自动链出错之后,怎么自己发现、归因和修复。
自动化系统有一个很容易被完成率掩盖的问题:任务都能跑完,人却越来越忙。
一条能自动生成需求、修改代码、执行测试的流水线,最终可以把每个任务推到完成状态。但把人工排障记录摊开,大部分时间并不在写代码,而在回答两个问题:这次失败算谁的?外部状态怎么对回来?剩下才是修系统本身的缺陷。
这意味着,继续增强生成能力,边际收益有限。真正缺的是一个能发现、归因、修复并验证系统自身缺陷的角色。我们把它叫作 AI 看门狗(AI Watchdog)。下文把这条自动生成需求、修改代码、执行测试的闭环称为 AI Loop。
需要先说明边界:本文讨论的不是监控大盘,而是一套面向 AI 自动化系统的自愈设计。它仍然需要人工兜底,尤其在高风险变更上。它适合已经稳定跑通自动化闭环、但人工诊断成本高的团队;不适合任务量太小、没有可观测性、没有测试与回滚能力的团队。
一句话设计
先把失败聚合成可归因的 incident,再用确定性守卫拦住已知错误;
只让模型回答“算谁的”和“怎么改”;
修复经过白名单、校验、观察窗与回滚,才算完成。
一、瓶颈不在生成,而在判断
自动化系统最容易衡量的指标是完成率:任务有没有完成、产物有没有生成、流水线有没有跑完。但这些指标只能证明系统能跑,不能证明系统跑得省心。
人工动作通常集中在三件事:
| 人工动作 | 典型问题 | 能否规则化 |
|---|---|---|
| 判断归属 | 这次失败是上游输入、编排逻辑、执行环境还是外部依赖 | 大部分可以 |
| 对齐状态 | 外部资源、分支、变更清单、状态看板是否一致 | 可以 |
| 修复系统 | 提示词、契约、代码、配置需要改哪里 | 一部分可以 |
第 1、2 件事有明确的规则,适合交给确定性代码;第 3 件事高频但风险分层明显,适合让模型提出最小改动,再由安全协议兜底。
生成能力决定系统能不能跑,诊断能力决定系统跑得贵不贵。
二、先降噪,再谈智能
自动化系统的问题不是没有信号,而是信号被噪音淹没。
最常见的噪音有两类:一类是重试风暴,例如同一批通知收件人解析失败后反复重试;另一类是状态冲突,例如上游状态重复上报,每次都返回冲突。它们数量大、原因单一、长期存在,却因为“非阻塞”既没人修,也没人被提醒。
如果告警系统把每次失败都原样吐出来,人只会学会忽略它。
降噪不是隐藏事件,而是把同一根因的 N 次失败折叠成一条有次数的 incident。告警的价值不取决于覆盖多少事件,而取决于人是否还愿意看。
三、复盘:最贵的不是改错代码
把人工排障记录按根因聚类,问题通常集中在几个方向:
| 聚类 | 典型表现 | 主要责任方 |
|---|---|---|
| 资源与分支生命周期 | 外部资源被清空、分支漂移、重建失败 | 编排代码 |
| 交接契约 | Agent 之间传递的结构化产物不稳定、判定端只认一种写法 | 提示词与配置、编排代码 |
| 错误信息 | 只告诉人“被阻断”,不说具体缺什么 | 编排代码 |
| 上游输入 | 目标错配、验收口径矛盾 | 上游 |
| 环境与外部依赖 | 共享环境被污染、依赖源缺失 | 环境或外部 |
| 合并与发布 | 依赖降级、整文件回退、提交范围失控 | 编排代码与配置 |
其中最贵的不是单点错误,而是连锁反应。
一个典型故障链是:外部资源(例如发布计划、环境、任务看板)被清空 → 恢复时重建出新的分支 → 工作副本仍停在旧分支 → 仓库准备失败 → 再次阻断。每一步其实都有补丁,但没有任何一处对“资源集合突然变小”做断言。补丁在止血,系统没有记忆。
另一类高频问题是格式问题判死业务。同一个交接字段,生成端写成字符串,判定端只认对象;或者结论被换行后解析不到。生成端没有自检,判定端只认一种写法,于是同一个契约问题会在多个任务上反复复发。
第三类是错误信息不可执行。只告诉人“质量判定为阻断”,却不给具体缺失项、文件或规则,人只能先复现再猜。不可执行的归因,等于没有归因。
这些现象指向同一个结论:先修证据,再修代码。历史事故里最贵的部分,往往不是 AI 改错了代码,而是证据没有对齐。
所以成熟的自愈系统,第一层一定是确定性守卫,而不是让模型直接改代码。
四、Incident 不是一次失败
传统监控按事件记录:某时某刻某个任务失败了。自愈系统按根因记录:
incident 是一个可归因的根因,不是一次失败,也不是一个任务。
同一根因跨任务只保留一条,用 signature 去重:
signature = hash(resultCode | node | action | normalizedReason | component)
归一化时要去掉时间戳、提交哈希、分支名、绝对路径和任务 ID,只保留阶段、动作、错误码、归一化后的原因和组件。
| 设计 | 原因 |
|---|---|
| 包含阶段与动作 | 同一个错误码在开发和测试阶段是两件事 |
| 包含组件 | 同一个错误在不同模块是两处契约 |
| 不包含任务 ID | 否则同一个 bug 每个任务一条,失去聚合意义 |
效果是,同一类交接产物错误跨多个任务复发,只留一条 incident,计数递增;上游状态冲突重复出现,也只留一条;外部资源集合被清空,同样只留一条。
一条 incident 记录的不是“某个任务又挂了”,而是“某类契约在某个阶段反复写错,已经跨多个任务发生”。
状态机如下:
stateDiagram-v2
state "无需修复" as skipped
[*] --> new
new --> triaged: 归因完成
triaged --> fixing: 开始修复
triaged --> skipped: 非系统问题
fixing --> verifying: 校验通过
verifying --> observing: 重载与健康检查通过
observing --> closed: 观察窗零复发
observing --> fused: 同签名复发
fixing --> fused: 连续修复失败
closed --> new: 复发后重新打开
fused --> [*]: 仅人工解除
台账只增不删。关闭后的记录归档保留,熔断和放弃的记录长期保留,因为它们的复盘价值最高。
台账不是日志,是待办。
五、架构:确定性骨架,两处过模型
| 维度 | 传统看门狗 | AI 看门狗 |
|---|---|---|
| 职责 | 监控与告警,出了问题叫人 | 监控 → 归因 → 修复 → 验证 → 发布 → 回滚 |
| 动作 | 记录指标、发通知,最多重启进程 | 改代码或配置,跑测试与构建,重载进程 |
| 判断 | 阈值规则 | 确定性守卫 + 结构化模型归因 |
| 交付物 | 告警 | incident 台账,含证据、修复分支、提交与回滚点 |
| 失败处理 | 继续告警 | 观察窗内复发自动回滚与熔断,转人工 |
AI 看门狗是独立进程,对主系统只有两条影响通道:改代码仓库,以及重载进程。它不共享主系统的内存,不直接写业务表,只维护自己的 incident 台账。
它还要求单实例:启动时抢锁,抢不到就只读运行,避免两个看门狗同时修同一套代码。
| 模块 | 类型 | 职责 |
|---|---|---|
| 采集 | 确定性 | 任务状态、事件数据、日志、健康检查 |
| 签名 | 确定性 | 归一化、去重、聚合 |
| 归因 | 模型 | 判断归属、组件、置信度与证据 |
| 守卫 | 确定性 | 四类断言 |
| 修复 | 模型 | 在独立工作区写最小改动,读回修复报告 |
| 发布 | 确定性 | 校验、等待空闲、合并、构建、重载、观察、回滚 |
| 策略 | 确定性 | 白名单、预算、并发、熔断、风险分级 |
| 接口 | 确定性 | 健康、台账、手动触发 |
数据流:
flowchart LR
C[采集] --> S[签名] --> T[归因] --> G[守卫]
G --> R[修复] --> V[校验] --> D[发布] --> O[观察] --> X[关闭]
G --> H[人工提案]
只有两处过模型:
- 归因:输入是固定证据包,输出是归属、组件、置信度与证据,不自由生成;置信度低于阈值只提案,不自动修。
- 修复:写出最小改动,受白名单、必须补测试、产物格式三重约束。
模型失败时,归因降级为未知,只落台账、只提案。模型不能绕过守卫:守卫产生的阻断不经过模型判断。
路由也不交给模型。节点推进与返工去向仍由确定性状态机负责,模型只回答“算谁的”和“怎么改”。
修复模块复用现有执行服务的工作区、会话、中断与产物读取能力,不自建第二个运行时。
六、四类守卫
守卫全部是确定性代码。前三类落在动作现场,第四类落在跨任务视图。
三方对账
分支是事实,变更清单是声明,发布目标是落地位置。三者对不上,就在动作前拦下。
| 条件 | 结论 |
|---|---|
| 分支有改动、清单缺文件 | 清单过期,列出缺失文件 |
| 清单有文件、分支无改动 | 清单有幽灵条目 |
| 工作副本分支不等于发布目标分支 | 分支漂移,附两个分支名 |
| 三者一致 | 通过 |
不可逆动作快照
动作前后各拍一张照:外部资源集合、状态看板、配置集合、变更目录、流水线数量。
| 条件 | 结论 |
|---|---|
| 资源集合变小且不是人工确认的结束状态 | 高危,立即告警 |
| 工作流阶段已回退,外部状态超过窗口未同步 | 状态过期 |
| 展开的配置数大于变更目录数 | 过度展开 |
| 交付输入为空但任务声明了配置 | 输入丢失 |
合并产物体检
| 检查 | 规则 |
|---|---|
| 依赖版本只升不降 | 目标分支原依赖版本降低即拒绝 |
| 目标文件不许整段回退 | 删除行数超过阈值且不在声明范围内即拒绝 |
| 提交范围 | 合并提交涉及文件必须落在声明集合内 |
| 工作区状态 | HEAD 在目标分支、无未合并文件、无 Git 写操作残留 |
重复失败熔断
- 同一 signature 在 24 小时内出现 2 次即升级;
- 同一任务同一错误码连续 2 次即暂停并通知;
- 观察窗内同签名再次出现,直接熔断并回滚。
很多事故不是第一次没发现,而是连续挂了几次才被人看见。等失败计数达到上限已经太晚。
分工,而不是重复
| 守卫 | 落点 | 理由 |
|---|---|---|
| 对账 | 动作前 | 现场才有上下文,能当场给可读结论 |
| 快照 | 动作前后 | 事后巡检只能发现“已经晚了” |
| 产物体检 | 推送前 | 必须在发布前拦 |
| 熔断 | 跨任务视图 | 单个业务侧没有全局视图 |
看门狗对前三类只做复核,不重写判据。两套逻辑各自演化,迟早会漂移。
七、自动修复的安全协议
让一个 AI 去改正在运行它的系统,安全不是附加项,而是产品本身。
隔离。 修复在独立的 Git 工作树里做,一个 incident 一个分支,同时只允许一个修复在飞,绝不在部署目录里直接改。
白名单。 只允许改业务源码、测试、提示词、技能配置和文档;禁止碰对外契约、状态解析、环境变量、依赖锁文件、数据库结构、凭据、镜像和看门狗自身代码。白名单在代码里硬编码,不由模型或配置决定。
校验。 按受影响模块执行类型检查、单测和构建,任一失败即丢弃分支。行为变更必须同时新增或修改测试,不允许只改测试不改逻辑。
发布。 部署目录必须干净;修复分支快进合并到主干;重新构建;等待主系统空闲;按依赖顺序重载进程;健康检查通过后记录重载前后的版本。
等待空闲的意义:重载会让正在跑的任务在节点边界重跑一轮,白烧一次模型调用;空闲窗口重载成本为零。
观察窗。 重载成功后进入一段观察期。同签名再次出现,或同组件出现新的高优先级 incident,自动回滚并熔断;其他新 incident 只记录。零复发才算关闭。
回滚。 回到重载前的版本,重新构建,按顺序重载,健康检查。回滚必须能在分钟级完成,不含构建时间。
熔断。 同一 incident 连续修复失败、发生一次回滚、当日自动修复次数达到上限、健康检查连续失败、部署目录不干净或无法快进,都会停止自动修复并转人工。熔断状态持久化,重启后仍然有效。
| 级别 | 条件 | 处理方式 |
|---|---|---|
| 自动 | 命中白名单、校验通过、置信度足够、非自身代码、非契约或数据结构 | 自动执行,事后通知 |
| 确认 | 命中白名单但涉及依赖、配置、跨模块契约,或置信度不足 | 人工一键确认 |
| 人工 | 契约、状态解析、对外接口、数据结构、凭据、看门狗自身 | 人工实现 |
看门狗自己的代码永远走人工。修自己的系统,必须先假设它会犯错。
每次动作都追加到 incident 的动作记录,同时写一份修复报告。数据库负责查询,文件负责脱离数据库复盘。
三个开关相互独立:总开关控制是否采集与修复,自动修复开关控制是否动代码与进程,演练模式让校验与发布全部走过场。
八、先证明看得见,再证明修得对
第一阶段不要打开自动修复。只做采集、聚合、归因、守卫和台账,自动修复开关保持关闭,发布流程用演练模式。
| 验证项 | 通过标准 |
|---|---|
| incident 聚合 | 同一根因跨任务只留一条,计数正确 |
| 降噪 | 重复噪音折叠后不丢真实失败 |
| 重复失败升级 | 同签名第二次出现即升级 |
| 健康检查 | 不误报正常服务 |
| 台账 | 证据、状态、动作可追溯 |
上线后不要只看自动修复率。修复率高但复发率高,说明系统在制造新的不稳定;修复率低但归因覆盖率高,至少说明人已经不用从头查。
| 指标 | 说明 |
|---|---|
| 归因覆盖率 | 有明确归属结论的 incident 占比 |
| 动作前拦截率 | 已知不一致在不可逆动作前被拦下的比例 |
| 自动修复率 | 自动化系统自身问题中被自动修复的比例 |
| 复发率 | 自动修复后观察窗内同签名再次出现的比例 |
| 噪音下降 | 重复事件折叠后告警量的下降幅度 |
诊断能力稳定之后,再分两步打开修复:先修低风险的提示词与配置,这类改动通常不需要重载进程;再修代码,这时才需要完整的校验、等待空闲、重载、观察窗和回滚。
怎么开始
- 先把失败事件按根因聚合,建 incident 台账。
- 给已知错误写确定性守卫,优先放在不可逆动作前后。
- 只让模型做归因和最小修复,守卫不经过模型。
- 修复流程先关掉自动执行,用演练模式跑校验、发布和回滚。
- 观察窗零复发后,再逐步打开低风险修复。
验收标准:同一根因只留一条 incident;已知不一致在动作前被拦;自动修复后观察窗内同签名零复发。
先证明看得见,再证明修得对。
九、适用边界
自愈系统不是所有团队都需要。
| 适合 | 不适合 |
|---|---|
| 自动化闭环已经稳定跑通,但人工诊断成本高 | 任务量太小,人工排障更便宜 |
| 同类失败跨任务复发 | 没有基本的可观测性 |
| 有测试、构建、发布流水线 | 没有自动化测试与回滚能力 |
| 能接受人工处理高风险变更 | 高风险领域且不允许自动变更 |
自愈不是零人工,而是把人的动作从逐条排障变成处理升级与高风险提案。
十、几个关键判断
降噪先于告警。 不聚合的通知系统,最终会训练人忽略所有通知。
守卫优先于修复。 能用断言解决的事情,不要动用模型。模型只负责“算谁的”和“怎么改”。
按根因聚合,不按失败记录。 按失败记录只能得到日志,按根因聚合才能得到待办。
修复的终点是观察窗,不是合并。 合并成功只代表代码进去了,零复发才代表问题解决了。
不能自伤,也不能阻塞。 看门狗挂了,主流程必须照常运行;看门狗自己的代码,永远走人工。
分工优于统一。 动作现场负责拦截,跨任务视图负责聚合与归因。把两类逻辑塞进一个地方,只会得到一套难以维护的判据。
先证明看得见,再证明修得对。 诊断没跑通之前,不要打开自动修复。
十一、结语
传统看门狗保证系统活着。AI 看门狗要保证系统犯错之后,能自己发现、自己纠正,并且下一次不再犯同样的错。
自动化解决的是执行成本,自愈解决的是维护成本。后者才是自动化能不能长期跑下去的分水岭。