Spec 开发模式:完整技术指南
版本: 1.0
最后更新: 2026-03-24
适用对象: 软件工程师、技术负责人、AI 辅助开发实践者
目录
1. 引言
1.1 什么是 Spec 开发模式
Spec 开发模式(Specification-Driven Development) 是一种以"规格说明文档"(Spec)为核心驱动力的软件开发方法论。在这种模式下,开发者不再直接编写代码,而是首先撰写清晰、结构化、机器可读的 Spec 文件来描述"需要构建什么",然后由 AI 编程助手(如 GitHub Copilot、Cursor、Claude 等)根据 Spec 自动生成实现代码。
核心理念:
1
| 人类负责定义 "What"(做什么) → AI 负责实现 "How"(怎么做)
|
Spec 开发模式代表了 AI 时代软件工程的一次范式转移——开发者的核心工作从"编写代码"转变为"编写精准的意图描述"。这不是简单地用自然语言 prompt 来驱动 AI,而是建立了一套系统化的规格描述框架,使 AI 能够准确理解需求并生成高质量的代码。
1.2 为什么需要 Spec 开发模式
传统开发面临的挑战
| 挑战 |
描述 |
| 需求失真 |
从需求文档到代码实现的过程中,信息逐层丢失和变形 |
| 上下文断裂 |
开发者在复杂系统中难以同时把握全局与细节 |
| AI 输出不可控 |
直接与 AI 对话式编程,结果往往不稳定、不一致 |
| 知识流失 |
技术决策和设计意图分散在代码注释、聊天记录、脑海中 |
| 协作瓶颈 |
多人开发时,对"应该做什么"的理解常有偏差 |
Spec 开发模式的核心优势
- 意图的精确传达:Spec 文件作为"唯一事实来源"(Single Source of Truth),消除了需求传递过程中的信息损耗。
- AI 产出的一致性:结构化的 Spec 比自由格式的 prompt 能产生更稳定、更高质量的代码输出。
- 可追溯性:每一行代码都可以追溯到对应的 Spec 条目,建立了完整的需求-实现映射链。
- 可复用性:Spec 文件可以在不同项目、不同 AI 工具之间复用,不绑定特定技术栈。
- 协作效率:团队成员通过 Review Spec(而非 Review Code)就能对齐需求理解。
- 知识沉淀:Spec 文件自然形成了项目的活文档(Living Documentation)。
1.3 Spec 开发模式的演进历程
1 2 3 4 5 6 7 8 9 10
| 传统瀑布模型 敏捷开发 AI 辅助开发 Spec 驱动开发 (Waterfall) (Agile) (AI-Assisted) (Spec-Driven) │ │ │ │ 需求文档 → User Story → 自然语言 Prompt → 结构化 Spec → 详细设计 → Task 拆分 → AI 生成代码 → Plan 生成 → 编码实现 编码实现 人工审查 AI 实现 → 自动验证 │ │ │ │ 问题:周期长 改进:迭代快 问题:AI 输出 改进:精准控制 变更成本高 响应变化 不可控、不一致 结果一致可靠
|
Spec 开发模式并非完全取代之前的方法论,而是在 AI 能力成熟的背景下,对需求描述和代码生成这两个环节的重新组织和优化。它吸收了:
- 瀑布模型的严谨性(完整的前期规格定义)
- 敏捷开发的迭代性(小步快跑、持续反馈)
- AI 辅助开发的生产力(自动化代码生成)
2. 核心概念
2.1 Spec(规格说明)
Spec(Specification)是 Spec 开发模式中的核心产物。它是一份结构化的文档,精确描述了一个功能、模块或系统的行为、约束和验收标准。
Spec 的本质
Spec 不仅仅是"需求文档",它更像是人类与 AI 之间的合约(Contract):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ┌─────────────────────────────────────────────────┐ │ Spec 文件 │ │ │ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ │ 目标描述 │ │ 行为定义 │ │ 约束条件 │ │ │ │ (What) │ │ (Behavior)│ │(Constraints│ │ │ └───────────┘ └───────────┘ └───────────┘ │ │ │ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ │ 验收标准 │ │ 技术决策 │ │ 上下文 │ │ │ │(Criteria) │ │(Decisions)│ │ (Context) │ │ │ └───────────┘ └───────────┘ └───────────┘ │ │ │ └─────────────────────────────────────────────────┘
|
Spec 的三个层次
| 层次 |
名称 |
描述 |
示例 |
| L1 |
系统级 Spec |
描述整个系统或子系统的架构和行为 |
“用户认证系统 Spec” |
| L2 |
模块级 Spec |
描述单个模块或功能的详细设计 |
“JWT Token 管理模块 Spec” |
| L3 |
任务级 Spec |
描述一个具体的开发任务 |
“实现 Token 刷新接口 Spec” |
2.2 Spec 驱动开发的核心原则
原则一:Spec First(规格先行)
在编写任何代码之前,必须先有对应的 Spec。
这不是教条式的流程约束,而是确保:
- 你真正理解了要构建的东西
- AI 有足够的上下文来生成正确的代码
- 团队对交付物有共同的理解
原则二:Spec as Contract(规格即合约)
Spec 是人类与 AI 之间的正式合约。
- 人类承诺:Spec 中描述的需求是准确和完整的
- AI 承诺:生成的代码严格遵循 Spec 中的定义
- 验证标准:代码是否满足 Spec 中的验收条件
原则三:Incremental Specification(增量式规格定义)
Spec 不需要一次性完美,可以逐步细化。
1
| 草稿 Spec(意图级)→ 详细 Spec(设计级)→ 精确 Spec(实现级)
|
这类似于敏捷开发中的"渐进式细化"(Progressive Elaboration),但应用于规格描述层面。
原则四:Verifiable Specification(可验证的规格)
每一条 Spec 都必须是可验证的。
- 避免模糊性描述(“系统应该很快”)
- 使用具体的量化指标(“API 响应时间 < 200ms”)
- 定义明确的验收标准(Given-When-Then 格式)
原则五:Context is King(上下文为王)
Spec 必须包含足够的上下文,使 AI 无需猜测。
上下文包括:
- 技术栈选择及原因
- 已有代码的结构和约定
- 外部依赖和集成要求
- 非功能性需求(性能、安全、可用性)
2.3 角色模型
在 Spec 开发模式中,参与者分为以下角色:
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 28
| ┌─────────────────────────────────────────────────────────┐ │ 人类角色 │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Spec Author │ │ Spec │ │ │ │ (规格作者) │ │ Reviewer │ │ │ │ │ │ (规格审查者) │ │ │ │ 负责编写和 │ │ │ │ │ │ 维护 Spec │ │ 负责审查 │ │ │ └──────────────┘ │ Spec 质量 │ │ │ └──────────────┘ │ └─────────────────────────────────────────────────────────┘ │ Spec 文件(合约) │ ┌─────────────────────────────────────────────────────────┐ │ AI 角色 │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Planning │ │ Implement. │ │ Verification │ │ │ │ Agent │ │ Agent │ │ Agent │ │ │ │ (规划代理) │ │ (实现代理) │ │ (验证代理) │ │ │ │ │ │ │ │ │ │ │ │ 解读 Spec │ │ 根据 Plan │ │ 检查代码是否 │ │ │ │ 生成执行计划 │ │ 生成代码 │ │ 满足 Spec │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘
|
| 角色 |
类型 |
职责 |
产出 |
| Spec Author |
人类 |
编写、维护 Spec 文件 |
Spec 文件 |
| Spec Reviewer |
人类 |
审查 Spec 的完整性和准确性 |
审查意见 |
| Planning Agent |
AI |
解读 Spec,生成可执行的实施计划 |
实施计划(Plan) |
| Implementation Agent |
AI |
根据 Plan 逐步生成代码 |
源代码 |
| Verification Agent |
AI |
验证代码是否符合 Spec 的验收标准 |
验证报告 |
注意: 在实际使用中,这些 AI 角色可能由同一个 AI 工具扮演(如 GitHub Copilot Agent Mode),通过不同的 prompt 阶段来切换职能。
2.4 核心术语表
| 术语 |
英文 |
定义 |
| Spec |
Specification |
结构化的规格说明文档,描述需要构建的功能/系统 |
| Spec 文件 |
Spec File |
承载 Spec 内容的物理文件(通常为 .md 格式) |
| Plan |
Implementation Plan |
由 AI 根据 Spec 生成的详细执行计划 |
| 验收标准 |
Acceptance Criteria |
Spec 中定义的、代码必须满足的条件 |
| Spec Review |
Spec Review |
对 Spec 文件进行审查的活动 |
| 上下文窗口 |
Context Window |
AI 模型单次处理的最大信息量 |
| Spec 链 |
Spec Chain |
多个相互关联的 Spec 之间的依赖关系 |
| 活文档 |
Living Documentation |
随项目演进持续更新的文档 |
| 意图级描述 |
Intent-Level Description |
描述"要做什么"而非"怎么做"的高层描述 |
| 渐进式细化 |
Progressive Elaboration |
逐步深入和完善 Spec 的过程 |
| 单一事实来源 |
Single Source of Truth (SSOT) |
某一信息只在一个地方权威定义 |
| 反馈循环 |
Feedback Loop |
实现结果反馈给 Spec 进行修正的迭代过程 |
| Spec 漂移 |
Spec Drift |
Spec 与实际代码逐渐不一致的现象 |
| Token 预算 |
Token Budget |
考虑 AI 上下文窗口限制时的内容规划策略 |
3. 工作流程详解
3.1 整体流程概览
Spec 开发模式遵循一个五阶段的闭环流程:
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 28 29 30 31 32 33 34
| ┌──────────────┐ │ 1. 需求分析 │ ← 人类主导 │ 与拆解 │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 2. Spec 编写 │ ← 人类主导,AI 辅助 │ │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 3. Plan 生成 │ ← AI 主导,人类审查 │ │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ 4. 代码实现 │ ← AI 主导,人类监督 │ │ └──────┬───────┘ │ ▼ ┌──────────────┐ 不通过 │ 5. 验证与 │ ──────────┐ │ 迭代 │ │ └──────┬───────┘ │ │ 通过 │ ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ 交付完成 │ │ 反馈修正 │ │ │ │ (回到2/3/4) │ └──────────────┘ └──────────────┘
|
关键特征:
- 每个阶段都有明确的输入和输出
- 人类和 AI 有清晰的职责边界
- 流程是可迭代的,验证不通过时回到相应阶段修正
- 整个流程的核心驱动力是 Spec 文件
3.2 阶段一:需求分析与拆解
主导者: 人类 | AI 参与度: 低(可选辅助)
目标
将模糊的业务需求转化为可管理的、可描述的功能单元。
关键活动
- 理解业务目标:明确这个需求要解决什么业务问题
- 划定范围边界:确定做什么、不做什么
- 功能拆解:将大需求拆分为独立的功能模块
- 确定优先级:用 MoSCoW 或其他方法排列优先级
- 识别依赖关系:明确模块间的依赖和调用关系
拆解策略
1 2 3 4 5 6 7 8 9
| 大需求(Epic) ├── 功能模块 A(Feature)→ 对应 L1 系统级 Spec │ ├── 子功能 A1 → 对应 L2 模块级 Spec │ │ ├── 任务 A1-1 → 对应 L3 任务级 Spec │ │ └── 任务 A1-2 → 对应 L3 任务级 Spec │ └── 子功能 A2 → 对应 L2 模块级 Spec │ └── 功能模块 B(Feature)→ 对应 L1 系统级 Spec └── ...
|
拆解原则
| 原则 |
说明 |
示例 |
| 单一职责 |
每个功能单元只做一件事 |
✅ “用户注册” ≠ ❌ “用户注册和登录” |
| 独立可交付 |
每个单元可以单独完成和验证 |
✅ “创建用户 API” 可以独立测试 |
| 适当粒度 |
不过大也不过小,1-3 天可完成 |
❌ 太大:“整个认证系统” / ❌ 太小:“添加一行日志” |
| 明确验证标准 |
能清晰判断"做完了没有" |
✅ “API 返回 201 状态码和用户 ID” |
输入与输出
|
内容 |
| 输入 |
业务需求文档、产品设计稿、用户故事、口头沟通 |
| 输出 |
功能拆解清单、优先级排列、依赖关系图、Spec 编写计划 |
3.3 阶段二:Spec 编写
主导者: 人类 | AI 参与度: 中(可协助生成初稿)
目标
为每个功能单元编写详细的、结构化的 Spec 文件。
关键活动
- 选择 Spec 模板:根据功能类型选择合适的模板
- 填写元信息:标题、作者、日期、状态、标签等
- 描述功能概述:用 1-3 段话说明这个功能是什么、为什么需要它
- 定义详细行为:描述系统在各种场景下的具体行为
- 列出技术约束:技术栈、性能要求、安全要求等
- 编写验收标准:用 Given-When-Then 格式定义验收条件
- 标注上下文信息:关联代码、外部依赖、设计决策说明
Spec 编写流程
1 2 3 4 5 6 7 8 9 10 11 12 13
| 第一遍:骨架(10分钟) → 填写标题、概述、核心目标 → 列出主要功能点(bullet points)
第二遍:充实(20-30分钟) → 为每个功能点添加详细行为描述 → 补充边界情况和异常处理 → 添加技术约束和依赖
第三遍:锐化(10-15分钟) → 编写验收标准(Given-When-Then) → 补充上下文引用 → 自查:AI 能否仅凭这份 Spec 完成实现?
|
AI 辅助 Spec 编写
你可以让 AI 帮助你生成 Spec 初稿,然后人工审查和修正:
1 2 3
| Prompt 示例: "请为一个用户注册功能编写 Spec。技术栈是 Node.js + Express + PostgreSQL。 需要支持邮箱注册和手机号注册,密码需要加密存储,注册后发送验证邮件。"
|
⚠️ 重要: AI 生成的 Spec 初稿必须经过人工审查。AI 可能遗漏边界情况、做出不合理的技术假设,或者添加不必要的复杂度。
输入与输出
|
内容 |
| 输入 |
功能拆解清单、技术栈信息、已有代码结构、设计文档 |
| 输出 |
完整的 Spec 文件(.md 格式) |
3.4 阶段三:Plan 生成
主导者: AI | AI 参与度: 高(人类审查后确认)
目标
AI 根据 Spec 生成详细的实施计划(Plan),明确实现的步骤、顺序和每一步的具体操作。
关键活动
- Spec 解析:AI 阅读并理解 Spec 的全部内容
- 代码库分析:AI 分析已有代码库,理解现有架构和约定
- Plan 生成:AI 生成分步实施计划
- 人类审查:开发者审查 Plan 的合理性
- Plan 确认/修正:必要时调整 Plan 后开始执行
Plan 的典型结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ## 实施计划
### 总览 - 涉及文件:5 个新建,3 个修改 - 预计步骤:12 步 - 关键依赖:Express router, bcrypt, PostgreSQL client
### 步骤详解
**Step 1: 创建数据库迁移文件** - 文件:`migrations/001_create_users_table.sql` - 操作:创建 users 表,包含 id, email, phone, password_hash, ... - 依赖:无
**Step 2: 创建用户模型** - 文件:`src/models/User.ts` - 操作:定义 User 接口和数据库操作方法 - 依赖:Step 1
**Step 3: ...**
|
审查 Plan 的关键检查项
- [ ] Plan 是否覆盖了 Spec 中的所有功能点?
- [ ] 步骤的执行顺序是否合理?
- [ ] 是否考虑了已有代码的架构约定?
- [ ] 是否有不必要的过度设计?
- [ ] 文件命名和目录结构是否符合项目规范?
- [ ] 是否遗漏了错误处理和边界情况?
输入与输出
|
内容 |
| 输入 |
Spec 文件、项目代码库、技术栈配置 |
| 输出 |
结构化的实施计划(Plan) |
3.5 阶段四:代码实现
主导者: AI | AI 参与度: 高(人类监督和微调)
目标
AI 按照 Plan 逐步生成代码,开发者实时监督并在必要时介入。
关键活动
- 逐步执行:AI 按 Plan 步骤依次生成代码
- 实时审查:开发者在每个关键步骤后审查生成的代码
- 及时纠正:发现偏差时立即反馈给 AI 进行修正
- 上下文维护:确保 AI 在多步骤执行中保持上下文一致性
实现策略
策略 A:全自动(适合简单任务)
1 2 3
| 让 AI 按 Plan 一口气完成所有步骤 → 整体审查 → 必要时调整
|
策略 B:分步执行(适合复杂任务,推荐)
1 2 3 4
| AI 完成 Step 1 → 人类审查 → 确认/修正 AI 完成 Step 2 → 人类审查 → 确认/修正 ... AI 完成 Step N → 人类审查 → 确认/修正
|
策略 C:骨架优先(适合架构性任务)
1 2 3 4
| 第一轮:AI 生成所有文件的骨架(接口、类型、函数签名) → 人类审查整体架构 第二轮:AI 填充具体实现 → 人类审查实现细节
|
实现过程中的关键注意事项
- 保持 Spec 可见:确保 AI 在实现过程中始终能引用 Spec 内容
- 警惕 AI 漂移:AI 可能在多步骤执行中逐渐偏离 Spec 的要求
- 及时保存上下文:对于长流程,定期总结已完成的工作
- 不要过度修改:避免在实现阶段引入 Spec 中没有定义的功能
输入与输出
|
内容 |
| 输入 |
Spec 文件、实施计划(Plan)、项目代码库 |
| 输出 |
源代码、配置文件、测试文件等 |
3.6 阶段五:验证与迭代
主导者: 人类 + AI 协同 | AI 参与度: 中高
目标
验证生成的代码是否满足 Spec 中定义的所有验收标准。
验证层次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ┌─────────────────────────────────────────────┐ │ 验证金字塔 │ │ │ │ ╱╲ │ │ ╱ ╲ L4: 用户验收测试(UAT) │ │ ╱────╲ │ │ ╱ ╲ L3: Spec 合规性验证 │ │ ╱────────╲ │ │ ╱ ╲ L2: 集成测试 │ │ ╱────────────╲ │ │ ╱ ╲ L1: 单元测试 │ │ ╱────────────────╲ │ │ ╱ ╲ L0: 静态检查/类型检查 │ │ ╱────────────────────╲ │ │ │ └─────────────────────────────────────────────┘
|
| 层次 |
验证内容 |
工具/方式 |
责任人 |
| L0 |
代码语法、类型正确性 |
Linter, TypeScript, Compiler |
AI 自动 |
| L1 |
单个函数/方法的正确性 |
Jest, PyTest, JUnit 等 |
AI 生成 + 人类审查 |
| L2 |
模块间交互的正确性 |
集成测试框架 |
AI + 人类 |
| L3 |
代码是否满足 Spec 的每一条验收标准 |
逐条对照检查 |
人类主导 |
| L4 |
功能是否满足业务需求 |
手动测试、演示 |
人类/产品团队 |
验证清单模板
1 2 3 4 5 6 7 8 9 10 11
| ## Spec 合规性验证清单
### Spec: [Spec 标题] ### 验证日期: YYYY-MM-DD
| # | 验收标准 | 状态 | 备注 | |---|---------|------|------| | AC-1 | 用户可以使用邮箱注册 | ✅ 通过 | | | AC-2 | 密码必须加密存储 | ✅ 通过 | 使用 bcrypt, cost=12 | | AC-3 | 注册后发送验证邮件 | ❌ 未通过 | 邮件模板未实现 | | AC-4 | 重复邮箱注册返回 409 | ✅ 通过 | |
|
迭代反馈
验证未通过时,根据问题性质决定回退到哪个阶段:
| 问题性质 |
回退到 |
示例 |
| 代码 Bug |
阶段四(代码实现) |
逻辑错误、遗漏边界处理 |
| Plan 不合理 |
阶段三(Plan 生成) |
实现步骤遗漏、架构不合理 |
| Spec 不完整 |
阶段二(Spec 编写) |
缺少边界情况定义、需求变更 |
| 需求理解偏差 |
阶段一(需求分析) |
整体方向错误 |
4. Spec 文件规范与编写指南
4.1 Spec 文件的标准结构
一份完整的 Spec 文件包含以下结构化组成部分:
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| --- # ===== YAML Frontmatter(元信息区)===== title: "功能名称" spec_id: "SPEC-2026-001" version: "1.0" status: "draft | in-review | approved | implemented | deprecated" author: "作者姓名" created: "2026-03-24" updated: "2026-03-24" tags: ["backend", "auth", "api"] priority: "P0 | P1 | P2 | P3" dependencies: - "SPEC-2026-000" ---
# [功能名称] Spec
## 1. 概述(Overview) 简要说明该功能是什么、为什么需要构建它。 - 1-3 段话 - 包含业务背景和动机
## 2. 目标与非目标(Goals & Non-Goals)
### 目标 - 本次要实现的功能和效果
### 非目标 - 明确不在本次范围内的事项(防止范围蔓延)
## 3. 详细设计(Detailed Design)
### 3.1 功能描述 详细的功能行为描述。
### 3.2 数据模型 数据结构、数据库表设计等。
### 3.3 API 设计(如适用) 接口定义、请求/响应格式。
### 3.4 流程图 关键流程的文字或图形描述。
## 4. 技术约束(Technical Constraints) - 技术栈要求 - 性能指标 - 安全要求 - 兼容性要求
## 5. 错误处理(Error Handling) 各种异常场景的处理策略。
## 6. 验收标准(Acceptance Criteria) 用 Given-When-Then 格式编写。
## 7. 上下文引用(Context References) - 关联文件路径 - 依赖的外部服务 - 参考的设计文档
## 8. 开放问题(Open Questions) 尚未确定的事项和待讨论的问题。
## 9. 变更记录(Changelog) | 日期 | 版本 | 变更说明 | 作者 | |------|------|---------|------|
|
4.2 编写原则
原则一:SMART 验收标准
每条验收标准都应该满足 SMART 原则:
| 字母 |
含义 |
说明 |
✅ 好的示例 |
❌ 差的示例 |
| S |
Specific(具体的) |
明确指出要做什么 |
“API 返回 JSON 格式,包含 id 和 name 字段” |
“API 返回用户数据” |
| M |
Measurable(可衡量的) |
有量化指标 |
“响应时间 < 200ms(P95)” |
“系统应该很快” |
| A |
Achievable(可实现的) |
技术上可行 |
“支持单张最大 5MB 的图片上传” |
“支持任意大小的文件上传” |
| R |
Relevant(相关的) |
与功能目标直接相关 |
“密码使用 bcrypt 加密存储” |
“使用最新版数据库” |
| T |
Time-bound(有时限的) |
有明确的完成定义 |
“验证邮件在用户注册后 30 秒内发出” |
“尽快发送验证邮件” |
原则二:Given-When-Then 行为描述
使用 Given-When-Then(GWT)格式描述系统行为,这是 BDD(行为驱动开发)的核心模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| **AC-1: 正常邮箱注册** - Given: 用户提供有效的邮箱地址和符合规则的密码 - When: 用户提交注册请求 - Then: - 系统创建新用户记录 - 密码使用 bcrypt(cost=12)加密存储 - 返回 HTTP 201,响应体包含 { id, email, createdAt } - 异步发送验证邮件到用户邮箱
**AC-2: 重复邮箱注册** - Given: 数据库中已存在 email = "user@example.com" 的用户 - When: 用户使用 "user@example.com" 提交注册 - Then: - 返回 HTTP 409 Conflict - 响应体包含 { error: "Email already registered" } - 不发送任何邮件
|
原则三:显式优于隐式
Spec 中不应有任何需要猜测的内容。 以下信息必须显式声明:
1 2 3 4 5 6 7 8 9 10 11
| ✅ 显式: - 使用 PostgreSQL 15+ 作为数据库 - 使用 UUID v4 作为用户 ID - 密码最少 8 个字符,必须包含大小写字母和数字 - 日期时间统一使用 ISO 8601 格式,UTC 时区
❌ 隐式(需要 AI 猜测): - 使用合适的数据库 (哪个数据库?) - 使用合理的 ID 方案 (自增?UUID?哪个版本?) - 密码需要有足够的复杂度 (什么叫"足够"?) - 日期格式要统一 (统一到什么格式?)
|
原则四:完整的边界定义
一份合格的 Spec 必须覆盖以下场景:
| 场景类型 |
说明 |
示例 |
| 正常路径(Happy Path) |
一切正常的标准流程 |
用户成功注册 |
| 边界情况(Edge Cases) |
极端输入和临界条件 |
邮箱长度恰好 254 个字符 |
| 异常路径(Error Path) |
各种错误情况 |
数据库连接失败 |
| 并发场景(Concurrency) |
多个请求同时到达 |
两个请求同时注册相同邮箱 |
| 安全场景(Security) |
恶意输入和攻击向量 |
SQL 注入、XSS 尝试 |
原则五:上下文自包含
理想状态:一个从未接触过这个项目的 AI,仅凭 Spec 文件就能正确完成实现。
需要包含的上下文信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ## 上下文引用
### 技术栈 - 语言:TypeScript 5.x - 运行时:Node.js 20 LTS - 框架:Express 4.x - 数据库:PostgreSQL 15 - ORM:Prisma 5.x
### 已有代码结构(关键引用) - 路由定义:`src/routes/index.ts`(参照已有路由注册方式) - 中间件:`src/middleware/auth.ts`(认证中间件) - 错误处理:`src/utils/errors.ts`(统一错误处理类) - 数据库连接:`src/db/prisma.ts`(Prisma client 实例)
### 编码约定 - 文件命名:kebab-case(如 `user-service.ts`) - 导出方式:named export(非 default export) - 错误处理:使用自定义 AppError 类抛出 - 日志:使用 winston logger
|
4.3 好的 Spec vs 差的 Spec
❌ 差的 Spec 示例
1 2 3 4 5 6 7 8 9 10 11 12
| # 用户注册
实现一个用户注册功能。
需求: - 用户可以注册 - 需要验证邮箱 - 密码要加密 - 有错误处理
技术: - 用 Node.js 写
|
问题分析:
- ❌ 没有元信息(作者、日期、版本、状态)
- ❌ 没有明确的技术栈版本
- ❌ "验证邮箱"含义模糊(格式验证?还是发送验证邮件?)
- ❌ "密码要加密"没有指定算法和参数
- ❌ "有错误处理"完全没有具体定义
- ❌ 没有验收标准
- ❌ 没有上下文引用
- ❌ 没有边界情况定义
✅ 好的 Spec 示例
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| --- title: "用户邮箱注册" spec_id: "SPEC-2026-012" version: "1.2" status: "approved" author: "张三" created: "2026-03-20" updated: "2026-03-24" tags: ["backend", "auth", "user", "api"] priority: "P0" dependencies: ["SPEC-2026-010"] # 邮件服务 Spec ---
# 用户邮箱注册 Spec
## 1. 概述
实现用户通过邮箱地址注册账号的功能。这是用户增长漏斗的第一步, 直接影响新用户获取。本功能仅覆盖邮箱注册路径,手机号注册见 SPEC-2026-013。
## 2. 目标与非目标
### 目标 - 用户可以使用有效邮箱地址和密码创建账号 - 注册后发送邮箱验证链接 - 防止重复注册 - 密码安全存储
### 非目标 - 第三方 OAuth 登录(见 SPEC-2026-015) - 手机号注册(见 SPEC-2026-013) - 用户个人资料填写(注册后独立流程) - 邮箱验证链接的点击处理(见 SPEC-2026-014)
## 3. 详细设计
### 3.1 API 端点
**POST /api/v1/auth/register**
请求体: ```json { "email": "user@example.com", "password": "SecurePass123", "name": "张三" }
|
成功响应(201 Created):
1 2 3 4 5 6 7
| { "id": "550e8400-e29b-41d4-a716-446655440000", "email": "user@example.com", "name": "张三", "emailVerified": false, "createdAt": "2026-03-24T10:30:00.000Z" }
|
3.2 数据模型
1 2 3 4 5 6 7 8 9 10 11
| CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email VARCHAR(254) NOT NULL UNIQUE, name VARCHAR(100) NOT NULL, password_hash VARCHAR(60) NOT NULL, email_verified BOOLEAN DEFAULT FALSE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() );
CREATE UNIQUE INDEX idx_users_email ON users(LOWER(email));
|
3.3 密码规则
- 最少 8 个字符,最多 128 个字符
- 必须包含至少 1 个大写字母、1 个小写字母、1 个数字
- 使用 bcrypt 加密,cost factor = 12
3.4 邮箱验证规则
- 遵循 RFC 5322 格式验证
- 最大长度 254 个字符
- 大小写不敏感(存储时转为小写)
4. 技术约束
- 框架:Express 4.x + TypeScript
- 数据库:PostgreSQL 15(已有 Prisma 配置)
- 密码库:bcryptjs
- 邮件队列:使用已有的
EmailService(src/services/email.ts)
- 参数验证:使用 zod schema
5. 错误处理
| 场景 |
HTTP 状态码 |
错误码 |
错误信息 |
| 邮箱格式无效 |
400 |
INVALID_EMAIL |
“Invalid email format” |
| 密码不满足规则 |
400 |
WEAK_PASSWORD |
“Password does not meet requirements” |
| 邮箱已注册 |
409 |
EMAIL_EXISTS |
“Email already registered” |
| name 为空 |
400 |
INVALID_NAME |
“Name is required” |
| 服务器内部错误 |
500 |
INTERNAL_ERROR |
“An unexpected error occurred” |
6. 验收标准
AC-1: 正常注册
- Given: 数据库中不存在 email = "new@example.com" 的用户
- When: POST /api/v1/auth/register { email: "new@example.com", password: “Abc12345”, name: “测试” }
- Then: 返回 201,响应包含用户 ID 和 email,密码以 bcrypt 哈希存储,异步发送验证邮件
AC-2: 重复邮箱
AC-3: 弱密码
- Given: 请求密码为 “123”
- When: 提交注册
- Then: 返回 400,错误码 WEAK_PASSWORD
AC-4: 邮箱大小写
AC-5: 并发注册
- Given: 两个请求在同一时刻使用相同邮箱注册
- When: 并发发送
- Then: 只有一个成功(201),另一个返回 409(数据库唯一约束保证)
7. 上下文引用
- 路由注册方式参照:
src/routes/auth.ts
- 错误处理规范参照:
src/utils/errors.ts 中的 AppError 类
- Prisma schema 位于:
prisma/schema.prisma
- 邮件服务:
src/services/email.ts 的 sendVerificationEmail() 方法
8. 开放问题
- [ ] 是否需要注册频率限制?(建议:同一 IP 每分钟最多 5 次)
- [ ] 密码存储是否需要加 pepper?(本期暂不处理)
9. 变更记录
| 日期 |
版本 |
变更说明 |
作者 |
| 2026-03-20 |
1.0 |
初始版本 |
张三 |
| 2026-03-22 |
1.1 |
添加并发场景验收标准 |
李四 |
| 2026-03-24 |
1.2 |
补充邮箱大小写处理规则 |
张三 |
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 28 29 30 31 32 33 34 35 36 37 38 39 40
|
以下提供三种常用的 Spec 模板,按场景选用:
```markdown --- title: "[API名称]" spec_id: "SPEC-YYYY-NNN" version: "1.0" status: "draft" author: "" created: "YYYY-MM-DD" tags: ["api"] priority: "" ---
[1-2 段话描述此 API 的用途和业务背景]
- ...
- ...
**[METHOD] /api/v1/[path]**
- Headers: [必要的请求头] - Body: ```json {}
|
响应
4. 数据模型
[表结构或数据结构定义]
5. 业务规则
6. 错误处理
7. 验收标准
AC-1: …
8. 上下文引用
9. 开放问题
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
```markdown --- title: "[功能名称]" spec_id: "SPEC-YYYY-NNN" version: "1.0" status: "draft" author: "" created: "YYYY-MM-DD" tags: ["frontend"] priority: "" ---
[功能描述和用户价值]
- 用户角色: [角色] - 前置条件: [条件] - 操作流程: 1. ... 2. ... - 预期结果: ...
[描述组件层次和布局]
- 点击 [元素]: [行为] - 输入 [字段]: [验证规则] - 滚动/拖拽: [行为]
| 状态 | 触发条件 | UI 表现 | |------|---------|--------|
- 桌面端(≥1024px): [布局] - 平板端(768-1023px): [布局] - 移动端(<768px): [布局]
| 操作 | API 端点 | 触发时机 | |------|---------|---------|
- 加载中: [显示方式] - 空状态: [显示方式] - 错误状态: [显示方式和重试机制]
**AC-1: ...** - Given: ... - When: ... - Then: ...
- 设计稿: [链接] - 组件库: [路径] - 样式规范: [路径]
|
模板 C:系统重构 Spec 模板
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 28 29 30
| --- title: "[重构名称]" spec_id: "SPEC-YYYY-NNN" version: "1.0" status: "draft" author: "" created: "YYYY-MM-DD" tags: ["refactor"] priority: "" ---
# [重构名称] Spec
## 1. 概述 ### 当前问题 [描述现有代码/架构的问题]
### 重构目标 [描述重构后期望达到的效果]
## 2. 影响范围 ### 需要修改的文件 - `path/to/file1.ts` — [修改内容] - `path/to/file2.ts` — [修改内容]
### 不应修改的文件 - `path/to/stable.ts` — [保持不变的原因]
## 3. 重构方案 ### 3.1 Before(当前状态)
|
[当前的代码结构/调用关系]
[重构后的代码结构/调用关系]
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
|
[渐进式迁移 or 一次性迁移,以及具体步骤]
- [ ] 所有现有测试必须通过 - [ ] API 对外接口不变 - [ ] 数据库 schema 不变 - [ ] [其他兼容性要求]
| 风险 | 概率 | 影响 | 缓解措施 | |------|------|------|---------|
**AC-1: 功能不变** - Given: 完成重构 - When: 运行所有现有测试 - Then: 全部通过,无新增失败
**AC-2: [性能/可读性/可维护性改进]** - Given: ... - When: ... - Then: ...
[如果重构出问题,如何回退]
|
5. 从零开始的实施步骤
本章以一个完整的端到端案例,手把手演示如何在一个全新项目中落地 Spec 开发模式。
5.1 项目初始化
Step 1:创建 Spec 目录结构
在项目根目录下创建 Spec 专用目录:
1
| mkdir -p specs/{system,modules,tasks,templates,archive}
|
目录说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| project-root/ ├── specs/ │ ├── system/ │ │ └── auth-system.md │ ├── modules/ │ │ ├── user-registration.md │ │ └── jwt-management.md │ ├── tasks/ │ │ ├── register-api.md │ │ └── token-refresh.md │ ├── templates/ │ │ ├── api-spec.md │ │ ├── frontend-spec.md │ │ └── refactor-spec.md │ └── archive/ │ └── ... ├── src/ ├── tests/ └── docs/
|
Step 2:创建 Spec 索引文件
在 specs/ 目录下创建索引文件,用于追踪所有 Spec 的状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <!-- specs/INDEX.md --> # Spec 索引
## 活跃 Spec
| Spec ID | 标题 | 级别 | 状态 | 优先级 | 负责人 | 链接 | |---------|------|------|------|--------|--------|------| | SPEC-001 | 认证系统架构 | L1 | approved | P0 | 张三 | [链接](system/auth-system.md) | | SPEC-002 | 用户邮箱注册 | L2 | in-progress | P0 | 张三 | [链接](modules/user-registration.md) | | SPEC-003 | Token 管理 | L2 | draft | P1 | 李四 | [链接](modules/jwt-management.md) |
## 已完成 Spec | Spec ID | 标题 | 完成日期 | 链接 | |---------|------|---------|------|
|
Step 3:配置 AI 工具的 Spec 感知
如果你使用 GitHub Copilot(Agent Mode),可在项目中添加指令文件:
1 2 3 4 5 6 7 8 9 10
| <!-- .github/copilot-instructions.md --> ## Spec 开发模式
本项目使用 Spec 驱动开发。在编写或修改代码时:
1. 首先检查 `specs/` 目录下是否存在对应的 Spec 文件 2. 严格按照 Spec 中的定义实现 3. 不要添加 Spec 中未定义的功能 4. 遵循 Spec 中指定的技术约束和编码约定 5. 实现完成后,对照验收标准逐一验证
|
5.2 目录结构规范
Spec 文件命名规范
1 2 3 4 5 6
| [层级标识]-[Spec编号]-[简短描述].md
示例: L1-001-auth-system.md L2-002-user-registration.md L3-003-register-api-endpoint.md
|
替代命名方式(更简洁)
1 2 3 4 5 6 7
| specs/ ├── system/ │ └── auth-system.md ├── modules/ │ └── user-registration.md └── tasks/ └── register-api-endpoint.md
|
建议: 对于中小型项目,使用目录来区分层级更加简洁。对于大型项目,在文件名中包含 Spec ID 更便于检索。
Spec 状态流转
1 2 3
| draft → in-review → approved → implementing → implemented → deprecated │ │ │ └─────────┴───── (需要修改时回退) ←────────────────┘
|
| 状态 |
含义 |
可进行的操作 |
draft |
草稿,正在编写 |
编辑、删除 |
in-review |
等待审查 |
评论、批准、打回 |
approved |
已批准,可以实现 |
开始实现 |
implementing |
正在实现中 |
代码开发 |
implemented |
已实现并验证通过 |
归档 |
deprecated |
已废弃 |
移至 archive 目录 |
5.3 编写第一个 Spec
以下是一个完整的实操演练,展示如何为一个"待办事项 API"编写 Spec。
第一遍:搭建骨架(约 5 分钟)
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 28 29 30 31 32 33 34 35 36 37 38
| --- title: "待办事项 CRUD API" spec_id: "SPEC-2026-001" version: "1.0" status: "draft" author: "你的名字" created: "2026-03-24" tags: ["backend", "api", "todo"] priority: "P0" ---
# 待办事项 CRUD API Spec
## 1. 概述 实现待办事项的增删改查 RESTful API。
## 2. 目标与非目标 ### 目标 - 创建、读取、更新、删除待办事项 - 支持按状态筛选 - 支持分页
### 非目标 - 用户认证(本期不做) - 标签系统 - 协作功能
## 3. 详细设计 [待填充]
## 4. 技术约束 [待填充]
## 5. 错误处理 [待填充]
## 6. 验收标准 [待填充]
|
第二遍:充实细节(约 20 分钟)
为每个 [待填充] 区域补充完整内容:
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
| ## 3. 详细设计
### 3.1 API 端点
| 方法 | 路径 | 描述 | |------|------|------| | POST | /api/v1/todos | 创建待办事项 | | GET | /api/v1/todos | 获取待办事项列表(支持筛选和分页) | | GET | /api/v1/todos/:id | 获取单个待办事项 | | PUT | /api/v1/todos/:id | 更新待办事项 | | DELETE | /api/v1/todos/:id | 删除待办事项 |
### 3.2 数据模型
```sql CREATE TABLE todos ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), title VARCHAR(200) NOT NULL, description TEXT, status VARCHAR(20) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'in_progress', 'completed')), due_date DATE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() );
|
3.3 请求与响应格式
创建待办事项 POST /api/v1/todos
请求体:
1 2 3 4 5
| { "title": "完成项目报告", "description": "编写 Q1 项目总结报告", "dueDate": "2026-04-01" }
|
成功响应(201):
1 2 3 4 5 6 7 8 9
| { "id": "550e8400-...", "title": "完成项目报告", "description": "编写 Q1 项目总结报告", "status": "pending", "dueDate": "2026-04-01", "createdAt": "2026-03-24T10:00:00.000Z", "updatedAt": "2026-03-24T10:00:00.000Z" }
|
获取列表 GET /api/v1/todos?status=pending&page=1&pageSize=20
成功响应(200):
1 2 3 4 5 6 7 8 9
| { "data": [...], "pagination": { "page": 1, "pageSize": 20, "total": 42, "totalPages": 3 } }
|
4. 技术约束
- 语言:TypeScript
- 框架:Express 4.x
- 数据库:PostgreSQL 15
- ORM:Prisma
- 参数验证:zod
- 分页默认值:page=1, pageSize=20, 最大 pageSize=100
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 28 29 30 31 32 33 34 35
|
```markdown
**AC-1: 创建待办事项** - Given: 请求体包含有效的 title - When: POST /api/v1/todos - Then: 返回 201,包含完整的 todo 对象,status 默认为 "pending"
**AC-2: title 为空时拒绝创建** - Given: 请求体 title 为空字符串或未提供 - When: POST /api/v1/todos - Then: 返回 400,error code: INVALID_TITLE
**AC-3: 按状态筛选** - Given: 数据库中有 pending 和 completed 状态的待办 - When: GET /api/v1/todos?status=pending - Then: 只返回 status = "pending" 的记录
**AC-4: 分页** - Given: 数据库中有 25 条记录 - When: GET /api/v1/todos?page=2&pageSize=10 - Then: 返回第 11-20 条记录,pagination.total = 25, totalPages = 3
**AC-5: 更新不存在的记录** - Given: 数据库中不存在 id = "nonexistent-uuid" - When: PUT /api/v1/todos/nonexistent-uuid - Then: 返回 404,error code: TODO_NOT_FOUND
**AC-6: 删除后确认** - Given: 存在一个 id = "xxx" 的待办 - When: DELETE /api/v1/todos/xxx,然后 GET /api/v1/todos/xxx - Then: DELETE 返回 204,GET 返回 404
|
5.4 从 Spec 到代码的完整流程
以下是拿着写好的 Spec 文件,与 AI 协同完成代码实现的完整操作流程:
Step 1:将 Spec 提交给 AI
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Prompt 模板:
请阅读以下 Spec 文件,为我生成实施计划(Plan)。
要求: 1. 列出需要创建/修改的所有文件 2. 每个文件需要实现的具体内容 3. 文件之间的依赖顺序 4. 预估每个步骤的复杂度(高/中/低)
Spec 文件内容: [粘贴或引用 Spec 文件]
项目当前结构: [提供关键的目录结构信息]
|
Step 2:审查 AI 生成的 Plan
收到 Plan 后,逐一检查:
1 2 3 4 5 6 7 8
| ## Plan 审查清单
- [ ] 所有 Spec 中定义的端点都已覆盖 - [ ] 文件命名符合项目约定 - [ ] 没有引入 Spec 中未要求的依赖 - [ ] 实现顺序合理(先模型 → 再服务 → 最后路由) - [ ] 包含了错误处理和参数验证 - [ ] 测试文件包含在 Plan 中
|
Step 3:逐步执行 Plan
1 2 3 4 5 6 7 8 9
| Prompt 模板(逐步执行):
请按照 Plan 的 Step [N] 执行: [Plan 中 Step N 的内容]
请确保: 1. 严格遵循 Spec 中的定义 2. 保持与已有代码风格一致 3. 包含必要的错误处理
|
Step 4:代码审查与验收
每一步完成后,对照验收标准检查:
1 2 3 4 5 6 7 8 9 10
| Prompt 模板(验证):
请对照以下验收标准,检查当前代码是否全部满足:
[列出相关的验收标准]
对于每一条标准,请说明: 1. 是否满足(✅/❌) 2. 满足的具体代码位置 3. 如果未满足,需要如何修改
|
5.5 迭代与反馈循环
场景一:验收标准未通过
1 2 3 4 5 6
| 流程: 1. 识别未通过的验收标准 2. 分析原因(代码 Bug?还是 Spec 遗漏?) 3. 如果是代码 Bug → 直接修复代码 4. 如果是 Spec 遗漏 → 先更新 Spec,再修复代码 5. 重新验证
|
场景二:实现过程中发现 Spec 不合理
1 2 3 4 5 6 7 8
| 流程: 1. 暂停代码实现 2. 记录发现的问题到 Spec 的"开放问题"中 3. 评估问题的影响范围 4. 如果是小问题 → 直接修正 Spec 并继续 5. 如果是大问题 → 与团队讨论后再修正 6. 更新 Spec 版本号和变更记录 7. 重新生成受影响步骤的 Plan
|
场景三:需求变更
1 2 3 4 5 6 7 8 9
| 流程: 1. 在 Spec 中标注变更的部分 2. 评估变更对已实现代码的影响 3. 更新 Spec 的"目标与非目标"部分 4. 更新受影响的验收标准 5. 更新 Spec 版本号(如 1.0 → 1.1) 6. 重新生成 Plan 中受影响的步骤 7. 实现变更 8. 重新验证所有验收标准(包括未变更的部分)
|
反馈循环的可视化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| Spec v1.0 代码 v1 ┌──────────┐ ┌──────────┐ │ │───── Plan ────▶│ │ │ │ │ │ │ │◀── 发现问题 ──│ │ └──────────┘ └──────────┘ │ │ 更新 Spec 修复代码 │ │ ▼ ▼ Spec v1.1 代码 v2 ┌──────────┐ ┌──────────┐ │ │───── Plan ────▶│ │ │ │ │ │ │ │◀── 验证通过 ──│ │ └──────────┘ └──────────┘ │ │ 归档 部署
|
6. 最佳实践
6.1 Spec 粒度控制
Spec 的粒度直接决定了开发效率和 AI 产出质量。粒度过粗,AI 缺少细节无法精确实现;粒度过细,写 Spec 的成本超过直接编码。
粒度评估矩阵
|
实现复杂度低 |
实现复杂度高 |
| 业务规则简单 |
L3 任务级即可(简要描述) |
L2 模块级(注重技术设计) |
| 业务规则复杂 |
L2 模块级(注重业务规则) |
L1+L2 组合(系统级+模块级) |
粒度的"金发女孩原则"
1 2 3 4 5 6 7 8 9
| 太粗 ────────────── 恰当 ────────────── 太细
"实现用户系统" "实现用户邮箱注册 "实现邮箱正则 API,包含密码加密、 验证函数,接受 邮箱验证、重复检测" string 参数, 返回 boolean"
AI 需要猜测太多 AI 有足够信息 不如直接写代码 实现细节 精确实现
|
粒度控制的经验法则
- 一个 Spec 对应 1-3 天的开发工作量
- 一个 Spec 产生的代码不超过 500 行(超过则考虑拆分)
- 一个 Spec 涉及的文件不超过 10 个
- 验收标准在 3-10 条之间(少于 3 条可能太粗,超过 10 条考虑拆分)
6.2 上下文管理策略
AI 模型的上下文窗口是有限的。即便是最新的模型,高效地管理上下文依然至关重要。
上下文分层策略
1 2 3 4 5 6 7 8 9 10 11 12 13
| ┌─────────────────────────────────────────────┐ │ 第 1 层:当前 Spec │ ← 必须完整包含 │ (完整的 Spec 文件内容) │ ├─────────────────────────────────────────────┤ │ 第 2 层:直接上下文 │ ← 根据需要引入 │ (Spec 引用的代码文件、类型定义) │ ├─────────────────────────────────────────────┤ │ 第 3 层:间接上下文 │ ← 按需提供摘要 │ (项目约定、架构文档、依赖 Spec) │ ├─────────────────────────────────────────────┤ │ 第 4 层:全局上下文 │ ← 通过指令文件持久化 │ (编码规范、技术栈决策、团队约定) │ └─────────────────────────────────────────────┘
|
上下文优化技巧
技巧 1:使用指令文件承载全局上下文
将不随 Spec 变化的全局信息放在指令文件中(如 .github/copilot-instructions.md),避免每次都在 Spec 中重复。
1 2 3 4 5 6 7
| <!-- .github/copilot-instructions.md --> ## 全局编码约定 - 使用 TypeScript strict mode - 文件命名:kebab-case - 错误使用 AppError 类 - 日志使用 winston - ...
|
技巧 2:在 Spec 中使用精确引用而非全文复制
1 2 3 4 5 6 7 8 9
| ✅ 好的做法: 上下文引用: - 错误处理方式参照 `src/utils/errors.ts` 中的 AppError 类 - 路由注册方式参照 `src/routes/auth.ts` 第 15-30 行
❌ 差的做法: 上下文引用: [在这里粘贴了 errors.ts 的全部 200 行代码] [在这里粘贴了 auth.ts 的全部 150 行代码]
|
技巧 3:为复杂系统建立"上下文摘要"文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <!-- specs/CONTEXT.md --> # 项目上下文摘要
## 架构概览 - 单体应用,Express + TypeScript - 三层架构:Controller → Service → Repository - PostgreSQL + Prisma ORM
## 关键文件索引 | 用途 | 文件 | 说明 | |------|------|------| | 路由入口 | src/routes/index.ts | 所有路由在此注册 | | 数据库连接 | src/db/prisma.ts | Prisma client 单例 | | 错误基类 | src/utils/errors.ts | AppError 定义 | | 认证中间件 | src/middleware/auth.ts | JWT 验证 |
## 数据库表概览 | 表名 | 关键字段 | 说明 | |------|---------|------| | users | id, email, password_hash | 用户表 | | todos | id, title, status, user_id | 待办事项表 |
|
技巧 4:长流程中的"上下文检查点"
在多步骤的代码实现过程中,定期创建上下文检查点:
1 2 3 4 5 6 7 8
| 每 3-5 步执行一次:
Prompt: "请总结一下到目前为止已完成的工作: 1. 已创建/修改了哪些文件 2. 已实现了哪些功能 3. 接下来还需要完成什么 4. 当前代码与 Spec 的一致性状态"
|
6.3 Spec 版本管理
Git 中的 Spec 管理策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
git checkout -b spec/user-registration
git add specs/modules/user-registration.md git commit -m "spec: add user registration spec (SPEC-002)"
git commit -m "feat: implement user registration (SPEC-002)"
git merge spec/user-registration
|
Spec 提交信息规范
1 2 3 4
| spec: add [功能名] spec ([Spec ID]) spec: update [功能名] spec ([Spec ID]) spec: deprecate [功能名] spec ([Spec ID]) feat: implement [功能名] ([Spec ID])
|
Spec 与代码的关联
在代码中通过注释关联对应的 Spec:
1 2 3 4 5 6 7 8 9
|
export async function registerUser(req: Request, res: Response) { }
|
6.4 团队协作中的 Spec 开发
Spec Review 流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Spec Author 编写 Spec │ ▼ 创建 PR / MR(仅包含 Spec 文件) │ ▼ Spec Reviewer 审查 ← 关注:完整性、准确性、可实现性 │ ┌────┴────┐ │ │ 通过 需修改 │ │ ▼ ▼ 批准 反馈意见 │ │ │ 修改后重新提交 │ │ ▼ │ 开始实现 ◄───┘
|
Spec Review 检查清单
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
| ## Spec Review Checklist
### 完整性 - [ ] 包含完整的元信息(title, id, version, status, author) - [ ] "目标与非目标"清晰明确 - [ ] 详细设计覆盖了所有功能点 - [ ] 错误处理场景完整(包括网络错误、并发、权限等) - [ ] 验收标准覆盖正常路径和异常路径 - [ ] 上下文引用充分
### 准确性 - [ ] 技术约束与项目实际一致 - [ ] 数据模型设计合理 - [ ] API 设计符合 RESTful 规范(如适用) - [ ] 没有与已有功能的冲突
### 可实现性 - [ ] 粒度适当(1-3 天工作量) - [ ] 依赖关系明确且已满足 - [ ] 技术方案可行 - [ ] 没有过度设计
### 可验证性 - [ ] 每条验收标准都是 SMART 的 - [ ] Given-When-Then 格式清晰 - [ ] 可以编写自动化测试来验证
|
团队 Spec 协作模式
模式 A:Author-Reviewer 模式(小团队,2-5 人)
1
| 开发者 A(Author)→ 编写 Spec → 开发者 B(Reviewer)→ 审查 → 开发者 A → 实现
|
模式 B:Spec Lead 模式(中型团队,5-15 人)
1 2 3 4 5 6 7
| Spec Lead 编写 L1/L2 级 Spec │ ▼ 分配给各开发者 │ ▼ 各开发者编写 L3 级 Spec → Spec Lead 审查 → 各开发者实现
|
模式 C:Spec Sprint 模式(大型团队)
1 2 3 4
| Sprint Planning 中专门安排 Spec 编写时间 Week 1 Day 1-2: 集体编写和审查 Spec Week 1 Day 3 - Week 2: 按 Spec 实现 Sprint Review: 对照 Spec 验收
|
6.5 常见反模式与避坑指南
反模式 1:Spec 形式主义
1 2 3 4 5 6
| 症状:为了写 Spec 而写 Spec,内容流于形式,实际不被参考 原因:团队不理解 Spec 的价值,当作行政负担 解决: - 从最痛的问题(如 AI 产出不一致)入手引入 Spec - 在 Spec 中只写真正有价值的内容,不追求格式完美 - 用实际效果说服团队(对比有 Spec vs 无 Spec 的 AI 输出质量)
|
反模式 2:Spec 瀑布综合征
1 2 3 4 5 6
| 症状:花几天时间写一份"完美"的 Spec,迟迟不开始实现 原因:混淆了 Spec 驱动和瀑布模型 解决: - 采用增量式 Spec 编写(草稿 → 充实 → 锐化) - 设定时间限制:首版 Spec 不超过 1 小时 - 接受 Spec 不完美,在实现过程中迭代
|
反模式 3:Spec 漂移(Spec 与代码不一致)
1 2 3 4 5 6 7
| 症状:代码已经演进了多个版本,Spec 还停留在初始状态 原因:只在开发前写 Spec,开发后不更新 解决: - 将 Spec 更新纳入 Definition of Done - 代码 Review 时同步检查 Spec 是否需要更新 - 使用 Spec 状态流转机制追踪 - 定期(如每个 Sprint)清理过期 Spec
|
反模式 4:巨型 Spec
1 2 3 4 5 6
| 症状:一份 Spec 长达数十页,覆盖整个子系统 原因:没有正确进行需求拆解 解决: - 遵循粒度控制原则(1-3 天工作量) - 使用 L1 → L2 → L3 的层次拆分 - 一份 Spec 的验收标准控制在 3-10 条
|
反模式 5:忽略非功能性需求
1 2 3 4 5 6
| 症状:Spec 只定义了功能行为,忽略了性能、安全、可用性等 原因:非功能性需求不如功能需求直观 解决: - 在 Spec 模板中加入"技术约束"强制填写区域 - 建立团队级别的非功能性需求基线 例:"所有 API 响应时间P95 < 500ms,除非 Spec 中另行说明"
|
反模式 6:AI 输出不审查
1 2 3 4 5 6
| 症状:AI 生成了代码就直接合并,不对照 Spec 验证 原因:过度信任 AI,跳过验证环节 解决: - 实施强制性的 Spec 合规性验证 - 使用验证清单模板逐条对照 - 在 CI/CD 中加入自动化测试(覆盖验收标准)
|
避坑速查表
| 坑 |
信号 |
解法 |
| Spec 太模糊 |
AI 频繁"猜测"实现方式 |
增加具体的技术细节和示例 |
| Spec 太详细 |
写 Spec 时间 > 编码时间 |
只指定"What",不指定"How" |
| Spec 无人维护 |
新成员看 Spec 被误导 |
纳入 DoD,定期清理 |
| Spec 堆积如山 |
大量 draft 状态 Spec 无人处理 |
限制 WIP(Work in Progress) |
| 团队抵触 Spec |
“写文档浪费时间” |
从痛点切入,渐进推广 |
| Spec 重复内容多 |
多个 Spec 中复制相同的技术约束 |
抽取到全局上下文/指令文件 |
7. 应用场景与案例
7.1 新项目从零启动
场景描述
团队要从零开发一个"在线课程管理平台",包含课程展示、用户注册、课程购买、视频播放等功能。
Spec 开发流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 第 1 周:Spec 编写阶段 ├── Day 1: 需求分析和功能拆解 │ → 产出:功能模块清单、优先级排列 │ ├── Day 2-3: L1 系统级 Spec │ → SPEC-001: 系统架构 Spec(技术栈、架构模式、部署方案) │ → SPEC-002: 数据库设计 Spec(ER 图、表结构、索引策略) │ ├── Day 4-5: L2 模块级 Spec(P0 模块) │ → SPEC-003: 用户认证模块 Spec │ → SPEC-004: 课程管理模块 Spec │ → SPEC-005: 支付模块 Spec │ 第 2-4 周:实现阶段(边实现 P0,边编写 P1 的 Spec) ├── Week 2: 实现 SPEC-003(用户认证)+ 编写 P1 Spec ├── Week 3: 实现 SPEC-004(课程管理) ├── Week 4: 实现 SPEC-005(支付)
|
关键技巧
- 先写系统架构 Spec:确定技术栈和全局约定后再写模块 Spec
- Spec 编写与实现并行推进:不需要等所有 Spec 写完才开始编码
- 每个 Sprint 的 Spec 存量控制在 2-3 个:保持 Spec 的时效性
L1 系统架构 Spec 示例片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| --- title: "在线课程平台系统架构" spec_id: "SPEC-2026-001" status: "approved" ---
# 系统架构 Spec
## 技术栈决策
| 层面 | 技术选型 | 选择原因 | |------|---------|---------| | 前端 | Next.js 14 (App Router) | SSR 支持、SEO 友好、团队熟悉 | | 后端 | Node.js + NestJS | TypeScript 全栈统一、装饰器风格 | | 数据库 | PostgreSQL 15 | 复杂查询支持好、成熟稳定 | | 缓存 | Redis 7 | 会话管理、热点数据缓存 | | 存储 | 对象存储(S3 兼容) | 视频和图片的存储 | | 部署 | Docker + K8s | 团队已有经验 |
## 架构模式
采用分层单体架构(Modular Monolith):
|
┌─────────────┐
│ Next.js │ ← 前端
│ Frontend │
└──────┬──────┘
│ HTTP/REST
┌──────▼──────┐
│ NestJS │ ← 后端
│ Backend │
├─────────────┤
│ Module: Auth│
│ Module: Course│
│ Module: Payment│
│ Module: Video│
└──────┬──────┘
│
┌───────────┼───────────┐
│ │ │
PostgreSQL Redis Object Storage
1 2 3 4 5 6 7 8 9 10
| ## 全局编码约定 (此部分同时写入 .github/copilot-instructions.md)
- 文件命名:kebab-case - 类命名:PascalCase - 函数/方法:camelCase - 每个模块包含:controller, service, repository, dto, entity - 错误处理:使用 NestJS 内置 HttpException 体系 - 日志:使用 NestJS Logger
|
7.2 遗留系统重构
场景描述
有一个运行了 3 年的电商后台管理系统,代码混乱、缺少文档、测试覆盖率很低。需要在不停机的前提下逐步重构。
Spec 开发策略:考古式 Spec(Archaeology Spec)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 阶段一:理解现状(考古) ├── 用 AI 辅助分析现有代码 ├── 为现有功能编写"现状 Spec"(As-Is Spec) │ — 描述系统当前的实际行为(包括已知 bug) │ — 标记哪些是"有意设计",哪些是"意外行为" │ 阶段二:规划目标(设计) ├── 为每个要重构的模块编写"目标 Spec"(To-Be Spec) │ — 基于 As-Is Spec,定义重构后的目标行为 │ — 明确哪些行为保持不变,哪些需要修改 │ 阶段三:渐进实施(迁移) ├── 按 To-Be Spec 逐模块重构 ├── 每个模块重构完成后,运行回归测试 └── 更新 Spec 状态
|
As-Is Spec 示例片段
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 28
| --- title: "[As-Is] 订单列表查询" spec_id: "SPEC-LEGACY-001" status: "approved" tags: ["legacy", "as-is", "orders"] ---
# [As-Is] 订单列表查询
## 1. 当前行为描述
### API 端点 GET /admin/orders (注意:未遵循 RESTful 规范,不带 api 版本号)
### 实际行为 1. 支持分页,但分页参数命名为 `p`(page)和 `s`(size) 2. 返回格式不统一,有时嵌套在 `data.list` 中,有时直接在 `data` 中 3. **已知 Bug**:当 status 参数为空字符串时返回全部数据(而非按"全部状态"筛选) 4. **性能问题**:未使用索引分页,大数据量时超过 5 秒
### 数据库查询 - 使用原始 SQL 拼接(存在 SQL 注入风险) - 无分页优化(使用 OFFSET)
## 2. 依赖方 - 前端管理面板(admin-panel repo) - 数据导出脚本(scripts/export-orders.py) - 第三方物流对接服务
|
To-Be Spec 关键区别
1 2 3 4 5 6 7 8 9
| ## 与 As-Is 的差异对照
| 方面 | As-Is(现状) | To-Be(目标) | 迁移策略 | |------|-------------|-------------|---------| | API 路径 | /admin/orders | /api/v2/admin/orders | 新旧并存,灰度切换 | | 分页参数 | p, s | page, pageSize | 兼容旧参数 3 个月 | | 返回格式 | 不一致 | 统一 { data, pagination } | 新 API 统一格式 | | SQL 注入 | 存在风险 | 使用参数化查询 | 立即修复 | | 分页性能 | OFFSET | Cursor-based | To-Be 实现 |
|
7.3 API 开发
场景描述
公司需要为移动端 App 开发一套完整的 RESTful API,包含用户、商品、订单等资源。
API Spec 的特殊关注点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ## API Spec 核心要素清单
### 1. 端点定义 - HTTP 方法 + 路径 - 路径参数和查询参数 - 请求头要求(Authorization, Content-Type 等)
### 2. 请求/响应契约 - 请求体 JSON Schema(字段、类型、必填/可选、验证规则) - 成功响应格式和状态码 - 所有可能的错误响应
### 3. 认证与授权 - 哪些端点需要认证? - 需要什么权限/角色?
### 4. 限流策略 - 请求频率限制 - 响应头中的限流信息
### 5. 版本策略 - URL 版本号(/api/v1/) - 向后兼容规则
|
实践建议
- 一个资源一个 Spec:
user-api.md、product-api.md、order-api.md
- 先定义统一的 API 约定 Spec:错误格式、分页格式、认证方式
- 包含完整的请求/响应示例:AI 对照示例生成代码更准确
- 标注幂等性:哪些操作是幂等的(PUT, DELETE),哪些不是(POST)
7.4 前端功能开发
场景描述
为一个 SaaS 产品的管理后台新增"数据分析仪表盘"页面。
前端 Spec 的特殊关注点
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
| ## 前端 Spec 核心要素清单
### 1. 页面/组件结构 - 组件树和层次关系 - 可复用组件 vs 页面专用组件
### 2. 状态管理 - 全局状态 vs 局部状态 - 数据流向 - 缓存策略
### 3. 交互行为 - 用户操作 → 系统响应 的完整映射 - 动画/过渡效果 - 键盘快捷键
### 4. 响应式设计 - 断点定义 - 不同屏幕尺寸下的布局差异
### 5. 异步状态处理 - 加载中状态(Loading) - 空状态(Empty State) - 错误状态(Error State) - 乐观更新策略(Optimistic Update)
|
示例:仪表盘 Spec 片段
1 2 3 4
| ## 3. 详细设计
### 3.1 页面结构
|
DashboardPage
├── PageHeader
│ ├── Title: "数据分析"
│ └── DateRangePicker(默认最近 7 天)
├── MetricCards(横排,等宽 4 列)
│ ├── Card: 总用户数
│ ├── Card: 活跃用户数
│ ├── Card: 收入总额
│ └── Card: 转化率
├── ChartSection(2 列布局)
│ ├── LineChart: 用户增长趋势
│ └── BarChart: 收入分布
└── DataTable
└── 最近交易记录(分页,每页 10 条)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
| 用户操作 | 系统响应 | |---------|---------| | 切换日期范围 | 所有图表和指标卡片重新加载数据 | | 悬停指标卡片 | 显示与上一周期的对比(↑12% 或 ↓5%) | | 点击图表数据点 | 显示该日期的详细数据弹窗 | | 调整浏览器宽度到 <768px | 指标卡片变为 2x2 布局,图表变为单列 |
| 状态 | UI 表现 | |------|--------| | 初始加载 | 指标卡片显示 Skeleton 动画,图表区域显示加载占位符 | | 数据为空 | 显示 Empty State 插画 + "暂无数据,请调整日期范围" | | 加载失败 | 显示错误提示 + "点击重试" 按钮 | | 部分加载失败 | 失败的组件单独显示错误状态,不影响其他组件 |
|
7.5 Bug 修复与问题排查
场景描述
生产环境报告"用户在特定条件下无法完成支付",需要排查和修复。
Bug 修复 Spec 模式
Bug 修复同样可以使用 Spec 模式,特别是对于复杂 Bug。
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| --- title: "[Bug] 特定条件下支付失败" spec_id: "SPEC-BUG-2026-042" status: "approved" author: "值班开发" created: "2026-03-24" tags: ["bug", "payment", "production", "P0"] ---
# [Bug] 特定条件下支付失败
## 1. Bug 描述
### 复现条件 - 用户余额恰好等于商品价格(分文不差) - 使用优惠券后实际支付金额为 0 - 用户点击"确认支付"
### 预期行为 - 支付成功,订单状态变为 "paid" - 扣减优惠券使用次数
### 实际行为 - 页面卡在"处理中"状态 30 秒后超时 - 订单状态仍为 "pending" - 优惠券已被标记为已使用(数据不一致)
### 影响范围 - 影响所有 100% 折扣的优惠券场景 - 过去 7 天有 23 个工单报告此问题
## 2. 根因分析
### 初步排查结果 - 当支付金额为 0 时,支付网关返回错误:"amount must be greater than 0" - 代码中未处理 0 金额的特殊情况 - 优惠券扣减在支付网关调用之前执行(事务不一致)
### 问题代码位置 - `src/services/payment.ts` 第 87-102 行 - `src/services/coupon.ts` 第 45 行
## 3. 修复方案
### 修复点 1: 0 金额支付逻辑 - 当实际支付金额为 0 时,跳过支付网关调用 - 直接将订单标记为 "paid" - 记录支付方式为 "coupon_full_discount"
### 修复点 2: 事务一致性 - 将优惠券扣减和订单状态更新包装在数据库事务中 - 如果任何一步失败,整体回滚
### 不应修改 - 支付网关调用逻辑(非 0 金额场景保持不变) - 前端支付流程
## 4. 验收标准
**AC-1: 0 金额支付成功** - Given: 用户使用 100% 折扣优惠券,实际支付 0 元 - When: 点击"确认支付" - Then: 支付成功,订单状态为 "paid",支付方式为 "coupon_full_discount"
**AC-2: 事务一致性** - Given: 优惠券扣减后发生错误 - When: 事务中的后续步骤失败 - Then: 优惠券使用记录回滚,保持可用状态
**AC-3: 回归验证** - Given: 正常的非 0 金额支付 - When: 完成支付流程 - Then: 行为不变,支付网关正常调用
**AC-4: 历史数据修复** - Given: 过去 7 天因此 Bug 导致的不一致数据 - When: 运行数据修复脚本 - Then: 23 个受影响订单的状态和优惠券数据恢复一致
## 5. 测试要求 - 单元测试:覆盖 0 金额分支 - 集成测试:模拟完整支付流程(0 金额 + 正常金额) - 回归测试:确保现有支付测试全部通过
|
Bug 修复使用 Spec 的好处
- 防止"修了一个 Bug,引入两个新 Bug":通过明确"不应修改"的范围
- 确保数据修复:Bug 修复不仅是代码修复,还包括受影响数据的处理
- 可追溯:之后可以查看 Bug Spec 了解修复决策的完整上下文
- 知识积累:相似的 Bug 可以参考历史 Spec 快速处理
8. 工具生态与高级主题
8.1 与主流 AI 编程工具的集成
GitHub Copilot(Agent Mode)
GitHub Copilot 的 Agent 模式是 Spec 开发模式的天然载体:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 集成方式:
1. 全局指令文件 .github/copilot-instructions.md → 放置全局编码约定、Spec 开发流程说明
2. 工作区指令文件 .vscode/copilot-instructions.md → 放置项目级别的约定
3. Prompt 文件(.prompt.md) → 可创建预设的 Spec 模板 prompt
4. Agent 模式执行流程 → 在 Chat 中引用 Spec 文件 → 要求 Copilot 根据 Spec 生成 Plan → 审查 Plan 后执行
|
最佳搭配:
- 使用
@workspace 让 Copilot 感知整个项目结构
- 将 Spec 文件直接拖入 Chat 作为上下文
- 使用"分步执行"策略,每步确认后再继续
Cursor
1 2 3 4 5 6 7 8 9 10 11 12 13
| 集成方式:
1. 项目规则文件 .cursor/rules → 类似 copilot-instructions.md,定义全局约定
2. Composer 模式 → 适合基于 Spec 的多文件生成 → 可以一次性提交 Spec + 相关上下文
3. Chat 模式 → 适合 Spec 的审查和优化 → 可以让 AI 帮助完善 Spec 内容
|
最佳搭配:
- Composer 模式适合"全自动"策略(简单任务)
- Chat 模式适合"分步执行"策略(复杂任务)
- 使用
@file 引用 Spec 文件和相关代码
Claude(API / Console)
1 2 3 4 5 6 7 8 9 10 11
| 集成方式:
1. System Prompt → 放置全局约定和 Spec 开发流程说明
2. Projects 功能 → 将 Spec 文件上传为 Project Knowledge → 所有对话自动包含 Spec 上下文
3. Extended Thinking → 适合让 AI 分析复杂 Spec 并生成 Plan
|
最佳搭配:
- 利用 Extended Thinking 处理复杂的系统级 Spec
- 使用 Projects 功能管理多个相关 Spec
- 适合"骨架优先"策略
工具对比
| 特性 |
GitHub Copilot |
Cursor |
Claude |
| IDE 集成 |
VS Code 原生 |
独立 IDE |
Web/API |
| 文件操作 |
✅ 直接读写 |
✅ 直接读写 |
❌ 需手动 |
| 多文件编辑 |
✅ Agent Mode |
✅ Composer |
❌ 逐文件 |
| 上下文容量 |
大 |
大 |
很大 |
| Spec 感知 |
通过指令文件 |
通过规则文件 |
通过 System Prompt |
| 最佳场景 |
日常开发 |
多文件重构 |
复杂设计分析 |
8.2 Spec 与测试驱动开发(TDD)的融合
Spec 开发模式可以与 TDD 完美融合,形成 Spec-Driven TDD 流程:
1 2
| 传统 TDD: ❌ Red → ✅ Green → ♻️ Refactor Spec-Driven TDD: 📋 Spec → ❌ Red → ✅ Green → ♻️ Refactor → ✅ Verify vs Spec
|
融合流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| Step 1: 编写 Spec(包含验收标准) │ ▼ Step 2: 根据验收标准生成测试用例 ← AI 辅助 │ · AC-1 → test: should create user with valid email │ · AC-2 → test: should reject duplicate email │ · AC-3 → test: should reject weak password │ ▼ Step 3: 运行测试(全部 ❌ Red) │ ▼ Step 4: 根据 Spec 实现代码 ← AI 辅助 │ ▼ Step 5: 运行测试(全部 ✅ Green) │ ▼ Step 6: 对照 Spec 验收标准验证(Verify vs Spec)
|
从验收标准到测试用例的映射
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 28 29
| Spec 验收标准: AC-1: 正常邮箱注册 - Given: 有效的邮箱和密码 - When: POST /api/v1/auth/register - Then: 返回 201,包含用户信息 // 自动映射的测试用例 describe('POST /api/v1/auth/register', () => { // AC-1: 正常邮箱注册 it('should return 201 with user info for valid registration', async () => { // Given const payload = { email: 'new@example.com', password: 'Abc12345', name: '测试用户' };
// When const res = await request(app) .post('/api/v1/auth/register') .send(payload);
// Then expect(res.status).toBe(201); expect(res.body).toHaveProperty('id'); expect(res.body.email).toBe('new@example.com'); expect(res.body.name).toBe('测试用户'); expect(res.body.emailVerified).toBe(false); }); });
|
Prompt 模板:从 Spec 生成测试
1 2 3 4 5 6 7 8 9 10 11
| 请根据以下 Spec 的验收标准,生成完整的测试用例。
要求: 1. 每一条验收标准(AC)对应至少一个测试用例 2. 使用 Given-When-Then 注释结构 3. 包含正常路径和异常路径 4. 使用 [Jest/PyTest/...] 测试框架 5. 测试文件路径:[指定路径]
验收标准: [粘贴 Spec 中的验收标准]
|
8.3 Spec 开发模式与传统开发模式对比
全面对比表
| 维度 |
传统开发 |
AI 对话式编程 |
Spec 驱动开发 |
| 核心驱动力 |
需求文档 + 人脑 |
自然语言 Prompt |
结构化 Spec |
| 代码编写者 |
人类 |
AI(人类审查) |
AI(人类监督) |
| 质量控制 |
Code Review |
人工审查 AI 输出 |
Spec 合规性验证 |
| 需求追溯 |
弱(需额外工具) |
无(对话历史会丢失) |
强(Spec ↔ Code 映射) |
| 一致性 |
依赖个人经验 |
低(每次对话独立) |
高(Spec 提供稳定锚点) |
| 可复现性 |
中(依赖文档质量) |
低(prompt 不够系统化) |
高(Spec 可重复使用) |
| 学习曲线 |
低 |
低 |
中(需学习 Spec 编写) |
| 适合的项目规模 |
任意 |
小型/原型 |
中型及以上 |
| 团队协作 |
通过代码 |
困难(对话不可共享) |
通过 Spec Review |
| 知识沉淀 |
在代码和文档中 |
在聊天记录中(易丢失) |
在 Spec 文件中(持久化) |
| 变更管理 |
修改代码 + 更新文档 |
重新对话 |
更新 Spec → 重新生成 |
| 效率天花板 |
受限于编码速度 |
受限于 AI 理解准确度 |
受限于 Spec 编写质量 |
什么时候不需要 Spec 开发模式?
| 场景 |
原因 |
替代方案 |
| 快速原型/POC |
速度优先,不需要长期维护 |
直接 AI 对话式编程 |
| 一行 Bug 修复 |
问题和修复都很明确 |
直接修改代码 |
| 探索性编程 |
还不知道要做什么 |
先探索,再写 Spec |
| 纯 UI 微调 |
视觉调整不适合文字描述 |
截图 + 口头描述 |
| 个人脚本/工具 |
只有自己使用,不需要协作 |
随意选择 |
8.4 进阶技巧
技巧一:多 Spec 编排
当多个 Spec 之间存在依赖关系时,需要进行编排。
1 2 3 4 5 6 7 8 9
| Spec 依赖图示例:
SPEC-001: 用户认证基础设施 ↓ SPEC-002: 邮箱注册 ←────────── SPEC-006: 邮件服务 ↓ SPEC-003: 登录/登出 ↓ SPEC-004: JWT Token 管理 ────→ SPEC-005: Token 刷新
|
编排规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ## Spec 执行顺序
### 第一批(无依赖) - SPEC-001: 用户认证基础设施 - SPEC-006: 邮件服务 → 这两个可以并行实现
### 第二批(依赖第一批) - SPEC-002: 邮箱注册(依赖 SPEC-001 + SPEC-006)
### 第三批(依赖第二批) - SPEC-003: 登录/登出(依赖 SPEC-002)
### 第四批(依赖第三批) - SPEC-004: JWT Token 管理(依赖 SPEC-003) - SPEC-005: Token 刷新(依赖 SPEC-004,可与 SPEC-004 串行)
|
技巧二:Spec 组合模式
对于复杂功能,使用"父 Spec + 子 Spec"的组合模式:
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 28 29
| ## 父 Spec(总览)
--- title: "支付系统" spec_id: "SPEC-PAY-000" type: "parent" children: - "SPEC-PAY-001" # 支付网关集成 - "SPEC-PAY-002" # 订单支付流程 - "SPEC-PAY-003" # 退款处理 - "SPEC-PAY-004" # 对账系统 ---
# 支付系统 Spec
## 子 Spec 概览
| Spec | 描述 | 优先级 | 依赖 | |------|------|--------|------| | PAY-001 | 支付网关集成 | P0 | 无 | | PAY-002 | 订单支付流程 | P0 | PAY-001 | | PAY-003 | 退款处理 | P1 | PAY-002 | | PAY-004 | 对账系统 | P2 | PAY-001, PAY-002 |
## 全局约束 (适用于所有子 Spec 的通用约束) - 所有金额使用最小货币单位(分)存储 - 支付状态机:pending → processing → success/failed - 所有支付操作必须有幂等性保障
|
技巧三:Spec 复盘(Spec Retrospective)
项目交付后进行 Spec 复盘,持续改进:
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
| ## Spec 复盘模板
### 项目/Sprint:[名称] ### 复盘日期:YYYY-MM-DD
### Spec 统计 - 编写的 Spec 数量:10 - 一次通过验证的比例:70% - 需要修改 Spec 的次数:8 次 - 平均 Spec 编写时间:45 分钟
### 好的做法(Keep) - AC-1 的 Given-When-Then 格式让测试编写很顺利 - 上下文引用帮助 AI 准确理解了项目约定
### 需要改进(Improve) - 前端 Spec 缺少响应式设计的描述,导致移动端 Bug - 部分 Spec 的"非目标"不够明确,AI 实现了不需要的功能
### 新发现(Learn) - 在 Spec 中包含"错误处理"的具体状态码列表,能显著提高 AI 的实现质量 - 数据模型 Spec 应该包含索引策略,否则 AI 不会主动添加
### 行动项(Action) - [ ] 更新 Spec 模板,加入"响应式设计"必填章节 - [ ] 建立团队级别的错误码清单 - [ ] 在 Spec Review Checklist 中加入"非目标边界检查"
|
技巧四:Spec 驱动的 AI 流水线
对于重复性的开发任务,可以构建"Spec → Code"的自动化流水线:
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 28 29 30 31 32 33
| ┌──────────────┐ │ Spec 模板 │ │ + 参数输入 │─────────┐ └──────────────┘ │ ▼ ┌──────────────────┐ │ Step 1: 生成 Spec │ ← AI 根据模板和参数生成完整 Spec └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Step 2: 人工审查 │ ← 快速确认 Spec 准确性 └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Step 3: 生成代码 │ ← AI 根据审查后 Spec 生成代码 └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Step 4: 生成测试 │ ← AI 根据验收标准生成测试 └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ Step 5: 运行测试 │ ← 自动验证 └────────┬─────────┘ │ 通过 / 失败 │ │ ▼ ▼ 完成 回到 Step 3 修复
|
适用场景:CRUD API 开发、表单页面开发、数据迁移脚本等高重复性任务。
9. FAQ(常见问题与解答)
Q1: Spec 开发模式会不会降低开发速度?
不会,反而会提高整体效率。
初学者可能觉得"先写 Spec 再写代码"比"直接写代码"慢。但实际上:
| 阶段 |
无 Spec |
有 Spec |
| 需求理解 |
靠猜测,后期频繁返工 |
提前明确,减少返工 |
| AI 代码生成 |
输出不稳定,需多次重试 |
一次命中率高 |
| Code Review |
需要理解意图 + 检查实现 |
只需对照 Spec 检查 |
| Bug 修复 |
不清楚"正确行为"是什么 |
有明确的验收标准 |
| 总耗时 |
通常更多 |
通常更少 |
经验数据:编写 Spec 额外花费的 30-60 分钟,通常能节省后续 2-4 小时的调试和返工时间。
Q2: 简单功能也需要写 Spec 吗?
视情况而定。 参考以下判断标准:
1 2 3 4 5 6 7 8 9 10 11 12
| 需要 Spec 的情况: ✅ 功能涉及多个文件 ✅ 有复杂的业务规则 ✅ 需要与团队其他成员协作 ✅ 功能会长期维护 ✅ 需要 AI 协助实现
不需要 Spec 的情况: ❌ 修改一行配置 ❌ 修正一个明确的 typo ❌ 添加一条简单的日志 ❌ 纯粹的代码格式化
|
简易规则:如果你能在 5 分钟内完成且不需要 AI 帮忙,就不需要 Spec。
Q3: Spec 应该写到什么程度才够详细?
"零猜测"测试:把 Spec 交给一个完全不了解项目的开发者(或 AI),如果他不需要问你任何问题就能完成实现,那就够详细了。
常见的"不够详细"信号:
- AI 生成代码时做了很多你没预期的技术选择
- 不同的人读同一份 Spec 会有不同的理解
- 验收标准中使用了"合适的"、"合理的"等模糊词
Q4: 如何说服团队采用 Spec 开发模式?
采用渐进式推广策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Level 1(试点): - 选择一个痛点明显的项目/模块 - 由 1-2 个人先试用 - 收集对比数据(有 Spec vs 无 Spec 的效果)
Level 2(推广): - 用试点数据展示效果 - 编写团队级 Spec 模板 - 开始在 Sprint Planning 中分配 Spec 编写时间
Level 3(制度化): - Spec Review 纳入开发流程 - Spec 更新纳入 Definition of Done - 建立 Spec 质量度量指标
|
Q5: Spec 和需求文档(PRD)有什么区别?
| 维度 |
PRD(产品需求文档) |
Spec(规格说明) |
| 作者 |
产品经理 |
开发者 |
| 受众 |
所有角色 |
开发者 + AI |
| 侧重 |
业务价值和用户体验 |
技术实现和系统行为 |
| 精确度 |
业务级别(较模糊) |
技术级别(精确) |
| 格式 |
自由格式 |
结构化格式 |
| 生命周期 |
开发前定稿 |
随开发持续更新 |
关系:PRD 是 Spec 的输入之一。PRD 告诉你"用户想要什么",Spec 告诉 AI"系统应该怎么做"。
Q6: 多人同时编写 Spec 会冲突吗?
可能会,但可以管理。 与代码冲突类似,Spec 冲突通过以下方式避免:
- 模块划分清晰:不同人负责不同模块的 Spec
- 使用 Git 分支:每个 Spec 一个分支,通过 PR 合并
- 定义全局约定 Spec:技术栈、编码规范等放在共享的上下文文件中,避免各自定义
- 每日 Spec Sync:团队快速同步各自 Spec 的进展(类似 Daily Standup)
Q7: AI 生成的代码不符合 Spec 怎么办?
按优先级处理:
1 2 3 4 5 6 7 8 9 10 11 12
| Step 1: 检查是 Spec 的问题还是 AI 的问题 - 如果 Spec 有歧义 → 修改 Spec,重新生成 - 如果 Spec 清晰但 AI 理解错误 → 进入 Step 2
Step 2: 优化 Prompt 策略 - 将 Spec 拆分为更小的部分逐步执行 - 提供更多上下文(相关代码文件) - 明确指出 AI 的错误并要求修正
Step 3: 手动修正 - 如果 AI 持续无法正确实现某个部分,手动修正代码 - 在 Spec 中标注"此部分需人工实现"
|
Q8: 如何衡量 Spec 开发模式的效果?
推荐的度量指标:
| 指标 |
计算方式 |
目标值 |
| Spec 首次通过率 |
一次验收通过的 Spec 数 / 总 Spec 数 |
> 70% |
| AI 输出采纳率 |
无需修改直接使用的 AI 代码行数 / 总生成行数 |
> 80% |
| 返工次数 |
Spec 批准后的修改次数 |
< 2 次/Spec |
| Bug 密度 |
Bug 数 / 千行代码 |
持续下降 |
| Spec 编写时间 |
平均每个 Spec 的编写时间 |
30-60 分钟 |
| 端到端交付时间 |
从需求到代码交付的总时间 |
比无 Spec 时更短 |
Q9: Spec 文件应该纳入 Git 版本管理吗?
绝对应该。 Spec 文件是项目的一等公民,理由:
- 变更追踪:谁在什么时候修改了 Spec 的哪些内容
- 协作工具:通过 PR Review 进行 Spec 审查
- 版本对应:代码 v1.2 对应 Spec v1.2
- 知识沉淀:Spec 的演进历史本身就是宝贵的项目知识
1 2 3 4 5 6 7
|
!specs/
specs/**/*.tmp specs/**/*.draft.md
|
Q10: Spec 开发模式适合个人开发者吗?
非常适合。 个人开发者使用 Spec 模式的好处:
- 思维整理:写 Spec 的过程就是理清思路的过程
- AI 协作:个人开发者使用 AI 工具的频率更高,Spec 能显著提高 AI 产出质量
- 项目延续性:几个月后重新打开项目,Spec 能帮你快速恢复上下文
- 简化版本:个人使用可以简化 Spec 格式,跳过 Review 流程
个人开发者的轻量 Spec 格式:
1 2 3 4 5 6 7 8 9 10 11 12
| # [功能名]
## 要做什么 - ...
## 怎么做 - 技术栈:... - 关键实现:...
## 验收条件 - [ ] 条件 1 - [ ] 条件 2
|
Q11: Spec 开发模式会被 AI 的进步淘汰吗?
不会,反而会更重要。 随着 AI 能力增强:
- AI 越强大 → 能处理的 Spec 越复杂 → Spec 的价值越大
- AI 越自主 → 越需要明确的"合约"来约束行为 → Spec 越重要
- 多 Agent 协作 → 需要统一的"任务描述格式" → Spec 是天然选择
类比:SQL 没有因为数据库引擎的进步而被淘汰,反而更加重要。Spec 之于 AI,就像 SQL 之于数据库——它是人类意图的精确表达语言。
Q12: 如何处理 Spec 中的不确定性?
使用"开放问题"章节明确记录不确定性,而非在 Spec 中留下模糊描述:
1 2 3 4 5 6 7 8 9
| ## 开放问题
### 已标记的不确定性 - [ ] **OQ-1**: 是否需要支持批量删除?(待产品确认,暂不实现) - [ ] **OQ-2**: 缓存时间设为多少合适?(暂定 5 分钟,后续根据监控调整) - [x] **OQ-3**: 使用 UUID v4 还是 v7?(已确定:使用 v7,有序性更好)
### 决策记录 - 2026-03-24: OQ-3 决定使用 UUID v7,原因是 v7 的时间有序性对数据库索引更友好
|
10. 附录
10.1 参考资源与延伸阅读
方法论相关
- BDD(行为驱动开发):Spec 中的 Given-When-Then 格式源自 BDD。[Dan North 的 BDD 简介]
- DDD(领域驱动设计):Spec 中的"通用语言"概念与 DDD 的 Ubiquitous Language 一脉相承
- Design by Contract:Spec 的"合约"概念源自 Bertrand Meyer 的 Design by Contract 理论
- Literate Programming:Donald Knuth 提出的"文学化编程"理念,Spec 某种程度上是其现代演绎
工具相关
- GitHub Copilot 文档:Agent Mode、指令文件配置
- Cursor 文档:Rules 配置、Composer 模式
- Claude 文档:System Prompt、Projects 功能
相关实践
- RFC(Request for Comments):许多科技公司使用的内部技术设计文档,Spec 的灵感之一
- ADR(Architecture Decision Records):架构决策记录,可以和 Spec 配合使用
- C4 Model:系统架构可视化模型,适合在 L1 系统级 Spec 中使用
10.2 术语索引
| 术语 |
章节 |
首次出现 |
| AC(Acceptance Criteria) |
4.2 |
验收标准编写原则 |
| Agent Mode |
8.1 |
AI 工具集成 |
| BDD |
4.2 |
Given-When-Then 格式 |
| Context Window |
2.4 |
核心术语表 |
| Design by Contract |
2.2 |
核心原则 |
| Feedback Loop |
5.5 |
迭代与反馈循环 |
| Given-When-Then (GWT) |
4.2 |
行为描述格式 |
| Implementation Agent |
2.3 |
角色模型 |
| Living Documentation |
1.2 |
Spec 核心优势 |
| MoSCoW |
3.2 |
优先级排列方法 |
| Plan |
3.4 |
实施计划 |
| Planning Agent |
2.3 |
角色模型 |
| Progressive Elaboration |
2.2 |
增量式规格定义 |
| SMART |
4.2 |
验收标准原则 |
| Spec |
2.1 |
规格说明 |
| Spec Chain |
2.4 |
Spec 依赖关系 |
| Spec Drift |
6.5 |
反模式 |
| Spec First |
2.2 |
核心原则 |
| SSOT |
1.2 |
单一事实来源 |
| Token Budget |
6.2 |
上下文管理 |
| Verification Agent |
2.3 |
角色模型 |
10.3 文档变更日志
| 日期 |
版本 |
变更说明 |
作者 |
| 2026-03-24 |
1.0 |
初始版本,包含完整的 Spec 开发模式指南 |
— |
结语
Spec 开发模式不是一套死板的流程规范,而是一种思维方式的转变:
从"我来写代码"转变为"我来定义意图,让 AI 实现代码"。
这种转变要求我们发展新的技能——精确描述意图的能力、结构化思考的能力、以及与 AI 有效协作的能力。Spec 文件就是这些能力的载体。
记住三个关键点:
- Spec First,但不是 Spec Only:先有 Spec,但 Spec 可以在实践中迭代
- 质量来自 Spec,而非来自 AI:AI 的输出质量上限取决于 Spec 的质量
- Spec 是投资,不是成本:花在 Spec 上的时间,会在后续阶段数倍返还
开始你的第一个 Spec 吧。不需要完美,从一个简单的模块开始,逐步感受 Spec 驱动开发带来的效率提升和质量改善。
本文档遵循 CC BY-SA 4.0 协议。欢迎修改和传播。