AgentHarness 课程

规范驱动编程(Spec-Driven Development)

9.8K字·25分钟·
Vibe Coding vs Spec Coding、Spec-Kit工作流、Constitution

引言

在 AI 编程的时代,最大的挑战不是"AI 能不能写代码"——它显然可以。真正的挑战是:

如何确保 AI 写出的代码,是你真正想要的?

传统的做法是"边做边改":你描述需求,AI 生成代码,你发现不对,再修改描述,AI 再生成……这个循环可能重复十几次,最终你得到的代码勉强能用,但谁也不敢说它"正确"。

规范驱动编程(Spec-Driven Development, SDD) 正是为解决这个问题而生。它的核心理念只有一个:

与其在错误的方向上快速前进,不如花时间把方向写清楚。


一、从第一性原理思考

1.1 软件开发的本质是什么?

让我们回到最根本的问题:软件开发的本质是什么?

不是写代码。代码只是最终产物。软件开发的本质是:

将人类的意图,转化为机器可执行的指令。

这个转化过程有两个关键环节:

人类意图 → [需求理解] → 规范文档 → [代码生成] → 可执行程序

传统开发中,两个环节都由人类完成。AI 时代,第二个环节可以交给 AI。但第一个环节——从意图到规范——仍然是人类的核心价值。

1.2 Vibe Coding 的根本问题

Vibe Coding(凭感觉编程)跳过了第一个环节:

人类意图 → [直接跳过] → AI 猜测 → 代码 → 发现不对 → 重来

这就像你让一个非常能干的助手"帮我准备一个会议",但不告诉他是哪种会议、多少人、什么主题。他可能会准备一个完美的技术分享 PPT,但你需要的是一个客户提案。

Vibe Coding 的根本问题不是 AI 不够聪明,而是你没有把意图说清楚。

1.3 Spec Coding 的解法

Spec Coding 补上了缺失的环节:

人类意图 → [写规范] → 规范文档 → [AI 生成] → 代码 → 验证(对照规范)

关键变化:

  • 规范成为"可执行的源代码"——AI 直接根据规范生成完整代码
  • 维护软件 = 维护规范——改规范,代码自动重新生成
  • 调试 = 修复规范——不是修代码,而是修规范中描述错误的部分
  • 重构 = 重构规范——规范变了,代码跟着变

二、Vibe Coding vs Spec Coding

2.1 详细对比

维度Vibe CodingSpec Coding
定义凭感觉/氛围编程以规范文档驱动编程
输入自然语言描述结构化规范文档
输出质量不可预测可预测、可验证
适用场景小玩具、原型验证复杂业务、企业级、长期维护
团队协作困难(谁知道"感觉"是什么?)自然(规范就是沟通语言)
可追溯性无(对话历史不可靠)完整(规范就是历史)
维护成本高(改代码 → 重新理解 → 改更多代码)低(改规范 → 代码自动重新生成)
关系过渡形态最终形态(企业级范式)

2.2 一个真实的例子

Vibe Coding 方式

你:帮我做一个用户注册功能
AI:好的(生成了邮箱+密码注册)
你:要支持手机号注册
AI:好的(加了手机号,但邮箱注册的验证逻辑被改坏了)
你:邮箱验证怎么坏了?
AI:抱歉,让我修复(修复了邮箱,但手机号的短信发送又出问题了)
...

Spec Coding 方式

## 用户注册功能规范

### 支持的注册方式
1. 邮箱注册:邮箱 + 密码 + 邮箱验证码
2. 手机号注册:手机号 + 短信验证码

### 验证规则
- 邮箱格式校验(RFC 5322)
- 密码强度:8位以上,含大小写和数字
- 验证码有效期:5 分钟
- 同一邮箱/手机号 1 分钟内只能发送 1 次验证码

### 接口定义
POST /api/auth/register
Body: { type: "email" | "phone", identifier: string, password: string, code: string }
Response: { code: 201, data: { userId: string, token: string } }

AI 一次性生成完整、正确的代码。没有来回修改。


三、Spec-Kit 工作流

Spec-Kit 是 GitHub 开源的规约编程工具,提供 8 个核心命令,形成完整的规范驱动工作流:

constitution → specify → clarify → plan → tasks → analyze → implement
    ↓            ↓         ↓        ↓       ↓        ↓         ↓
 项目原则    → 功能规范 → 需求澄清 → 实现计划 → 任务分解 → 一致性审核 → 代码实现

3.1 Constitution(项目宪法)

项目宪法定义了整个项目的核心原则和约束。它是一切规范的"元规范"。

# 项目宪法

## 核心原则
1. 用户体验优先于技术实现
2. 安全性不可妥协(OWASP Top 10 全覆盖)
3. 代码可读性 > 性能优化(可读的慢代码 > 不可读的快代码)

## 技术约束
- 前端:React 18 + TypeScript + Tailwind CSS
- 后端:Node.js + Express + Prisma
- 数据库:PostgreSQL(主库)+ Redis(缓存)
- 部署:Docker + Kubernetes

## 编码规范
- 测试覆盖率 > 80%
- 所有 API 必须有 OpenAPI 文档
- 错误处理必须完善(不允许未捕获异常)
- 日志必须结构化(JSON 格式)

## 禁止事项
- 不使用 any 类型
- 不在组件中直接调用 API(使用 hooks/services 层)
- 不使用 console.log(使用 logger 服务)
- 不硬编码密钥(使用环境变量)

为什么需要项目宪法?

没有宪法,每个功能的规范可能相互矛盾。比如一个功能用 MongoDB,另一个用 PostgreSQL;一个用 RESTful,另一个用 GraphQL。项目宪法确保所有功能在统一的技术框架下工作。

3.2 Specify(功能规范)

为每个功能编写详细的规范文档:

# 用户认证模块 - 功能规范

## 背景
平台需要支持用户注册、登录、登出功能。当前无用户系统。

## 用户故事
- 作为新用户,我可以通过邮箱注册账号
- 作为新用户,我可以通过手机号注册账号
- 作为已注册用户,我可以通过邮箱+密码登录
- 作为已登录用户,我可以登出当前会话

## 技术要求
- 密码使用 bcrypt 加密(salt rounds: 12)
- 登录成功返回 JWT token(有效期 7 天)
- 注册需要验证码确认(邮箱/短信)
- 同一 IP 每小时最多注册 10 个账号(防刷)

## 接口定义

### POST /api/auth/register
请求:
{
  "type": "email",
  "identifier": "user@example.com",
  "password": "SecurePass123",
  "code": "123456"
}

成功响应(201):
{
  "code": 201,
  "data": { "userId": "uuid", "token": "jwt..." }
}

错误响应:
- 400: 参数缺失或格式错误
- 409: 邮箱/手机号已注册
- 429: 验证码发送过于频繁

## 验收标准
- [ ] 邮箱注册 → 收到验证码 → 输入验证码 → 注册成功
- [ ] 手机号注册 → 收到短信 → 输入验证码 → 注册成功
- [ ] 重复邮箱注册 → 返回 409
- [ ] 错误验证码 → 返回 400
- [ ] 密码强度不足 → 返回 400 + 具体提示

3.3 Clarify(需求澄清)

AI 会根据规范提出澄清问题:

AI: 关于验证码的重发机制,规范中提到"1分钟内只能发送1次",
    但还需要确认:

    1. 验证码重发次数限制:
       A) 无限制(只要间隔1分钟)
       B) 每天最多 10 次
       C) 每小时最多 5 次

    2. 验证码输入错误的处理:
       A) 无限次尝试(直到过期)
       B) 连续错误 5 次后锁定 15 分钟
       C) 连续错误 3 次后作废,需要重新获取

    3. 注册成功后的跳转:
       A) 直接跳转到首页
       B) 跳转到个人资料完善页
       C) 跳转到登录页(需要重新登录)

为什么要这一步? 因为规范再详细,也不可能覆盖所有细节。AI 的澄清问题往往涉及你没考虑到的边界情况。

3.4 Plan(实现计划)

实现计划:

1. 数据模型设计(30分钟)
   - 创建 User 模型(Prisma schema)
   - 创建 VerificationCode 模型
   - 运行数据库迁移

2. 验证码服务(45分钟)
   - 邮件验证码生成与发送
   - 短信验证码生成与发送(接入腾讯云 SMS)
   - 验证码校验逻辑

3. 注册接口(30分钟)
   - 参数校验
   - 重复检查
   - 密码加密
   - 用户创建

4. 登录接口(20分钟)
   - 邮箱+密码验证
   - JWT token 生成

5. 登出接口(10分钟)
   - Token 失效处理

6. 安全加固(20分钟)
   - IP 限流
   - 验证码错误次数限制
   - 密码强度校验

7. 测试(45分钟)
   - 单元测试
   - 集成测试
   - 边界情况测试

总计:约 3.5 小时

3.5 Tasks(任务分解)

Task 1: 创建 Prisma schema(User + VerificationCode)
  依赖:无
  预计:10 分钟

Task 2: 实现验证码服务(生成 + 发送 + 校验)
  依赖:Task 1
  预计:30 分钟

Task 3: 实现注册接口
  依赖:Task 2
  预计:20 分钟

Task 4: 实现登录接口
  依赖:Task 1
  预计:15 分钟

Task 5: 实现登出接口
  依赖:Task 4
  预计:10 分钟

Task 6: 安全加固(IP限流 + 错误次数限制)
  依赖:Task 3, Task 4
  预计:20 分钟

Task 7: 编写测试
  依赖:Task 3, Task 4, Task 5
  预计:30 分钟

3.6 Analyze(一致性审核)

AI 检查规范之间是否一致:

一致性审核结果:

✅ 注册接口与数据模型一致
✅ 密码加密方式与项目宪法一致(bcrypt)
⚠️ 警告:规范中提到"JWT 有效期 7 天",但项目宪法中建议"敏感操作需要二次验证"
   → 建议:登录后 7 天内可访问普通功能,但修改密码/绑定手机需要重新验证

✅ 所有接口都有错误码定义
✅ 验收标准覆盖了主要场景
⚠️ 警告:验收标准缺少"并发注册"场景
   → 建议:添加"同一邮箱并发注册只创建一个账号"的测试

3.7 Implement(代码实现)

AI 根据规范自动生成完整代码:

// src/modules/auth/register.ts
import bcrypt from 'bcrypt';
import { prisma } from '@/lib/prisma';
import { sendVerificationCode } from '@/services/verification';
import { ApiError } from '@/lib/errors';

export async function register(req: Request, res: Response) {
  const { type, identifier, password, code } = req.body;

  // 参数校验
  if (!type || !identifier || !password || !code) {
    throw new ApiError(400, '参数缺失:type, identifier, password, code 均为必填');
  }

  if (!['email', 'phone'].includes(type)) {
    throw new ApiError(400, 'type 必须为 email 或 phone');
  }

  // 密码强度校验
  if (password.length < 8 || !/[A-Z]/.test(password) || !/[a-z]/.test(password) || !/[0-9]/.test(password)) {
    throw new ApiError(400, '密码必须8位以上,含大小写字母和数字');
  }

  // 验证码校验
  const isValid = await verifyCode(identifier, code);
  if (!isValid) {
    throw new ApiError(400, '验证码错误或已过期');
  }

  // 重复检查
  const existing = await prisma.user.findUnique({
    where: type === 'email' ? { email: identifier } : { phone: identifier }
  });
  if (existing) {
    throw new ApiError(409, type === 'email' ? '邮箱已注册' : '手机号已注册');
  }

  // 创建用户
  const hashedPassword = await bcrypt.hash(password, 12);
  const user = await prisma.user.create({
    data: {
      ...(type === 'email' ? { email: identifier } : { phone: identifier }),
      password: hashedPassword,
    }
  });

  // 生成 token
  const token = generateJwt({ userId: user.id });

  return res.status(201).json({
    code: 201,
    data: { userId: user.id, token }
  });
}

四、Vibe Coding → Spec Coding 的演进路径

4.1 四个阶段

阶段 1: 纯 Vibe Coding
  "帮我做一个登录页面"
  → 适合:个人项目、原型验证
  → 问题:代码不可控、难以维护

阶段 2: 轻量 Spec
  写 1-2 页的需求文档,AI 根据文档生成代码
  → 适合:小团队、MVP 阶段
  → 改进:有文档可追溯

阶段 3: 完整 Spec-Kit
  Constitution → Specify → Clarify → Plan → Tasks → Analyze → Implement
  → 适合:正式项目、团队协作
  → 改进:全流程规范化

阶段 4: Spec as Code
  规范文件纳入版本控制,修改规范 = 修改软件
  → 适合:企业级、长期维护
  → 改进:规范即代码,代码即规范

4.2 什么时候用什么方式?

场景推荐方式原因
学习新技术Vibe Coding快速试错,不需要规范
个人小工具轻量 Spec有个文档记录就够了
团队项目完整 Spec-Kit需要多人协作、代码审查
企业级系统Spec as Code长期维护、合规要求
生产环境修复Vibe Coding紧急修复,先解决问题
新功能开发完整 Spec-Kit需要充分的需求分析

五、实战案例:从零到一的 Spec 驱动开发

5.1 场景:开发一个任务管理应用

第 1 步:写 Constitution(10分钟)

# 任务管理应用 - 项目宪法

## 核心原则
1. 简洁优先:功能不多但每个都好用
2. 离线可用:核心功能不依赖网络
3. 数据安全:任务数据本地加密存储

## 技术栈
- 前端:React + IndexedDB(离线存储)
- 后端:Supabase(同步服务)
- 部署:Vercel

第 2 步:写功能规范(20分钟)

# 任务创建功能规范

## 用户故事
- 作为用户,我可以快速创建任务(标题 + 描述)
- 作为用户,我可以为任务设置截止日期
- 作为用户,我可以为任务添加标签

## 验收标准
- [ ] 输入标题后按 Enter 即可创建
- [ ] 截止日期支持自然语言("明天"、"下周五")
- [ ] 标签支持自动补全
- [ ] 离线创建的任务在联网后自动同步

第 3 步:AI 澄清 → 确认 → 实现

AI 提问后确认方案,然后一次性生成完整代码。

结果:2 小时完成一个可工作的任务管理应用,代码质量远高于 Vibe Coding 的结果。


六、概念体系总结

规范驱动编程涉及的完整概念链:

Constitution(宪法)
  ↓ 定义原则
Specification(规范)
  ↓ 描述需求
Rules(规则)
  ↓ 约束行为
Skills(技能)
  ↓ 武装能力
Memory(记忆)
  ↓ 积累知识
Spec-Kit(工具链)
  ↓ 编排流程
Sub-agents(子代理)
  ↓ 并行执行
Hooks(钩子)
  ↓ 质量保障
概念角色类比
Constitution项目宪法国家宪法
Specification功能规范法律条文
Rules约束行为规章制度
Skills武装能力专业培训
Memory积累知识经验传承
Spec-Kit编排流程司法程序
Sub-agents并行执行专业部门
Hooks质量保障监察机构

七、常见陷阱与最佳实践

陷阱 1:过度设计

❌ 花 3 天写规范,然后用 1 小时写代码
✅ 花 1 小时写规范,然后用 3 小时写代码

规范的目的是提高效率,不是成为负担。

陷阱 2:规范不更新

❌ 规范写完就放着,代码改了规范没改
✅ 每次代码变更都同步更新规范

过时的规范比没有规范更危险。

陷阱 3:规范太模糊

❌ "系统要快"  → 什么是快?1秒?100ms?
✅ "首屏加载时间 < 2 秒(Lighthouse 评分 > 90)"

规范必须是可验证的。

最佳实践 1:先写验收标准

## 验收标准
- [ ] 用户输入邮箱后,60秒内收到验证码
- [ ] 验证码输入正确后,跳转到首页
- [ ] 验证码输入错误 5 次后,锁定 15 分钟

验收标准是规范的灵魂——它定义了"什么算完成"。

最佳实践 2:用示例驱动规范

## 请求示例
curl -X POST /api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"type":"email","identifier":"user@example.com","password":"SecurePass123","code":"123456"}'

## 成功响应示例
{"code":201,"data":{"userId":"abc-123","token":"eyJ..."}}

## 错误响应示例
{"code":409,"message":"邮箱已注册"}

示比文字描述更清晰。


八、动手实验

实验 1:用 Spec-Kit 流程开发一个功能

  1. 选择一个你想开发的功能(如"密码重置")
  2. 花 10 分钟写功能规范(用户故事 + 验收标准 + 接口定义)
  3. 让 AI 提出澄清问题并回答
  4. 让 AI 生成实现计划和任务分解
  5. 执行实现,验证是否符合规范
  6. 对比与直接 Vibe Coding 的差异

实验 2:为现有项目补充 Constitution

  1. 选择一个你正在开发的项目
  2. 写一份项目宪法(核心原则 + 技术约束 + 编码规范)
  3. 用这份宪法指导下一个功能的开发
  4. 观察 AI 的输出质量是否有提升

总结

规范驱动编程不是要增加你的工作量,而是要改变你的工作方式

  • 以前:你写代码,AI 帮你写代码
  • 现在:你写规范,AI 根据规范写代码

你的核心价值从"写代码"变成了"写规范"——而这恰恰是人类最擅长的事情:理解需求、定义标准、做出决策。

记住:AI 可以写代码,但只有你能定义"什么是正确的代码"。这就是规范驱动编程的本质。