AI Coding 控盘规则:水流理论与最小混沌单元

团队里推 AI Coding 半年,被同学问得最多的一个问题:「它写代码的速度我 review 不过来,怎么办?」

我最开始的回答很老实:「那就认真看,安全第一。」执行了一个月发现这个回答等于没回答——人均每天面对几千行 AI 生成的 diff,认真看的结果就是 AI 提效的部分全部被 review 吃回去,甚至倒贴。后来我们换了思路,摸了半年,现在的答案变成一句话:别看代码,看证据。人定方向、边界和验收标准,模型在边界内自主推进,用证据链收口。

这句话展开就是这篇。里面每条规则背后都有真实学费,我尽量把学费也写出来。

先认清对手:两个底层事实

所有控盘手法都建立在对模型本性的两个认识上,认识不到位,招数都是白学。

第一,模型是概率生成器,自由空间越大越容易跑偏。你说「做个用户导出功能」,它会给你一个「业界最佳实践」风味的实现——代码漂亮、结构标准、和你系统的真实约定貌合神离。这不是它蠢,是你给的搜索空间太大,它只能往训练分布的均值上靠。对策只有一个:动手前把搜索空间压进 spec——目标、可动范围、明确不做,写清楚。

第二,上下文宝贵且会腐烂,给得越多效果越差。长对话拖到后面模型明显变笨,这个大家都体感过。很多人的应对是「上下文压缩」,我的看法是压缩只是有损延缓——真正的解法是 spec 外置成文件,长任务定期 clean restart:从干净窗口加 spec 文件重新出发,比拖着一窗口腐烂历史往前挪快得多。我们现在超过半天的任务默认每天至少重启一次会话,纯赚。

顺带一个我很喜欢的区分:省 token 是成本问题,省上下文是质量问题。别用成本思维做质量决策——该给的关键上下文不给,省下的钱会加倍赔在返工上。

水流理论,和那次溃堤

我们内部把 AI 编程比作引水:水自己会流,人干三件事——筑边界(spec)、设观测点(checkpoint)、修安全通道(灰度和回滚)。

这个比喻真正的价值在于它给了一对判断词,用来回答控盘中最高频的灵魂拷问:它跑出我的预期了,要不要打断?

漫溢:还在边界内,方案跟你预想的不同,但目标正确。比如你以为它会改三个文件,它选择加一个中间层。放着,继续观察。这里最难的是忍住「这不是我的写法」的干预冲动——你要的是结果正确,不是复刻你的手笔。我见过最亏的用法就是事事纠正,模型的自主性红利全被抵消,等于雇了个赛车手然后全程扶着方向盘。

溃堤:违反 spec、擅自扩大 scope、或者连续验证失败还在换姿势硬试。立刻打断,回 spec 重切任务。

学费来了。四月份有个任务,Agent 在中途「顺手」把一个它认为写得不好的模块重构了——这明确超出了 spec 边界,典型溃堤。我当时的判断是「再看看,说不定重构得还行」。三个小时后我面对的是一个两千多行、混合了目标功能和自作主张重构的 diff,两者纠缠在一起没法拆分验收。最后整个分支废弃重来。把溃堤当漫溢,代价是指数增长的——第一时间打断损失十分钟,「再看看」三次之后损失一天。现在我们的纪律是:scope 扩大零容忍,发现即打断,没有「说不定」。

最小混沌单元

任务该切多大交给模型?我们的原则八个字:小到可检查,大到可自治。

往小切的极端是一次一个函数——那你退化回了逐行监工,比自己写还累。往大切的极端是一次一个系统——风险不是失败,是失败得太晚:错误方向跑一整天才暴露,回滚半径是整个任务。

合适的颗粒度长什么样?我的手感是:模型能自主推进两三个小时、你在 checkpoint 花十分钟能判断对错、错了扔掉不心疼。按这个标准,「实现导出功能的后端接口含测试」是一个好单元,「实现整个导出功能前后端」太大,「写导出接口的参数校验」太小。

切法上还有个技巧:把最可能被推翻的决策放最前面的单元里。数据模型、接口签名这类牵一发动全身的东西先出来让人拍板,机械性的实现放后面——这样即使返工,废掉的都是便宜的部分。

spec 长什么样

说了半天 spec,贴一个我们实际在用的骨架。刻意保持简短——spec 不是设计文档,是给模型(和未来的自己)看的边界声明:

# spec: 订单导出功能

## 目标
运营后台增加订单批量导出,CSV 格式,异步生成 + 站内信通知

## 明确不做
- 不做 Excel 格式(问过运营,CSV 够用)
- 不做自定义列(第一版全量列)
- 不动现有的同步导出小接口

## 关键决策
- 异步任务复用现有 job 队列,不引入新组件(决策人:我,
  理由:量级撑得住,新组件的运维成本不值)

## 验收标准
- 10 万行订单导出可完成,任务状态可查询
- 导出中重复点击不产生重复任务
- 全部现有测试保持通过

## 待补充
- 导出文件的保留时长,等运营确认

几个格式上的讲究。「明确不做」和「目标」同等重要——它直接封掉了模型最容易漫溢的方向(「我顺便支持了 Excel」)。「关键决策」要带理由和决策人,这是防止后续会话把已拍板的事重新翻出来讨论——没有这一栏时,模型隔三差五会「建议引入消息队列」,每次都要重新解释一遍为什么不。「待补充」是诚实地标出边界上的洞,让模型撞到时知道该停下来问,而不是自己编一个答案。

这份东西写下来通常十五到三十分钟。我知道很多人嫌这个步骤重——「我口头说两句它就能干」。能干,但你省的这半小时,会在它以「业界惯例」填补你没说清的地方时,连本带息还回来。

checkpoint 上该做什么

设了观测点,站在观测点上具体干什么?我们归纳了六种动作,按频率排:

放行——一切正常,什么都不说,让它继续。最常见,也最考验克制。

校准——方向对,局部偏了。指出具体偏差,给一句修正,不打断整体推进。

追问——证据不足以判断。「你说测试过了,把输出贴出来。」注意追问的对象是证据,不是过程——别问「你是怎么想的」,问「拿什么证明」。

拍板——它停在「待补充」的洞前面等决策。给决策,顺手把决策写回 spec。

转向——溃堤了。停止当前任务包,回 spec 重切。转向时有个纪律:已经产出的部分先归档再废弃,里面往往有下次能用的调研信息。

收口——单元完成,走证据链验收,然后把新知识回写归档。

六个动作里,新手最缺的是第一个(忍不住指点)和最后一个(验收完就走,不归档)。中间四个都好学,这两个靠自觉。

验收:证据链长什么样

「看证据不看代码」落到操作层面,就是任务包收口时我要求看到的四样东西:

1. 测试证据    新增/修改的测试 + 运行输出原文(不是「测试通过了」四个字)
2. 运行证据    关键路径的实际执行日志或响应示例
3. 边界证据    diff 文件清单,逐一确认落在 spec 声明的范围内
4. 对照证据    spec 里每条验收标准的逐条勾对

模型完全有能力自动产出这份证据包,前提是你在任务说明里把它列为交付物。不列,你收到的永远是「已完成,请查收」。

有同学问:证据也可能造假吧?会。我们真遇到过测试输出是「构造」出来的(它没跑,直接生成了一份像样的输出)。应对是关键任务的证据脚本化——验收命令由我们提供、hook 强制执行,输出直接进 CI 记录,模型只负责让它变绿。又是那个原则:机制能管的事,不要靠信任。

收尾:第七步最值钱

把整套流程串起来是七步:读地形 → 落 spec → 切任务包 → 放手跑 → 溃堤时转向 → 证据验收 → 回写归档

最后一步最容易省略,也最值钱:把过程中澄清的事实、拍板的决策、发现的坑写回 spec 和 codemap。为什么值钱?因为 spec 和 codemap 是跨会话、跨模型版本存续的资产,而对话历史是易耗品——下次任务的「读地形」读的就是这次的归档。我们坚持回写三个月后,新任务的冷启动成本肉眼可见地降了:模型(和新同事)越来越少地问出「这里为什么这么设计」,因为答案都在地图上。

有人听完这套说:「这不就是带实习生么。」结构上像,但有个本质区别值得记住:这个实习生产出是人类百倍速,而且它的失败是统计性的——同一个坑它以稳定概率反复踩,不会吃一堑长一智(除非你把「智」写进 spec 或机制里)。所以控盘体系不能建立在磨合和信任上,只能建立在结构上:边界、观测点、安全通道。信任留给人,结构留给模型。