主题
SDD 规格驱动
一句话:SDD 把开发重心从“写代码”前移到“写规格”,用一份可验证、可持久化、可拆分的 Spec 作为唯一真相源驱动 AI 生成代码——换来可并行、可审计、可验收,代价是前期多一道人工评审,以及规格与代码的双份维护。
为什么需要
直接对话写代码(Vibe Coding)在小项目里很快,因为返工代价低、上下文短、一个人就能兜住。到了企业级,这四个前提全部不成立,失控点各有各的根因:
| 失控点 | 根因 | SDD 怎么解 | 代价 |
|---|---|---|---|
| 需求模糊 | 提示词只有结论没有约束,AI 用默认值填空 | 业务规则、边界、异常写成带阈值和单位的条目 | 写规格从分钟级变成小时级,写的人还得懂业务 |
| 上下文丢失 | 对话是易失状态,换会话或超窗口就断片 | 规格落盘,任意 Agent 可重放同一份输入 | 双份维护,不同步就多出第二个真相源 |
| 没有验收标准 | “做完了”是模型自述,不是可观测状态 | AC 写成可执行断言,进 CI 判定 | AC 写不好的规格比没规格更危险,会给出虚假安全感 |
| 无法并行 | 单会话单线程,一人只能陪一个 AI | 规格按任务切分,多 Agent 各领一单 | 依赖要人确认,拆错则并行互相覆盖 |
| 不可审计 | 决策散落在对话里,事后无法复现 | 规格→任务→代码→测试全链路可追溯 | 流程变重,小改动也要过门禁,团队会想绕开 |
这张表的读法是:每一项收益都对应一笔成本,SDD 的价值不在“写得更快”,而在返工更少、责任可定位。所以它适合错一次代价高的系统,不是所有项目。
核心机制
五阶段:把返工挡在便宜的阶段
门禁放在阶段之间而不是阶段之内,因为返工成本随阶段后移快速上升:规格里一句歧义在 Plan 阶段改是一行字,在 Verify 阶段改是一片代码(经验值:越往后贵一个量级)。回退箭头只指向上一阶段而非起点,是因为只有出错的那一层需要重做;退回起点会让已确认内容反复推翻,评审变成走过场。Specify → Plan → Tasks → Implement → Verify 是方法论抽象;具体工具(Spec Kit、Kiro 等)的命令与门禁更多,以官方文档为准。
| 阶段 | 输入 | 产出物 | AI 做什么 | 人的把关点 |
|---|---|---|---|---|
| Specify | 业务诉求、现有流程 | Requirements.md | 起草用户故事、补边缘场景 | AC 是否可验证、是否与真实业务一致 |
| Plan | Requirements.md、现有架构 | Design.md + 项目宪法 | 出架构、选型、数据模型、风险 | 是否符合现有系统约束、宪法是否被违反 |
| Tasks | Design.md | Tasks.md | 拆任务、排依赖、写完成定义 | 每个任务能否独立验证、粒度是否合理 |
| Implement | Tasks.md、代码库 | 代码、单测、提交 | 按任务编码、跑测试、自验证 | 抽查关键任务、是否越权改无关文件 |
| Verify | 全部产物 | 验收报告、覆盖率、扫描结果 | 对照 AC 跑验证、汇总差异 | 最终 CR 与上线决策 |
Implement 阶段最脆弱:AI 会跳任务,或在没跑通时声明完成。所以该阶段的退出条件必须是命令返回码,而不是模型的一句话。项目宪法在 Plan 阶段生效,把测试覆盖率、性能基线、依赖白名单这类不可谈判的约束提前钉死,后面就不用每轮重复交代。
把 SDD 跑成 Agent 工作流
方法论落到 Agent 上,关键是把“谁决定下一步”从模型手里拿走:确定性状态机控流程,Agent Loop 控阶段内的灵活,Spec 作为单一真相源。状态机的编排方式可类比持久化工作流/图编排引擎(Temporal、LangGraph 等),详见 04-LangGraph核心机制。
阶段推进由代码判断,LLM 只在阶段内推理,因为让模型判断“该不该进下一步”既不可复现也无法审计。回退边只回一层,修复上限 3 次(经验值)是防死循环的硬阈值——AI 容易在错误方向上反复改,无限循环既烧 token 也修不好。三个 HITL(规格评审、任务拆解、最终验收)都落在方向性决策上,方向错了后面全错;其余阶段的自动化才有意义。
- 阶段内 Agent Loop:观察→推理→调工具→观察,出口由代码校验(文件存在、输出符合 schema、测试退出码为 0),不通过就留在本阶段。
- 每阶段一个 Skill 包:只定义三样——system prompt、allowed_tools、output_schema;MCP 按阶段最小权限,澄清阶段读文档,评审只读不写,实现才可写文件,验证只可执行命令不可改源码。
- 三层记忆:工作记忆放当前阶段相关文件与最近工具结果,阶段结束即弃;短期记忆(checkpoint)放完整 Spec、任务列表与进度,覆盖整个会话;长期记忆放项目宪法、架构图、历史决策,跨会话持久化。
- Spec 是 SSOT:实现阶段不读原始需求只读 Spec;需求变更先改 Spec 再改代码,否则会出现“AI 按旧需求写、人已经改主意”。
实战场景
两个场景是同一个背景的两面:SDD 的全部收益都挂在“Spec 是唯一真相源”这一句话上,而最容易让它失效的不是工具,是纪律与措辞。
事故复盘:Spec 变过期文档的 60 天
故障现象与代价。引入 SDD 两个月后,新人按 specs/refund/spec.md 里的旧规则做了退款流程,联调时被告知“运营规则一个月前就改了”,整段返工 6 人日,上线延期半个迭代(事例规模,按团队校准)。比返工更糟的是没有人说得清文档和代码哪个对——本该是唯一真相源的 AC,变成了第二个真相源。
漂移过程还原。每一步单独看都合理,叠加起来就是文档腐烂:
- 第 14 天:一次常规需求 PR 改了折扣阈值只改代码没动 Spec;评审者当时盯的是代码 diff,diff 列表里缺 Spec 这件事没人负责看见。
- 第 31 天:线上 hotfix,紧急之下没人想起 Spec,事后承诺“回头补”,没有任何机制把“回头”排进日程。
- 第 45 天:团队默契地改成“以代码为准,Spec 看看就好”,需求确认退化为读代码反推规则,此前写规格的全部投入归零。
根因:纪律没有机器兜底必然失守。“变更先改 Spec”靠人审来保证,而评审注意力是稀缺资源:代码 diff 是默认焦点,Spec diff 是附加项,迭代越紧漏检率越高。指望人在每个 PR 上二次校对两份文档,不是低效门禁,是不存在的门禁。
修法。三条动作全部落在 CI 上:
- Spec 与代码同批提交成为硬规则:PR 里出现测试改名或断言变化、却没有对应 Spec diff,直接阻断,即本篇生产动作“规格同步”条目。
- AC 编号与测试用例命名映射进 CI 双向校验:Spec 里的 AC 没有对应测试是红,测试引用了 Spec 里不存在的 AC 编号也是红。“改了代码没改文档”靠人眼会漏,靠编号比对漏不掉。
- hotfix 设例外通道:允许先恢复服务,24 小时内回写 Spec 并挂工单(经验值,按团队 SLA 校准);超时未回写转为该团队下个发布的阻断项。
为什么机制对症。漂移的根源是成本不对称:改 Spec 多花一步,不改没有任何即时后果。CI 映射把“没有后果”变成“红灯”,把真相源从“靠人记得”换成“靠退出码”。这正是本篇边界里“纪律一松,Spec 就退化成过期文档”“门禁不自动化就会变成仪式”两条的落地形态——后者对 Spec 门禁本身同样成立。
案例:一条业务规则救回一次资损
故障现象与代价。大促开始一小时内出现满减与优惠券叠加的订单,单笔优惠超过货款的九成(事故口径,按活动校准),财务事后拦截结算,直接损失加对客补偿约两天该品类毛利。复盘时发现代码审查没有错——实现与需求完全一致,是需求本身没闭合。
排查定位。回溯 Spec 优惠章节,只有一条:“注意优惠叠加规则”。没有边界、没有阈值、没有默认行为,AI 每一轮都用默认值填空。同一个需求迭代了三次,AI 给出三种猜法:
- 只在前端校验叠加,接口层直接绕过。
- 允许叠加但设整体折扣上限,上限值 AI 自行虚构。
- 静默套用满减、忽略优惠券,对用户无任何失败提示。
三个版本都能通过评审与测试——因为 AC 里根本没有断言互斥,三种实现对“注意”二字都算正确。
修好之后。把一句话重写成带阈值与默认行为的业务规则和对应 AC:
text
BR-07 满减与优惠券互斥,不可叠加使用;用户同时选择时,保留对用户更优的一种,
并在响应中返回互斥说明字段;任何组合的总优惠不得超过货款的 90%
(经验值,需财务按活动校准)。
AC-07 给定同时选中满减与优惠券,当提交结算,则仅一种优惠生效,
且响应含非空互斥说明字段。为什么机制对症。这就是“为什么需要”表格里“需求模糊 → AI 用默认值填空”那一行的直接兑现:规则写成带阈值和单位的断言,AI 实现阶段会自动带上互斥校验,因为它没有需要猜的空间;AC 可断言,第三、四种猜法在合并门禁就被拦住,而不是等 T+1 财务拦截。对“错一次代价高”的系统,这一条 BR 就是整套 SDD 的回报所在。
最小上手
前提:任意支持 Skills 与 MCP 的编码助手(Claude Code、Cursor 等,版本以官方文档为准)。把模板存为 specs/<feature>/spec.md,先由人填第 8、9 节,再让 AI 补 2–7 节——验收标准先写,AI 才不会自我合理化。
markdown
# <功能名> Specification
## 1. 概述
背景;目标;范围(做什么、不做什么)
## 2. 用户故事
作为【角色】,我希望【功能】,以便【价值】
## 3. 业务规则
BR-01(每条带阈值、单位、默认值)
## 4. 功能需求
FR-01(每条至少对应一条 AC)
## 5. 非功能需求
性能 / 安全 / 可用性(带数字和测量条件)
## 6. 数据模型
表、字段、索引;状态与合法迁移
## 7. API
端点、请求/响应、错误码、幂等语义
## 8. 验收标准
AC-01(给定 / 当 / 则,可自动断言)
## 9. 边缘场景
空输入、并发、超时、部分失败、重试AC 优先写成一条自动化断言;性能、安全等无法用单测表达的,用基准或专项检查兜底,但必须有可观测判据,见 05-SDD+TDD双驱动实战 的 AC 映射。
text
AC-01 给定 1000 行合法文件,当调用导入,则 30s 内 success=1000 且无错误记录
AC-02 给定 3 行重复 SKU,当导入完成,则 skipped=3 且报告行号与源文件一致
AC-03 给定缺少必填字段,当校验,则报告中的 field 与 reason 均非空
AC-04 给定导入进行中,当并发写商品,则 P95 延迟不超过基线 20%
AC-05 给定非白名单文件类型,当上传,则返回 415 且临时目录无残留写不出可观测判据的 AC 是需求描述,不是验收标准;它会让人以为已经约束住了,实际仍靠感觉验收。
生产动作
- 规格门禁:Spec 合并前机器检查——每个 FR 至少一条 AC、每个数字带单位与测量条件、第 9 节非空;缺一项打回。
- 任务粒度:单任务不超过半天(经验值),完成定义必须是命令或断言;任务估时超过一天,回退 Tasks 阶段重拆。
- 实现门禁:以测试、构建、lint 的退出码为准,不采信完成声明;每个任务一次提交,提交信息带任务号,便于回滚定位。
- 修复上限:同一测试连续修复 3 次(经验值)仍失败,自动转人工,附件带上三次 diff 与失败输出。
- 规格同步:变更先改 Spec 再改代码,两者同批提交;CI 校验 AC 编号与测试用例命名一一对应。
- 权限下发:按阶段给 MCP 白名单,实现阶段才给写权限,验证阶段只给执行权限,避免 AI 顺手改源码绕过测试。
- 排障路径:现象“AI 反复声明完成但 CI 红”→ 查任务完成定义是自然语言还是可执行断言 → 是前者就回退 Tasks 重写,不要在下游反复重试。
边界
- 适合:需求可枚举、验收口径明确、多人或多 Agent 协作、需要审计的中长期系统。
- 不适合:探索性原型、一次性脚本、纯视觉微调。规格成本高于收益,这类直接用对话式编程更快。
- 规格不是越细越好:细到实现细节就变成代码的重复描述。规格应停在“可验证的行为”,不规定用哪个循环。
- 双份维护是固有成本:只能靠“变更必须先进 Spec”的纪律压低,工具消除不了;纪律一松,Spec 就会退化成过期文档。
- 门禁不自动化就会变成仪式:人审不过来就橡皮图章,带病交付比没有 SDD 更难排查。
- 并行度受拆解质量限制:拆错依赖,多 Agent 并行会互相覆盖,合并成本高于串行。
常见坑
- 规格太粗:“做一个登录功能”——认证方式、密码策略、锁定阈值全空着,AI 只能猜。写成“连续失败 5 次锁定 30 分钟”才可验证。
- 跳过验证门禁:信了“已完成”就合并。门禁必须是 CI 里的命令,人只处理红灯。
- 规格与代码不同步:PR 只改代码不改 Spec,下一个人按旧规格开发。把 Spec 与代码放进同一批提交,CI 校验 AC 与测试用例的命名映射。
- 任务拆太大:“实现整个支付模块”做不完也无法验证。拆到每个任务有可执行的完成定义,超过一天就回退重拆。
讲清楚
SDD 的本质是把开发从写代码前移到写规格:Spec 是唯一真相源,代码和测试都从它派生。它解决对话式编程在企业里的四个硬伤——需求模糊、上下文易失、没有验收标准、无法并行审计;做法是把模糊处写成带阈值的业务规则,把完成定义写成可执行断言,把规格拆成可独立验证的任务。代价是前期多一道人工评审,并且规格和代码要双份维护,不同步就会多出第二个真相源。落地时用确定性状态机控七阶段、Agent Loop 控阶段内灵活、三个 HITL 卡方向;错一次代价高的系统值得这么做,一次性脚本不该上这套流程。
适用:2026 年主流 SDD 工具与 Agent 框架 | 初稿 2026-10