用途
Spec Driven Development(规格驱动开发,简称 SDD)是一套把「机器可读的规格」置于开发工作流中心的方法。它的基本主张是:先写规格,智能体再写代码,两者依据同一份事实来源。
它针对的问题是:AI 智能体写代码很快,但不记得你的意图。你用一次提示词描述一个功能,智能体把它建出来,三个会话之后另一个智能体(或你自己)改动它,结果偏离了最初的需求——因为规格只存在于你的脑中。第二个问题是并行工作的智能体之间没有共享契约:两个分别实现同一接口前后端的智能体,会在字段名、可空性和错误结构上产生分歧,除非有东西把它们钉在一起。
主要能力
SDD 让规格承担三种角色:
- 智能体指令:在任何实现工作开始前,作为 grounding 文件加载进上下文。
- 智能体之间的契约:前端与后端智能体共享同一份规格,双方都受其约束。
- 回归锚点:未来的改动必须先更新规格,才能动代码。
规格文件结构
规格应当靠近它所描述的代码。每个功能或模块边界一份规格。示例目录结构:
src/
features/
billing/
billing.spec.md ← spec lives here
billing.service.ts
billing.controller.ts
billing.test.ts
规格是结构化文档,不是散文。结构化意味着任何智能体都能一致地解析它。
最小规格模板
# Feature: <name>
## Purpose
One sentence. What user problem does this solve?
## Scope
- IN: what this feature handles
- OUT: what it explicitly does not handle
## Inputs
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| ... | ... | ... | ... |
## Outputs
| Field | Type | Notes |
|-------|------|-------|
| ... | ... | ... |
## Behavior
Numbered, testable statements:
1. If X, then Y.
2. Error Z is returned when W.
3. Side effect: event E is emitted after A.
## Constraints
- Performance: response < 200ms at p99
- Security: input is sanitized before passing to DB
- Compatibility: must work with schema version >= 3
## Open Questions
- [ ] Should field X be nullable when user has no billing history?
使用方式
SDD 的工作流分为四步:
- 写规格(人与智能体协作):spec.md 被提交、评审、批准。
- 依据规格实现:智能体在写代码前先读 spec.md,并把行为语句当作验收标准引用。
- 依据规格测试:每条行为语句至少对应一个测试。
- 变更控制:任何功能改动都要求先更新规格;PR diff 必须包含 spec.md 的改动。
将智能体 grounding 到规格
开始实现工作时,显式把规格放进智能体的上下文。提示词或该功能目录的 CLAUDE.md 中可以写:
<!-- In your prompt or CLAUDE.md for the feature directory -->
Before implementing, read billing.spec.md. Every behavior statement in that file
is an acceptance criterion. Do not implement anything outside the defined scope.
使用 Claude Code 时,可以用目录级 CLAUDE.md 自动加载规格:
<!-- src/features/billing/CLAUDE.md -->
@billing.spec.md
All work in this directory must conform to the spec above.
Flag any spec ambiguity before writing code, not after.
多智能体协作
当智能体并行工作时,规格是防止漂移的契约:
[Spec] billing.spec.md
├── [Agent A] Implements backend service
│ reads spec → produces billing.service.ts
└── [Agent B] Implements frontend form
reads spec → produces BillingForm.tsx
两个智能体被同一组字段名、类型和错误结构 grounding。若 Agent A 返回 { invoice_id: string } 而 Agent B 期望 { invoiceId: string },规格会捕捉到这个冲突,而不是等到凌晨两点的集成测试。
规格一致性检查
把验证构建进工作流:
# In CI or pre-commit: check that spec and implementation stay in sync
# Example: extract endpoint contracts from spec and diff against OpenAPI output
在 TypeScript 项目中,从规格派生类型而不是复制它们:
// billing.types.ts — generated from or directly references billing.spec.md
// When spec changes, types change. When types change without spec change → flag it.
规格演进
规格不是冻结的,需求会变。规则是:先更新规格,再评审规格变更(PR、结对评审或异步评论),然后实现代码改动。绝不让代码悄悄漂移。滞后的规格比没有规格更糟——它会主动误导智能体。
适用场景与粒度
并非每个文件都需要规格。在错位成本高的地方应用 SDD:
适用 SDD:
- 公共 API 与服务边界
- 涉及多个利益相关方的功能
- 并行智能体工作
- 任何面向客户的内容
跳过 SDD:
- 内部工具函数
- 无行为变更的重构
- 单次会话的一次性脚本
- 构建配置与工具搭建
限制与反模式
资料列出的反模式包括:
- 规格写成散文:「billing 系统应该优雅地处理发票。」不可执行,智能体每次都会做出不同解释。
- 先写代码后写规格:从现有代码反推产物是描述,不是规格,其约束价值已经消失。
- 一份巨型规格:为整个应用写 500 行规格粒度过粗,应在功能或模块边界拆分。
- 孤儿规格:没有任何智能体读过的规格。如果你无法在提示词中引用它或通过 CLAUDE.md 自动加载它,它就不提供 grounding 价值。
- 规格作秀:为满足流程要求而写规格,却从不将智能体绑定到它。
效果衡量
以下信号表明 SDD 在起作用:智能体就范围提出澄清问题而不是自行假设;首次实现即符合规格、无需纠正;并行智能体之间的集成缺陷可测量地下降;代码评审引用规格语句,而不只是代码风格;改动功能时自然地先编辑规格。