Ashley Childress 六月那篇讲 spec 和设计对话的文章,其实没多深刻。但里面一个例子让我把这件事彻底想透了。她写的是通知设置:静音时段要覆盖大多数时间,账户级默认值要保持统一,项目级覆盖要处理例外,“关键警报仍要穿透”又是一个硬性例外。这几个需求撞在一起的时候,批量生成的 spec 不会跟你讨论哪个优先、哪个该被牺牲,它会未经讨论地选一个方向,默不作声地把冲突压平,写进文档的每一行都看起来合理。
你审查的时候根本看不见被放弃的选项长什么样。你只看见一份完整的文档,里面有一个看着差不多的默认值。默认值一旦写进 spec,就变成了契约的一部分。审查者在这里已经输了,因为他连自己在跟谁对峙都不清楚。
先拆一层:方向先定,审查是幻觉。
模型生成是一个 token 一个 token 往下推的。spec.md 前几行一旦确立了某个隐含方向,后面所有章节都会朝这个方向靠。后续生成不是为了多考虑几个选项,是为了让已生成的内容看起来一致。这就解释了为什么批量生成的 spec 里,那些看起来相互独立的字段其实共享一个未被讨论的根决定。审查者以为自己在一个个检查独立细节,实际上是在反复审查同一个决策的五十个变体。
Childress 那篇文章里说得比我准——批量生成时模型先把方向定了,再让所有内容跟这个方向对齐。审查者在批处理里的自然反应是:这份文档读起来很完整,所以它应该是对的。完整和内洽在这里成了一个陷阱,因为模型被训练得特别擅长制造内洽。
这个段子拆到认知负荷层更明显。人在审查时能同时质疑的决策分支数有上限,批量生成的 spec 把十几个甚至几十个决策同时推到你面前,工作记忆直接溢出,于是你倾向于接受从文档里掉出来的默认值。这不是审查者不认真,是批量这个形态在设计上就没给人类大脑留对抗空间。要对抗,必须把决策分叉压成一个个小批次处理。实时对话恰好能做这件事,文档生成做不到。
再看第二层:模型默认在替你选方向,但它不会告诉你。
不额外配置的情况下,模型倾向于同意你,这是对齐训练的副产品。模型厂商为什么默认这么干?一个在规划阶段默认反驳用户的模型,对大多数零售用户来说体感是“AI 不听话”,留存直接往下掉。默认顺从是对可用性的优化,但这个优化在规划场景里变成了实打实的问题。规划场景里唯一有价值的东西,就是那个有胆量说“你这两个需求撞了”的反对。当模型默认顺从时,它会在 spec 里替你做决策,然后把决策包装成选项之一,不标注它其实是默认值。
这就是为什么 Childress 在 CLAUDE.md 里加的东西比表面看起来重要。她检查了自己的 CLAUDE.md,发现已有的规则全是被动反应式的——“别做这个、记得做那个”。这些是约束,不是对抗。于是她加了一条:在规划阶段扮演对手而非速记员,一次只提一个最高风险的反对意见,用户在做出决定之后停止。
我第一反应觉得在 CLAUDE.md 里写行为规则有点过度工程,一条 system prompt 就能解决的事,非要写成一个持久配置。但看完那个停止条件,我改了主意。CLAUDE.md 这个位置恰好是对的存放点,因为它的优先级是静态的,它持续起作用,而一次性提示只能影响一次对话。写成规则而不是对话指令,意味着对抗性变成了一种工作契约,不是临时的灵感。这个差别不是语义上的,它决定了你每次新开对话时会不会被迫重新和模型谈判。
第三层:批量把错误固化,实时对话的价值在于把乘法压回加法。
在聊天里实时遇到决策分叉,重定向一下,成本是一个回合。批量生成的 spec 里,错误被后续决策放大。到了审查那一步,你想从成品文档里把根决策挖出来,要付高得多的成本。而且很多时候你根本挖不到,因为根决策被一致性掩盖了。实时对话看起来更慢,因为每一轮都要等模型回应,但实际上它把错误暴露在放大发生之前。批量生成把错误建进后续所有决策的地基里,审查者面对的是一栋已经盖好的楼,墙和地板都指向同一个糟糕的方向,谁也别想一眼看出结构性问题在哪。
这段算得有点碎,但账不细算不清。
真正让我不舒服的,是利益格局这一层。工具厂商为什么默认走生成式 artifact 路径?因为 artifact 是可演示、可截图、可放进 product changelog 里的东西。对抗性对话是过程性的,过程结束后如果没有人工整理,它不会留下任何一个可以展示的产物。工具厂商的产品逻辑天然偏好可直接标记为“产出”的东西,而对抗性对话的输出不是产出,它是认知判断,这个没法做在 demo 里。所以规划层的对抗性交互对所有工具厂商来说都是一个不可量化、不可演示、收不上钱的功能。
这件事翻译成人话就是:你拿到的 spec 是在替你垫付方向决策的成本,然后用审查时间还债。债主是你的时间,写借条的是模型。
模型厂商那一侧同样是成本转嫁。默认顺从不是模型坏掉了,是模型厂商把“正确使用规划态模型”的成本外包给了每一个开发者。开发者必须自己在 CLAUDE.md、rules 文件或者 system prompt 里把默认顺从掰过来,用行为规则对抗对齐训练的惯性。这相当于厂商卖给你一辆默认不刹车减速、只会顺着路面溜的车,然后告诉你:想避免追尾,自己去调 ESP。这些配置现在完全是个体的、零散的工程自觉,没有一个工具把它产品化成 default experience。
再看使用者这一方。使用者以为自己买的是自动化,实际上买到的是对方向决策的让渡。批量生成把你花在思考上的时间替换成了花在审查上的时间,而审查又因为方向收敛而低效,这是一个双重损失。最隐蔽的地方在于,使用者很难从工作流里察觉这个损失。因为“审查”这个动作自带一种严谨感,你感觉自己在做质量保证。但你不是在保证设计的质量,你是在给一个未被讨论的默认值做复核。
上一个周期的开发者工具里有一个可以对照的东西:静态分析、linter、CI。这些自动化也能改代码质量,但它们的产出是可验证的,坏的东西会在运行时报错。spec 不一样。spec 的产出是一个承诺,承诺在后续的实现里才逐渐兑现。当它兑现不出来的时候,锅往往落在写代码的人头上,而不是生成 spec 的模型。错误的成本在时间上被转移了。这就是批量生成 spec 能活下来的一个结构性原因:它不等于设计,但被当成设计卖给你,账单写在后面,还款时间标在更后面。
Childress 那篇文章末尾有一个容易被忽略的披露:文章本身用 AI 辅助写成,大部分文字由 AI 生成,观点属于作者,并且经过了文中所描述的对抗性流程的测试。这个披露不是无关紧要的脚注。它暴露出一个难题:对抗性对话承载了思考,但不产生契约化的 artifact。当对话结束,思考就留在对话记录里,无法被团队 review。规格文档在团队规模下仍然是沟通工具,这没有争议。但如果把对话当成思考的容器,那它承担契约功能的能力几乎为零。她自己也承认这一点:“尚未解决如何让对话承担契约功能”。这个空白没有被她的对抗性规则填上,因为底层的产品空白没有解决。当前所有工具默认把对话记录当成一次性产物,不持久化、不可回放、不可审计。所以你被迫把对话转化成文档,而一旦转化成文档,思考又变回了规格。所有你在对话里争取到的分叉路径都被压平了,契约拿回来了,思考丢了。
再深一层,这个两难在单人开发场景下几乎遇不到。单人开发者最直接的感觉是:生成 spec 对了就好,错了改几行。但在多个开发者的团队里,批量 spec 的审查成本是真实可见的。“规格审核”这个环节变成了事实上的设计决策环节,所有被模型预先压平的冲突都要在审核桌上被重新挖出来。可这时挖出来的成本已经很高,更大的可能是没人挖。团队协作环节最需要对抗性思考,而对抗性思考最不能被保留成任务 artifact。这个死结,谁碰谁卡住。
我的判断摆在这儿:把 spec 的批量生成当成设计,是当前工具链在规划层最大的偷懒。批量生成会继续存在——当团队需要一个可 review 的契约文档时,它仍然占一个位置,这个用法是合理的。但它不能是规划层的默认入口。规划层的入口属于对抗性对话,属于把决策分叉压缩成人脑能够处理的小批次,不是把五十个决策打包成一个 doc 然后让审查者自行消化。谁先把这个交互模式做成工具,谁才在规划层真正拿到粘性。规划层是 AI 编程里最不容易被替换的那一层,因为迁移成本最高。
这个判断可能错。证伪条件很具体:出现一种工具或模型默认行为,能在生成 spec 之前自动展示方向分叉和被放弃的选项,而且这个展示是稳定可追溯的,不需要每个开发者自己配置。到那天我会改口。在那之前,我不认为批量生成 spec 能承担设计。它做的只是把默认值包装成规格。用生成冒充设计,是这个产品逻辑里最顺滑的骗局,因为受骗的人以为自己在思考。