前言
截至 2026 年 7 月,GitHub 上关于 SDD 的库,spec-kit 已经有了 12 万多 Star,OpenSpec 也有 6 万多 Star。能在 GitHub 拿下这么高的 Star,想必是有说法的。AI 写代码已经那么快了,那么强了,为什么我们还需要 SDD?这篇文章就想聊聊这个。
我们平时怎么用 AI 开发的?
我们平时使用 AI 开发的流程,大概是下面这样的:
swift
提个需求
↓
让 AI 去读项目
↓
让 AI 开始写代码
↓
yes、yes、yes,don't ask me again
↓
运行和测试
↓
有 bug、需求没理解对
↓
鞭笞 AI:"你这里写的不对,我的意思是 xxxxx"
↓
AI 继续改
↓
N 轮之后终于搞定
↓
不愧是我
比如我们要给一个 Todo App 增加提醒功能,只需要告诉 AI:
给 Todo App 增加任务提醒功能。
AI 很快就能修改数据模型、增加时间选择页面,然后调用系统通知接口。
运行之后,也确实可以收到通知。
但真正开始测试的时候,可能会发现很多没有说清楚的问题:
- 用户拒绝通知权限后怎么办?
- 修改时间,旧的通知要不要取消?
- 删除或者完成任务后,通知还要不要触发?
- 点击通知后,应该进入哪个页面?
于是我们继续补充提示词,AI 继续修改代码。
但是其实并不是 AI 不会写,而是我们在写之前,没有交代清楚我们真正想要的结果,而那些没有说出来的部分,就只能 AI 自己去猜,猜对了,功能就能很快完成,猜错了,我们就得不断修改。
实际开发中,我们当然不一定只有一句需求,一般还会有一份需求文档。需求文档能够让我们知道这个功能是什么,但是不代表每一种情况下应该怎么表现、怎么交互都写得很明确。
测试同学在编写用例时,经常还会想到权限失败、重复操作、状态变化或者异常数据等场景。这部分的思考,应该在代码实现之前完成,不然 AI 可能会没有注意到这些细节。
当然,也不是在这个阶段就把所有测试用例写完。如果预期结果已经明确,只是需要更换设备、系统版本或者数据组合进行验证,那就留到测试阶段处理。
SDD 就是来解决这个问题的。
SDD 是什么?
SDD 全称 Specification-Driven Development,翻译过来就是规格驱动开发。
简单来说,就是在让 AI 写代码之前,先把要做的事情整理成一份明确的规格,然后再根据规格生成技术方案、任务和代码。
它的一个典型的流程是:
swift
提出需求
↓
Specification:AI 问你想干啥,什么情况才算完成
↓
Plan:AI 给你描述它打算怎么实现
↓
Tasks:AI 将它的方案拆分成可以执行的任务
↓
Implement:AI 根据任务实现代码
↓
Verify:回到最开始的规格,检查结果是否符合需求
如果你用过 plan 模式,你应该会觉得这套流程似曾相识。
正经点就是:
- Specification:说明要做什么,什么情况算完成
- Plan:说明准备怎么实现
- Tasks:将方案拆成可以执行的任务
- Implement:根据任务实现代码
- Verify:回到最开始的规格,检查结果是否符合要求
为什么需要 SDD?
就是 AI 太快了,写代码太快了,快到你还没有真正的交代好需求,它就已经给你写完了,然后你回头发现,这里写的不对、那里缺了点东西,就得修修补补。

所以它解决的问题是:
代码已经写完了,需求还没有真正想清楚。
它做的事情,就是 把原本在编码之后才发现的问题,尽量提前到编码之前解决。
以前是:
- 先写代码
- 运行后发现需求遗漏
- 修改需求和代码
SDD 是:
- 先整理需求
- 发现遗漏并确认
- 再生成代码
它并不能消除所有的返工,但在只有几段文字的时候修改需求,通常比代码已经散落到多个模块之后再修改简单。
另外,它还顺带解决了一个很重要的问题,就是 上下文的问题。
直接使用 AI 开发的时候,很多决定会散落在你和 AI 的聊天记录里,换一个会话、换一个 Agent,或者过一段时间再回来,或者你不小心关闭了这个会话,可能就会忘记当时为什么要这样实现。
而 Spec、Plan 和 Tasks 可以和代码一起保存在项目中,后面的 AI 可以直接读取,不需要我们每次都重新解释一遍。
用了之后会怎么样?
还是以 Todo App 的提醒功能来举例。
这次我们不让 AI 立即写代码,而是先告诉它:
给 Todo App 增加任务提醒功能。
先不要修改代码,帮我整理功能范围、用户行为和验收条件。
对于没有说清楚的地方先向我提问,不要自行决定。
经过几轮的确认之后,我们可能得到一份简单的规格:
text
## 目标
用户可以为未完成的任务设置一个提醒时间。
## 验收条件
- 用户可以创建不包含提醒的任务;
- 修改提醒时间后,只保留新的通知;
- 完成或者删除任务后,取消对应通知;
- 用户拒绝通知权限后,页面需要给出提示;
- 点击通知后,打开对应任务。
## 不包含
- 不支持重复提醒;
- 不支持服务端推送。
规格确认后,再让 AI 根据项目生成技术方案:
根据已经确认的规格和当前项目结构,生成技术方案。
说明需要修改哪些模块,以及这些模块各自负责什么。
方案确认后,再拆成任务:
根据规格和技术方案拆分任务。
每个任务需要有明确的完成条件和验证方式。
最后才进入代码实现,并在完成后根据规格逐条验收。
所以在使用 SDD 后,开发过程并没有发生什么神奇的变化,仍然要写代码、运行测试、检查结果。
真正发生变化的是,AI 不再只依赖一句临时提示词,而是根据一组经过确认的内容去干活。
所以,聊天驱动代码变成了,规格驱动代码。
怎么用?
它并不需要你去安装什么工具,它只是一套规则,最简单的,在项目中自己加几个文件就能用起来:
swift
docs/
└── specs/
└── task-reminder/
├── spec.md
├── plan.md
└── tasks.md
然后给自己定几条规则:
- Spec 没有确认之前,不开始设计和实现
- Plan 没有确认之前,不开始拆任务
- 每个任务都需要说明怎么验证
- 实现中发现新需求,先更新 Spec
- 完成后根据 Spec 逐条验收
另外也不需要每个任务都走完整流程。
- 小任务直接实现
- 有一些边界条件的:Spec -> Tasks -> Implement -> Verify
- 影响多个模块:Spec -> Plan -> Tasks -> Implement -> Verify
SDD 的重点不在于生成多少份文档,而是根据任务复杂度,决定需要提前说清楚多少内容。
GitHub 上那些 SDD 库
Spec Kit
spec-kit 提供的完整能力大致如下。这里为了方便理解是列了完整的流程,但并不是每个需求都必须依次执行所有步骤:
swift
Constitution(项目级)
↓
Specify
↓
Clarify(可选)
↓
Plan
↓
Checklist(可选)
↓
Tasks
↓
Analyze(可选)
↓
Implement
↓
Converge
其中,Constitution 主要用于定义项目长期遵守的原则,一般不需要为每个需求重复执行。
Clarify、Checklist 和 Analyze 都是按需使用的可选命令。
看看每一步都在做什么。
-
Constitution(项目级):定义整个项目需要遵守的原则
- 使用什么架构和技术栈
- 代码需要符合什么质量标准
- 哪些内容必须经过测试
- 是否允许添加第三方依赖
-
Specify:将原始需求整理成
spec.md- 要解决什么问题
- 用户可以做什么
- 系统应该表现出什么行为
- 什么情况才算完成
-
Clarify(可选):找出规格中没有说清楚的地方
- 是否存在多种理解
- 有没有遗漏边界情况
- 哪些内容是 AI 自己做出的假设
- 将确认后的答案写回
spec.md
-
Plan:根据规格生成技术方案
- 使用什么系统 API
- 需要修改哪些模块
- 数据如何流转
- 使用什么方式进行测试
-
Checklist(可选):检查规格本身的质量
- 需求是否完整
- 表达是否明确
- 不同需求之间是否冲突
- 每一项是否可以验证
-
Tasks:将技术方案拆成任务
- 每个任务需要修改什么
- 需要修改哪些文件
- 任务之间有什么依赖
- 完成之后如何验证
-
Analyze(可选):检查 Spec、Plan 和 Tasks 是否一致
- 规格中的行为是否都有对应方案
- 方案中的内容是否都被拆成任务
- 是否存在遗漏或者冲突
-
Implement:根据
tasks.md实现代码- 按照依赖顺序执行任务
- 运行对应测试
- 更新任务完成状态
-
Converge:根据原始规格检查最终结果
- 哪些要求已经实现
- 哪些要求还没有实现
- 发现遗漏后补充任务并继续实现
它的整个过程可以概括为:
- 先确定项目规则
- 把需求说清楚
- 找出需求中的歧义
- 设计实现方案
- 拆成可以执行的任务
- 实现代码
- 回到原始需求验收
OpenSpec
OpenSpec 和 Spec Kit 不同的是,OpenSpec 不强调必须依次经过多个阶段,而是把每个需求当成项目的一次变更。
项目中会同时保存两种规格:
openspec/specs/
记录系统当前已经确认的行为。
openspec/changes/
记录当前正在开发的变更。
OpenSpec 默认提供 Explore、Propose、Apply、Update、Sync 和 Archive 六个核心 Workflow。
Verify 不在默认的 Core Profile 中,但可以按需启用。它们的使用方式大致如下:

具体流程可以参考 OpenSpec OPSX 文档。
我们看看每一步都在做什么:
Explore
在正式创建变更前探索需求:
- 读取现有项目
- 理解当前实现
- 比较不同方案
- 找出没有说清楚的问题
- 不创建正式变更,也不修改代码
如果需求已经明确,可以直接跳过。
Propose
为需求创建一个独立的变更目录:
swift
openspec/
└── changes/
└── change-name/
├── proposal.md
├── specs/
├── design.md
└── tasks.md
其中:
proposal.md:为什么要做,会影响什么specs/:系统行为发生了什么变化design.md:准备如何实现tasks.md:需要完成哪些任务
规格会通过下面几种方式描述变化:
ADDED:新增要求MODIFIED:修改已有要求REMOVED:删除要求RENAMED:只修改名称
design.md 不是所有需求都必须生成。如果变更涉及多个模块、数据模型、外部依赖或者重要技术选择,就需要先写 Design,简单修改可以省略。
Apply
根据变更中的文档实现代码:
- 读取 Proposal、Specs、Design 和 Tasks
- 按照任务列表修改代码
- 完成后更新任务状态
- 实现中发现需求或者方案发生变化时,先使用 Update 更新已有产物
这也是 OpenSpec 和固定阶段流程不同的地方:实现过程中如果需求或者方案发生变化,可以使用 Update 回到前面的产物,再继续 Apply。
Update
如果需求、技术方案或者任务发生变化,使用 Update 更新已经存在的变更产物:
- 修改已有的 Proposal、Specs、Design 或 Tasks
- 检查其他产物是否需要一起调整
- 保持需求、设计和任务之间的一致
- 不创建缺失的产物,也不修改代码
Update 不是 Apply 之后必须执行的固定步骤,而是在需求或者方案发生变化时按需使用。
如果代码已经按照旧方案实现,更新产物之后,还需要再次 Apply,让代码和新的方案保持一致。
Verify
检查代码是否符合变更内容:
- 所有任务是否完成
- 每条要求是否已经实现
- 边界情况是否处理
- 实现是否符合 Design
Verify 默认不在 Core Profile 中,需要手动启用:
swift
openspec config profile
openspec update
在配置中勾选 verify 后,具体入口取决于所使用的 Agent 和 Delivery。
如果使用 Commands Delivery,通常是:
swift
/opsx:verify
如果使用 Codex 的 Skills Delivery,则是:
swift
$openspec-verify-change
复杂功能或者跨模块修改适合执行 Verify,简单并且已经充分测试的修改可以跳过。具体配置方式可以参考 OpenSpec Commands。
Sync
将当前变更中的规格合并到项目主规格:
swift
openspec/changes/change-name/specs/ -> openspec/specs/
Sync 可以在开发过程中主动执行,让其他变更提前读取最新规格。
如果功能实现后马上归档,也可以不单独执行,等 Archive 时一起同步。
Archive
结束并归档本次变更:
- 检查文档和任务状态
- 提示同步尚未合并的规格
- 将变更移动到
archive/ - 保留 Proposal、Design、Tasks 和 Spec 的完整历史
归档后的结构大概是:
swift
openspec/
├── specs/
│ └── 当前有效的规格
└── changes/
└── archive/
└── 已经完成的变更
所以 OpenSpec 的整个过程可以概括为:
- 理解需求
- 建立一次独立变更
- 描述系统行为发生了什么变化
- 根据变更实现代码
- 需求或者方案变化时,更新已有产物
- 按需检查代码是否符合变更内容
- 把变化合并到当前规格
- 归档完整的开发历史
cc-sdd
cc-sdd 最关注两件事:
- 通过 Spec 明确模块边界和依赖关系
- 规格确认后,让 Agent 长时间、逐任务完成实现
cc-sdd 的整体流程如下:

具体流程可以参考 cc-sdd Workflow。
也来看看它的每一步在做什么:
Steering
记录整个项目的长期上下文:
- 使用什么架构和技术栈
- 代码目录如何组织
- 项目有哪些开发规范
- 模块之间有什么依赖
- 使用什么测试和验证方式
Steering 主要用于已有项目。如果 Agent 已经可以从其他文件获取完整项目规则,可以按需使用。
Discovery
判断当前需求应该采用什么开发方式:
- 直接实现,不创建 Spec
- 修改一个已有 Spec
- 创建一个新 Spec
- 将大需求拆成多个 Spec
- 将不同部分混合处理
Discovery 会保存 brief.md,让后面的 Agent 不需要重新理解需求。如果需要拆成多个 Spec,还会生成 roadmap.md。
所以 Discovery 不只是澄清需求,还负责判断这次工作到底需不需要进入完整 SDD。
Spec Init
为功能创建独立工作区:
swift
.kiro/
└── specs/
└── feature-name/
后面的 Requirements、Design 和 Tasks 都会保存在这个目录中。
Design
生成技术设计:
- 调查当前项目实现
- 设计模块、接口和数据流
- 说明需要修改哪些文件
- 明确每个模块负责什么
- 记录模块之间允许的依赖
design.md 中会包含一份 File Structure Plan,用来划分后面任务可以修改的文件范围。
cc-sdd 将这一步称为 Boundary-First,也就是先确定边界,再让多个 Agent 独立工作。
Tasks
将 Design 拆成任务:
- 每个任务只负责一块明确工作
- 标记任务之间的依赖
- 说明允许修改的文件和模块
- 记录完成条件和验证方式
任务中会出现类似的标记:
swift
_Boundary: 这个任务可以修改什么
_Depends: 这个任务依赖什么
这样 Agent 执行任务时,不会随意修改范围之外的模块。
Spec Batch
如果 Discovery 判断需求过大,可以使用:
/kiro-spec-batch
它会:
- 根据 Roadmap 创建多个 Spec
- 并行生成不同 Spec
- 检查多个 Spec 之间是否存在冲突
- 检查接口和职责是否重复
- 确保每个 Spec 可以独立交付
Implementation
规格经过确认后,使用:
/kiro-impl
cc-sdd 支持两种实现方式。
自动模式:
- 每次只执行一个任务
- 为任务创建一个新的实现 Agent
- 使用 TDD 完成代码
- 再由独立的 Reviewer Agent 检查结果
- 失败时使用新的调试 Agent 分析原因
- 将经验写回
tasks.md,供后续任务读取
手动模式:
- 指定需要执行的任务
- 在当前会话中完成实现
- 同样按照测试、实现和验证的方式执行
具体执行方式可以参考 cc-sdd Skill Reference。
Validation
检查多个任务组合后的最终结果:
- 各任务是否都已经完成
- 实现是否违反模块边界
- 不同任务之间是否保持一致
- 测试、构建和静态检查是否通过
- 上游修改是否要求重新验证下游任务
单个任务的正确性主要由 Reviewer Agent 检查,Validation 更关注多个任务组合之后是否仍然能够正常工作。
cc-sdd 的核心
cc-sdd 不把 Spec 看成控制所有实现细节的总文档。
它更倾向于把 Spec 看成模块之间的合同:
- 这个模块负责什么
- 不负责什么
- 可以依赖什么
- 修改后需要重新验证什么
具体实现仍然可以由 Agent 自由决定,但不能越过已经确认的边界。cc-sdd 的设计说明 也明确提出,代码仍然是最终运行的真实结果,Spec 负责让责任和边界变得清楚。
所以 cc-sdd 的整个流程可以概括为:
- 先判断需不需要 Spec
- 将需求拆成可以独立交付的范围
- 明确模块边界和依赖
- 拆成一个个独立任务
- 由不同 Agent 实现和审查
- 最后验证任务之间是否能够正确协作
它们有什么区别?
看完前面噼里啪啦的一堆流程,会发现它们都在做同一件事:先把需求变成 Spec,再生成设计、任务和代码。
区别在于,它们关注的问题不同。
Spec Kit 更关注需求、方案和任务是否完整、一致。
它围绕需求、设计和任务提供一套完整能力,并根据任务复杂度按需使用 Clarify、Checklist 和 Analyze。
它是在问:
这个需求有没有被完整地说明和实现?
OpenSpec 更关注项目发生了什么变化。
它把每次需求记录成一次独立的变更,完成后再合并到项目当前的规格中,并保留完整的变更历史。
它是在问:
这次开发给现有系统增加、修改或者删除了什么?
cc-sdd 更关注任务应该怎么拆,以及 Agent 应该怎样执行。
它会先明确模块边界和任务依赖,再让不同 Agent 分别负责实现、审查和验证。
它是在问:
怎样把工作拆开,让 Agent 可以长时间执行,又不会互相干扰?
所以简单来说:
- Spec Kit:强调让需求、方案和任务保持完整、一致
- OpenSpec:强调管理持续发生的变更
- cc-sdd:强调划分边界并让 Agent 持续执行
TDD 是什么?
说完 SDD,再说一下 TDD。
TDD 全称 Test-Driven Development,也就是测试驱动开发。它并不是代码写完以后再补测试,而是按照下面的流程反复开发:
text
先写一个测试,并确认它会失败(Red)
↓
写刚好能让测试通过的代码(Green)
↓
在测试仍然通过的前提喜爱整理代码(Refactor)
↓
继续实现下一行为
例如 SDD 先规定:
完成任务后,需要取消对应的提醒。
到了 TDD 阶段,就会先为这个行为编写测试,再实现取消提醒的代码,直到测试通过。
它和 SDD 并不是二选一的关系,它们解决的问题并不一样:
SDD 先决定应该实现哪些行为,TDD 再用测试逐个实现这些行为。
它们不在同一个层级里。可以把 TDD 理解成 SDD 的 Implement 阶段里,一种可选的开发方式:
text
SDD 工具负责外层流程
规格
↓
设计
↓
任务
↓
实现
↓
验证
在"实现"这一步里
可以选择使用 TDD
还是用 Todo 提醒功能举例。
最开始我们发现一个问题:
用户完成任务后,提醒还要不要触发?
这个问题应该由 SDD 处理,因为此时连正确结果是什么都不知道。经过确认,规格中写明:
用户完成任务后,需要取消对应的提醒。
接下来进入实现阶段,TDD 才开始发挥作用:
- 先写一个测试:完成任务后,应该调用取消提醒的方法
- 运行测试,因为代码还没有实现,所以测试失败
- 编写取消提醒的代码,让测试通过
- 整理代码,然后继续实现下一个行为
因此:
- SDD 发现并确认 "完成任务后应该取消提醒"
- TDD 确保这条行为被代码正确实现
TDD 不会替你决定完成任务后究竟要不要取消提醒。如果需求没有提到权限失败,TDD 也不会凭空替你补出这个场景。它只能在预期结果已经确定后,将这个结果变成测试,再推动代码实现。
还有,SDD 并不要求必须使用 TDD。在刚刚的几个库中,cc-sdd 明确将 TDD 放进了实现流程;Spec Kit 可以按需生成测试先行的任务;OpenSpec 则不限制具体的实现方式。TDD 是 SDD 进入到代码实现阶段后,可以采用的一种开发方式。
需要打造自己的 SDD 吗?
其实看完你可能会发现,它们都很强,但是它们不一定和你平时的开发流程很契合。不过好在,我们可以自己打造专属于自己的 SDD。
这里的关键是,你在意的是什么,你希望 AI 帮你做到哪些东西,并把这个流程给规范下来。
以我自己为例,我关注的是:
- 需求上有什么遗漏或者不合理的地方吗?
- 代码准备怎么实现,大概会做哪些改动,为什么要选择这个方案?
- 会改哪里,影响的范围是哪些?
- 需要测试哪些场景,怎么样算测试通过?
- 这次改动如何长期记录和归档?
但是列完之后我发现好像 OpenSpec 就很符合我的需求,所以打造自己的 SDD 这个大业就暂时搁置了,抛砖引玉,只是做一个思路的分享,后续可能我会将 TDD 的流程也引入进来,再说吧。