AI 乱改代码?试试这套 SDD 规范驱动工作流

AI 乱改代码?试试这套 SDD 规范驱动工作流
在 AI Coding 快速普及的这两年越来越多的团队开始使用 Codex、Cursor、Claude Code 等工具辅助开发。围绕这些工具也出现了大量关于 Prompt、Skills、MCP 的使用教程。但很多内容都停留在“单点提效”层面教你怎么写 Prompt、怎么装工具、怎么调用能力却很少回答一个更关键的问题当 AI 进入研发流程后我们该如何建立一套稳定、可持续、可复用的工程协作方式这篇文章就围绕这个问题展开。先看一下团队在使用 AI 辅助开发时最常见的几个问题Prompt 过于简单AI 获取的信息不足会自行补全上下文导致实现结果跑偏一次性丢给 AI 的信息太多但没有明确重点和验收标准最终输出容易失焦代码实现可能不符合团队规范甚至无意中扩大改动范围一些关键术语和业务背景只存在于当前会话新开会话后又要重新解释这些问题的症结往往在于研发上下文缺乏有效组织这是单纯优化 Prompt 难以逾越的瓶颈。因此我们需要将重心转向工程化搭建一套让 AI 在既定规则内稳定运行的流程。这正是今天我们要探讨的核心——SDDSpec-Driven Development规范驱动开发。二、SDD 规范驱动开发SDD 是什么SDDSpec-Driven Development规范驱动开发并不是一个全新的概念。它在软件工程领域很早就已经出现核心理念是先定义规则再进行实现。只是过去编写和维护规格文档的成本较高所以并没有真正成为主流开发方式。随着 2024、2025 年 AI Coding 的快速发展AI 已经可以高效生成代码但也暴露出需求理解不稳、改动范围失控、上下文无法持续复用等问题。在这个背景下SDD 被重新讨论起来。比如 GitHub 的 Spec Kit 就把 AI 开发流程固化为Specify - Plan - Tasks - Implement让 AI 更像一个执行者而人的重心则前移到需求定义、架构设计、约束说明和验收标准上。SDD 与传统方案的区别熟悉传统研发流程的人会发现这其实就是“先写技术方案再开发”的 AI 版本但是也和之前略有不同。与传统方案相比SDD 的区别大致如下维度传统方案SDD文档读者人AI 人文档颗粒度可读即可需要结构化便于 AI 解析验收标准相对模糊尽量可验证、可判断文档与代码关系容易逐渐脱节由规格驱动实现更容易保持一致看到这里很多人会有一个自然的疑问原本写方案就已经很耗时了现在还要把文档写得更细、更结构化成本会不会更高答案是现在已经有很多成熟的工具可以辅助我们编写 Spec整体成本其实更低其实在生成 Spec 时我们也会进一步加深对需求的理解而这部分投入换来的是后续编码阶段更低的返工率和更稳定的协作质量。SDD 如何解决这些问题前面提到的“AI 乱改代码”很多时候并不是单一问题而是几个问题叠在一起AI 不知道需求边界会自行补逻辑AI 不知道验收标准有可能会提前结束AI 不理解项目约束容易改出不符合团队习惯的代码AI 缺少长期上下文新会话里又会重复犯同样的问题SDD 要解决的就是把这些原本藏在需求评审、技术方案、开发经验里的信息提前整理成 AI 可以持续读取复用的规格文档。比如Spec解决“要做什么、不能做什么”的问题。它会写清楚用户场景、功能边界、异常情况和验收标准。这样 AI 在实现时就不需要自己猜需求也不容易把无关逻辑一起改掉。Design解决“应该怎么做”的问题。这里会说明我们的技术方案、模块影响范围、数据流、接口依赖和兼容性要求等。Tasks解决“先做哪一块、做到什么程度”的问题。它会把需求拆成可执行、可验证的小任务。AI 每次只处理一个明确范围改动就更容易收敛更方便人做 review 和回滚。这样一来AI 从分析、计划到编码都能围绕同一组规格文档展开。人负责定义规则和判断结果AI 负责在规则内完成实现。随着这些 Spec 文档在项目里持续沉淀它们还会逐渐形成项目级知识库。后续再开启新会话时AI 不需要从零理解业务也不需要反复解释同一批规则协作稳定性会明显提升。三、工具选型OpenSpec目前 SDD 已经出现了很多优秀的工具帮辅助我们提效比较常见的方案包括 OpenSpec、Spec Kit、superpowers 等。如果团队希望轻量接入、尽快落地我会更倾向于选择OpenSpec。它不一定适合所有场景但对现有团队流程的侵入更小落地门槛也更低。初始化方式比较直接安装 OpenSpec 后在项目中执行openspec init再选择对应的 AI Coding 工具即可生成如下目录结构openspec/ ├── specs/ # Source of truth (your systems behavior) │ └── domain/ │ └── spec.md ├── changes/ # Proposed updates (one folder per change) │ └── change-name/ │ ├── proposal.md │ ├── design.md │ ├── tasks.md │ └── specs/ # Delta specs (whats changing) │ └── domain/ │ └── spec.md └── config.yaml # Project configuration (optional)我们重点关注如下几个核心文件文件作用spec.md定义需求、边界、行为、约束、验收标准作为 AI 的长期上下文design.md记录具体的技术方案与实现设计proposal.md描述背景、目标、影响面与推进理由tasks.md任务拆解与执行进度参考以 Codex 为例如果已经接入了对应能力可以通过/opsx的快捷指令快速进入这套流程。更多能力可以参考 OpenSpec GitHub。命令中文含义什么时候用opsx-propose新建需求Change刚接到一个新需求时opsx-explore探索、讨论需求需求还不清晰需要分析时opsx-update更新已有需求文档需求发生变化时opsx-apply根据任务实现代码需求确认后开始开发时opsx-sync将变更同步到正式 Spec开发完成需要更新正式规范时opsx-archive归档完成的需求整个需求结束后OpenSpec 只是这套工作流的一种承载方式核心不是某个具体工具而是“先定义规格再约束执行再持续沉淀”的协作方式。在理想状态下我们不直接从代码开始而是先定义和持续修正 Spec 文档再让 AI 围绕这些文档进行 Coding。一次 OpenSpec 的生命周期大致如下整体架构OpenSpec 解决了“按规格推进开发”的主流程但要让 AI 输出更稳定还需要把上下文获取、项目规则和自动化校验一起补齐。整体上可以把这套协作方式理解为下面这张图四、实际落地只看流程图和整体的架构图很多没实践过的人还是会觉得抽象可能并不清楚 MCP、Skills 等约束在里面扮演的角色 不清楚在什么阶段应该使用哪个指令下面我们沿着一次常见的 AI Coding 协作流程看看 OpenSpec 的一套流程在实际研发中是怎么落地。生成 Spec一次复杂需求开始时我们可以先使用/opsx:propose 需求内容、技术方案等生成一版 Spec 文档。但实操下来会发现如果完全依赖复制粘贴把信息塞进对话框不仅效率低也容易遗漏关键信息最终影响 Spec 的完整性。MCP获取更全的上下文因此我们需要借助 MCP 的能力让 AI 能够直接获取散落在Figma、语雀、Yapi等工具里的上下文。把研发流程中常用的数据源统一封装到 MCP Server 中一方面可以减少手动复制带来的信息损耗另一方面也能让 Spec 的生成更贴近真实业务上下文。有了这个能力之后我们再进行 Spec 编写就可以/opsx:propose 产品文档 链接1 技术方案 链接2 ...AI 输出完成之后仍然需要我们介入检查。因为当前项目可能还没有足够多的历史 SpecAI 对业务知识的理解并不完整生成内容里可能会出现错误的业务词汇、不合理的架构设计等问题。这时直接修改生成的 Spec 文档即可。随着 Spec 持续丰富后续生成时这类问题也会越来越少。文档修改完成之后就可以进行最为关键的下一步生成代码生成代码这一步我们只需/opsx:apply即可让 AI 根据 Spec 文档快速生成代码但是实操下来会发现使用/opsx:apply之后它虽然理解了业务名词和逻辑但仍然会扩大改动范围或者产出一些不符合团队规范的命名和实现。这一步我们就需要借助一些额外的手段来约束这些不规范行为1. Skills把软约束变成可复用的规则层每个团队都有自己的开发规范如果每次把这些团队通用规则都通过 Prompt 和 Spec 的方式告诉AI会造成很大的资源浪费在这里我们可以把这些软约束变成可复用的规则层。在我的工作流中 Skills 分为两层 底层 Skill约束模型 上层 Skill指导模型理解业务底层 Skill你可以把这个Skill理解成“给模型的长期工作习惯”放一些编码通用规则比如编码前先思考优先做小改动不随意扩大范围修改后要自查并说明影响面遇到不确定的地方先确认不要硬猜...这类的通用规则放在工具全局所有项目共享使用。推荐使用andrej-karpathy-Skills上层 Skill但真正和你项目业务强相关的东西往往是另一层内容比如我们的项目架构哪一层负责请求哪一层负责数据处理组件命名习惯业务里的专有名词哪些历史坑不能再踩这部分更适合做成项目级 Skill持续迭代放在我们的项目中。Skills 和 Spec 本质上都是在给 AI 提供上下文但是放的内容 Spec 重心在做什么而 Skills 重心在怎么做。2. AGENTS.md给 AI 的项目入场说明书除了 Skills还可以利用AGENTS.md。很多 AI Coding 工具都会优先读取项目中的规则说明文件。它适合放那些“进入项目后默认就该知道”的内容可以把它理解成项目给 AI 的入场说明书。例如比较适合放进去的内容包括项目结构怎么读哪些规范优先级最高哪些目录或文件不要随便改...如果你不知道这个文件格式怎么写这一步同样可以使用 AI 去生成你只需要验证他生成的文档即可。为什么这些内容不全部放进 Skills因为两者的触发机制和作用范围并不完全一样Skills 是按需激活更适合通用规则或者单项定制规则像我们上面提到的通用编码规范等等。AGENTS.md 是进入我们项目生效存放我们当前项目的定制规则像我们这个特殊项目代码结构等等。在很多工具里AGENTS.md 的读取时机会比 Skills 更早因此它特别适合放最底层、最稳定的项目规则。3. Hooks把软约束升级成硬约束即便有了 Spec、Skills 和 AGENTS.mdAI 仍然可能在复杂任务里偶尔“抽风”。因为我们上面那些约束都是软约束AI 可能并不会遵守这个约定我们想要强验证和规范我们的代码就需要使用 Hooks 能力。很多 AI Coding 工具都提供了 Hook 能力允许我们在特定生命周期节点执行脚本。以 Codex Hooks 为例常见的节点包括UserPromptSubmit用户提示词提交后、AI 接收前PreToolUse调用工具前可以拦截高风险操作PostToolUse工具执行后、结果返回给 AI 前Stop会话停止前可执行检查、测试或 CR 流程例如在实践中会发现 Codex AGENTS.md/Prompt 已经写了”前端代码不能直接写中文要走国际化“但在长会话或复杂任务里AI 还是偶尔会输出中文硬编码。这时候就可以在代码修改后强制执行一个检测脚本#!/bin/bash FILE$1 # 检测中文 if grep -nE [\u4e00-\u9fa5] $FILE; then echo echo 检测到中文硬编码 echo 请改成 echo t(xxx) exit 2 fi exit 0hook 示意配置如下{ Hooks: { PostToolUse: [ { matcher: Edit|Write, Hooks: [ { type: command, command: ./scripts/check-i18n.sh $CLAUDE_FILE } ] } ] } }在拥有了这些配置后AI 产出的质量会有明显提升。AI Coding 完成后我们需要继续做的工作是review AI 生成的代码验证界面与交互是否符合预期识别这次协作中暴露出来的新问题这些问题后续可以反过来沉淀到 Skills、AGENTS.md 和 Hooks 中形成下一轮更稳定的协作基础。规格同步实际开发中我们经常会遇到一些计划外的变化代码写到一半产品临时调整了交互后端接口字段发生变化开发过程中发现原来的技术方案走不通或者 review 时发现某个边界场景之前没有考虑到等。这些变化本身很正常但在 AI Coding 流程里如果只改代码、不更新 Spec就会埋下一个问题代码已经变了但 AI 后续读取到的规则还是旧的。短期看这可能没什么影响因为当前会话里大家都还记得发生了什么。但一旦换一个会话或者过几天继续迭代AI 仍然会按照旧 Spec 理解需求。结果就是它可能把你刚修过的逻辑又改回去或者在旧规则基础上继续生成代码导致代码和规格越来越不一致。这个时候有两种做法先通过/opsx:sync 变动描述去修改 Spec 文档然后基于最新的 Spec 文档去/opsx:apply特殊情况我们手动修改了代码然后一定要使用/opsx:sync 描述去更新 Spec这样就可以保证我们的代码和 Spec 保持一致。归档沉淀当所有任务完成、验证通过后最后一步就是/opsx:archive。很多人会把 archive 理解成“把这次任务结束掉”但在 SDD 里它更重要的作用是把一次临时协作中产生的有效经验沉淀成后续可以复用的项目上下文。一次需求做完以后真正有价值的东西不只有代码本身还包括这次需求最终确认下来的功能边界哪些设计决策被采纳哪些方案被放弃实现过程中发现了哪些历史问题哪些规则值得沉淀到主 Spec、Skills 或 AGENTS.md哪些测试和验收方式可以复用到后续同类需求如果不归档这些信息往往只存在于当前会话、临时分支或某个人的记忆里。等下次再做类似需求时AI 还是要重新理解一遍团队也要重新解释一遍很多已经踩过的坑还会再踩一次。比如某次需求中我们发现“后台导出类功能必须区分任务创建成功和文件生成成功”。这个规则如果只留在当前代码里下一次 AI 做另一个导出功能时未必会知道。但如果在 archive 时把它沉淀进项目规范后续类似需求就能直接复用这条经验。从长期来看archive 做得越扎实项目里的上下文就越完整。AI 对项目的“熟悉度”不是凭空产生的而是靠这些持续沉淀下来的规格、规则和历史决策一点点建立起来的。后续协作的边际成本也会随着这些上下文的积累逐渐降低。适用场景不是所有需求都值得走完整的 SDD 流程有些时候直接 Vibe Coding 可能效率更高更推荐使用 SDD 的场景包括新业务模块复杂功能开发多人协作项目长期维护项目大型重构一个很实用的经验判断是如果一个需求预计会持续超过 2 天通常就值得建立 Spec因为这类需求的复杂度已经足够高AI 很难仅靠一轮对话稳定完成而一旦有了 Spec后续协作成本会明显下降。不太推荐使用 SDD 的场景包括过于简单的改动纯样式调整一次性方案验证非持续性的临时脚本这些场景本身信息密度不高强行走一整套 SDD 流程反而会拖慢效率。实用技巧刚开始生成 Spec 时不要追求一步到位。先有一版能工作的草稿再在验证过程中持续补齐。先写清楚用户场景和目标再讨论实现细节不要一上来就陷入技术方案。一次只推进一个最小闭环例如“补一个页面能力”或“修一条配置链路”避免范围持续膨胀。如果需求还不稳定先把不确定项显式列出来再开始实现避免边做边猜。任务拆分尽量按“可提交、可验证、可回退”来切不要把多个业务点揉成一个大改动。每完成一个子任务就做一次最小验证至少确认页面渲染、请求参数和类型检查没有明显问题。五、总结现在模型的能力已经很强了但它并不会自动替我们完成所有判断。真正决定产出质量的还是取决于我们的用法SDD 只是当下一种比较好的选择但未来肯定远不止于此。