ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用SDD+OpenSpec+SuperPowers实现可追溯的AI编码实践

2026/9/11 20:26:01 拓冰建站 浏览量
用SDD+OpenSpec+SuperPowers实现可追溯的AI编码实践 最近这一年我身边用 AI 写代码的团队越来越多了但一个尴尬的现象也随之出现代码量上去了安全感没上去。功能确实能跑但没人能说清楚某一行代码为什么这么写、当时基于什么需求、有没有替代方案。说白了AI 编码最大的问题不是写不出代码而是写出来的代码不可追溯、不可验证、不可维护。我自己在几个项目里反复折腾后慢慢摸索出一套组合拳用 SDDSpecification-Driven Development作为顶层方法论搭配 OpenSpec 和 SuperPowers 两个框架落地。这套方案不是悬在空中的理论而是能让 AI 按需产出、每行代码都有据可查的实操路径。这篇文章就把我的实践过程、踩过的坑和具体玩法一次性讲清楚。1. 先捋清楚当前 AI 编码到底乱在哪1.1 我观察到的三种典型乱象你如果让 AI 直接写一个稍微复杂一点的功能最常见的现象就是“看起来都对跑起来就炸”。我遇到过最典型的一次让 AI 实现一个订单超时自动关闭的逻辑它很贴心地写了个定时任务但定时任务的触发频率是每 5 分钟一次而业务要求是订单创建后 30 分钟关闭中间没有任何扫描 offset 的概念。结果就是大量订单在 35 分钟、40 分钟甚至更晚才被关闭线上监控直接报错。这种问题不是偶发而是普遍存在。第二种乱象是 AI 会把上一段对话里的上下文错误地带到下一段。你在同一个会话里先让它写了一个 Python 的 FastAPI 接口又让它写一个 Java 的 Spring 服务它可能就会把 Python 风格的命名规范带进 Java 代码里甚至把 FastAPI 的依赖注入方式硬套到 Spring 上。我见过最离谱的一次AI 在一个 Java 项目里生成了 Python 风格的路径拼接逻辑编译能过测试直接挂。第三种乱象更隐蔽AI 生成的代码没有任何“来路说明”。它不会告诉你这个常量值为什么是 30 而不是 60不会告诉你这个边界条件是从哪个需求文档里推导出来的也不会告诉你它顺手帮你改掉的那个方法签名是为了什么。等代码 review 的时候你问它“为什么这里要加锁”它可能回你一句“这是常见实践”。这种没有决策记录、没有需求关联的代码维护成本极高甚至比没人维护的遗留系统还难搞。1.2 乱象的根源缺规范、缺上下文、缺审计总结下来AI 编码乱象的根源逃不出三个词缺规范、缺上下文、缺审计。缺规范指的是没有给 AI 一套清晰的、可执行的约束条件。大多数时候我们只给了 AI 一个“需求”而不是一份“规格”。需求是模糊的规格是清晰的。你让 AI“优化一下登录逻辑”它能给你找出几十种“优化”方式但你没有告诉它优化的边界是“保持接口兼容”还是“允许破坏性变更”它自然就会自由发挥。缺上下文则是因为 AI 的上下文窗口虽然越来越大但项目相关的信息散布在需求文档、设计文档、代码注释、历史提交记录里AI 很难全部拿到。你不能指望 AI 自己把整个 git 历史翻一遍来理解你的项目它只会基于当前会话里能看见的内容作答。一旦你给的信息不完整它就会用自己的“常识”补齐而这些常识往往和你的业务场景对不上。缺审计就更直接了。如果你没有一个机制去记录“这个决策是谁在什么时间基于什么原因做出的”那 AI 产出的每一行代码就都是无根之木。出了问题只能从头排查而 AI 如果再来“优化”一次可能又把之前踩过的坑重新踩一遍。1.3 SDD 为什么能成为破局抓手我接触 SDD 是在一次内部技术分享上当时听到的概念很简单先写规格再写代码。看代码的人应该能通过规格文件理解代码为什么存在改代码的人应该能通过规格文件判断改动会不会破坏契约。这听起来像传统软件工程里的“设计先行”但 SDD 和传统设计文档最大的区别是SDD 的规格文件是活文档是和代码同步演化的。它不是一个评审完就丢进 wiki 里的 PDF而是整个开发流程中的“单一事实来源”。在 AI 编码的场景下这个特性格外重要因为 AI 不会自己主动去翻需求文档但如果你把规格文件放在项目根目录并且在规则里强制要求 AI 每次修改代码前先读对应的规格文件它就能做到“带着约束写代码”。后来我又接触到 OpenSpec 和 SuperPowers 这两个框架发现它们刚好从两个维度补上了 SDD 落地的关键缺口OpenSpec 负责把“规格”这个东西变成标准化的、可版本化的文件结构让 AI 好读、好理解、好引用SuperPowers 负责在 AI 执行编码时注入一套行为准则从流程层面强制 AI 走“先理解规格、再动手实现、最后记录决策”的路径。两者合在一起就是我标题里说的“双框架”。2. OpenSpec 和 SuperPowers 在双框架里的分工2.1 OpenSpec把需求变成机器可读的规格先说 OpenSpec。我理解它的核心价值不是“帮你写文档”而是“帮你把需求结构化”让规格文件成为 AI 编码时的硬约束。它定义了一套推荐的目录结构和文件组织方式你在项目里跑起来之后大概是这个形态repo/ ├── specs/ │ ├── 001-order-timeout-close/ │ │ ├── spec.md │ │ ├── decisions.md │ │ └── acceptance.md │ ├── 002-login-captcha/ │ │ ├── spec.md │ │ ├── decisions.md │ │ └── acceptance.md ├── src/ ├── tests/ ├── .superpowers/ │ ├── rules.md │ └── workflow/ └── AGENTS.md每个业务功能一个目录里面至少包含三份文件spec.md 描述需求背景、功能范围、约束条件和验收标准decisions.md 记录实现过程中所有关键决策及原因acceptance.md 明确验收场景和测试流程。以“登录接口增加验证码校验”为例OpenSpec 风格下的 spec.md 长这样# Spec: 登录接口验证码校验 ## Context - 现有登录接口无验证码存在暴力破解风险 - 需要在保持响应结构兼容的前提下增加验证码 ## Requirements 1. 用户在登录前必须先获取验证码 2. 登录请求必须携带验证码及会话标识 3. 验证码有效期 5 分钟失败次数超过 5 次后刷新 ## Constraints - 不改变现有 HTTP 状态码约定 - 不引入新的第三方依赖 ## Acceptance Criteria - 无验证码请求返回 400 - 验证码错误返回 4001 - 同一会话连续 5 次验证失败后旧验证码立即失效这份文件的语气很关键它不是在描述“怎么做”而是在描述“要满足什么条件”。AI 读到这种文件时会把它当成契约而不是参考资料这能极大减少自由发挥空间。2.2 SuperPowers给 AI 配上编码行为准则SuperPowers 的定位和 OpenSpec 完全不同。OpenSpec 定义的是“做什么”SuperPowers 定义的是“怎么做”。我第一次看到 SuperPowers 这个名字时以为它是一堆现成的代码生成模板后来才意识到它更像一套“给 AI 用的行为准则注入器”。你可以把它理解为一个规则包把 AI 编程时需要遵守的流程、约束、检查清单、输出格式统一写进规则文件然后让 AI 编码助手在每次会话开始时自动加载这些规则。比如我的一套基础规则大概是这样的# .superpowers/rules.md ## 全局规则 - 每次修改代码前必须先读取 specs/ 下对应功能的 spec.md - 若 spec.md 缺失暂停编码并提示用户先补充规格 ## 编码规则 - 所有函数必须包含 docstring注明关联的 spec 编号 - 禁止在代码中硬编码业务常量常量必须提取到配置文件中 - 如果有多种实现方案优先选择 spec.md 中约束较少的方案 ## 提交规则 - git commit message 必须以 spec 编号开头例如 001: 实现订单超时关闭任务 - 提交前必须运行 tests/ 下的全量测试 - 提交后自动触发 DECISIONS.md 更新这套规则文件的核心作用是把“人靠自觉”变成“流程强制”。以前我要求团队成员在代码里写注释总有人忘现在让 AI 在规则驱动下写代码它每一行都会主动关联 spec 编号因为规则文件里写得清清楚楚。2.3 两个框架如何衔接成一条完整链路OpenSpec 和 SuperPowers 之间不是“二选一”的关系而是前后衔接、互相强化。我这里列一下我自己项目的运转流程需求方提出需求后先由人工或者 AI 辅助人工把需求整理成 OpenSpec 规格文件放入 specs/ 目录然后在 SuperPowers 的 rules.md 里声明“所有编码工作必须先读取相关 spec”AI 编码助手启动后会自动加载 rules.md接着按规则找到 specs/ 下的对应文件再开始写代码写完代码后AI 会按照规则里的“提交规则”检查一遍确保代码注释、提交信息、测试结果都满足要求最后如果实现过程中有任何偏离 spec 的地方AI 必须把决策记录到 decisions.md 里而不是悄悄改代码。这套链路跑通之后最大的感受是“安全感回来了”。任何一行代码你都能往前追到 spec再往前追到需求再往前追到当时的决策记录。AI 不再是悬浮在项目之上的“黑盒写手”而是一个真正参与项目流程的协作者。3. 完整实操从需求到可追溯代码3.1 环境初始化把两个框架请进项目这套组合拳不需要安装特别复杂的服务核心就是把文件结构和规则配置准备好。我通常用下面的命令初始化一个项目目录mkdir -p specs mkdir -p .superpowers/workflow touch AGENTS.md touch .superpowers/rules.md然后在 AGENTS.md 里写入“项目级引导说明”让 AI 编码助手在进入项目时能第一时间读到这里。我的 AGENTS.md 通常非常简单# AGENTS.md 本仓库采用 SDD 规范驱动开发任何编码任务开始前请按以下顺序执行 1. 阅读 .superpowers/rules.md 2. 在 specs/ 目录下找到对应功能规格文件 3. 如果规格文件不存在先询问用户是否需要创建 4. 完成编码后根据规则提示运行测试并更新决策记录这里的关键是AGENTS.md 是 AI 编码工具Cursor、Copilot CLI、Windsurf 等默认会优先读取的入口文件。你不需要每次对话都重复一遍“记得先读规范”只要把它写进 AGENTS.mdAI 就会自动遵循。3.2 用 OpenSpec 写一份合格的需求规格很多人第一次写 OpenSpec 规格时会犯一个错误写得太像技术方案。比如“点击按钮后调用 /captcha 接口拿到返回的 base64 图片和 captchaId”这是实现方案不是规格。一份合格的规格应该描述“问题是什么、约束是什么、怎样算完成”把“怎么做”留给编码者在 AI 场景里就是留给 AI。我通常用四个问题来引导自己这个功能解决什么问题在什么场景下生效有什么是不能碰的用什么标准来判断做完了以验证码需求为例我把上面四个问题的答案填进 spec.md 后它变成了“Context Requirements Constraints Acceptance Criteria”的结构。这里面最容易被忽略的部分是 Constraints。因为 AI 很容易“过度设计”如果你不写清楚“不引入新的第三方依赖”“不改变现有状态码约定”它可能会给你引一个验证码库然后把接口文档也改了。写完 spec.md 之后我还会在同一个目录下创建空的 decisions.md 和 acceptance.md。decisions.md 是一份运行日志在开发过程中逐步补充acceptance.md 是对照验收标准的测试清单可以手写也可以让 AI 在生成实现代码时同步生成。3.3 用 SuperPowers 约束 AI 编码行为SuperPowers 落地的关键是把规则写得“可执行、可检查”。不要写“注意代码质量”这种废话而要写“函数必须有 docstring且 docstring 第一行包含 spec 编号”这种能被程序或人工精确判断的规则。我自己用的规则文件分三层。第一层是全局规则约束所有文件第二层是任务规则针对某类任务比如“接口开发”“数据库变更”“测试编写”做细化第三层是提交规则约束 git commit 和合并请求的格式。这里给出一个更完整的 rules.md 示例片段# .superpowers/rules.yaml global: - 所有代码修改必须引用 spec 编号格式为 spec#001 - 禁止修改 specs/ 以外的需求文件 - 若在实现过程中发现规格不合理先停止编码记录问题 task: api: - 接口参数校验必须放在业务逻辑之前 - 新增接口必须同步生成对应的测试用例 database: - 禁止使用裸 SQL 拼接用户输入 - 表结构变更必须包含回滚脚本 commit: - 提交信息必须匹配 ^\\d{3}: .$ - 提交前运行 npm test 或 pytest如果你用 Cursor 或类似工具可以把 rules.yaml 的路径配置到工具的额外指令里如果是 CLI Agent可以直接在 AGENTS.md 里写“启动时自动加载 .superpowers/rules.yaml”。实际操作中我建议把规则文件同时放到项目根目录和用户配置目录防止某些工具不认项目内文件。3.4 让 AI 按规格生成代码并留痕一切准备就绪后真正的编码过程反而变得很“机械”。我会把任务描述写成这样的 prompt请根据 specs/002-login-captcha/spec.md 实现登录验证码功能。 要求 1. 先读取 spec.md列出你理解的验收标准 2. 按 .superpowers/rules.yaml 中的规则编码 3. 编码完成后运行测试并反馈结果 4. 如果实现过程与 spec 存在偏差将决策记录写入 decisions.md这里有个细节值得强调让 AI 先复述验收标准再开始写代码。这个步骤能有效防止它一上来就闷头写。我试过很多次只要 AI 先输出“我理解的验收标准是……”后面跑偏的概率会大幅下降。原因是它把 spec 里的关键信息提前加载到了上下文的前置位置后续生成代码时会更容易保持一致性。代码生成过程中我还会时不时人工打断问一句“你刚刚那个常量值是从哪个需求推导的”如果 AI 答不上来说明它没有真正基于 spec 编码而是在凭直觉写。这时我会回到规则文件加强“常量值必须来源于 spec 或配置文件”的约束。3.5 验证与验收确保每一行都有据可查编码完成不等于功能完成在 SDD 流程里验证和验收是最后一道关卡。我的做法是让 AI 先生成一份“验证报告”内容必须包含测试命令、测试结果、覆盖的验收标准编号和未覆盖项的原因。真实场景下我见过最舒服的一次验证输出是这样的## 验证报告spec#002 登录验证码 ### 测试命令 pytest tests/test_login_captcha.py -v ### 测试结果 7 passed, 0 failed ### 验收标准覆盖 - AC-1: 无验证码请求返回 400 ✓ - AC-2: 验证码错误返回 4001 ✓ - AC-3: 连续失败 5 次后旧验证码失效 ✓ ### 未覆盖项 - 无本次实现覆盖全部验收标准有了这份报告review 代码的人可以在几分钟内判断“代码是否达到规格要求”。如果你还配置了 CI还可以让 CI 自动执行 acceptance.md 里的测试清单并把结果回写到 spec 目录这样追溯链路就完整了。4. 没有 OpenSpec 和有 OpenSpec 到底差在哪4.1 对比实验同一个需求两种做法为了验证这套流程到底有没有用我在自己的一个开源示例项目里做过一次对比实验。需求是“实现一个带缓存的用户信息查询接口缓存时间 10 分钟”。第一次我不给 AI 提供任何规格文件只在 prompt 里说“实现用户信息查询接口带缓存”。AI 很快写完了代码用的是全局静态 Map 做缓存没有过期策略也没有考虑并发问题。代码能跑但显然不符合“10 分钟过期”的隐含要求更别提线程安全性了。第二次我先用 OpenSpec 写好了 spec.md里面明确写了“查询用户信息时先查缓存、缓存命中则直接返回、缓存 miss 时查数据库并写入缓存、TTL 为 600 秒且首次访问创建、并发请求下不能重复查数据库”。然后让 AI 基于 spec 实现结果它自动选择了 Caffeine 作为本地缓存库并设计了一个合理的过期刷新策略还附上了测试用例。两次结果高下立判。区别不在于 AI 能力提升了而在于第二次我给了 AI 一份“可执行的边界说明书”。4.2 效果差异背后的原因拆解为什么同样的 AI 模型在有无 OpenSpec 的情况下表现差距这么大我觉得核心原因有三个。第一AI 是“依据输入做生成”的系统。你输入模糊它就输出模糊你输入精确它就尽量输出精确。OpenSpec 提供的结构化 spec 本质上是一种高质量的输入它把模糊需求转换成了 AI 更容易理解的格式。第二spec.md 里的 Constraints 和 Acceptance Criteria 构成了一种“过滤机制”。AI 生成候选代码时会基于这些约束剔除明显不合规的方案。比如你在 Constraints 里写“不引入第三方依赖”AI 就会优先用 JDK 自带的并发工具实现缓存而不是引入 Caffeine。不是因为它更聪明而是因为它被明确限制了。第三也是我认为最重要的一点OpenSpec 让“追溯”变得容易了。当你发现缓存实现有问题时你能立刻回到 spec.md 去看当时的约束是不是漏了一条当你需要修改功能时你能通过 spec 编号直接找到所有关联代码。这种“代码和需求可互相定位”的能力是裸 prompt 永远给不了你的。5. 常见问题与排查技巧实录5.1 典型问题速查表现象可能原因排查方法 / 解决建议AI 生成的代码和 spec 明显不符规则文件未加载检查 AGENTS.md 和 .superpowers/rules.md 是否在项目根目录确认工具是否读取了项目内规则AI 在实现时悄悄改了 spec 外的代码规则中缺少“禁止修改范围”约束在 rules.md 中增加“只允许修改 specs/xxxx/ 关联文件列表其他文件改动需明确授权”spec 文件更新后 AI 仍然按旧 spec 编码上下文里旧 spec 占主导新会话中先让 AI 重新读取 spec 文件或把 spec 文件的关键结论写进 AGENTS.mddecisions.md 没有自动更新SuperPowers 规则未定义“何时更新”在规则中写明“每次编码完成后如果出现偏离 spec 的决策必须追加到 decisions.md否则禁止提交”测试用例与验收标准不对应缺少验收标准映射在 acceptance.md 中为每条验收标准编号并要求 AI 生成代码时在测试用例中标注对应的 AC 编号多个 AI 编码工具规则冲突不同工具读取的规则文件不同统一在项目根目录维护 AGENTS.md并在其中引用其他规则文件的路径保证所有工具走同一入口5.2 我踩过的三个大坑第一个坑是“规则写得太大而全”。我最开始照着网上别人分享的superpowers配置塞了上百条规则进去结果 AI 每次编码前光解析规则就要很久而且规则之间互相矛盾AI 反而不知道该听哪条。后来我砍到只剩 20 多条核心规则效果反而好了很多。现在我的原则是一条规则如果不能被明确检查就不写。第二个坑是“spec 文件变成一次性文档”。有些同事写 spec 只是为了应付流程需求一变就另开一个新 spec旧 spec 里全是过时的内容。这样做的后果是 AI 在新会话里读到旧 spec 后会被错误信息带偏。我现在强制要求需求变更时只能修改旧 spec并在文件头部加一段 Change Log不能新建文件除非旧 spec 已经被完全弃用。第三个坑是“过度依赖 AI 记录决策”。一开始我以为只要给 AI 规定了“必须更新 decisions.md”它就能自动记录所有关键决策。实际试下来发现AI 只会记录它主动做出的决策如果你在 prompt 里给了它有歧义的约束它可能不会把“我不确定”写进 decisions.md而是直接选一个默认行为。所以我的补救措施是在规则里增加一条“如果发现需求有歧义必须在 decisions.md 中记录‘由于 XX 不确定本次采用 XX 方式’否则视为未完成”。这三个坑让我意识到SDD OpenSpec SuperPowers 这套组合不是“装完就万事大吉”它需要人为维护规则的质量和 spec 的准确性。但长远来看这种维护是值得的因为每一条被记录下来的决策、每一份和代码同步演化的规格都会在未来的某次维护中替你省下大量排查时间。我在实际使用这套流程半年之后最大的变化是我敢让 AI 独立完成更多任务了。以前让 AI 改一个老模块的代码我总担心它把别的地方改坏现在只要它遵循“先读 spec、再实现、再记录决策”这条路径我就敢在它提交后直接看 diff 和验证报告因为每个改动都能向前追溯到需求和约束。如果你也在被 AI 编码的不可控性折磨可以按这篇文章的结构先把 OpenSpec 和 SuperPowers 搭起来哪怕只做一个功能需求也能明显感受到“可追溯代码”带来的安心感。