1. 为什么SDD能治好AI编程的“脑补”顽疾
先讲个真实翻车现场。上个月我接手一个内部数据看板项目,需求文档写得明明白白:“按部门维度展示工单完成率,支持日期范围筛选”。我图省事,直接用一段长提示词把需求甩给Claude Code,让它自己“看着办”。
结果它确实办得挺快——三分钟交出一版带图表、带筛选、带导出Excel的页面。表面看很完美,可一打开代码我愣住了:它顺手帮我“补充”了权限系统、暗黑模式、国际化文案,甚至给数据接口设计了缓存策略。这些功能我一个字没提,需求方也没提,纯属AI脑补出来的“锦上添花”。
更要命的是,验收时需求方说:“我要的是工单完成率,不是处理时效;筛选范围是自然日不是工作日。”我在屏幕前沉默了——因为对话历史里那几十轮来回改稿,早就说不清当初到底定的什么口径。项目最后返工了三天,核心原因就一句话:口头和提示词层面的“说清楚”,根本经不起工程化审视。
事后复盘,我当时缺少的正是SDD那套“先规范、后编码”的做事框架。不用“大概意思”,而是把每个需求用结构化文件固定下来,让AI在任何一次对话、任何一次修改里都能回到同一份“契约”上,而不是靠它对聊天记录的模糊记忆自由发挥。这就是SDD——Specification-Driven Development,规范驱动开发——存在的理由。
围绕这套方法,现在社区里最热的两样东西是OpenSpec和SuperPowers。前者把规范变成项目里的实体文件,后者把AI的干活方式拆成一整套可复用技能,两个配合起来,基本就是让我前面那种翻车事故从源头消失。这篇文章我会把SDD的门道、OpenSpec怎么落地、SuperPowers怎么装怎么配,以及三者组合的完整实战流程,一次讲透。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. OpenSpec:让技术规范变成可评审、可追踪的文件资产
2.1 OpenSpec到底解决了什么问题
先给结论:OpenSpec是一个把“需求讨论”变成“文件变更”的开源工具链。它不是写文档的模板库,也不是项目管理软件,而是一套约束AI和人都按同一个格式工作的规范协议。
我理解OpenSpec的切入点在于:过去我们让AI改代码,输入的是“口语”,输出的是“代码”,中间的“理解”是不可见的。AI说它懂了,它真懂了吗?没人知道。OpenSpec强迫你在这两者之间插入一层机器可读、人也可审的规范文件——你说清楚要改什么、为什么改、怎么验收,AI读了这份规范之后才开始动代码。这层文件的存在的最大价值不是“写得好看”,而是把需求和实现之间的映射关系固化成可追踪的资产。
打个比方:以前和AI协作像和一个记性很差但手脚麻利的外包聊天,你交代完需求,他干完活就忘了,你追加一句“上次那个逻辑再调一下”,他一脸茫然。OpenSpec相当于给他配了个工单系统,每个需求都建了档、挂了号,不管过了多久,翻档案就能恢复全部上下文。
2.2 目录结构:一个提案就是一个独立文件夹
OpenSpec的目录结构非常简单直接,一套标准的OpenSpec项目长这样:
text复制openspec/
├── project.md
├── specs/
│ ├── epic-1/
│ │ ├── proposal.md
│ │ └── specs/
│ │ ├── feature-a.md
│ │ └── feature-b.md
│ └── epic-2/
│ ├── proposal.md
│ └── specs/
│ └── feature-c.md
└── archive/
project.md:项目级说明,记录全局约定,比如技术栈、架构约束、命名规范、测试要求。这部分是给所有AI辅助工具看的“基本法”。specs/:当前活跃的规范目录,每一个Epic对应一个子目录。- 每个Epic目录下有一个
proposal.md,解释这个Epic要解决什么问题、包含哪些需求条目。 - 每个Epic下可以拆多个
specs/*.md,分别描述单个Feature的详细规范。 archive/:已经完成的、不再活跃的Epic归档区,保证specs/里永远只有“正在进行中的事”。
我第一次建这种目录的时候觉得“就这?这么简单?”但实际用下来才意识到,简单是刻意的。OpenSpec要的不是厚重的需求文档,而是一个轻量、能持续更新、AI能快速读取的文件集合。
2.3 规范文件里到底写什么:一个Feature的完整模板
这是我从OpenSpec官方文档提炼后自己一直在用的精简模板,每个specs/*.md文件基本包含下面这些块:
markdown复制# Feature: 工单完成率统计
## 需求背景
运营团队需要按部门实时掌握工单处理效率,用于周会汇报和绩效考核。
## 需求描述
- 用户进入数据看板页面后,默认展示本月各部门工单完成率。
- 支持通过日期范围选择器筛选统计区间。
- 支持按部门进行多选过滤。
## 验收标准
- [ ] 接口返回字段包含 department_id、completion_rate、total_tickets、completed_tickets
- [ ] completion_rate 计算口径 = completed_tickets / total_tickets * 100
- [ ] 日期范围默认为本月1日至今日,可选范围为近12个月
- [ ] 部门多选为空时默认全选
## 影响范围
- 新增文件:src/api/dashboard.ts
- 修改文件:src/pages/Dashboard.tsx
- 涉及组件:DateRangePicker、DepartmentFilter
## 技术方案
- 前端调用 GET /api/v1/dashboard/completion-rate?start_date=&end_date=&departments=
- 后端在 gateway 服务中新增 handler,查询工单表按部门聚合。
- 数据量超过单表百万行时,考虑按月份建立索引。
这套内容看起来就像普通的PRD,但有一个关键差异:每个字段都是给AI执行时当“硬约束”用的,不是给人阅读用的。比如“验收标准”里的每条勾选项,AI实现完之后必须逐条自检并汇报结果,不能泛泛地说“完成”。
我自己的体会是,写规范文件最花时间的是“影响范围”和“验收标准”两块。前者逼着我先把改动边界划清楚,避免AI东一榔头西一棒子把不相关文件都改了;后者逼着我把“什么叫做好”定义成可验证的语句,而不是“体验要好”“速度要快”这种没法验收的废话。
2.4 OpenSpec的自检体系:AI像考试一样过验收清单
OpenSpec工作流里还有一个我特别喜欢的点:它把每次变更拆成Analysis、Code、Debug三个阶段的闭环(社区常叫ACD流程)。
- Analysis阶段:AI读取
proposal.md和相关specs/*.md,分析影响范围、依赖关系、潜在风险,然后把分析结果写回到specs里。 - Code阶段:AI严格按照规范的验收标准开发,每实现一条就把对应勾选项标记为完成。
- Debug阶段:跑测试、跑lint、人工抽查代码,任何不符合验收标准的问题都回到Analysis修正规范或Code修正实现。
这个闭环思路上其实很像TDD:TDD用测试约束代码行为,SDD用规范约束AI行为。不同之处在于,TDD约束的是“函数的输入输出”,SDD约束的是“整个需求从设计到验收的全过程”。
很多人在OpenSpec之前都用过“给AI写一个超长prompt,里面包含需求说明”的方法,但超长prompt的问题是:没有结构化,AI很容易在长对话中丢失早期约束;没有版本管理,需求变了你改的是聊天记录,没法追踪谁在什么时候改了什么;没有评审入口,你和AI之间没有一份“共同阅读的文件”,讨论的颗粒度永远是对话级的。
OpenSpec把这些问题全部变成文件系统里实实在在的改动。需求变更时,你不是重新打一段字,而是修改specs/里的文件并提交commit。每个人(包括AI)看到的都是同一份最新规范,这就是它稳定性的来源。
3. SuperPowers:把零散提示词升级成AI的系统化技能库
3.1 SuperPowers的本质:一套“AI技能包”
如果说OpenSpec解决的是“需求怎么定义”,那SuperPowers解决的就是“AI怎么干活”。准确地说,SuperPowers是GitHub上一个开源项目,为Claude Code(以及Codex、OpenCode等支持Skills机制的AI编码工具)提供了一套预置的Skill集合。每个Skill是一个Markdown文件(或一组文件),里面写清楚AI遇到某类任务时必须要遵守的工作步骤、思考模板和输出格式。
我的理解是:普通提示词是给AI一段“怎么回答”的指令,Skill是给AI一套“怎么思考”的方法论。 区别非常明显——你用普通提示词让AI写单元测试,它可能随便生成几个happy path用例就算完事;但加载了SuperPowers的test-driven-development Skill后,它会先分析现有代码的可测试性、列出测试计划、按红绿重构节奏推进、最后做覆盖率检查。整个执行链条,和TDD教练在手把手带它,是一样的效果。
SuperPowers这个项目后来还集成和借鉴了社区里很多优秀Skill,包括代码审查、系统设计、规划、调试、写提交信息等几十个方向。它不需要单独装一个插件,而是利用Claude Code原生支持的SKILL.md机制,让AI在进入特定任务时自动读取对应技能说明。
3.2 安装与初始化:实际验证过的稳定路径
根据官方README和社区里最近的实践反馈,目前最稳定的安装路径是这样的:
bash复制# 1. 克隆仓库到本地
git clone https://github.com/obra/superpowers.git
# 2. 创建skills目录(如果Claude Code项目还没有)
mkdir -p .claude/skills
# 3. 把需要的skills软链或复制到项目skills目录
ln -s "$(pwd)/superpowers/skills" .claude/skills/superpowers
安装完之后,可以用Claude Code的/skills命令验证是否被识别。正常情况下列表里会出现superpowers相关的所有Skill,比如brainstorming、writing-plans、executing-plans、debugging、test-driven-development等。
有一点需要特别提醒:软链要使用项目的相对路径或者绝对路径,别直接复制到根目录层级,否则Claude Code识别不到。 我第一次装就栽在路径上,以为复制过去就行,结果Claude Code完全没反应,排查半天才发现skills目录必须放在项目根目录的.claude/skills下。
另外,当下社区里另一个高频词是“OpenSpec搭配SuperPowers一起使用”,这是因为OpenSpec负责定义“做什么”,SuperPowers的writing-plans、executing-plans等Skill负责定义“怎么做”。两者天然互补:OpenSpec给AI一份结构化的需求档案,SuperPowers帮AI用一套成熟的工程方法论把档案里的需求变成代码。
3.3 核心Skill逐个拆解:哪些真正提升了交付质量
我用SuperPowers这套技能包跑了两个完整项目后,挑出几个实际提升最明显的Skill说:
brainstorming:这个Skill会引导AI在动手前先提出多个候选方案,并针对每个方案列出优缺点,而不是直接给出一个看似最优的实现。以前让AI“实现一个缓存模块”,它默认就是Redis+装饰器;用了brainstorming之后它会主动比较内存缓存、本地文件缓存、Redis、多级缓存这些方案的取舍,让我有机会根据项目实际情况做决策,而不是被AI带着走。
writing-plans:这是我最喜欢的一个Skill。它会要求AI把一个大的实现需求拆分成若干个有序步骤(Step),每个Step里写清楚目标文件、关键逻辑、依赖关系和验证方式。最终产出的Plan是一个可执行的Markdown文档。这个流程和OpenSpec其实有重合,但角度不同:OpenSpec的specs偏重“需求规范”,writing-plans偏重“任务执行计划”。两者配合使用,效果是AI从拿到需求到动手写第一行代码之间,有了一条完整的推导链路。
executing-plans:这个Skill要求AI严格按照Plan执行,每完成一个Step就停下来做自检、更新进度状态。它的核心价值是防止AI在长任务里跑偏——没有这种阶段性自检时,AI可能埋头写了200行代码,结果方向早已偏离需求;有检查点之后,偏差最多积累到一两步之内就能被发现。
test-driven-development:让AI写测试时,这个Skill会引导它先写失败测试、再跑红、再实现、再跑绿、最后重构,每个循环都留有输出记录。对我的价值是:AI生成的测试不是“凑覆盖率”的摆设,而真正反映需求逻辑的验证集。
3.4 SuperPowers的局限性和我的取舍
SuperPowers不是银弹,它有明显的使用前提:**它假设你用的AI编码工具支持Skills机制。**目前最顺滑的搭档是Claude Code,Codex和OpenCode也能用但需要看版本支持情况。如果你的主力工具是GitHub Copilot这类未开放Skills机制的IDE插件,那SuperPowers暂时用不上。
另一个取舍是:**Skill不是越多越好。**我一开始图新鲜把全部Skill都链进去了,结果Claude Code每次启动都要读取大量上下文,首响应变慢,而且AI有时候会同时受到多个Skill影响,行为变得不太可预测。后来我把skills目录精简到十几个高频实用的,稳定性和响应速度都好了很多。
还有一个容易忽略的点:SuperPowers的Skill本质上是“通用的工程方法论”,它不包含你的业务知识。比如debugging Skill会让AI按“复现-定位-修复-回归”的流程排查问题,但它不会告诉你你们项目的数据库连接池为什么会断。所以SuperPowers要配合项目自身上下文使用,不能指望它替代业务理解和架构设计。
4. 三件套合体:一个真实全栈需求的完整落地实录
4.1 从需求到规范:把一句话变成一份OpenSpec
讲完原理,来走一遍真实流程。我用最近的一个小需求做例子:给一个B端工单系统新增“待办事项分类看板”。
需求方原始描述只有一句:“我要首页能按优先级看到我的待办数量,最好能点进去看明细。”
这句话离可执行差得太远了。我做了下面几件事,整个过程全部用OpenSpec落地:
**第一步,把模糊需求翻译成结构化条目。**打开编辑器,创建openspec/specs/dashboard-todo/proposal.md:
markdown复制# Proposal: 首页待办分类看板
## 问题陈述
用户登录首页后无法快速了解自己的待办分布情况,需要进入多个页面分别查看,效率低。
## 目标
在首页新增一个“待办分类看板”区域,按紧急、高、中、低四个优先级展示待办数量,支持点击查看当前优先级下的明细列表。
## 非目标
- 不做拖拽排序。
- 不做实时推送,数据刷新频率为5分钟一次。
- 不做移动端适配(当前版本仅桌面端)。
## 功能列表
- [ ] F1: 按优先级展示待办数量卡片
- [ ] F2: 点击卡片进入对应优先级的待办明细页
- [ ] F3: 数据每5分钟自动刷新
注意“非目标”这一节,这是我强烈建议大家一定要写的内容。AI(以及很多人)最喜欢在需求模糊的地方自己加戏,非目标就是明确告诉AI和所有人:“这些事本次不干”,有效挡掉了AI的“顺手脑补”。
**第二步,写每个功能点的详细规格。**以F1为例,创建openspec/specs/dashboard-todo/specs/priority-cards.md:
markdown复制# Feature: 优先级待办数量卡片
## 需求描述
在首页展示四个卡片:紧急、高、中、低,分别显示当前用户在该优先级下的待办数量。点击卡片跳转至对应优先级列表页。
## 验收标准
- [ ] 接口 GET /api/v1/todos/count-by-priority 返回 { emergency: number, high: number, medium: number, low: number }
- [ ] 四个卡片按紧急、高、中、低顺序从左到右排列
- [ ] 卡片上的数量为当前登录用户的数据,而非全部用户
- [ ] 点击卡片跳转至 /todos?priority=emergency 等对应路由
- [ ] 页面加载时并行请求数据,不阻塞其他首屏组件
- [ ] 追加后端单元测试,覆盖空数据、部分优先级缺省两种情况
## 数据规格
json复制{
"emergency": 3,
"high": 7,
"medium": 5,
"low": 12
}
code复制
这些验收标准就是后面要求AI逐条打勾的清单。写的时候我会刻意写“可测试”的语句,比如“返回字段包含”“点击跳转至”“覆盖两种边界情况”,绝不写“体验良好”“交互流畅”这种没法验证的词。
**第三步,让AI审视规范,补齐遗漏。**接下来把`openspec/`目录丢给Claude Code,让它作为“需求评审人”读一遍,指出规范里前后不一致、边界缺失、实现成本过高的地方。这一步非常有用——AI会从实现角度反问:“数据刷新5分钟的策略是前端setInterval还是后端轮询?重新请求时是否需要防抖?跳转列表页有没有需要保留筛选状态?”这些追问很大程度上修正了我原始规范里的盲区。
### 4.2 让AI写执行计划,而不是直接写代码
规范落定后,下一步不是让AI开写,而是让AI先生成执行计划。这就是SuperPowers的`writing-plans` Skill登场的时候。
我给你看看实际生成的Plan结构长什么样(精简版):
```markdown
# Implementation Plan: 首页待办分类看板
## Step 1: 新增后端聚合接口
- 文件:src/api/routes/todo.ts
- 操作:新增 /todos/count-by-priority 路由
- 实现要点:
- 从JWT中解析当前用户ID
- 按优先级分组统计todos表
- 对缺省优先级补0
- 验证:curl 请求接口,确认返回JSON包含4个优先级字段
## Step 2: 定义前端API方法
- 文件:src/api/todo.ts
- 操作:新增 fetchTodoCountByPriority
- 实现要点:
- 类型定义对应后端返回结构
- 错误处理时抛出自定义异常
- 验证:前端单元测试 mock 接口,验证类型字段完整
## Step 3: 实现首页卡片组件
- 文件:src/components/TodoPriorityCards/index.tsx
- 操作:渲染四个卡片组件
- 实现要点:
- 使用 flex 布局,间距16px
- 点击跳转使用 react-router 的 useNavigate
- 加载中显示骨架屏
- 验证:Storybook 渲染检查,点击事件测试
## Step 4: 接入数据刷新机制
- 文件:src/hooks/useTodoPriorityCount.ts
- 操作:实现数据请求、定时刷新、组件卸载时清理计时器
- 实现要点:
- 每5分钟调用一次接口
- 页面隐藏时暂停刷新,重新可见时立即刷新
- 验证:定时器测试,使用 vi.useFakeTimers 验证5分钟间隔
## Step 5: 集成与联调
- 文件:src/pages/Dashboard.tsx
- 操作:在页面中渲染卡片区域,完成联调
- 实现要点:
- API Base URL 使用环境变量
- 处理接口超时与错误提示
- 验证:手动测试全流程,确认无控制台报错
这份Plan的好处是:它把“代码改动”拆成了可以逐个验证的小步骤。我只需要快速扫一遍Plan,确认每个Step的方向正确,就可以放手让AI执行。如果某个Step的方向不对,我改的是Plan里的文字,比让AI改200行代码再返工要便宜太多。
4.3 执行、验证、纠偏:SuperPowers让AI不跑偏
Plan确认后,让Claude Code进入executing-plans模式,它会严格按照Plan的Step顺序推进,每完成一个Step就停下来汇报结果、更新进度。整个执行过程中,我看到的最有价值的反馈是:它真的会在Step之间自检,而不是闷头一口气写完所有代码。
有一个场景让我印象深刻。它执行到Step 4时报告:“当前项目使用的React Router版本是v6,useNavigate的用法正确,但Dashboard路由的懒加载会导致页面切换时组件卸载重建,定时刷新机制应该放在useEffect依赖项中考虑,否则每次切换路由都会重新创建定时器。”这种对实现细节的警觉,正是SuperPowers的技能描述里反复强调的“不要盲目照做,要考虑上下文”。
执行完之后,AI会把Plan里每个Step的验证结果贴出来,我再结合实际代码抽查一遍,确认确实不是“嘴上说完成了”。这个抽查环节非常关键——AI说它“添加了单元测试并全部通过”,你要能打开测试文件看到真实的测试用例和运行结果,而不是被一句话带过去。
4.4 六步实践指南在三件套中的落地映射
社区里最近流传很广的“SDD六步实践指南”(来自ThoughtWorks杰出工程师Birgitta Böckeler的框架),我实际跑下来觉得这套三件套本身就是六步法的最佳载体。六步大致是:识别需求边界、定义验收标准、拆解技术方案、编写执行计划、分步实现与验证、复盘归档。
对应到工具链上,识别需求边界靠OpenSpec的proposal和“非目标”清单,定义验收标准靠规格文件里的“验收标准”勾选块,拆解技术方案靠规格文件里的“技术方案”和“影响范围”,编写执行计划靠SuperPowers的writing-plans,实现与验证靠executing-plans和ACD闭环,复盘归档靠OpenSpec的archive目录。
这套映射跑通之后,我最大的感受是:以前我和AI之间是“老板与实习生”的关系,我说一句它干一件,干错了再让它改;现在我和AI之间是“架构师与高级工程师”的关系,我把需求和验收边界定义好,它自己会拆分任务、按步骤执行、主动报告风险和进度。
5. 用了一个月之后的踩坑记录与参数调优
5.1 最容易忽视的坑:规范文件过时
SDD工作流最大的坑不是AI不听话,而是规范文件容易和代码脱节。需求在实现过程中临时调整了,代码改了,但openspec/specs/里的验收标准没人同步更新。等到下次给AI提新需求时,它读到的还是一份过期的规范,结果按旧逻辑“正确”地实现了错的需求。
我的应对方案是约定一条纪律:**凡是AI在实现过程中偏离了原始验收标准,必须同步修改对应的spec文件,并在commit message里引用spec变更记录。**这条纪律一开始靠人肉盯,坚持了几周后变成了团队习惯,规范文件的有效性大幅提升。
5.2 SuperPowers上下文膨胀问题
前文提到过,一开始把全部Skill都链进去会导致启动变慢。这里给一个我实测过的配置建议:**项目级.claude/skills目录只放当前项目必需的Skill,通用型Skill(比如brainstorming、writing-plans、executing-plans、debugging)可以放到用户级配置目录,给所有项目共享。**我在macOS上的用户级目录是~/.claude/skills,项目级目录保持精简,两者互不干扰。
另外,如果你发现某个Skill在当前AI编码工具里没被加载,先检查工具版本和SKILL.md的格式。SuperPowers的issues区有不少人反馈“装了没反应”,最后排查基本都是版本兼容问题,升级到最新版Claude Code就好了。
5.3 OpenSpec规范文件粒度控制
还有个大坑是规范粒度。我一开始写Feature规格容易写得过于细致,把函数签名、组件props、路由路径全写在验收标准里。结果AI实现时被绑得死死的,遇到设计上的小问题也不敢自己调整,动不动停下来问我。后来我发现OpenSpec的精髓是**定义“什么是对的”,而不是定义“怎么做”。**函数签名、组件结构属于技术实现细节,应该交给AI在writing-plans阶段自行决策;规范层只需要把接口行为、业务规则、边界条件写清楚。
调整之后,规范文件从“超详细SOP”变成“契约与边界”,AI的自由度和规范性都回到了合理水平。
一个更具体的经验:**OpenSpec规范的验收标准控制在3-8条之间是性价比最高的。**少于3条说明粒度太大,AI容易发挥过度;多于8条说明拆得还不够细,建议拆成多个Feature文件。
5.4 建议的目录与配置模板
最后分享一套我目前正在用的、经过实战调优的默认结构,供你直接抄作业:
text复制my-project/
├── .claude/
│ └── skills/
│ ├── writing-plans # 按需软链
│ ├── executing-plans
│ └── test-driven-development
├── openspec/
│ ├── project.md
│ ├── specs/
│ │ └── active-epic/
│ │ ├── proposal.md
│ │ └── specs/
│ │ ├── feature-1.md
│ │ └── feature-2.md
│ └── archive/
├── src/
└── package.json
如果你用的是Claude Code,可以在项目根目录加一个CLAUDE.md,里面写上“开始任何开发任务前,先检查openspec/specs目录,确定是否有涉及当前改动的规范文件;如果没有,先创建或更新规范,再进入实现阶段”之类的全局行为约束。这等于从项目层面给AI装了“先看规范再动手”的强制引导。
最后再分享几个实际体验
写这篇文章时正好是我把OpenSpec和SuperPowers组合使用的第九周。坦白说,第一周非常不适应——以前我习惯拿到需求就直接和AI“对聊”,现在要先把需求变成结构化的规范文件,第一反应是“这也太重了”。但坚持下来的结果是实打实的:这两个月我做的四个功能迭代,几乎没有出现过AI跑偏到不可挽回的返工,每次需求变更有清楚的diff记录可以回溯,AI产出的代码稳定性和可审查性都明显高于裸奔时期。
如果你准备尝试这套工作流,我建议不要一步到位全部上齐。先从OpenSpec开始,把当前正在做的第一个需求写成规范的proposal和spec,让AI按规范执行一次,感受一下“先定义后编码”的节奏;第二到三周再接入SuperPowers的writing-plans和executing-plans两个Skill,跑完一个完整闭环;确认流程顺畅后,再逐步增加其他Skill。这样渐进式切换,适应成本会低很多,也比一次性推翻原有工作方式要稳。这套组合不一定适合所有团队——如果你的需求极其简单、改动量很小、AI用一次对话就能搞定,那上这套流程确实显得多余。但凡是那种“需求方自己都说不清楚、AI又特别喜欢自以为是”的项目,我强烈建议你认真尝试一次,看看规范的力量有多大。
