文章引用泰勒科学管理思想,指出AI不会追问你真正意图,导致按印象构建代码。强调将“如何做”书面化的重要性。

一个世纪前,还没人在用这个词的时候,Frederick Taylor 走进一间机械加工车间,证实了一个至今依然成立的道理:你不是靠告诉工人要更聪明来增加新技能的。你把工作的做法写下来,这样任何人——哪怕是从未见过旧师傅的人——都能复现它。Henry Ford 把同样的理念变成了一条生产线,那里根本没有师傅,只有写好的操作规程。手工作坊变成了标准作业,产量跃升了一个数量级。Taylor 什么也没发明。他只是证明了把"怎么做"写下来本身就是生产力。
AI 编码以更尖锐的方式重述了这个教训。你交给任务的模型永远不会问你真正的意思是什么。你说"给这个接口加个超时",它不会问你指的是连接超时还是读取超时——它会选一个,假设自己是对的,然后充满信心地写代码。问题不在于它选错了;人也会选错。问题在于它选错的方式:它不相信自己在猜测。它相信自己在执行。所以如果"怎么做"只存在于对话中,AI 就是在按印象构建,在光标关闭时留下什么印象就交付什么。
这篇文章讲的是金字塔的契约层——意图被钉入文件的那一层。上一篇文章讲了决策:为什么是这样。这一篇讲的是怎么做,以及如何让"怎么做"成为模型读到的法律而不是提示。
Change one field, break nineteen places
TradeOMS 有一个核心数据处理模块,叫 CDP,所有其他模块都调用它。它恰好遇到了这篇文章要讲的那种失败。后端切换了响应字段的 JSON 属性名,使用了 @JsonProperty("items")。本身无害。但响应契约从未被写下来——它只存在于讨论这个变更的对话中,是一项口头协议。
对话忘记告诉任何人的是:前端和 19 个测试文件都在读取 data.content。后端现在发的是 items;测试和 UI 还在请求 content。一个字段重命名,十九处损坏,直到涟漪扫描一次性把它们全部暴露出来。
在人类团队里,这不过是"接口漂移了"。重命名字段的那个工程师至少记得自己改了什么,所以旧名字下次会触发警报。AI 没有这种记忆。重命名字段的模型只是在执行一条指令——它的上下文中没有任何警告说前端还在期待旧名字。没有"我来过这里"的条件反射。它只是执行。
第二种更糟糕的失败来自同一个根源。对 218 个前端 API 调用点进行涟漪扫描,发现 22 个后端端点悄悄返回 HTTP 500。控制器签名已经改了;前端从未跟进。22 条死路由,没有一个人类或模型知道——直到扫描把它们挖出来。不是你清单上"已知的未知"bug。这些是未知未知:你甚至无法问"这坏了吗?"因为你不知道坏的存在。人类审查只能问"我看的这个对吗?"它无法问"我没看的那个坏了吗?"一个没有书面契约的系统没有办法听到自己无声的死亡。
两起事件共有一个根源:在前端和后端之间,在代码和测试之间,有口头协议但没有书面契约。口头协议靠记得它的人来承载。书面契约由文件来验证。在 AI 项目中,人们记不住的,AI 记得更少。
Hammurabi carved the first contract layer
这个问题的最古老修复方法太古老了,以至于早于工程本身。约公元前 1754 年,Hammurabi 王将全部法律刻在一块石柱上,立在公共广场。为什么一个国王要这么做?因为不成文的规则不是规则——它们是下一个决定者想让它们成为的任何东西。写下来,放在每个人行动前都会读到的地方,漂移就停止了。每个人都要对同样的刻文负责。
这正是契约对 AI 代码库所做的。它是你约束条件的 Hammurabi 法典——写下的、公开的、不可能"忘记"的、每个打开仓库的模型都能读的。
The spec contract: three fields that bind
第一种契约是规格说明。不是描述——是契约。描述可以模糊;契约不能。最少规格说明绑定三样东西,任何一样缺失,AI 都会用自己的"常识"填补空白:
Scope — 什么包含在内,同样重要的是什么排除在外。不知道自己不在构建什么的 AI 会愉快地"优化"它以为你指的相邻模块。
Assumptions — 系统默认什么。这是最容易跳过的字段,也是代价最高的字段。我之前那次缓存事故恰好就是这个:一个限速端点很慢,没有记录慢是上游限速这一假设,所以模型得出结论"慢 = 加缓存"。少一个假设,错误的修复。AI 的"常识"来自互联网,而不是你的业务。
Acceptance — 决定"完成"的客观测试。没有验收标准,你就不能说工作是对是错;你只能去感受。在 AI 项目中,靠感受来验收是代价最高的方式。
规格说明的全部价值在于:它把"怎么做"从对话中的协议变成了文件中的契约。对话会漂移;契约不会。下一个会话打开仓库,在白纸黑字中读到范围、假设和验收,而不是上一轮对话模糊的印象。
Data contracts: the signature is the boundary
第二种契约——也是最物质化的——是数据契约:接口签名、DTO 形状、字段名。这是约束系统中最接近物理定律的东西,因为它可以在编译时或运行时验证,不需要任何判断。在 TradeOMS 中,这表现为一个真实目录 docs/15-api-contracts,每个路由的请求/响应签名都存在一个 AI 不允许修改的文件中。这是一个 Level 1 硬约束——碰不碰都没有商量余地。
但文件本身不是防御。防御是一份能自我检查的契约。在 22 条死端点之后,TradeOMS 构建了一个路由门控 check-api-route-consistency.py,自动验证每个前端 API 路径和字段与后端实现的对比,任何不匹配都会阻塞。结果用一条曲线讲完了整个故事:
首次运行:233 处前端调用与后端暴露之间的不匹配。
中途修复时,数量升到 370——因为门控现在暴露的是没人见过的问题,而不是在隐藏它们。
终态:零。
233 → 370 → 0 这个形状是门控最有力的论据。问题以前不是不存在;而是看不见。没人能列出"这里有 22 条坏路由",因为它们不存在于已知条目中。数据契约是第一件让看不见的表面开口说话的东西:它匹配或不匹配,没有灰色地带。对于 AI 来说,这是决定性的,因为 AI 的专长是生产看起来对的错误,而签名检查是世界上最不给人留情面的裁判——对就是对,错就是错,没有模糊空间。
有一个管理箴言,人们在有人要更多指标时就会搬出来:你只能管理你实际计数的东西。在 AI 编码中这句话反过来更尖锐——你只能管理你能衡量的接口。你无法审查你只能感受的表面;你可以检查一份契约文件。这也是数据契约是 Level 1、不可触碰的原因——一旦它变成可协商的,它就退回口头协议。
FMEA: price the ways it can break
第三种、最容易被忽视的契约形式是规格说明内部的风险审计:FMEA,失效模式与影响分析。很简单。当你写规格说明时,列出功能可能失效的每一种方式,然后按三个轴给每个打分——业务影响的严重程度、发生的可能性、当前门控的可检测性。三个相乘得到 RPN,对任何超过阈值的内容强制要求对策,通常是 RPN 100。
在 TradeOMS 的 24 份规格说明中,FMEA 浮现出 40 多个失效场景,每个 RPN 100 以上的都得到了真正的对策:
KYC,RPN 392——未授权客户查看授权客户数据;对策,权限注解加权限门控。
Quote,RPN 294——外部汇率源失败并暴露原始错误;对策,带优雅降级提示的回退汇率缓存。
Order,RPN 210——对同一订单的并发编辑;对策,乐观锁。
FMEA 的价值不在于那张表;在于它改变了测试用例的来源。以前,测试是头脑风暴出来的——"我应该覆盖什么?"现在由 FMEA 驱动:每个高 RPN 模式映射到一个测试用例、一个门控和一个 SOP。规格说明不再说"我想要什么",开始说"我害怕什么以及如何防御"。把恐惧写下来,AI 就知道哪些边界是禁区。
Three powers: check the checkers
契约的可信度取决于验证它的人。在 derekcoding 方法论中,这是三轨纪律——三本账本相互锁定:一份 WBS 说明要构建什么,一份 Issue Log 记录什么是坏的(每条都有回归链接),以及一份包含 374 个案例的测试用例账本,每个案例记录测试是真跑了还是只是声称 PASS。
最锋利的规则是权力分离:报告者、修复者和验证者不能是同一个人——或同一个 agent。这就是法律原则:立案的法庭不能同时审判它。当一个 agent 写了代码、接受了自己的工作、盖上 PASS 时,契约已经悄无声息地不复存在了。数据已经说明了一切:82 次提交通过了,其中 46 次根本不包含任何代码变更——纯粹的"我说我完成了",背后什么都没有。当裁判和运动员是同一个 agent 时,这就是会发生的事。
三轨的核心是让"这真的完成了吗"成为一个可审计的事实,而不是声称的状态。契约存在是为了让"我声称完成了"和"证据证明完成了"成为两件不同的事。
一个附注供你参考:同样的契约本能出现在代码之外。我的本地知识库 derekinside 有一个 chunk-split 契约和明确的实体关联规则——它自己的知识"数据契约"。没有这个 split 规则,摄入的知识会碰撞成一团乱麻;有了它,知识可以检索、关联和可靠地演化。契约层是任何系统——代码或知识——中"稳定"的来源。
如果你想今天就开始做,这份清单很短。下次你给模型一个任务时,写一份三行规格说明,包含范围、假设和验收。选一个共享接口,把它的签名钉在一个模型不能触碰的文件里。加一个自动化门控,比较前端调用和后端实现。跑一次 FMEA,对你最高的 RPN 强制要求修复。把写作者和验证者分开,哪怕是非正式的。
做到一半,你的 AI 就停止了按印象构建,开始按契约构建。Taylor 失传的那句话是 AI 让它变得紧迫的那句:契约不是来限制 AI 的。它是来保护它的——因为从不需要猜测的 AI 是唯一你能信任的。
明天我们往下一层,走到不让坏工作进来的门控:让检查先于代码。契约说的是应该怎样;门控是让"应该"真正发生的东西。