寒 DATA VAULT数据仓
EN / 中
CAP XIV · № 014
DATA WAREHOUSE · AI · SYSTEM
— · — UTC
DATA VAULT
CAPITULUM · XIV

On Plans as Hypotheses计划不是证据 · 只是一台很会说服人的路由器

№ 014 · 2026.04.29 · AI · SYSTEM · 3,200 字 · 13 MIN

有一份方案, 把一个修复讲得干净利落: 问题定位清楚, 改动列得明白, 风险标在该标的地方, 末尾还跟着"已修正""已收敛"这种让人想直接点头的词。我读完差点就放行了。

幸好没有。后来真有人把那段被声称"已经覆盖"的代码从头读了一遍, 才发现它写的根本不是方案描述的那回事 —— 它从设计上就只做核对, 不会主动去推进那个关键动作。方案里那条"插一条记录, 等后台来接手"的路, 实际上没人会接, 那笔本该回滚的资源永远回不来。

那份方案没撒谎。它只是把"我认为按这个思路应该能修好", 写成了"已修正"。中间少掉的那一层, 是现实摩擦。从那以后我给自己定了一条规矩: 方案永远只能是假设, 不能是证据。 它可以告诉我下一步去哪里找证据, 但不能自己充当证据。

方案的天赋是叙事, 不是证明

模型生成方案的能力确实强, 因为它本质上擅长把零散信息组织成连贯叙事。"我准备改这几处"会被写成一条清晰的路线, "我觉得风险在这里"会被写成一段稳重的判断, "我已经检查过"会被写成一个让人安心的完成状态。读起来像一份已经做完的工程复盘。

但工程事实不是叙事决定的。一个字段有没有被校验, 不取决于方案里有没有写"增加校验"; 一个后台任务会不会误删数据, 不取决于方案里有没有写"加了保护"; 一个登录态会不会错乱, 不取决于构建日志是不是绿的。

工程事实有它自己的位置。它在某一行代码里, 在数据库的某条记录里, 在浏览器真实渲染出来的那个页面里, 在一个真实请求穿过整个系统之后留下的痕迹里。这些位置, 方案碰不到, 只能指。

所以我现在拿到一份方案, 第一反应不是"这份方案合不合理", 而是问: 它把我路由到了哪几个我能亲自去看的位置?

"已修正"不是状态, 是一句声明

协作里有三个词特别容易让人松手: "已修正""已解决""已收敛"。

在人和人之间, 这三个词背后有一层社会承诺。一个工程师跟你说"已修正", 你默认他至少编译过、看过、跑过一遍。模型说"已修正", 它表达的只是当前这段上下文里推理出来的结论, 不是世界的状态。这两者听起来一样, 可靠性差着一个数量级。

这不是它在骗人。它只是把"按这份改动, 推理上应该能修好"压缩成了两个字"已修正", 压缩的过程里, 那层和现实碰撞的摩擦被丢掉了。

我后来干脆把这类词全部翻译回它的原形:

已修正  = 一句修正声明, 去找对应的代码证据
已解决  = 一句解决声明, 去找对应的运行时证据
已收敛  = 一句收敛声明, 去找对应的边界条件证据

这个翻译动作很小, 但出奇有效。它不改任何技术内容, 只是把那点情绪上的安全感摘掉, 剩下的就只有一件事: 下一步该去哪验。

证据分三层: 代码、本地、活着的系统

我现在验一份方案, 会把证据分成三层, 一层比一层贵, 也一层比一层硬。

第一层是代码事实。 打开那个具体的文件, 那个具体的函数, 那个具体的条件分支。不要让方案替你说"这里已经覆盖了", 要自己看那一行到底覆盖没覆盖。这一层最怕泛读 —— 模型很擅长把一个局部的小改动, 讲成一次贯穿全链路的修复, 而泛读的人会信。前面那个差点放行的方案, 栽的就是没人下到这一层, 直到有人真的从头读那段代码, 藏着的假设才露出来。

第二层是本地事实。 在能控制的环境里跑最窄的那个验证: 一次类型检查, 一个单测, 一段脚本, 一次最小复现。它只证明一件事 —— 这条路径在受控条件下不会立刻坏掉。它不证明线上没事。

第三层是活着的系统。 对前端是真实浏览器, 对交易是真实的数据库和状态机, 对部署是测试或生产环境里一条真请求走完的链路。很多问题只在这一层才现形: 缓存、会话、网关、容器里的环境变量、定时任务的时间窗、几个月前留下的老数据形状。这些东西, 前两层永远照不到。

这三层不是每次都得全跑。改动很窄, 到第一层或第二层就够了。但只要它碰到用户资产、身份态、钱、库存、会自己写数据的后台任务, 第三层就不再是锦上添花, 它就是唯一的事实来源。

独立外审的价值不是更聪明, 是更冷

我一开始以为"让一个模型去审另一个模型"的价值, 在于换的那个可能更聪明。后来发现完全不是。真正的价值是它冷。

主实施那一方写了方案、读了代码、改了文件、跑了测试, 它会一点点把自己走的这条路当成天经地义的路。它知道自己为什么这么改, 也记得自己已经在哪些地方使过劲。这些上下文会沉淀成一种很软的惯性: 它更容易相信自己的修复已经盖住了问题, 因为它太清楚自己努力过了。

一个不共享这段上下文的外部审查者没有这笔情感债。它只看到两样东西: 声明, 和证据。它不会因为"这个方案前面已经讨论很久了"就调低怀疑, 也不会因为"刚才已经修过一轮了"就默认剩下都是小毛病。我见过它一上来就把被反复确认过的判断推翻, 因为它根本不知道那个判断被确认过几次, 它只去现网代码里数了一遍, 发现对不上。

这种冷不是敌意, 是把叙事的黏性撕掉。它把判断从"我理解你这一路有多不容易"硬拉回到"事实到底成不成立"。这件事自己审自己永远做不到, 不是能力问题, 是位置问题 —— 你站在自己的上下文里, 没法假装没读过它。也正因为这样, 这个外部审查必须和实施方物理隔离: 它做独立判断的时候, 手里不能预先攥着实施方的结论, 否则它读到的那一刻, 独立性就已经没了。

GO、小修、阻塞, 是工程语言

另一个慢慢长出来的习惯, 是把审查结论压成三个词: GO、小修、阻塞。

这不是为了显得果断, 是为了不让讨论无限发散。

GO 不是说完美, 是说当前的风险落在能接受的范围里, 可以进下一阶段。小修 是说有真问题, 但不动主路径, 修完不需要重新设计。阻塞 是说再往前走, 会把一个错误的状态带进更贵的阶段 —— 越晚发现, 回滚越疼。

这个三分法对模型协作格外有用, 因为模型很容易给你一长串"建议", 一条接一条, 都挺有道理。建议一多, 人就丢了优先级, 开始在细节里打转。先把结论钉成这三个词里的一个, 后面所有细节就都得服从同一个问题: 这件事到底挡不挡下一步。挡, 就是阻塞, 别的都不重要; 不挡, 那它就是小修, 别拿它拖住主线。

方案是路由器, 不是法官

如果这篇只能留一句, 我会留这句: 方案是路由器, 不是法官。

路由器的活, 是把流量送到对的地方。一份方案该干的也是这个 —— 告诉我去哪个文件、看哪个条件、跑哪个验证、查哪条数据、打开哪个页面。它做得好不好, 看的是它指的那些地方准不准, 不是它的故事讲得圆不圆。

法官的活是下结论。这个权力不能交给方案。结论只能从那条三层证据链里长出来, 别的来源一概不算。

这件事看着像是改了一道协作流程, 其实改的是读东西的姿势。以前我读一份方案, 是在掂量"它聪不聪明"; 现在我读一份方案, 是在掂量"它有没有把我送到事实跟前"。一份指不到事实的方案, 写得再完整, 也只是一篇文学; 一份能精准指到事实的方案, 哪怕短得只剩几行, 也够进工程了。

与其让模型更强, 不如让事实更近

很多人把协作里出的问题归到模型能力上: 换个更强的, 开个更大的上下文窗口, 写个更复杂的指令。这条路不能说没用, 但我越来越觉得, 真正改结果的是另一件事 —— 让事实离协作更近。

把仓库结构写清楚, 把验证命令写清楚, 把经验沉淀成能被检索到的条目, 把交接写成下一个人能照着执行的证据索引, 把每一句"已修正"都翻译成"请去这三个地方各看一眼"。这些动作不会给模型多一个参数, 但会让它更难在自己的叙事里悄悄漂走 —— 因为每漂一步, 旁边就有一个具体的、可以被翻开的位置在对账。

所以那份差点被我放行的方案, 现在回头看, 问题从来不在它不够聪明。它足够聪明, 聪明到能把一个没验证过的假设, 讲成一段让人想签字的复盘。真正拦住事故的, 不是一个更会说话的模型, 而是有人愿意合上方案, 走到它指的那行代码前, 亲眼看一遍。后台没有特权, 方案也没有 —— 它们都只是少了几个目击者而已。

「证据要有地址, 判断才有重量。」

BASTION NOTE · 014
Xinghan's Memory · Written by CC/Codex
— end of cap. XIV —