主题
Spec 开发模式:完整技术指南
提示信息
版本: 1.0
最后更新: 2026-07-28
适用对象: 软件工程师、技术负责人、AI 辅助开发实践者
1. 引言
1.1 什么是 Spec 开发模式
Spec 开发模式(Specification-Driven Development) 是一种以"规格说明文档"(Spec)为核心驱动力的软件开发方法论。在这种模式下,开发者不再直接编写代码,而是首先撰写清晰、结构化、机器可读的 Spec 文件来描述"需要构建什么",然后由 AI 编程助手(如 GitHub Copilot、Cursor、Claude 等)根据 Spec 自动生成实现代码。
核心理念:
人类负责定义 "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 开发模式的演进历程
传统瀑布模型 敏捷开发 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):
┌───────────────────────────────────────────────────┐
│ 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 不需要一次性完美,可以逐步细化。
草稿 Spec(意图级)→ 详细 Spec(设计级)→ 精确 Spec(实现级)这类似于敏捷开发中的"渐进式细化"(Progressive Elaboration),但应用于规格描述层面。
原则四:Verifiable Specification(可验证的规格)
每一条 Spec 都必须是可验证的。
- 避免模糊性描述("系统应该很快")
- 使用具体的量化指标("API 响应时间 < 200ms")
- 定义明确的验收标准(Given-When-Then 格式)
原则五:Context is King(上下文为王)
Spec 必须包含足够的上下文,使 AI 无需猜测。
上下文包括:
- 技术栈选择及原因
- 已有代码的结构和约定
- 外部依赖和集成要求
- 非功能性需求(性能、安全、可用性)
2.3 角色模型
在 Spec 开发模式中,参与者分为以下角色:
┌──────────────────────────────────────────────────────────┐
│ 人类角色 │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 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. Spec 编写 │ ← 人类主导,AI 辅助
│ │
└──────┬───────┘
│
▼
┌──────────────┐
│ 3. Plan 生成 │ ← AI 主导,人类审查
│ │
└──────┬───────┘
│
▼
┌──────────────┐
│ 4. 代码实现 │ ← AI 主导,人类监督
│ │
└──────┬───────┘
│
▼
┌──────────────┐ 不通过
│ 5. 验证与 │ ──────────┐
│ 迭代 │ │
└──────┬───────┘ │
│ 通过 │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ 交付完成 │ │ 反馈修正 │
│ │ │ (回到2/3/4) │
└──────────────┘ └──────────────┘关键特征:
- 每个阶段都有明确的输入和输出
- 人类和 AI 有清晰的职责边界
- 流程是可迭代的,验证不通过时回到相应阶段修正
- 整个流程的核心驱动力是 Spec 文件
3.2 阶段一:需求分析与拆解
主导者: 人类 | AI 参与度: 低(可选辅助)
目标
将模糊的业务需求转化为可管理的、可描述的功能单元。
关键活动
- 理解业务目标:明确这个需求要解决什么业务问题
- 划定范围边界:确定做什么、不做什么
- 功能拆解:将大需求拆分为独立的功能模块
- 确定优先级:用 MoSCoW 或其他方法排列优先级
- 识别依赖关系:明确模块间的依赖和调用关系
拆解策略
大需求(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 编写流程
第一遍:骨架(10分钟)
→ 填写标题、概述、核心目标
→ 列出主要功能点(bullet points)
第二遍:充实(20-30分钟)
→ 为每个功能点添加详细行为描述
→ 补充边界情况和异常处理
→ 添加技术约束和依赖
第三遍:锐化(10-15分钟)
→ 编写验收标准(Given-When-Then)
→ 补充上下文引用
→ 自查:AI 能否仅凭这份 Spec 完成实现?AI 辅助 Spec 编写
你可以让 AI 帮助你生成 Spec 初稿,然后人工审查和修正:
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 的典型结构
markdown
## 实施计划
### 总览
- 涉及文件: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:全自动(适合简单任务)
让 AI 按 Plan 一口气完成所有步骤
→ 整体审查
→ 必要时调整策略 B:分步执行(适合复杂任务,推荐)
AI 完成 Step 1 → 人类审查 → 确认/修正
AI 完成 Step 2 → 人类审查 → 确认/修正
...
AI 完成 Step N → 人类审查 → 确认/修正策略 C:骨架优先(适合架构性任务)
第一轮:AI 生成所有文件的骨架(接口、类型、函数签名)
→ 人类审查整体架构
第二轮:AI 填充具体实现
→ 人类审查实现细节实现过程中的关键注意事项
- 保持 Spec 可见:确保 AI 在实现过程中始终能引用 Spec 内容
- 警惕 AI 漂移:AI 可能在多步骤执行中逐渐偏离 Spec 的要求
- 及时保存上下文:对于长流程,定期总结已完成的工作
- 不要过度修改:避免在实现阶段引入 Spec 中没有定义的功能
输入与输出
| 内容 | |
|---|---|
| 输入 | Spec 文件、实施计划(Plan)、项目代码库 |
| 输出 | 源代码、配置文件、测试文件等 |
3.6 阶段五:验证与迭代
主导者: 人类 + AI 协同 | AI 参与度: 中高
目标
验证生成的代码是否满足 Spec 中定义的所有验收标准。
验证层次
┌─────────────────────────────────────────────┐
│ 验证金字塔 │
│ │
│ ╱╲ │
│ ╱ ╲ L4: 用户验收测试(UAT) │
│ ╱────╲ │
│ ╱ ╲ L3: Spec 合规性验证 │
│ ╱────────╲ │
│ ╱ ╲ L2: 集成测试 │
│ ╱────────────╲ │
│ ╱ ╲ L1: 单元测试 │
│ ╱────────────────╲ │
│ ╱ ╲ L0: 静态检查/类型检查 │
│ ╱────────────────────╲ │
│ │
└─────────────────────────────────────────────┘| 层次 | 验证内容 | 工具/方式 | 责任人 |
|---|---|---|---|
| L0 | 代码语法、类型正确性 | Linter, TypeScript, Compiler | AI 自动 |
| L1 | 单个函数/方法的正确性 | Jest, PyTest, JUnit 等 | AI 生成 + 人类审查 |
| L2 | 模块间交互的正确性 | 集成测试框架 | AI + 人类 |
| L3 | 代码是否满足 Spec 的每一条验收标准 | 逐条对照检查 | 人类主导 |
| L4 | 功能是否满足业务需求 | 手动测试、演示 | 人类/产品团队 |
验证清单模板
markdown
## 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 文件包含以下结构化组成部分:
markdown
---
# ===== 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(行为驱动开发)的核心模式:
markdown
**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 中不应有任何需要猜测的内容。 以下信息必须显式声明:
markdown
✅ 显式:
- 使用 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 文件就能正确完成实现。
需要包含的上下文信息:
markdown
## 上下文引用
### 技术栈
- 语言: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 logger4.3 好的 Spec vs 差的 Spec
❌ 差的 Spec 示例
markdown
# 用户注册
实现一个用户注册功能。
需求:
- 用户可以注册
- 需要验证邮箱
- 密码要加密
- 有错误处理
技术:
- 用 Node.js 写问题分析:
- ❌ 没有元信息(作者、日期、版本、状态)
- ❌ 没有明确的技术栈版本
- ❌ "验证邮箱"含义模糊(格式验证?还是发送验证邮件?)
- ❌ "密码要加密"没有指定算法和参数
- ❌ "有错误处理"完全没有具体定义
- ❌ 没有验收标准
- ❌ 没有上下文引用
- ❌ 没有边界情况定义
✅ 好的 Spec 示例
markdown
---
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):
json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"name": "张三",
"emailVerified": false,
"createdAt": "2026-03-24T10:30:00.000Z"
}3.2 数据模型
sql
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, -- bcrypt hash
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
- Then: 返回 201,响应包含用户 ID 和 email,密码以 bcrypt 哈希存储,异步发送验证邮件
AC-2: 重复邮箱
- Given: 数据库中已存在 email = "exist@example.com"
- When: POST /api/v1/auth/register
- Then: 返回 409,错误码 EMAIL_EXISTS
AC-3: 弱密码
- Given: 请求密码为 "123"
- When: 提交注册
- Then: 返回 400,错误码 WEAK_PASSWORD
AC-4: 邮箱大小写
- Given: 已存在 email = "user@example.com"
- When: 使用 "User@Example.COM" 注册
- Then: 返回 409(大小写不敏感判重)
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 | 补充邮箱大小写处理规则 | 张三 |
### 4.4 Spec 模板
以下提供三种常用的 Spec 模板,按场景选用:
#### 模板 A:API 端点 Spec 模板
```markdown
---
title: "[API名称]"
spec_id: "SPEC-YYYY-NNN"
version: "1.0"
status: "draft"
author: ""
created: "YYYY-MM-DD"
tags: ["api"]
priority: ""
---
# [API名称] Spec
## 1. 概述
[1-2 段话描述此 API 的用途和业务背景]
## 2. 目标与非目标
### 目标
- ...
### 非目标
- ...
## 3. API 设计
### 端点
**[METHOD] /api/v1/[path]**
### 请求
- Headers: [必要的请求头]
- Body:
```json
{}响应
- 成功 ([状态码]):
json
{}- 错误 ([状态码]):
json
{}4. 数据模型
[表结构或数据结构定义]
5. 业务规则
- 规则 1: ...
- 规则 2: ...
6. 错误处理
| 场景 | HTTP 状态码 | 错误码 | 错误信息 |
|---|
7. 验收标准
AC-1: ...
- Given: ...
- When: ...
- Then: ...
8. 上下文引用
- ...
9. 开放问题
- ...
#### 模板 B:前端功能 Spec 模板
```markdown
---
title: "[功能名称]"
spec_id: "SPEC-YYYY-NNN"
version: "1.0"
status: "draft"
author: ""
created: "YYYY-MM-DD"
tags: ["frontend"]
priority: ""
---
# [功能名称] Spec
## 1. 概述
[功能描述和用户价值]
## 2. 用户场景
### 场景 1: [场景名称]
- 用户角色: [角色]
- 前置条件: [条件]
- 操作流程:
1. ...
2. ...
- 预期结果: ...
## 3. UI/UX 设计
### 3.1 页面结构
[描述组件层次和布局]
### 3.2 交互行为
- 点击 [元素]: [行为]
- 输入 [字段]: [验证规则]
- 滚动/拖拽: [行为]
### 3.3 状态管理
| 状态 | 触发条件 | UI 表现 |
|------|---------|--------|
### 3.4 响应式设计
- 桌面端(≥1024px): [布局]
- 平板端(768-1023px): [布局]
- 移动端(<768px): [布局]
## 4. API 集成
| 操作 | API 端点 | 触发时机 |
|------|---------|---------|
## 5. 错误与加载状态
- 加载中: [显示方式]
- 空状态: [显示方式]
- 错误状态: [显示方式和重试机制]
## 6. 验收标准
**AC-1: ...**
- Given: ...
- When: ...
- Then: ...
## 7. 上下文引用
- 设计稿: [链接]
- 组件库: [路径]
- 样式规范: [路径]模板 C:系统重构 Spec 模板
markdown
---
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(当前状态)[当前的代码结构/调用关系]
### 3.2 After(目标状态)[重构后的代码结构/调用关系]
### 3.3 迁移策略
[渐进式迁移 or 一次性迁移,以及具体步骤]
## 4. 兼容性要求
- [ ] 所有现有测试必须通过
- [ ] API 对外接口不变
- [ ] 数据库 schema 不变
- [ ] [其他兼容性要求]
## 5. 风险评估
| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
## 6. 验收标准
**AC-1: 功能不变**
- Given: 完成重构
- When: 运行所有现有测试
- Then: 全部通过,无新增失败
**AC-2: [性能/可读性/可维护性改进]**
- Given: ...
- When: ...
- Then: ...
## 7. 回滚方案
[如果重构出问题,如何回退]5. 从零开始的实施步骤
本章以一个完整的端到端案例,手把手演示如何在一个全新项目中落地 Spec 开发模式。
5.1 项目初始化
Step 1:创建 Spec 目录结构
在项目根目录下创建 Spec 专用目录:
bash
mkdir -p specs/{system,modules,tasks,templates,archive}目录说明:
project-root/
├── specs/ # Spec 文件总目录
│ ├── system/ # L1 系统级 Spec
│ │ └── auth-system.md
│ ├── modules/ # L2 模块级 Spec
│ │ ├── user-registration.md
│ │ └── jwt-management.md
│ ├── tasks/ # L3 任务级 Spec
│ │ ├── register-api.md
│ │ └── token-refresh.md
│ ├── templates/ # Spec 模板
│ │ ├── api-spec.md
│ │ ├── frontend-spec.md
│ │ └── refactor-spec.md
│ └── archive/ # 已完成/废弃的 Spec
│ └── ...
├── src/ # 源代码目录
├── tests/ # 测试目录
└── docs/ # 其他文档Step 2:创建 Spec 索引文件
在 specs/ 目录下创建索引文件,用于追踪所有 Spec 的状态:
markdown
<!-- 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),可在项目中添加指令文件:
markdown
<!-- .github/copilot-instructions.md -->
## Spec 开发模式
本项目使用 Spec 驱动开发。在编写或修改代码时:
1. 首先检查 `specs/` 目录下是否存在对应的 Spec 文件
2. 严格按照 Spec 中的定义实现
3. 不要添加 Spec 中未定义的功能
4. 遵循 Spec 中指定的技术约束和编码约定
5. 实现完成后,对照验收标准逐一验证5.2 目录结构规范
Spec 文件命名规范
[层级标识]-[Spec编号]-[简短描述].md
示例:
L1-001-auth-system.md
L2-002-user-registration.md
L3-003-register-api-endpoint.md替代命名方式(更简洁)
specs/
├── system/
│ └── auth-system.md # 层级由目录体现
├── modules/
│ └── user-registration.md
└── tasks/
└── register-api-endpoint.md建议: 对于中小型项目,使用目录来区分层级更加简洁。对于大型项目,在文件名中包含 Spec ID 更便于检索。
Spec 状态流转
draft → in-review → approved → implementing → implemented → deprecated
│ │ │
└─────────┴───── (需要修改时回退) ←────────────────┘| 状态 | 含义 | 可进行的操作 |
|---|---|---|
draft | 草稿,正在编写 | 编辑、删除 |
in-review | 等待审查 | 评论、批准、打回 |
approved | 已批准,可以实现 | 开始实现 |
implementing | 正在实现中 | 代码开发 |
implemented | 已实现并验证通过 | 归档 |
deprecated | 已废弃 | 移至 archive 目录 |
5.3 编写第一个 Spec
以下是一个完整的实操演练,展示如何为一个"待办事项 API"编写 Spec。
第一遍:搭建骨架(约 5 分钟)
markdown
---
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 分钟)
为每个 [待填充] 区域补充完整内容:
markdown
## 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
请求体:
json
{
"title": "完成项目报告",
"description": "编写 Q1 项目总结报告",
"dueDate": "2026-04-01"
}成功响应(201):
json
{
"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):
json
{
"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
#### 第三遍:锐化验收标准(约 10 分钟)
```markdown
## 6. 验收标准
**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 返回 4045.4 从 Spec 到代码的完整流程
以下是拿着写好的 Spec 文件,与 AI 协同完成代码实现的完整操作流程:
Step 1:将 Spec 提交给 AI
Prompt 模板:
请阅读以下 Spec 文件,为我生成实施计划(Plan)。
要求:
1. 列出需要创建/修改的所有文件
2. 每个文件需要实现的具体内容
3. 文件之间的依赖顺序
4. 预估每个步骤的复杂度(高/中/低)
Spec 文件内容:
[粘贴或引用 Spec 文件]
项目当前结构:
[提供关键的目录结构信息]Step 2:审查 AI 生成的 Plan
收到 Plan 后,逐一检查:
markdown
## Plan 审查清单
- [ ] 所有 Spec 中定义的端点都已覆盖
- [ ] 文件命名符合项目约定
- [ ] 没有引入 Spec 中未要求的依赖
- [ ] 实现顺序合理(先模型 → 再服务 → 最后路由)
- [ ] 包含了错误处理和参数验证
- [ ] 测试文件包含在 Plan 中Step 3:逐步执行 Plan
Prompt 模板(逐步执行):
请按照 Plan 的 Step [N] 执行:
[Plan 中 Step N 的内容]
请确保:
1. 严格遵循 Spec 中的定义
2. 保持与已有代码风格一致
3. 包含必要的错误处理Step 4:代码审查与验收
每一步完成后,对照验收标准检查:
Prompt 模板(验证):
请对照以下验收标准,检查当前代码是否全部满足:
[列出相关的验收标准]
对于每一条标准,请说明:
1. 是否满足(✅/❌)
2. 满足的具体代码位置
3. 如果未满足,需要如何修改5.5 迭代与反馈循环
场景一:验收标准未通过
流程:
1. 识别未通过的验收标准
2. 分析原因(代码 Bug?还是 Spec 遗漏?)
3. 如果是代码 Bug → 直接修复代码
4. 如果是 Spec 遗漏 → 先更新 Spec,再修复代码
5. 重新验证场景二:实现过程中发现 Spec 不合理
流程:
1. 暂停代码实现
2. 记录发现的问题到 Spec 的"开放问题"中
3. 评估问题的影响范围
4. 如果是小问题 → 直接修正 Spec 并继续
5. 如果是大问题 → 与团队讨论后再修正
6. 更新 Spec 版本号和变更记录
7. 重新生成受影响步骤的 Plan场景三:需求变更
流程:
1. 在 Spec 中标注变更的部分
2. 评估变更对已实现代码的影响
3. 更新 Spec 的"目标与非目标"部分
4. 更新受影响的验收标准
5. 更新 Spec 版本号(如 1.0 → 1.1)
6. 重新生成 Plan 中受影响的步骤
7. 实现变更
8. 重新验证所有验收标准(包括未变更的部分)反馈循环的可视化
Spec v1.0 代码 v1
┌──────────┐ ┌──────────┐
│ │───── Plan ────▶│ │
│ │ │ │
│ │◀── 发现问题 ──│ │
└──────────┘ └──────────┘
│ │
更新 Spec 修复代码
│ │
▼ ▼
Spec v1.1 代码 v2
┌──────────┐ ┌──────────┐
│ │───── Plan ────▶│ │
│ │ │ │
│ │◀── 验证通过 ──│ │
└──────────┘ └──────────┘
│ │
归档 部署6. 最佳实践
6.1 Spec 粒度控制
Spec 的粒度直接决定了开发效率和 AI 产出质量。粒度过粗,AI 缺少细节无法精确实现;粒度过细,写 Spec 的成本超过直接编码。
粒度评估矩阵
| 实现复杂度低 | 实现复杂度高 | |
|---|---|---|
| 业务规则简单 | L3 任务级即可(简要描述) | L2 模块级(注重技术设计) |
| 业务规则复杂 | L2 模块级(注重业务规则) | L1+L2 组合(系统级+模块级) |
粒度的"金发女孩原则"
太粗 ────────────── 恰当 ────────────── 太细
"实现用户系统" "实现用户邮箱注册 "实现邮箱正则
API,包含密码加密、 验证函数,接受
邮箱验证、重复检测" string 参数,
返回 boolean"
AI 需要猜测太多 AI 有足够信息 不如直接写代码
实现细节 精确实现粒度控制的经验法则
- 一个 Spec 对应 1-3 天的开发工作量
- 一个 Spec 产生的代码不超过 500 行(超过则考虑拆分)
- 一个 Spec 涉及的文件不超过 10 个
- 验收标准在 3-10 条之间(少于 3 条可能太粗,超过 10 条考虑拆分)
6.2 上下文管理策略
AI 模型的上下文窗口是有限的。即便是最新的模型,高效地管理上下文依然至关重要。
上下文分层策略
┌─────────────────────────────────────────────┐
│ 第 1 层:当前 Spec │ ← 必须完整包含
│ (完整的 Spec 文件内容) │
├─────────────────────────────────────────────┤
│ 第 2 层:直接上下文 │ ← 根据需要引入
│ (Spec 引用的代码文件、类型定义) │
├─────────────────────────────────────────────┤
│ 第 3 层:间接上下文 │ ← 按需提供摘要
│ (项目约定、架构文档、依赖 Spec) │
├─────────────────────────────────────────────┤
│ 第 4 层:全局上下文 │ ← 通过指令文件持久化
│ (编码规范、技术栈决策、团队约定) │
└─────────────────────────────────────────────┘上下文优化技巧
技巧 1:使用指令文件承载全局上下文
将不随 Spec 变化的全局信息放在指令文件中(如 .github/copilot-instructions.md),避免每次都在 Spec 中重复。
markdown
<!-- .github/copilot-instructions.md -->
## 全局编码约定
- 使用 TypeScript strict mode
- 文件命名:kebab-case
- 错误使用 AppError 类
- 日志使用 winston
- ...技巧 2:在 Spec 中使用精确引用而非全文复制
markdown
✅ 好的做法:
上下文引用:
- 错误处理方式参照 `src/utils/errors.ts` 中的 AppError 类
- 路由注册方式参照 `src/routes/auth.ts` 第 15-30 行
❌ 差的做法:
上下文引用:
[在这里粘贴了 errors.ts 的全部 200 行代码]
[在这里粘贴了 auth.ts 的全部 150 行代码]技巧 3:为复杂系统建立"上下文摘要"文件
markdown
<!-- 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:长流程中的"上下文检查点"
在多步骤的代码实现过程中,定期创建上下文检查点:
每 3-5 步执行一次:
Prompt:
"请总结一下到目前为止已完成的工作:
1. 已创建/修改了哪些文件
2. 已实现了哪些功能
3. 接下来还需要完成什么
4. 当前代码与 Spec 的一致性状态"6.3 Spec 版本管理
Git 中的 Spec 管理策略
bash
# 推荐的 Git 工作流
# 1. 创建 Spec 分支
git checkout -b spec/user-registration
# 2. 编写并提交 Spec
git add specs/modules/user-registration.md
git commit -m "spec: add user registration spec (SPEC-002)"
# 3. Spec Review(通过 PR)
# 创建 PR,团队成员 review Spec
# 4. Spec 批准后,在同一分支上开始实现
# ... 代码开发 ...
git commit -m "feat: implement user registration (SPEC-002)"
# 5. 合并
git merge spec/user-registrationSpec 提交信息规范
spec: add [功能名] spec ([Spec ID]) # 新增 Spec
spec: update [功能名] spec ([Spec ID]) # 修改 Spec
spec: deprecate [功能名] spec ([Spec ID]) # 废弃 Spec
feat: implement [功能名] ([Spec ID]) # 实现 SpecSpec 与代码的关联
在代码中通过注释关联对应的 Spec:
typescript
/**
* 用户注册控制器
* @spec SPEC-2026-002 用户邮箱注册
* @see specs/modules/user-registration.md
*/
export async function registerUser(req: Request, res: Response) {
// AC-1: 正常注册
// ...
}6.4 团队协作中的 Spec 开发
Spec Review 流程
Spec Author 编写 Spec
│
▼
创建 PR / MR(仅包含 Spec 文件)
│
▼
Spec Reviewer 审查 ← 关注:完整性、准确性、可实现性
│
┌────┴────┐
│ │
通过 需修改
│ │
▼ ▼
批准 反馈意见
│ │
│ 修改后重新提交
│ │
▼ │
开始实现 ◄───┘Spec Review 检查清单
markdown
## Spec Review Checklist
### 完整性
- [ ] 包含完整的元信息(title, id, version, status, author)
- [ ] "目标与非目标"清晰明确
- [ ] 详细设计覆盖了所有功能点
- [ ] 错误处理场景完整(包括网络错误、并发、权限等)
- [ ] 验收标准覆盖正常路径和异常路径
- [ ] 上下文引用充分
### 准确性
- [ ] 技术约束与项目实际一致
- [ ] 数据模型设计合理
- [ ] API 设计符合 RESTful 规范(如适用)
- [ ] 没有与已有功能的冲突
### 可实现性
- [ ] 粒度适当(1-3 天工作量)
- [ ] 依赖关系明确且已满足
- [ ] 技术方案可行
- [ ] 没有过度设计
### 可验证性
- [ ] 每条验收标准都是 SMART 的
- [ ] Given-When-Then 格式清晰
- [ ] 可以编写自动化测试来验证团队 Spec 协作模式
模式 A:Author-Reviewer 模式(小团队,2-5 人)
开发者 A(Author)→ 编写 Spec → 开发者 B(Reviewer)→ 审查 → 开发者 A → 实现模式 B:Spec Lead 模式(中型团队,5-15 人)
Spec Lead 编写 L1/L2 级 Spec
│
▼
分配给各开发者
│
▼
各开发者编写 L3 级 Spec → Spec Lead 审查 → 各开发者实现模式 C:Spec Sprint 模式(大型团队)
Sprint Planning 中专门安排 Spec 编写时间
Week 1 Day 1-2: 集体编写和审查 Spec
Week 1 Day 3 - Week 2: 按 Spec 实现
Sprint Review: 对照 Spec 验收6.5 常见反模式与避坑指南
反模式 1:Spec 形式主义
症状:为了写 Spec 而写 Spec,内容流于形式,实际不被参考
原因:团队不理解 Spec 的价值,当作行政负担
解决:
- 从最痛的问题(如 AI 产出不一致)入手引入 Spec
- 在 Spec 中只写真正有价值的内容,不追求格式完美
- 用实际效果说服团队(对比有 Spec vs 无 Spec 的 AI 输出质量)反模式 2:Spec 瀑布综合征
症状:花几天时间写一份"完美"的 Spec,迟迟不开始实现
原因:混淆了 Spec 驱动和瀑布模型
解决:
- 采用增量式 Spec 编写(草稿 → 充实 → 锐化)
- 设定时间限制:首版 Spec 不超过 1 小时
- 接受 Spec 不完美,在实现过程中迭代反模式 3:Spec 漂移(Spec 与代码不一致)
症状:代码已经演进了多个版本,Spec 还停留在初始状态
原因:只在开发前写 Spec,开发后不更新
解决:
- 将 Spec 更新纳入 Definition of Done
- 代码 Review 时同步检查 Spec 是否需要更新
- 使用 Spec 状态流转机制追踪
- 定期(如每个 Sprint)清理过期 Spec反模式 4:巨型 Spec
症状:一份 Spec 长达数十页,覆盖整个子系统
原因:没有正确进行需求拆解
解决:
- 遵循粒度控制原则(1-3 天工作量)
- 使用 L1 → L2 → L3 的层次拆分
- 一份 Spec 的验收标准控制在 3-10 条反模式 5:忽略非功能性需求
症状:Spec 只定义了功能行为,忽略了性能、安全、可用性等
原因:非功能性需求不如功能需求直观
解决:
- 在 Spec 模板中加入"技术约束"强制填写区域
- 建立团队级别的非功能性需求基线
例:"所有 API 响应时间P95 < 500ms,除非 Spec 中另行说明"反模式 6:AI 输出不审查
症状: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 周: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 示例片段
markdown
---
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
## 全局编码约定
(此部分同时写入 .github/copilot-instructions.md)
- 文件命名:kebab-case
- 类命名:PascalCase
- 函数/方法:camelCase
- 每个模块包含:controller, service, repository, dto, entity
- 错误处理:使用 NestJS 内置 HttpException 体系
- 日志:使用 NestJS Logger7.2 遗留系统重构
场景描述
有一个运行了 3 年的电商后台管理系统,代码混乱、缺少文档、测试覆盖率很低。需要在不停机的前提下逐步重构。
Spec 开发策略:考古式 Spec(Archaeology Spec)
阶段一:理解现状(考古)
├── 用 AI 辅助分析现有代码
├── 为现有功能编写"现状 Spec"(As-Is Spec)
│ — 描述系统当前的实际行为(包括已知 bug)
│ — 标记哪些是"有意设计",哪些是"意外行为"
│
阶段二:规划目标(设计)
├── 为每个要重构的模块编写"目标 Spec"(To-Be Spec)
│ — 基于 As-Is Spec,定义重构后的目标行为
│ — 明确哪些行为保持不变,哪些需要修改
│
阶段三:渐进实施(迁移)
├── 按 To-Be Spec 逐模块重构
├── 每个模块重构完成后,运行回归测试
└── 更新 Spec 状态As-Is Spec 示例片段
markdown
---
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 关键区别
markdown
## 与 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 的特殊关注点
markdown
## 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 的特殊关注点
markdown
## 前端 Spec 核心要素清单
### 1. 页面/组件结构
- 组件树和层次关系
- 可复用组件 vs 页面专用组件
### 2. 状态管理
- 全局状态 vs 局部状态
- 数据流向
- 缓存策略
### 3. 交互行为
- 用户操作 → 系统响应 的完整映射
- 动画/过渡效果
- 键盘快捷键
### 4. 响应式设计
- 断点定义
- 不同屏幕尺寸下的布局差异
### 5. 异步状态处理
- 加载中状态(Loading)
- 空状态(Empty State)
- 错误状态(Error State)
- 乐观更新策略(Optimistic Update)示例:仪表盘 Spec 片段
markdown
## 3. 详细设计
### 3.1 页面结构DashboardPage ├── PageHeader │ ├── Title: "数据分析" │ └── DateRangePicker(默认最近 7 天) ├── MetricCards(横排,等宽 4 列) │ ├── Card: 总用户数 │ ├── Card: 活跃用户数 │ ├── Card: 收入总额 │ └── Card: 转化率 ├── ChartSection(2 列布局) │ ├── LineChart: 用户增长趋势 │ └── BarChart: 收入分布 └── DataTable └── 最近交易记录(分页,每页 10 条)
### 3.2 交互行为
| 用户操作 | 系统响应 |
|---------|---------|
| 切换日期范围 | 所有图表和指标卡片重新加载数据 |
| 悬停指标卡片 | 显示与上一周期的对比(↑12% 或 ↓5%) |
| 点击图表数据点 | 显示该日期的详细数据弹窗 |
| 调整浏览器宽度到 <768px | 指标卡片变为 2x2 布局,图表变为单列 |
### 3.3 加载状态
| 状态 | UI 表现 |
|------|--------|
| 初始加载 | 指标卡片显示 Skeleton 动画,图表区域显示加载占位符 |
| 数据为空 | 显示 Empty State 插画 + "暂无数据,请调整日期范围" |
| 加载失败 | 显示错误提示 + "点击重试" 按钮 |
| 部分加载失败 | 失败的组件单独显示错误状态,不影响其他组件 |7.5 Bug 修复与问题排查
场景描述
生产环境报告"用户在特定条件下无法完成支付",需要排查和修复。
Bug 修复 Spec 模式
Bug 修复同样可以使用 Spec 模式,特别是对于复杂 Bug。
markdown
---
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. 全局指令文件
.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. 项目规则文件
.cursor/rules
→ 类似 copilot-instructions.md,定义全局约定
2. Composer 模式
→ 适合基于 Spec 的多文件生成
→ 可以一次性提交 Spec + 相关上下文
3. Chat 模式
→ 适合 Spec 的审查和优化
→ 可以让 AI 帮助完善 Spec 内容最佳搭配:
- Composer 模式适合"全自动"策略(简单任务)
- Chat 模式适合"分步执行"策略(复杂任务)
- 使用
@file引用 Spec 文件和相关代码
Claude(API / Console)
集成方式:
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 流程:
传统 TDD: ❌ Red → ✅ Green → ♻️ Refactor
Spec-Driven TDD: 📋 Spec → ❌ Red → ✅ Green → ♻️ Refactor → ✅ Verify vs Spec融合流程
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)从验收标准到测试用例的映射
markdown
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 生成测试
请根据以下 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 之间存在依赖关系时,需要进行编排。
Spec 依赖图示例:
SPEC-001: 用户认证基础设施
↓
SPEC-002: 邮箱注册 ←────────── SPEC-006: 邮件服务
↓
SPEC-003: 登录/登出
↓
SPEC-004: JWT Token 管理 ────→ SPEC-005: Token 刷新编排规则:
markdown
## 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"的组合模式:
markdown
## 父 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 复盘,持续改进:
markdown
## 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"的自动化流水线:
┌──────────────┐
│ 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 吗?
视情况而定。 参考以下判断标准:
需要 Spec 的情况:
✅ 功能涉及多个文件
✅ 有复杂的业务规则
✅ 需要与团队其他成员协作
✅ 功能会长期维护
✅ 需要 AI 协助实现
不需要 Spec 的情况:
❌ 修改一行配置
❌ 修正一个明确的 typo
❌ 添加一条简单的日志
❌ 纯粹的代码格式化简易规则:如果你能在 5 分钟内完成且不需要 AI 帮忙,就不需要 Spec。
Q3: Spec 应该写到什么程度才够详细?
"零猜测"测试:把 Spec 交给一个完全不了解项目的开发者(或 AI),如果他不需要问你任何问题就能完成实现,那就够详细了。
常见的"不够详细"信号:
- AI 生成代码时做了很多你没预期的技术选择
- 不同的人读同一份 Spec 会有不同的理解
- 验收标准中使用了"合适的"、"合理的"等模糊词
Q4: 如何说服团队采用 Spec 开发模式?
采用渐进式推广策略:
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 怎么办?
按优先级处理:
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 的演进历史本身就是宝贵的项目知识
bash
# 推荐的 .gitignore 配置
# 不要忽略 specs 目录
!specs/
# 可以忽略 Spec 编写过程中的临时文件
specs/**/*.tmp
specs/**/*.draft.md # 如果使用临时草稿文件Q10: Spec 开发模式适合个人开发者吗?
非常适合。 个人开发者使用 Spec 模式的好处:
- 思维整理:写 Spec 的过程就是理清思路的过程
- AI 协作:个人开发者使用 AI 工具的频率更高,Spec 能显著提高 AI 产出质量
- 项目延续性:几个月后重新打开项目,Spec 能帮你快速恢复上下文
- 简化版本:个人使用可以简化 Spec 格式,跳过 Review 流程
个人开发者的轻量 Spec 格式:
markdown
# [功能名]
## 要做什么
- ...
## 怎么做
- 技术栈:...
- 关键实现:...
## 验收条件
- [ ] 条件 1
- [ ] 条件 2Q11: Spec 开发模式会被 AI 的进步淘汰吗?
不会,反而会更重要。 随着 AI 能力增强:
- AI 越强大 → 能处理的 Spec 越复杂 → Spec 的价值越大
- AI 越自主 → 越需要明确的"合约"来约束行为 → Spec 越重要
- 多 Agent 协作 → 需要统一的"任务描述格式" → Spec 是天然选择
类比:SQL 没有因为数据库引擎的进步而被淘汰,反而更加重要。Spec 之于 AI,就像 SQL 之于数据库——它是人类意图的精确表达语言。
Q12: 如何处理 Spec 中的不确定性?
使用"开放问题"章节明确记录不确定性,而非在 Spec 中留下模糊描述:
markdown
## 开放问题
### 已标记的不确定性
- [ ] **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 协议。欢迎修改和传播。本文来源:https://niziming.github.io/2026/03/24/Spec模式开发


