寒 DATA VAULT数据仓
EN / 中
CAP II · № 008
DATA WAREHOUSE · AI · AUDIT
— · — UTC
DATA VAULT
CAPITULUM · II

On the Cold Eye冷眼 — 为什么必须让 AI 审 AI

№ 008 · 2026.04.26 · AI · AUDIT · 3,400 字 · 14 MIN

上一篇 (№ 007) 我提到, 一个 23-bug 的 plan 经过 Claude 自审 3 轮"收敛"后, 又被独立的 Codex 外审 6 轮拎出 60+ 个问题。这一篇专门讲为什么会这样, 以及怎么把它做成纪律。

这件事的本质, 不是 "AI 不够聪明", 是 结构性的。

一个 agent 的心智, 会被自己的方案污染

主 agent 在写 plan 的过程中, 已经把自己的假设嵌进去了。等它回头审自己的 plan, 看到的不是"这份方案", 而是"我心里的那份方案"。

这种心智污染有几个具体表现:

它倾向于相信自己写过的东西。 "我前面写了这个函数 transactional, 后面继续这么用就好了" — 但前面那个判断本身就可能是错的。

它倾向于看到自己想看到的。 一段代码, 它眼里只有"这部分支持我的方案"的部分, 看不到旁边那段会推翻方案的代码。

它倾向于"差不多就行"。 一旦它觉得方案大致 work, 就会停止深挖, 进入收尾节奏。

这不是 LLM 特有的毛病, 人类工程师也有。区别只在于 — 我们写代码 review 工具, 是为了让另一双眼睛看; 让 AI 审 AI, 是同一个道理。

7 类结构化盲点

过去几个月跑下来, 我把 Claude 自审漏掉的问题归了几类。这些不是 random bug, 是 结构化的 — 也就是说, 它们会反复出现, 而且我们能针对性补上。

① Commit 位置误判。Agent 在 50-100 行 Read 窗口里把"某处有 commit()" 当作函数自己 transactional, 实际是外层调用方在 commit, 里面那个是测试残留。

② 调用方数量目测。"这个改动影响 17 处调用方", 实际 grep -c 之后是 22 处。听起来差不多, 但漏掉的 5 处往往就是 bug 出处。

③ 凭训练数据编 API。最危险的一类。Agent 会写 "调用 WalletLockResponse.history_id" — 这个字段听起来合理, 但代码里不存在。它是从训练数据里幻想出来的、看起来对的、不存在的东西。

④ 特征对象 / 文件名幻想。"backfill 文件 001_init.sql" — 实际 sql/ 目录从 008 起步。"auto_accept_trade 在 trading.listings" — 实际在 user.profiles。Agent 凭直觉编, ls 一下穿帮。

⑤ 大小写 / 枚举错配。Python enum 实际是 lock_for_trading, plan 里反手写成 LOCK_FOR_TRADING。CHECK 约束一上线立刻报错 rollback。

⑥ 状态机自相矛盾。这一段说"去 LOCK_ATTEMPTED 状态", 那一段还引用 LOCK_ATTEMPTED。Plan 作者不会跨段落对账, 但代码上线那天就要踩坑。

⑦ 架构级时序。单次 Read 看不出跨服务调用在事务中的先后顺序是否会引起不一致。这一类最隐蔽, 因为它需要"在脑子里跑一遍"才能发现, 而 LLM 的"跑一遍"非常容易跳步。

这 7 类我现在都列在团队的 PITFALLS 文档里, 每次跑外审之前先把它当 checklist 喂给 Codex。

独立 context 是怎么补上盲点的

关键词 — 独立, 不信任, 实查。

独立: Codex 是新会话, 零记忆。它没看过这份 plan 是怎么形成的, 也没参与过哪一段争论。它读 plan 的方式跟读一份陌生论文一样 — 每个论断都需要证据。

不信任: 它不信 plan 里"我们之前讨论过这个所以"这种叙述。也不信"显然 X 是这样"这种省略。它要看到 file:line。

实查: 它不只看文档, 还跑命令。grep / Read / MCP DB query — 一切结论都要现场验证, 不靠记忆和直觉。

文档可能跟现网漂移 (历史 migration drift / 部署遗漏), MCP 实查现网 schema 是唯一权威。

这一条尤其关键。我们写 plan 的时候, 经常默认"代码就是文档说的那样"。但实际上, 代码每天在变, 文档可能两个月没更新, schema 可能因为某次 hotfix migration 漂移过。

这种情况下, 唯一靠谱的做法是 — 问数据库。MCP 工具直接连进生产 schema, SELECT 一下表结构 / CHECK 约束 / 索引, 看到的就是真相。

EVT-20260427-001 那次, audit-agent 用 MCP 实查发现了一个 plan 6 轮外审 + 3 轮自审都没暴露的问题: 邮件 dispatch 函数里硬编码了一个旧的通知类型枚举, 跟 phase 3.3 新增的类型不匹配。这个问题如果没被发现, 上线那天每个新订单都会 dispatch 失败 — 但因为是异步的, 用户看不到, 只在日志里默默堆积。

这就是"心智污染"看不到的盲区, 也是独立 context + 实查能精确补上的地方。

实操: /audit 必须独立 context 跑

我现在跑 /audit 的硬规则有两条:

1. 必须用独立 agent 跑。 用 Agent(subagent_type='general-purpose', run_in_background:true) 启动, 在 background 跑避免污染主 agent context。主 agent 已经看过 plan + research + 实施代码, 心智已经被污染, 不可能客观。

2. 必须有 MCP 实查工具。 audit-agent 必须能直接查现网 DB schema (mcp__ggboys-deploy__tool_db_query), 不能纯文档 + grep。

给 audit-agent 的 prompt 包含一份明确的"必查清单":

· 安全 (注入 / 权限 / 敏感字段日志)

· 正确性 (业务逻辑 / 状态机 / 边界)

· 健壮性 (异常 / 重试 / 幂等)

· 安装可用 (migration / 配置 / 依赖)

· 文档自洽 (文档 vs 代码漂移)

· 跨文件一致 (字段名 / 枚举值)

· 性能 (N+1 / 索引 / 锁)

· 全局 (架构级影响)

输出结构化报告: 严重度 (CRITICAL / HIGH / MEDIUM / LOW / INFO) + 文件:行号 + 修复建议。

规则: HIGH 必须修后才能部署 prod。MEDIUM/LOW 标 phase 4 followup。

两种审查的本质差异

把 Claude 自审 vs Codex 外审做个对照, 差异是结构性的:

Claude 自审 — 热上下文 / 信自己的方案 / 倾向"差不多就行" / 容易 anchor 在自己的思路。

Codex 外审 — 冷眼 / 不信任何外部叙述 / 每条结论都 grep 现网代码 / 不怕打脸 / 每轮新会话零记忆独立性。

所以你看到的现象是: Claude 自审 3 轮就开始声明"收敛", Codex 第 1 轮立刻找出 4 个 blocker, 而且 每一轮都能找出新问题, 一直到第 5-6 轮边际收益才递减。

这不是 Codex 比 Claude 强。换过来, 让 Codex 写 plan 让 Claude 审, 大概率结果是镜像的 — 因为本质在于"独立"两个字, 不在于哪个模型更牛。

这件事意外的哲学

我最早遇到这种现象的时候, 第一反应是沮丧 — "我用了一个号称很强的 AI, 它居然连自己的方案都审不准?"

但跑得多了反而平静了下来。AI 的盲点是 结构化的, 不是 random — 这其实是好消息。

结构化意味着可以被流程化补上。我现在的 workflow 是:

research → makeplan → annotationloop 自审 → 一轮 broad Codex 外审 → 处理批注 → 必要时 focused / final-go-check 外审 → 实施 → /audit 独立审查 → 部署。

这条链每加一节, 都是为了堵一类已知的盲点。它看起来繁琐, 但比起线上事故的代价, 几乎是白送。

更深一层 — 这件事让我对 AI 的边界有了新的理解。AI 不是"一个会写代码的全能助手", 它是 一组能在不同角色下发挥不同强项的工具。同一个模型, 让它写, 它会写出某种风格的代码 + 某种类型的盲点; 让它审, 它能看到一些自己写时看不到的东西。

把它放对位置, 比让它做更多事重要得多。


下一篇 (№ 009) 写关于 AI 工作记忆的工程笔记 — 怎么让 AI 记住你, 不是技术问题, 是协作纪律问题。

保持冷静, 继续向前.

「不 识 庐 山 真 面 目, 只 缘 身 在 此 山 中」

苏 轼 · 题 西 林 壁
Xinghan's Memory · Written by CC/Codex
— end of cap. II —