夜雨聆风学习资料网

ARTICLE · 1148521

AI 编程最贵的 bug,是“正确地做错事”

AI 编程最贵的 bug,是“正确地做错事”

引子

一个功能,上周让 AI 写完了。这周还在修。

修到最后你发现:不是代码写错了。

是需求,从一开始就理解偏了。

这是今天 AI 辅助开发里最常见的浪费。它不是"写错了一个函数",而是"把一个错的东西,非常正确地写了出来"。

后者更贵。因为前者改一行代码,后者要推翻一整周。

问题出在哪?

出在:过去我们给 AI 的需求,载体是聊天记录。

聊天记录有四宗罪。

一,会滚出上下文。你翻到下一个任务,它就没了。

二,没有版本。改了什么、谁改的,说不清。

三,不可审阅。代码可以 review,需求只能靠"凭记忆"。

四,不可并行。两个人同时让 AI 改同一个模块,互相覆盖。

失序:需求碎在聊天记录里

所以行业里冒出了一个词:规格驱动开发(Spec-Driven Development)。

而在这一堆工具里,目前最实用的一组搭配,是两个:

OpenSpec 管"说清楚",Superpowers 管"做对事"。

这篇文章,讲的就是这两个技能配合使用的三条最佳实践,和四个最容易踩的坑。

一、第一个实践:先把需求从聊天记录里"捞"出来

先说 OpenSpec。

它是一个轻量的、开源的规格驱动框架。安装只要一行:

npm install -g @fission-ai/openspec@latestcd your-project && openspec init --tools claude

需要 Node 20.19.0 以上。

它做的事,本质上是"把合同写下来"。

每一次变更,不再是聊天记录里的一段话,而是仓库里的一个文件夹:

openspec/changes/add-payment-webhooks/├── proposal.md   # 为什么要做这次变更├── specs/        # 增量规范(Delta Specs)├── design.md     # 技术方案怎么做└── tasks.md      # 实现清单

四个文件,回答四个问题:为什么做、要变成什么样、怎么做、分几步做。

契约:一份写在仓库里的书面约定

而它最关键的设计,是增量规范(Delta Specs)。

它不要求你把整个系统的规格重写一遍,只描述"这次变了什么":

## ADDED Requirements## MODIFIED Requirements## REMOVED Requirements

这个设计的价值在哪?

一句话:它让规格,可以像代码一样被增量维护。

传统做法是先写一份完整规格再开工。那适合从零开始的新项目。

但现实中,九成的需求是"给现有系统加个东西"。你不可能每次都重写一遍规格。

增量规范解决了这个问题。两个变更只要动的是不同需求,就不会冲突,可以并行。

做完之后一归档,增量自动合并进主规格树 openspec/specs/。

你的"系统说明书",就这样一次变更、一次变更地长出来。

这一点,连 Thoughtworks 都专门写进了技术雷达。他们给的评价很准:OpenSpec 是增量的、工具无关的,尤其适合存量系统。

这句话很重要。因为绝大多数人的代码库,都不是从零开始的。

核心命令,记住四条就够:

/opsx:new       # 创建一个变更/opsx:ff        # 一次性生成所有规划文档/opsx:apply     # 按任务清单实现/opsx:archive   # 归档,增量合并进主规格

复杂场景还有 /opsx:explore(先探索再动手)、/opsx:verify(归档前验证)、/opsx:bulk-archive(批量归档)。

注意,OpenSpec 还有一个别的工具少有的东西:openspec validate。

需求写得好不好,它可以做程序化校验。这一点,是"建议"和"闸门"的分界线。

最佳实践 · 第一条

把 /opsx:ff 之后的那次人工审阅,当成整条流水线里最值钱的一步。

因为在这里改一句话,成本是 1。在代码里改,成本是 100。

审的时候盯三件事:

一,proposal 的边界对不对。别多,也别少。

二,规格里的要求,用的是 MUST 还是 SHOULD。这决定了 AI 的用力程度。

三,任务拆得够不够细。

二、第二个实践:给 AI 装上"硬闸门"

再说 Superpowers。

如果 OpenSpec 解决的是"说什么",那 Superpowers 解决的是"怎么做"。

它出自 Jesse Vincent 之手。

这个名字你可能不熟,但他做的东西你大概率用过。他写了 Request Tracker,2005 到 2008 年管理 Perl 6 项目,联合创办了 Keyboardio,还做了 K-9 Mail——后来被 Mozilla 收购,变成了 Android 版 Thunderbird。

一句话概括这个人:他一直在给别人造基础设施,而且极其在意"流程"。

Superpowers 要解决的问题非常具体。

AI 编程助手的默认行为是:收到请求,立刻开始写代码。

没有分支,没有测试,没有 review。

问题不在智能,在纪律。

它的做法很有启发:不靠"讲道理",靠"硬闸门"。

闸门:不达标就过不去

看三个最典型的。

第一个,brainstorming。

它的硬性约束是:在你确认设计方案之前,不允许启动任何实现动作。

不能写代码,不能搭脚手架,不能"先试试看"。

为什么?因为大部分被浪费的工作量,都来自"先干起来再说"。

第二个,TDD。

这条规则是"没有失败的测试,不许写生产代码"。

原文的措辞非常强硬,大意是——先写了实现代码再补测试?删掉,重来。

不是警告。是删除。

为什么必须这么狠?

因为模型的天性是"讨好"。

你让它补个测试,它会写一个"验证这段代码做了什么"的测试。那叫同义反复,不叫测试。

删掉,是唯一能切断这个循环的办法。

第三个,writing-plans。

它要求:计划要细到"每个任务 2 到 5 分钟、精确到文件路径、给全代码上下文、写清验证方式"。

而且写计划时,要假设执行者是一个"对你的代码库零上下文、品味还不怎么样"的人。

听起来苛刻。但它有个非常现实的前提:

下一步的执行者,可能是子 agent。它对你代码库的了解,就是零。

有个真实结果值得看一眼。

一个叫 chardet 的 Python 字符编码检测库,新版本性能提升了 41 倍,准确率到 96.8%,顺手剃掉了一批积压多年的老问题。

作者说,那套覆盖 2161 个文件、99 种编码的测试,正是 TDD 这条硬闸门逼出来的副产品。

最佳实践 · 第二条

不要试图"温和地"使用这些技能。要么全开,要么不用。

闸门的价值,就在于它不让步。

你让它通融一次,它就退化成一个"建议"。而 AI 对"建议"的态度,你懂的。

三、为什么偏偏是这两个

市面上做规格驱动的工具不少。

GitHub 有 Spec Kit,还有更重的 BMAD,以及绑定特定 IDE 的 Kiro。

为什么最后落到 OpenSpec 加 Superpowers 这一组?

因为它们的"性格",是互补的。

Thoughtworks 在技术雷达里点破了一件事:很多规格驱动框架和技能工作流,更适合从零开始的新项目(greenfield)。而 OpenSpec 的特别之处,是它对存量系统(brownfield)更友好。

方法就是前面说的增量规范——不重写全量规格,只描述这次变了什么。

而 Superpowers 补的,恰恰是 OpenSpec 不擅长的那一半。

OpenSpec 的长处是"把要求写清楚",但它管不住 AI 写代码时的具体动作。

tasks.md 只说做什么,不说怎么做。

Superpowers 反过来:它管得住动作,但它不知道"该做什么"——它手里没有需求档案。

一个管 What,一个管 How。

一个偏"文档",一个偏"行为"。

一个靠 CLI 校验强制,一个靠硬闸门强制。

这就是它们能拼在一起的原因:接口干净,没有重叠,也没有空档。

顺便说一句,还有第三层,很多人会忽略。

在需求层(OpenSpec)和流程层(Superpowers)之上,还有一层:工程纪律层——代码规范、测试覆盖率、安全检查。

这一层,光靠 AI 遵从是不够的。必须再配一道 CI 闸门。

因为"模型说它会遵守",和"构建失败了就合不进去",是两回事。

四、真正难的部分:两条流水线怎么接上

到这里,两个技能各自都好用。

但真正的坑,出现在它们交界的地方。

先把分工说清楚:

需求层,OpenSpec 主导。 管说什么(What)。产出 proposal、specs、design。强度靠 CLI 校验,可程序化强制。

流程层,Superpowers 主导。 管怎么做(How)。产出计划、测试报告、审查记录。强度靠模型遵从加硬闸门。

一句话:OpenSpec 管"说清楚",Superpowers 管"做对事"。

它们能接上,是因为有一个天然的接口:

OpenSpec 的 tasks.md,正好是 Superpowers writing-plans 的输入。

双闭环:一个环保需求,一个环保质量

完整的双闭环流程,六步。

第一步:输入 PRD,人工审。

把 MVP 的 PRD 切成若干个 markdown 文件,人先过一遍。

这是整条流水线里,唯一一个"人必须完全负责"的环节。别省。

第二步:brainstorming 做设计探索。

在 superpowers/specs/ 下,产出一份带时间戳的设计文档。

这一步是在"想清楚",不是在"写代码"。

第三步:交给 OpenSpec 立契约。

执行 propose 时,明确指定"根据这份设计文档创建提案"。

OpenSpec 会生成一个 change,里面有 proposal、design、按领域划分的 specs,和对应的 tasks。

到此,聊天记录里的模糊想法,正式变成了一份书面契约。

第四步:交叉验证。

这是很多人会跳过、但最该做的一步。

拿 OpenSpec 生成的 spec,回头对一遍 PRD。看有没有漂移。

需求漂移不是一次发生的。是每一环丢一点、加一点,最后累积成的。

这一步,是整条链路上唯一的刹车点。

第五步:交给 Superpowers 执行。

把整个 change 丢过去,让它显式执行 writing-plan,输出到 superpowers/plans/。

然后按 Subagent-Driven 模式,用 TDD 实现每一个任务,原子提交。

提交通常落在框架自动创建的 worktree 里,天然避开了版本冲突。

这里有个关键取舍:跳过 OpenSpec 的 /opsx:apply。

为什么?

因为 OpenSpec 的 apply 是"让 AI 按任务清单写代码"。而 Superpowers 的 TDD 流程做得更好——它有测试纪律、代码审查、验证机制。

用后者替代前者,是这套组合里的核心判断。

第六步:回到 OpenSpec 归档。

执行 /opsx:archive。

这里有一个必须提前知道的"副作用":

因为执行阶段是 Superpowers 操作的,tasks.md 里的勾选框很可能还是空的。

工件状态是 done,但任务没打勾。

这不是 bug。

直接忽略那些没打勾的任务,确认归档。 归档的规格会合并进 openspec/specs/,同时在 changes/archive/ 里留一份历史。

如果你在意这个状态不一致,也有办法:手动把 - [ ] 改成 - [x],或者写一个桥接技能自动同步。

回头看这六步,你会发现:人一共介入了三次。

审 PRD,审 spec,审每个任务的产出。

这三次介入,不是流程的负担。它们是流程的全部价值所在。

AI 能替你写代码,但不能替你决定"什么是对的"。

最佳实践 · 第三条

双闭环的价值,不在于"两个工具都用上了",而在于那个交叉验证点。

工具接不接得上,是效率问题。

规格有没有漂移,是生死问题。

五、四个最常见的坑

坑 01

跳过 OpenSpec,直接让 AI 写代码。

结果:需求漂移。

你会在第三周才发现,做的和当初说的,不是一回事。

坑 02

跳过 Superpowers,自己手动实现。

结果:流程失控。

代码能跑,但没有测试、没有审查。三天后,没人敢改。

坑 03

把技能当"建议"用。

删掉 TDD 的删除逻辑,在 brainstorming 的闸门前放行一次。

闸门一旦松动,它就只是个装饰。

坑 04

在需求每小时变一次的原型项目上,硬上这套流程。

规格驱动是有成本的。

什么时候该用?一句话判断:

当"理解错"的代价,超过"写文档"的成本时,用。反之,别用。

总结

把 AI 从"打字员"变成"工程师",靠的不是更强的模型。

靠的是两样东西:

一份写在仓库里的契约(OpenSpec),和一套不许让步的闸门(Superpowers)。

前者保证你做对的事。

后者保证你把事做对。

行动建议就三条。

一,从下一个"跨多个文件、涉及行为变更"的需求开始。先跑 /opsx:ff,人工审一遍 spec,再动代码。

二,装上 Superpowers,完整地用。不要挑着用。

三,在 OpenSpec 和 Superpowers 之间,保住那个交叉验证点。

它看起来最"不产出代码",但它是唯一能挡住需求漂移的地方。

AI 写代码很快。

但快的另一面,是乱。

先立规矩,再写代码。

相关学习资料