主题
SPEC 规范编写实战指南
一句话:好的 SPEC 不是在描述「AI 应该做什么」,而是在定义「什么算做完」;它是一份可验收的契约,不是一篇散文。
适用范围:本文的写法与工具无关。文中提到的工具目录和配置项以各工具官方文档为准,产品迭代后可能改名。
为什么需要
大多数第一次写 SPEC 的人会写成这样:
markdown
# 用户管理功能
做一个用户管理模块,支持增删改查。要有登录。界面要好看,性能要好,代码要规范。发给任何 AI,产出都需要大量返工。问题不在模型,在四个空位:
| 空位 | 表现 | AI 只能怎么补 |
|---|---|---|
| 无边界 | 「用户管理」包不包括注册、权限、头像? | 按语料猜,可能多写也可能少写 |
| 无验收 | 「性能要好」是多少 QPS、多少毫秒? | 忽略,无法转成目标 |
| 无约束 | 「代码要规范」是哪套分层和风格? | 用默认模板,可能和项目不搭 |
| 无优先级 | 登录和增删改查谁先做? | 按自己的常识排序 |
一份好 SPEC 的四个判据:有经验的开发者读完能画出主流程;AI 读完后澄清问题不超过 3 个;验收标准能自动化验证;三个月后新人能看懂当时的取舍。
核心机制
四块结构:目标、范围、约束、验收
markdown
# 功能:<名称>
## 1. 目标
一句话说明为谁解决什么问题;可量化时写指标。
## 2. 范围
做:明确列出。
不做:明确列出(与「做」同等重要)。
依赖:依赖哪些已有模块或外部服务。
## 3. 约束
技术栈、架构分层、安全要求、兼容性。
每条约束写具体值,不写「要安全」「要规范」。
## 4. 验收
每条用 GIVEN / WHEN / THEN,至少一条能在本地执行。
异常和边界至少各一条。四块缺一块,AI 就要猜一块。「不做」尤其容易被省略,而它决定了 AI 会不会顺手扩张范围。
粒度:跟着「改错的代价」走
| 功能类型 | 写到什么程度 | 原因 |
|---|---|---|
| 支付、认证、数据迁移 | 验收到 Given/When/Then,含异常与回滚 | 改错代价高,需要可执行契约 |
| 普通 CRUD | 数据模型 + 接口契约 | 行为简单,写太细会拖慢变更 |
| UI 展示 | 页面结构 + 字段来源 | 视觉细节用原型表达更有效 |
| 探索性功能 | 目标 + 假设 + 衡量指标 | 方向未定,过细会限制探索 |
判断方法:这个需求变了,要改几处?改起来越贵,越值得写细;改起来越频繁,越应该写粗。
EARS:把自然语言压成固定句式
EARS(Easy Approach to Requirements Syntax)由 Rolls-Royce 的 Mavin 等人在 2009 年提出,Kiro 等工具采用。它用固定句式减少歧义:
| 模式 | 句式 | 例子 |
|---|---|---|
| 普遍型 | 系统应 [行为] | 系统应对密码做 BCrypt 哈希存储 |
| 事件驱动 | WHEN [触发] 系统应 [行为] | WHEN 提交登录,系统应在 200ms 内返回 |
| 状态驱动 | WHILE [状态] 系统应 [行为] | WHILE 维护模式,非管理员请求返回 503 |
| 条件型 | IF [条件] THEN 系统应 [行为] | IF 连续 5 次失败,THEN 锁定 30 分钟 |
| 可选特性 | WHERE [配置] 系统应 [行为] | WHERE 审计开启,系统应记录管理员操作 |
EARS 的价值是逼你写清条件和主体,不是让文档看起来高级。普通 CRUD 不必强行套五种句式。
验收判据必须可执行
「系统应运行良好」不是验收标准,因为它无法变成测试。可执行的验收至少包含三样:输入、可观察的输出、判定条件。
text
❌ 登录失败要锁定。
✅ GIVEN 账户 alice 已连续失败 4 次
WHEN 第 5 次提交错误密码
THEN 返回 HTTP 423,响应体 code=LOCKED
AND 紧接着提交正确密码仍返回 423
AND 30 分钟后提交正确密码返回 200
可执行判据:上述四条写成集成测试;本地命令
`pytest tests/test_login_lock.py -q` 全绿。性能类验收要带条件:并发数、数据量、测量位置。没有条件的「P99 < 200ms」不可复现。
最小上手
用 10 分钟给一个小功能写一份可跑的 SPEC:
- 建
specs/login-lock/spec.md,按四块结构填。 - 目标写一句;范围各写三条;约束写具体值;验收写两条正常、两条异常。
- 把「不做」写清楚,例如「不做 IP 封禁、不做管理员解锁」。
- 给 AI 的提示固定为:先读 spec;复述理解并列澄清问题;确认后再写代码。
- 让它先写测试并运行,确认测试因为功能未实现而失败。
跑通的标志:AI 没有直接写业务代码;每条验收都能对应到一个测试;测试第一次运行是红的。
生产动作
- 规范进 git,和代码同 PR。 只改代码不改规范时,CI 至少给出警告。
- 主规范不写实现细节。 类名、参数默认值、表结构放
design.md;判断标准是用户可感知的行为变不变。 - 工具只做指针。 规范放
specs/,各工具配置引用它:
| 工具 | 官方可用的规范入口(写作时) | 注意 |
|---|---|---|
| Claude Code | CLAUDE.md、自定义 commands/Skills、hooks | /spec 不是内置命令 |
| Cursor | .cursor/rules/*.mdc、.cursor/commands/ | 规范正文放 specs/ |
| GitHub Copilot | .github/copilot-instructions.md、prompt files | Spec Kit 是独立工具 |
| Windsurf | .windsurf/rules/、workflows | .windsurfrules 为旧格式 |
| Aider | CONVENTIONS.md、--read | 启动时读入 spec |
| Cline | .clinerules/、Plan/Act | 靠规则引用 spec |
- 长度按经验控制。 单文件几百到一千多字通常够用;超过时优先拆分(一个功能一个文件),不要压缩掉验收标准。这是经验值,不是模型硬限制。
- AI 忽略 SPEC 时按顺序排查:规范是否太长且混入无关内容;工具是否读到了规范(检查路径和规则文件);验收标准是否可执行;最后才考虑换模型。
边界
- SPEC 不是实现文档。 写进类名、SQL、参数默认值,需求一变就要改多处。
- SPEC 不是测试。 验收标准是测试的输入;没有落成测试,它仍然只是文档。
- EARS 不消除所有歧义。 它约束句式,不保证需求本身正确;业务规则仍需领域专家确认。
- 工具目录会变。 本文的路径是写作时点的常见配置,升级后以官方文档为准。
- 写得越细不一定越好。 探索性需求和频繁变更的模块,过细的规范会变成负担。
讲清楚
SPEC 的核心不是把功能描述得更长,而是定义「什么算做完」。一份能用的 SPEC 有四块:目标、范围(尤其是不做什么)、具体约束、可执行验收。验收标准要写成 Given/When/Then,并且能落成一条测试;写成「运行良好」等于没写。粒度跟着改错的代价走:支付、认证写细,普通 CRUD 写清数据和接口即可。EARS 是压缩歧义的工具,不是必填格式。最后,规范要放在仓库里、和代码同 PR,各工具配置只做指针;否则规范一定会和代码脱节。
初稿 2026-07 | 最后修订 2026-10 | 事实核查:订正 Claude Code
/spec、Copilot Spec Kit 等误标为内置的能力;移除无出处的通过率与模型遵循度数字