需求说了三遍,AI 还是写歪
#这两年 “vibe coding” 确实很爽:我们用自然语言一顿输出,模型哗哗吐代码;跑起来就留,跑不起来就继续聊,主打一个“先动起来再说”。但它也很容易把人逼疯:需求散在聊天记录里,改着改着就忘了最初要什么;团队协作更痛,review 只能盯着 diff 猜“你到底改了啥”。
所以我们今天换个更省心的方法:把“规范”当成我们和 AI 共同对齐的那张“收据”。先把 What/Why 写清楚,再让 AI 去写 How。写代码这件事反而变得更可控、更可复盘。
规范驱动开发(SDD)的核心思想
#规范驱动开发(Spec-Driven Development)翻转了传统的AI编程范式。与其让AI猜测你想要什么,不如在写代码前就和AI达成一致:用可执行的、活生生的规范作为共同的理解基础。并且你在每个阶段的职责不是随便指挥一下,而是验证、反思、修正。
通常分为三部分
- 规范(Spec):用户旅程、需求、验收标准(What / Why)
- 计划(Plan):技术栈、架构决策、约束条件(How 的框架)
- 任务(Tasks):可执行的原子任务清单(怎么一步步落地)
关键点在于:每一步都有检查点。我们不是让 AI 一把梭,而是让 AI 先把东西写出来,我们先审清楚,再让它写代码。这一步对团队协作尤其香:因为你 review 的不只是代码,还能检查这次到底要改什么。
SDD相比Vibe编程的核心优势
#spec-kit:适合0→1 阶段的初次开发
#如果我们现在要从零开始创建一个新项目,我强烈建议大家试试 spec-kit。它的长项在于能快速把一个模糊的想法,通过 Constitution → Specify → Plan → Tasks 这一套组合,拉成一个可执行的计划。
安装并初始化
#1
| uv tool install specify-cli --from git+https://github.com/github/spec-kit.git
|
1
2
3
4
5
6
7
8
9
10
| # 创建一个新项目(会生成一个文件夹)
specify init <PROJECT_NAME>
# 或在现有项目中初始化
specify init . --ai claude
# or
specify init --here --ai claude
# 检查已安装的工具
specify check
|
注:specify init . --ai后面可以接任何ai agent,具体可见:支持的 AI 代理
避坑指南:如果使用的是 Codex,安装完记得配一下环境变量。因为斜杠命令目前在 Codex 里只支持系统级别,不支持项目级别。嫌麻烦的朋友可以试试用 opencode 接入。
怎么使用?
#基本命令:
可选命令
用于提升质量和验证的附加命令:
流程演示
#1. 确立项目原则
使用 /speckit.constitution 命令来创建项目的指导原则和开发准则,这些原则将指导所有后续的开发工作。
1
| /speckit.constitution 以“离线可复现 + 双入口共用同一套Python逻辑 + menu.json单一事实源 + 严格校验与规范化写回 + 先过滤后抽样(闭区间) + seed记录可复现 + 权重非法值在校验阶段拦截 + 候选为空必须有明确错误提示(CLI非0退出/GUI提示卡片) + CLI/GUI在同菜单同区间同seed下必须抽中同一条目”为核心,制定项目开发准则与验收红线,并要求所有变更必须保持一致性与可解释性(记录seed、区间、候选数等)。
|
2. 创建规格说明书
使用 /speckit.specify 命令来描述你想要构建的内容。重点关注做什么和为什么做 ,而不是技术栈。
1
| /speckit.specify 做一个离线奶茶抽签小工具:用户输入min/max价格区间(闭区间),系统从本地menu.json里的候选饮品中先过滤再按weight抽出一杯,并展示结果。工具必须同时提供CLI与GUI两种入口,且两者共用同一套Python业务逻辑,保证同一份菜单+同价格区间+同seed时结果完全一致。抽签结果需要记录seed与选中条目的id/name(建议同时记录brand/price、min/max、algorithm、过滤后候选数量),用于复现与解释结果变化。禁止联网抓取真实门店菜单与实时价格,本次以本地menu.json为唯一数据源。
|
3. 制定技术实施方案
使用 /speckit.plan 命令来提供你的技术栈和架构选择。
1
| /speckit.plan Python 3.12 + uv;将“菜单读取/校验/规范化导出/价格过滤/基于seed的加权抽样/菜单CRUD写回(含备份)”做成同一套可复用的Python核心模块,CLI与GUI都只做薄封装以确保一致性。CLI用Typer实现并至少提供milktea validate、milktea export、milktea spin以及菜单增删改查命令;GUI用pywebview加载frontend/index.html,前端通过window.pywebview.api调用Python侧API完成读取菜单、编辑写回与抽签;也允许改用本地FastAPI提供CRUD与抽签接口但必须复用同一套核心逻辑。抽签算法严格遵循:先按min<=price<=max过滤,候选为空时CLI非0退出且stderr提示、GUI给明确提示;过滤后按weight(缺省1)抽样,非法weight在校验阶段拦截;seed可由用户提供或系统生成但必须记录并展示。环境安装:uv venv --python 3.12;uv pip install typer pywebview fastapi。
|
4. 拆分为具体任务
使用 /speckit.tasks 根据您的实施计划创建可操作的任务列表。
5. 执行实施方案
使用 /speckit.implement 来执行所有任务,并根据计划构建您的功能特性。
OpenSpec:适合 1→n 的长期迭代
#我们现在再来看openspec,他非常适合1-n。GitHub仓库:OpenSpec
OpenSpec: 1 → n 阶段的开发范式演进
❌ 传统开发(意图散失)
变更意图:散落在聊天记录中,过两天就丢,无法溯源。
影响评估:改动了哪些能力、哪些边界?说不清,全凭经验猜。
评审盲区:Review 只能翻代码 diff,看不见“需求到底变了什么”。
✅ OpenSpec(规格真相)
openspec/specs/沉淀当前真相,它是系统能力的唯一索引。
openspec/changes/容纳变更提案,让每一次演进意图显性化。
先审需求,后写代码:通过后 Archive 合回 Specs,规格越用越完整。
他的流程示意图如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| ┌────────────────────┐
│ 起草变更 │
│ 提案 │
└────────┬───────────┘
│ 与您的AI共享意图
▼
┌────────────────────┐
│ 审核与对齐 │
│ (编辑规格/任务) │◀──── 反馈循环 ──────┐
└────────┬───────────┘ │
│ 批准的计划 │
▼ │
┌────────────────────┐ │
│ 执行任务 │──────────────────────┘
│ (AI编写代码) │
└────────┬───────────┘
│ 交付变更
▼
┌────────────────────┐
│ 归档与更新 │
│ 规格(源) │
└────────────────────┘
1. 起草一个变更提案,捕获您想要的规格更新。
2. 与您的AI助手审核提案,直到所有人同意。
3. 执行引用已同意规格的任务。
4. 归档变更,将批准的更新合并回源规格中。
|
OpenSpec 官方前置条件是 Node.js >= 20.19.0,先 node --version 看一眼。
1
| npm install -g @fission-ai/openspec@latest
|
验证安装:
在项目中初始化OpenSpec
#1
2
| cd my-project
openspec init
|
初始化时它会引导你选择要集成的 AI 工具,并在项目里生成 openspec/ 结构、以及必要的 agent 指令。
设置完成后会出现一段提示,类似于:
1
2
3
4
5
6
7
8
9
10
11
12
13
| Next steps - Copy these prompts to Codex:
────────────────────────────────────────────────────────────
1. Populate your project context:
"Please read openspec/project.md and help me fill it out
with details about my project, tech stack, and conventions"
2. Create your first change proposal:
"I want to add [YOUR FEATURE HERE]. Please create an
OpenSpec change proposal for this feature"
3. Learn the OpenSpec workflow:
"Please explain the OpenSpec workflow from openspec/AGENTS.md
and how I should work with you on this project"
|
翻译:
1
2
3
4
5
6
7
8
9
10
11
12
13
| 下一步操作 - 将这些提示复制到codex:
────────────────────────────────────────────────────────────
1. 填充项目上下文:
请阅读 openspec/project.md 并协助我完成内容填写
包含我的项目详情、技术栈及规范"
2. 创建您的首个变更提案:
我想添加[在此处填写您的功能]。请创建一个
OpenSpec 对此功能的变更提案
3. 学习 OpenSpec 工作流:
请解释来自 openspec/AGENTS.md 的 OpenSpec 工作流。
以及我该如何与你共同推进这个项目
|
我们按照这个步骤进行就可以了。
具体使用方式
#openspec最好的一点是他足够的轻量化,我们不止可以通过斜杠命令启动,也可以使用自然语言调用。下面展示一个具体的使用流程
流程演示
#1. 起草提案
首先要求您的AI创建变更提案:
1
2
3
4
5
| 您: 创建 无论是在 CLI 还是 GUI 中抽中条目后,不仅仅展示结果,而是生成一张“数字化小票”*。GUI 表现: 弹出一张由 HTML/CSS 渲染的精美小票卡片,包含店铺 Logo、饮品名称、价格、以及底部的“防伪码”。CLI 表现: 使用 ASCII Art 或 rich 库的 Panel 组件,在终端打印出一张长条形的小票样式 的OpenSpec变更提案
(斜杠命令工具的快捷方式: /openspec:proposal add-milktea-offline-picker)
AI: 我将为 add-milktea-offline-picker 创建OpenSpec变更提案。
*在 openspec/changes/add-milktea-offline-picker/ 中搭建proposal.md、tasks.md和规范增量(spec.md等)*
|
2. 验证与审查
检查变更是否正确创建并审查提案:
1
2
3
| $ openspec list # 确认变更文件夹存在
$ openspec validate add-profile-filters # 验证规范格式
$ openspec show add-profile-filters # 审查提案、任务和规范增量
|
3. 完善规范
反复迭代规范,直到满足您的需求:
1
2
3
4
| 您: 为这个小票增加:记录种子与哈希,生成可复现的防伪数字凭证。
AI: 我将更新规范增量与tasks,补充以下场景:
*编辑 openspec/changes/add-milktea-offline-picker/specs/... 与 tasks.md*
|
4. 实施变更
一旦规范看起来不错,开始实施:
1
2
3
4
5
6
| 您: 规范看起来不错。让我们实施这个变更。
(斜杠命令工具的快捷方式: /openspec:apply add-milktea-offline-picker)
AI: 我将处理 add-milktea-offline-picker 变更中的任务。
*按 tasks.md 实施:核心模块 -> CLI(Typer) -> GUI(pywebview桥/FastAPI) -> 测试与复现用例*
*逐项标记任务完成*
|
5. 归档已完成的变更
实施完成后,归档变更:
1
2
3
4
5
6
7
8
| AI: 所有任务已完成。实施已准备就绪。
您: 请归档变更
(斜杠命令工具的快捷方式: /openspec:archive add-profile-filters)
AI: 我将归档 add-profile-filters 变更。
*运行: openspec-cn archive add-profile-filters --yes*
✓ 变更成功归档。规范已更新。准备下一个功能!
|
或者在终端中自己运行命令:
1
| $ openspec archive add-profile-filters --yes # 无提示归档已完成的变更
|
注意: 具有原生斜杠命令的工具(Claude Code、CodeBuddy、Cursor、Codex、Qoder、RooCode)可以使用显示的快捷方式。所有其他工具都通过自然语言请求工作,如"创建OpenSpec提案"、“应用OpenSpec变更"或"归档变更”。
什么时候用哪个?
#如果你只想记住一个判断方式,就用这个:
- 我们还在开荒、要把“想法”变成“可执行工程” → 用 spec-kit(0→1)
- 我们已经有仓库、有代码、接下来要持续迭代、要把“每次变更”写成可审收据 → 用 OpenSpec(1→n)
Spec-kit和OpenSpec对比表:
参考资料
#