夜雨聆风学习资料网

ARTICLE · 1132285

从沟通文档到工程契约:SDD 重塑 AI 辅助开发

从沟通文档到工程契约:SDD 重塑 AI 辅助开发
METHODOLOGY · 方法论拆解2026.10

从沟通文档到工程契约

SDD 重塑 AI 辅助开发

Spec-Driven Development · 四阶段流程 · 三文件体系

qztmy

AI编程方法论

📦 6 Parts + Conclusion

👉 滑动

PART 01

SDD 是什么

定义与反转

PART 02

为什么 SDD

问题与解法

PART 03

SDD 完整流程

四阶段+三文件

PART 04

Spec 怎么写

好坏对比+迭代

PART 05

SDD vs Vibe Coding

范式对比

PART 06

局限与陷阱

实战避坑

01

PART

SDD 是什么

WHAT IS SDD · 定义与反转

SDD(Spec-Driven Development)是一种以规格文档为核心的开发方法——先写 Spec,再让 AI 生成代码。

它和传统开发的根本区别在于:传统开发里代码是真值,Spec 只是给人看的沟通文档,写得糙点顶多影响沟通效率;SDD 里Spec 才是真值,代码是派生产物,Spec 写得好不好直接决定代码质量——因为现在写代码的是 AI,它只认 Spec。

02

PART

为什么 SDD

WHY SDD · 问题与解法

直接把需求丢给 AI 让它写代码,效果很不稳定——经常是代码写完后才发现,它一开始就没理解需求,整个推倒重来。

问题的根源在于:模糊的需求给了 AI 无限的解释空间,它按自己的理解填补了空白,而这些理解往往和你的真实意图不符。

在 AI 时代,人机分工的核心原则应该是:人定义 WHAT(做什么),AI 实现 HOW(怎么做)。SDD 的本质就是用结构化的 Spec 把 WHAT钉死,让 AI 在明确的边界内发挥。

03

PART

SDD 完整流程

FULL WORKFLOW · 四阶段+三文件

SDD 四阶段模型

Specify(规格定义)→ Plan(方案规划)→ Implement(代码实现)→ Validate(验证确认)

阶段
主导者
产出
Specify
人
spec.md
Plan
人 + AI
plan.md
Implement
AI
tasks.md + 代码
Validate
人 + AI
验收报告

spec.md / plan.md / tasks.md 每份需用户审批后进入下一阶段。验收报告不生成独立文件,直接基于 spec.md 的验收标准执行验证并报告结果。

三文件 + 项目宪法体系

GitHub 的 Spec Kit 简洁的三文件体系:

spec.md —— 需求规格

回答"背景"和"目标"、"功能需求"、"非功能需求"、"边界"、"验收标准",不涉及"怎么做"。

...spec.md

# CLI 工具添加 --version 参数 Spec

## 问题陈述

当前 mycli 命令没有 --version 参数,用户无法查看

当前安装的版本号,排查问题时不知道用的是哪个版本。

## 成功标准

- 执行 mycli --version 输出版本号并退出,退出码 0

- 版本号格式为 vMAJOR.MINOR.PATCH(如 v1.2.0)

- 版本号在构建时通过 ldflags 注入,源码中不硬编码

## 验收标准

- AC1:mycli --version 输出 vX.Y.Z 格式版本号并退出,退出码 0

- AC2:mycli -v 与 --version 行为一致

- AC3:版本号通过 go build -ldflags 注入,源码中无硬编码

- AC4:未注入版本号时输出 v0.0.0-dev

## 非目标

- 不做版本检查或自动更新

- 不输出构建时间、commit hash 等额外信息

## 约束

- 兼容现有 mycli 的参数解析方式(标准库 flag)

- 不引入新依赖

plan.md —— 架构方案

基于 spec.md 生成的技术方案,AI 起草、人审核。回答"怎么做"。

...plan.md

# CLI 工具添加 --version 参数 Plan

## 架构概览

在现有 mycli 主入口中注册 --version / -v flag,

解析后输出版本号并退出。版本号通过包级变量持有,

默认值 v0.0.0-dev,构建时由 ldflags 覆盖。

## 核心数据结构

### version 变量

- 类型:string

- 默认值:"v0.0.0-dev"

- 注入方式:go build -ldflags "-X main.version=v1.2.0"

## 技术决策

| 决策点 | 选择 | 理由 |

| 参数解析 | 标准库 flag | spec 约束"兼容现有方式" |

| 版本号注入 | ldflags -X main.version | spec 约束"源码不硬编码" |

| 短参数 -v | 复用 flag.Bool 注册同名 flag | spec 要求 -v 与 --version 一致 |

tasks.md —— 任务清单

将 plan 拆解为可执行的原子任务,每个任务可独立验证。

...tasks.md

# CLI 工具添加 --version 参数 Tasks

## T1: 定义 version 变量并注册 flag

**文件:** main.go

**依赖:** 无

**步骤:**

1. 定义包级变量 var version = "v0.0.0-dev"

2. 在 main() 中注册 flag.Bool 处理 --version 和 -v

3. 解析后若为 true,输出 version 并 os.Exit(0)

**验证:** go build 编译通过;./mycli --version 输出 v0.0.0-dev

## T2: 验证 ldflags 注入

**依赖:** T1

**验证:** go build -ldflags "-X main.version=v1.2.0"

./mycli --version 输出 v1.2.0,./mycli -v 输出 v1.2.0

## 执行顺序

T1 → T2

constitution.md —— 不可变的项目原则

项目级别的「宪法」,定义所有 Spec 都必须遵守的不可违背约束,把团队技术决策固化为 AI 的「潜意识」。

...constitution.md

# 项目宪法

## 技术栈

- 语言:Go 1.21+

- 模块管理:Go Modules

## 不可违背的约束

- 所有数据库查询必须使用参数化查询

- 敏感数据(密码、token、身份证号)禁止出现在日志中

- 所有公开 API 必须有单元测试

- 禁止引入新依赖,除非 constitution.md 中已登记

## 代码规范

- 遵循 Effective Go 和 Go Code Review Comments

- 错误处理必须显式判断,禁止忽略 error 返回值

- 包名使用小写单词,不使用下划线或驼峰

04

PART

Spec 怎么写

HOW TO WRITE · 好坏对比+迭代

好 Spec 的六要素

要素
作用
示例
问题陈述
为什么做
"mycli 没有 --version,无法查看版本号"
成功标准
做到什么程度算完
"输出版本号并退出,退出码 0"
用户故事
谁在什么场景下用
"作为用户,我可以执行 --version"
验收标准
怎么验证
"-v 与 --version 行为一致"
非目标
什么不做
"不做版本检查或自动更新"
约束
技术约束
"兼容标准库 flag,不引入新依赖"

好 Spec vs 坏 Spec

坏 Spec:

...坏 Spec ❌

mycli 需要支持 --version 参数,显示版本信息。

版本号要好看,用 cobra 库实现。

四个致命问题:

1. 模糊——"好看"是什么格式?

2. 遗漏边界——-v 短参数支持吗?

3. 缺乏理由——为什么要加?

4. 混入 HOW——"用 cobra"是实现方案

好 Spec:

...好 Spec ✓

## 问题陈述

当前 mycli 没有 --version 参数,用户无法

查看版本号,排查问题时不知道用的是哪个版本。

## 成功标准

- 执行 mycli --version 输出版本号并退出,退出码 0

- 版本号格式为 vMAJOR.MINOR.PATCH(如 v1.2.0)

- 版本号在构建时通过 ldflags 注入,源码中不硬编码

## 非目标

- 不做版本检查或自动更新

- 不输出构建时间、commit hash 等额外信息

差异的本质:好 Spec 是可测试的,坏 Spec 是可解释的。

粒度控制:一个实用的检验标准

Spec 的粒度很难拿捏。太粗,AI 会自作主张填补细节;太细,本质上就是在写伪代码。Spec Kit 提出了一个优雅的检验标准:

"用不同技术栈实现这个 Spec,Spec 是否仍然有效?"

❌ "使用 cobra 库注册 --version flag"

只对 cobra 方案有效,混入了 HOW

✓ "支持 --version 和 -v,输出版本号并退出,退出码 0"

无论用 cobra、标准库 flag 还是手写解析都成立

约束部分可以出现技术约束(如"兼容现有参数解析方式"),但那是"外部限制",不是"实现方案"。

实战经验:Spec 需要 3-5 轮迭代

第一版 Spec 通常问题百出。以 CLI --version 为例,第一版可能只写了:

...第一版 Spec

## 成功标准

- 执行 mycli --version 输出版本号

让 AI 基于这版 Spec 起草 plan 时,问题立刻暴露:

• -v 短参数要不要支持?Spec 没说

• 版本号格式是什么?1.2.0 还是 v1.2.0?

• 未注入版本号时输出什么?

• 版本号从哪来?硬编码还是构建时注入?

修改 Spec 补全这些边界后,重新起草 plan,可能又发现新的盲点。这个「Spec → Plan → Review Spec → 修改 Spec → 重新 Plan」的循环通常要跑3-5 轮,直到 Spec 足够清晰。

这是把传统开发中"开发到一半发现需求有问题"的代价前移到了成本最低的阶段——改一行 Spec 的成本远低于改一百行代码。

附

APPENDIX

一个简单高效的 Spec Skill 完整版

SPEC-DRIVEN SKILL · 可直接复用

以下是自己使用的 spec-driven skill 完整版,可基于此生成自己的 spec skill。它定义了完整的四阶段流程、文件模板、自检清单和审批节点。

...spec-driven SKILL.md

name: spec-driven

description: "SDD 规格驱动开发:将 Spec 作为唯一真实来源,人定义 WHAT,AI 实现 HOW。通过 constitution.md + spec.md → plan.md → tasks.md 文件体系,在 Specify → Plan → Implement → Validate 四阶段中驱动 AI 编程。在开始任何功能、模块开发前使用。"

---

# SDD 规格驱动开发

将 Spec 作为唯一真实来源,代码作为其派生产物。**先定义 WHAT,再让 AI 做 HOW。**

<HARD-GATE>

spec.md、plan.md、tasks.md 全部获得用户批准之前,禁止编写任何实现代码。无论项目看起来多简单,一律走完流程。

</HARD-GATE>

## 文件体系与流程

遵循三文件体系 + 项目宪法:

```

constitution.md(项目宪法,不可变约束)

    +

spec.md(做什么)→ plan.md(怎么做)→ tasks.md(按什么顺序做)→ 代码 → 验收报告

```

| 阶段 | 主导者 | 产出 | 关键动作 |

|------|--------|------|---------|

| Specify | **人** | spec.md | 定义问题、边界、成功标准 |

| Plan | 人 + AI | plan.md | 架构选型、模块划分、接口定义 |

| Implement | **AI** | tasks.md + 代码 | 按 plan 逐任务实现 |

| Validate | 人 + AI | 验收报告 | 基于 spec.md 的 AC 验证 + 人工 Review |

spec.md / plan.md / tasks.md 每份需用户审批后进入下一阶段。验收报告不生成独立文件,直接基于 spec.md 的验收标准执行验证并报告结果。

---

## 阶段零:项目宪法 → constitution.md

在写 spec.md 前,先建立项目级「宪法」——所有 Spec 必须遵守的不可违背约束,把团队技术决策固化为 AI 的「潜意识」,避免每个 Spec

重复声明基本约束。

### constitution.md 模板

```markdown

# 项目宪法

## 技术栈

- 语言:Go 1.21+

- 模块管理:Go Modules

## 不可违背的约束

- 禁止引入新依赖,除非 constitution.md 中已登记

- 所有公开 API 必须有单元测试

- 错误处理必须显式判断,禁止忽略 error 返回值

## 代码规范

- ...

```

### 使用方式

- Specify 阶段开始前检查 constitution.md 是否存在,不存在则引导用户创建

- 生成 spec.md 时自动遵守其约束

- 自检阶段验证 spec.md 是否违反约束

---

## 阶段一:Specify → spec.md

**输入:** 用户的初步想法或粗略描述

**输出:** spec.md

**主导者:** 人

### 步骤

1. **了解上下文**:阅读现有代码、文档和提交记录,搞清楚当前状态和本次要做的新东西。

2. **澄清需求**:一次只问一个问题,能用选择题就不用开放题。关注问题陈述(为什么做)、成功标准(做到什么程度算完,必须可测试)、非目标(哪些不做)、约束(技术约束)。如果需求涉及多个独立子系统,先帮用户拆分。

3. **提出方案**:提出 2-3 种方案,说清优劣和推荐理由。推荐方案放第一个。

4. **分段呈现**:逐段呈现,每段确认后再展示下一段。

### spec.md 六要素

| 要素 | 作用 | 示例 |

|------|------|------|

| 问题陈述 | 定义「为什么做」 | "当前 mycli 没有 --version 参数,用户无法查看版本号" |

| 成功标准 | 定义「做到什么程度算完」 | "执行 mycli --version 输出版本号并退出,退出码 0" |

| 用户故事 | 定义「谁在什么场景下用」 | "作为用户,我可以执行 mycli --version 查看版本号" |

| 验收标准 | 定义「怎么验证」 | "mycli -v 与 --version 行为一致" |

| 非目标 | 定义「什么不做」 | "不做版本检查或自动更新" |

| 约束 | 定义「技术约束」 | "兼容现有参数解析方式(标准库 flag),不引入新依赖" |

### spec.md 模板

```markdown

# [标题] Spec

## 问题陈述

(要解决什么问题,当前已有什么)

## 成功标准

- ...(必须是可测试的,如 "P95 < 200ms" 而非 "系统应该很快")

## 用户故事

- 作为一个 [角色],我可以 [操作],以便 [目的]

## 验收标准

- AC1: ...

- AC2: ...

## 非目标

- ...

## 约束

- ...

```

### 好 Spec vs 坏 Spec

**坏 Spec:** `mycli 需要支持 --version 参数,显示版本信息。版本号要好看,用 cobra 库实现。`

——模糊(「好看」是什么格式?)、遗漏边界(`-v` 短参数支持吗?)、缺乏理由、混入 HOW。

**好 Spec:**

```

## 问题陈述

当前 mycli 没有 --version 参数,用户无法查看版本号,排查问题时不知道用的是哪个版本。

## 成功标准

- 执行 mycli --version 输出 vX.Y.Z 格式版本号并退出,退出码 0

## 非目标

- 不做版本检查或自动更新

## 约束

- 兼容现有参数解析方式(标准库 flag),不引入新依赖

```

**差异的本质:好 Spec 是可测试的,坏 Spec 是可解释的。**

### 粒度检验标准

> "用不同技术栈实现这个 Spec,Spec 是否仍然有效?"

- ❌「使用 cobra 库注册 --version flag」——只对 cobra 方案有效,混入了 HOW

- ✅「支持 --version 和 -v,输出版本号并退出,退出码 0」——无论底层用 cobra、标准库 flag 还是手写解析都成立

约束可出现技术约束(如「兼容现有参数解析方式(标准库 flag)」),但那是「外部限制」,不是「实现方案」。

### 写作规则

- **聚焦行为描述**——「支持 --version 参数,输出版本号并退出」——而非「注册 `flag.Bool("version", false, "show version")`」

- **保持语言无关**——同一份 spec 应该适用于 Go、Java 和 Python

- **方法名、类名、数据结构定义留给 plan.md**,具体文件路径留给 tasks.md

- **成功标准必须可测试**——「执行 mycli --version 退出码为 0」而非「mycli --version 应该正常工作」

- **每个小节写完整**,所有内容就绪后再提交审批

- **每条验收标准至少对应一条用户故事**

### 自检

1. **占位符扫描**——有没有 TBD、TODO、未完成的小节?有就补上。

2. **语言泄漏**——有没有方法名、类型定义或特定语言的术语?有就删掉。

3. **歧义检查**——有没有哪条需求可以被理解成两种意思?有就选一种,写明确。

4. **粒度检验**——换一个技术栈实现,这个 Spec 是否仍然有效?如果否,说明混入了 HOW。

5. **可测试性**——成功标准是否都是可测试的硬约束?

6. **验收覆盖**——每条用户故事是否都有对应的验收标准?

7. **宪法对齐**——spec.md 是否违反了 constitution.md 的约束?

### 用户审批

> spec.md 已生成。请 review:

> - 问题陈述是否清晰?成功标准是否可测试?

> - 非目标是否合理?验收标准是否可观测?

>

> 确认后进入方案规划阶段。

---

## 阶段二:Plan → plan.md

**输入:** 已批准的 spec.md

**输出:** plan.md

**主导者:** 人 + AI(AI 起草,人审核修改)

### 流程

1. 重新阅读已批准的 spec.md

2. 设计满足所有功能需求的架构

3. 定义核心数据结构和接口

4. 画出模块间的交互和数据流

5. 记录关键技术决策及其理由

6. **逐段呈现**,每段获得用户确认

### Spec-Plan 迭代

第一版 Spec 通常问题百出。让 AI 基于第一版 Spec 起草 plan 后回头审视 Spec,往往能暴露大量盲点。「Spec → Plan → Review Spec →

修改 Spec → 重新 Plan」的循环通常要跑 **3-5 轮**。改一行 Spec 的成本远低于改一百行代码。

### plan.md 模板

```markdown

# [标题] Plan

## 架构概览

(组件/模块划分,每个组件一段话)

## 核心数据结构

### [结构体名]

(字段定义及说明)

### [接口名]

(方法签名及用途)

## 模块设计

### [模块 A]

**职责:** ...

**对外接口:** ...

**依赖:** ...

## 模块交互

(调用链、数据流。哪个模块调哪个,什么顺序。)

## 文件组织

```

project/

├── internal/prompt/

│ ├── builder.go — Builder、Section 类型、BuildSystemPrompt

│ └── ...

└── ...

```

## 技术决策

| 决策点 | 选择 | 理由 |

|--------|------|------|

| ... | ... | ... |

```

### 写作规则

- **数据结构和方法签名在这一层定义**

- **说清架构如何满足 spec 的每条需求**

- **文件组织写到目录和文件级别**

- **技术决策同时写明选择和理由**

- **本文档与语言相关**——根据用户选择的语言来生成

### 自检

1. **spec 覆盖**——spec 的每条需求是否都在架构中有归属?列出缺口。

2. **接口完整性**——光看接口描述,能不能独立实现每个模块?

3. **依赖清晰度**——模块间的依赖是否明确且无环?

4. **矛盾检查**——有没有技术决策和 spec 需求冲突?

5. **宪法对齐**——架构是否遵守了 constitution.md 的约束?

### 用户审批

> plan.md 已生成。请 review:

> - 架构划分是否合理?核心接口定义是否完整?

> - 模块间交互是否清晰?技术决策是否认同?

>

> 确认后进入任务拆解阶段。

---

## 阶段三:Implement → tasks.md + 代码

**输入:** 已批准的 spec.md + plan.md

**输出:** tasks.md + 代码 + 测试

**主导者:** AI

### 流程

1. 重新阅读 spec.md 和 plan.md

2. 列出文件清单——要创建、修改、测试哪些文件

3. 把 plan.md 的组件拆成有序任务

4. 每个任务是**一个聚焦的工作单元**,2-5 分钟可完成

5. 每个任务带有明确的验证方式

6. 呈现 tasks.md 给用户审批后,按任务实现代码

### tasks.md 模板

````markdown

# [标题] Tasks

## 文件清单

| 操作 | 文件 | 职责 |

|------|------|------|

| 新建 | `internal/prompt/builder.go` | Builder、Section 类型、主入口 |

| 修改 | `internal/tui/tui.go` | 接入 BuildSystemPrompt |

## T1: [任务名]

**文件:** `path/to/file`

**依赖:** 无

**步骤:**

1. 定义 Section 结构体,包含 Name、Priority、Content 字段

2. 定义 Builder 结构体,实现 Add 和 Build 方法

**验证:** `go build ./internal/prompt/...` 编译通过

## 执行顺序

```

T1 → T2 → T3

            ↘

T4(可并行)→ T5 → T6

```

````

### 写作规则

- **文件路径可以写**——这是实现层,需要具体

- **每个任务必须有「验证」部分**——「运行 X,期望看到 Y」

- **每个任务自包含**,写清楚完整细节(执行者可能不按顺序读)

- **依赖关系必须明确**——如果 T3 依赖 T1,写出来

- **粒度 2-5 分钟**——超过就拆更小

### 自检

1. **plan 覆盖**——plan.md 的每个组件是否至少有一个任务?

2. **占位符扫描**——有没有模糊的步骤或「类似 TX」的引用?

3. **依赖链**——是否存在合法的执行顺序,没有循环依赖?

4. **验证完整性**——每个任务是否都有具体的验证步骤?

5. **类型一致性**——函数名/类型名和 plan.md 定义的是否一致?

### 用户审批

> tasks.md 已生成,共 N 个任务。请 review:

> - 任务粒度是否合适?依赖关系是否正确?

> - 有没有遗漏的实现步骤?

>

> 确认后开始实现。

### 实现

tasks.md 通过审批后,AI 按任务实现代码:

1. 读 tasks.md,为所有任务创建进度追踪

2. 按执行顺序逐个完成任务:按步骤执行 → 运行验证步骤 → **先有证据再下结论**(先跑命令、看输出,再报状态)→ 验证通过后才标记完成

3. 如果被阻塞:停下来问,不要猜

4. 所有任务完成后进入 Validate 阶段

**规则:**

- 按 tasks.md 的步骤执行,除非被阻塞否则不自由发挥

- 每个任务完成后必须跑验证,「应该没问题」不算证据

- 验证不通过就先修,修好再往下走

- 每个任务或每组逻辑相关的任务完成后提交代码

---

## 阶段四:Validate → 验收报告

**输入:** spec.md + plan.md + tasks.md + 实现代码

**输出:** 验收报告(不生成独立文件,直接基于 spec.md 的验收标准执行验证并报告结果)

**主导者:** 人 + AI

### 流程

1. 读 spec.md 的验收标准——每条对应一个验证项

2. 读 spec.md 的成功标准——每条对应一个性能/指标验证

3. 补充编译/测试/lint 检查

4. 至少一个端到端场景(覆盖完整用户流程)

5. 逐项执行验证,记录证据

### 验证项来源

| 来源 | 验证什么 | 怎么验证 |

|------|---------|---------|

| spec.md 的验收标准 | 功能是否实现 | 按 AC 描述运行/观察 |

| spec.md 的成功标准 | 指标是否达标 | 跑性能测试/统计 |

| plan.md 的模块交互 | 集成是否正确 | 集成测试 |

| tasks.md 的任务验证 | 任务级验证 | 跑各任务的验证命令 |

| constitution.md 的约束 | 约束是否遵守 | 静态检查/Review |

### 规则

- **先有证据再下结论。** 先跑命令,看输出,然后再报告。

- 报告**实际结果**,不是预期结果。

- **Spec 替代的是需求文档,不是 Code Review。** 即使有 Spec,AI 代码仍需要严格的 Review。

- 有不通过的条目不丢人——修好重跑即可。

### 验收报告

```

## 验收报告

### 通过(N/M)

- [x] AC1 — 证据:...

- [x] 成功标准 "P95 < 200ms" — 证据:压测结果 P95=150ms

### 未通过(如有)

- [ ] AC3 — 预期:X,实际:Y,修复方案:...

### 端到端

- [x] 场景 1 — 结果:...

```

---

## 危险信号

出现以下想法时,停下来——你在为跳过流程找理由:

| 想法 | 现实 |

|------|------|

| 「这个太简单了,不需要写 spec」 | 越简单的项目,未被审视的假设越多 |

| 「我直接写代码就行」 | HARD GATE:spec.md 通过了才能动代码 |

| 「spec 太明显了,直接跳到 plan」 | 「明显」意味着没被验证过,写出来让用户确认 |

| 「验证等做完了再补」 | spec.md 的验收标准就是验证依据,实现前就应明确 |

| 「测试过了就说明没问题」 | 测试验证代码,验收标准验证需求 |

| 「有了 Spec 就不用 Review 了」 | Spec 替代的是需求文档,不是 Code Review |

## 核心原则

- **Spec 是唯一真实来源**——代码是派生产物

- **人定义 WHAT,AI 实现 HOW**

- **一次一个问题**,优先用选择题

- **逐段审批**,每段确认后再继续

- **成功标准必须可测试**

- **YAGNI 铁律**——只设计和实现 spec 提到的内容

- **先有证据再下结论**——先跑验证,再报告结果

- **Spec 是活的**——随时可以增量更新,和代码变更同步

05

PART

SDD vs Vibe Coding

PARADIGM COMPARE · 范式对比

什么是 Vibe Coding

2025 年初,Andrej Karpathy 提出 Vibe Coding 概念,核心理念是:用自然语言描述需求,让 AI 全权负责编码,开发者不需要读代码、理解代码,报错了直接丢给 AI 修。

这种方式在原型验证、个人脚本、一次性数据处理等场景下确实快——几小时就能跑起一个应用。但快不等于可持续。

为什么 Vibe Coding 走不远

根本原因是上下文会丢失。LLM 在长对话中容易偏离最初意图,越往后越依赖"脑补"填补空白。项目简单时偏差可控,项目复杂后小偏差会滚成大问题。

问题
说明
只见树木
局部合理但全局混乱
质量靠运气
异常处理、边界条件经常漏
技术债滚雪球
走一步看一步,补丁越打越多
决策不可追溯
设计权衡散落在对话里
上下文断裂
隔几天再改要重新解释背景
协作靠口口相传
其他人只看到代码,看不到意图

几百行代码时 AI 还能看全貌,几万行时就只能基于局部做决策——而这些决策往往和其他模块冲突。

SDD 怎么补上这个缺口

Spec 是代码的压缩表示。10 万行代码的项目,Spec 可能只有几千行。AI 读完 Spec 就能掌握全局约束,不用靠脑补,改动前就知道边界在哪。

核心差异

维度
Vibe Coding
SDD
核心假设
AI 能猜对意图
AI 需明确规格
启动速度
极快,开口就能写
较慢,先写 Spec
可维护性
差,改着成黑盒
好,Spec 即文档
可协作性
差,只有作者懂
好,Spec 是共享语言
安全性
差,边界靠 AI 自觉
较好,Spec 约束边界
适用规模
小项目(几百行)
中大型项目
天花板
上下文一丢就失控
看 Spec 体系质量

个人最佳实践

Vibe Coding 和 SDD 不是对立的,而是适用于不同阶段。我的做法是分阶段切换:

1. 探索期用 Vibe Coding——快速试错,验证想法是否成立

2. 决定要做后立刻补 Spec——把探索中得到的认知固化成规格

3. 正式开发严格 SDD——所有变更先改 Spec,再改代码

探索和规格化是前后衔接的两步,不是非此即彼。

06

PART

局限与陷阱

PITFALLS · 实战避坑

SDD 不是银弹。下面这些局限和陷阱,都是实战中真实踩过的坑。

局限 01

文档爆炸

情形:每个功能都走三件套,几十个功能文档堆了几百份。

结果:改一个接口要同步改三份文件,漏改就脱节。

缓解:按模块组织——一个模块一份 Spec,子功能用章节区分。做完的模块归档。

局限 02

大项目的 Spec 膨胀

情形:Spec 膨胀到几千行,AI 读完上下文也快满了。

结果:Spec 本身成了上下文负担,这是 SDD 最难突破的天花板。

缓解:分层 Spec——项目级 constitution.md 定义全局约束,模块级 Spec 只描述本模块。

陷阱 01

粒度过细

情形:Spec 写得比代码还长,连变量命名都要规定。

结果:退化成"用自然语言写伪代码",分工优势荡然无存。

缓解:拿粒度标准检查——"换一个技术栈,这个 Spec 还成立吗?"

陷阱 02

规格落后

情形:代码迭代了十几个版本,Spec 还停在 V1。

结果:AI 拿过时 Spec 做增量开发,越改越乱。

缓解:Spec 不是一次性产物。需求变了、发现 BUG 了,同步更新 Spec。

陷阱 03

规格形式主义化

情形:改个颜色也走全流程。

结果:开发人员嫌烦,绕过流程直接改代码,SDD 名存实亡。

缓解:判断标准:这个改动可能影响其他模块吗?会,走 Spec;不会,直接改。

陷阱 04

虚假信心

情形:有了详细 Spec,放松对 AI 代码的审查。

结果:Spec 只定义"做什么",不保证实现是对的、安全的。

缓解:Spec 替代需求文档,Code Review 和 Validate 不能省。

陷阱 05

工具复杂性

情形:引入 Spec Kit + Claude Code + CI/CD + 校验脚本 + Linter……

结果:配工具的时间比写 Spec 还长,本末倒置。

缓解:从最简方案开始:一个 spec.md + 一个 AI Agent。

Spec 是代码的压缩表示

人定义 WHAT,AI 实现 HOW

END · qztmy

相关学习资料