Skip to content

Spec 到底该怎么写? ​

导读 ​

Spec 是把模糊任务收束成 AI 可执行、可自查、可验收的契约。它的重心不是规定怎么做,而是定义什么算做完:写清目标、边界约束和可逐条打勾的验收标准,把 HOW 留给 AI。

传统 Spec 与人机协作 Spec 不一样在哪 ​

  • 传统 Spec 大量是形式约束:交付物结构、接口形态、目录、技术栈、流程、模板。它假设执行者没有自主性,需求可预测,路径可提前定。

  • 人机协作 Spec 应该以验收标准为主:定义「什么结果可接受」,让 AI 在方案空间里自主搜索。它假设 AI 有规划能力,而人不需要懂实现。

常见误区:把 Spec 写成操作手册

写死步骤会让 AI 从智能体退化成脚本执行器。

为什么 Vibe Coding 必须配上 Spec

Vibe Coding 主打即兴:随口说想法,AI 出代码,边写边调。 但它天生有几个硬伤:上下文容量有限,记忆不可靠,空白处就靠脑补。memory.md 这类补救方案目前并不稳定。

  1. AI 喜欢自行加需求:对话多了,悄悄夹带私货,范围持续膨胀,慢慢跑偏;
  2. 长会话遗忘约定:模型忘掉之前定好的数据结构、命名规则,偷偷乱改;
  3. 可运行 ≠ 合格:跑起来只是最低门槛,异常、边界、安全经常漏掉;
  4. 项目一大就崩盘:小 demo 很爽,多模块迭代之后技术债爆炸,改一处崩一片。

Spec‑Coding:面向 AI Agent 的轻量规格实践 ​

这套实践来自 spec‑coding.dev。下面用 Spec‑Coding 来指代这套方法。这套方法我实际用了一段时间,不可否认这是一个巧妙的方法论,但普通用户使用就显得有些笨拙和束缚。有兴趣的可以去它的项目了解一下。本文借用了它的经验,但是在他的基础之上又做了大量的减法。

Spec‑Coding 认为:绝大多数返工不是代码质量差,而是人和 AI 之间假设不一致。如果你花 10 分钟写好一份 spec,往往可以避免 AI 反复产出三版错误实现。

同时,Spec‑Coding 给出了一个「验收标准」的标准:「功能必须具体到能独立进行一次测试」。也就是说,如果你写不出这份 spec,说明这个功能本身就还没有满足启动的前提。

Spec‑Coding 的 Spec 标准骨架
  1. Context(上下文) 记录现有代码位置、关键文件、已有的系统模式。告诉 AI 现有系统长什么样,哪些模块需要复用,避免 AI 凭空造一套新结构。只陈述现状,不写需求。

  2. Goal(目标) 写交付之后系统、用户会获得什么行为。重点写 WHAT,不是 HOW。描述「发生什么结果」,不要写一步步操作流程。

  3. Plan(实施计划) 可评审的实现步骤,写明涉及的文件名、依赖。这里可以写实现思路,但 Plan 是建议方案而非铁律;如果 AI 有更好方案,在 spec 内讨论更新 Plan,而不是直接改代码。

  4. Out of scope(不在本次范围,最容易被忽视但价值极高) 明确列出本次绝对不做的事情:顺手的重构、锦上添花功能、相关但不属于当前迭代的需求。这是对抗 AI「顺便做一点」范围膨胀最关键的防线。很多时候 spec 最大价值恰恰来自这一节。

  5. Acceptance(验收标准) 全部要写成可观测、可验证的行为。禁止「体验良好、代码优雅、性能不错」这类模糊描述。要写清楚正常场景,更要写异常、失败场景:过期输入、重复提交、权限不足等边界情况。任何人不需要读代码,就可以逐条核对是否达成。

  6. Evidence(证据与回滚) 定义合并前必须具备的产出:单元测试、集成测试、需要截图的 UI 状态;同时明确灰度开关、观测指标、回退路径。回滚不是事后补救,要提前写进 spec,不能等到线上故障再想怎么回退。

本文的轻量实践做了三处减法:

Plan 降级为可选建议,轻量版可以没有 Plan;

Context 视 AI 是否冷启动决定写不写;

Evidence 里的回滚按风险等级选配。

差 Spec 与好 Spec 对比 ​

举例子:给结账页加优惠券功能

差 Spec:路径预设型 ​

markdown
# 优惠券功能

## 目标
优化结账体验,支持优惠券。

## 实现
- 在结账页加一个优惠券输入框
- 把用户输入过的券码存下来,下次自动带出
- 调用后台校验服务判断券是否可用
- 校验通过后重新计算总价
- 样式参考现有的地址选择组件

## 完成
优惠券功能正常运行。

这份 Spec 的问题不在「写得太少」,而在把本该由 AI 规划的 HOW 写成了完成条件,真正该写清的 DONE 却是空的。

  1. 「优化体验」不可判定——没说清什么变化算优化,AI 只能猜,你也只能凭感觉验收。

  2. 「正常运行」不可判定——没说什么算正常;做完了没法打勾,出错时也没法说「这条没过」。

  3. 实现步骤写死了方案——「存下来下次带出」「调后台校验」是方案选择,不是可验收标准;把步骤写进完成条件,等于用操作手册冒充验收契约。

结果是:AI 可能严格按这五步做完了,但它极不稳定,甚至可以断言——AI 呈现的效果一定不等于你脑子里的效果,而你纠正 AI 的这个动作困难重重。

好 Spec:验收契约型 ​

markdown
# 优惠券结账

## 目标
结账时可用一张优惠券;失败时用户看得懂原因,能重试。

## 约束
- 一次只能用一张券,不做叠加。
- 不改动支付流程、订单确认页和数据库。

## 验收标准
- AC-1 成功:购物车 120 元,用有效券 SAVE20 → 总价变 100 元,出现“SAVE20”折扣行。
- AC-2 过期:用已过期的券 → 总价不变,提示“券已过期”。
- AC-3 重复:用户再次输入同一张券并点击应用 → 不出现第二条折扣行。
- AC-4 不越界:改动只涉及结账页和提示文案,不碰支付和订单确认。

## 验证
每条标准都要有能看到的证据:截图或测试结果。

## 终止
四条全过 → 交付;连续两轮过不了,或要动约束里的东西 → 停下问我。

结论:每一行都在回答「什么算做完」或「怎么证明」

  1. HOW 全部留空——用不用输入框、券码存不存、调哪个服务,一个字不写;那是 AI 的规划空间,写死就把方案上限锁死了。

  2. AC 覆盖三条路径加一条边界——AC-1/2/3 分别管成功、失败、重复,AC-4 把「不越界」变成可检查的条件;验证和终止各一句,让这份 Spec 在工作循环里成为一个有退出条件的循环,而不是一个礼貌的愿望。

  3. 终止条件是出口——「连续两轮过不了就停下问我」明确告诉 AI:遇到阻碍可以停,不必硬编。这一层极容易被忽略,也是一个非常省 token 的设计。

一眼能看到的差异 ​

差 Spec好 Spec
读完知道什么要做哪几步什么算做完
「完成」指什么功能正常运行四条可逐条打勾的标准
出错路径没写,AI 自己猜过期、重复都写了
会不会越做越多没边界约束 + AC-4 挡住
什么时候停不知道全过交付,过不了问人
AI 的角色按步骤执行的脚本在验收契约内自己想办法

除特别声明外,本书内容采用 CC BY-NC-SA 4.0 授权