跳到正文

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:

  1. 建 specs/login-lock/spec.md,按四块结构填。
  2. 目标写一句;范围各写三条;约束写具体值;验收写两条正常、两条异常。
  3. 把「不做」写清楚,例如「不做 IP 封禁、不做管理员解锁」。
  4. 给 AI 的提示固定为:先读 spec;复述理解并列澄清问题;确认后再写代码。
  5. 让它先写测试并运行,确认测试因为功能未实现而失败。

跑通的标志:AI 没有直接写业务代码;每条验收都能对应到一个测试;测试第一次运行是红的。

生产动作 ​

  • 规范进 git,和代码同 PR。 只改代码不改规范时,CI 至少给出警告。
  • 主规范不写实现细节。 类名、参数默认值、表结构放 design.md;判断标准是用户可感知的行为变不变。
  • 工具只做指针。 规范放 specs/,各工具配置引用它:
工具官方可用的规范入口(写作时)注意
Claude CodeCLAUDE.md、自定义 commands/Skills、hooks/spec 不是内置命令
Cursor.cursor/rules/*.mdc、.cursor/commands/规范正文放 specs/
GitHub Copilot.github/copilot-instructions.md、prompt filesSpec Kit 是独立工具
Windsurf.windsurf/rules/、workflows.windsurfrules 为旧格式
AiderCONVENTIONS.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 等误标为内置的能力;移除无出处的通过率与模型遵循度数字

把一门技术讲透到既懂也会用