当 GitHub 把"先写文档再写代码"做成了工具链——speckit 深度解析

0 阅读5分钟

一、SDD:一种让 AI 先读规范再写代码的方法论

SDD(Specification-Driven Development,规约驱动开发)的核心主张很简单:先写规范,再写代码——所有实现必须从规范推导而来,规范是系统的唯一事实源。

这个理念本身并不新鲜。API-first、Design-first 都是类似思路。SDD 的不��之处在于,它是专门为 AI 辅助开发 设计的——通过结构化的规范文档来约束 LLM 的行为,让 AI 不再"自由发挥",而是"按规范执行"。

二、speckit:五阶段流水线

speckit 是 SDD 方法论的开源参考实现,提供了一套完整的 Claude Code 命令工具链。它将开发过程强制划分为五个顺序执行的阶段:

Constitution(宪法)→ Specify(规约)→ Plan(计划)→ Tasks(任务)→ Implement(实现)
阶段产物作用
Constitutionconstitution.md定义项目不可变的架构原则和约束,所有后续阶段必须遵守
Specifyspec.md用自然语言 + 结构化模板描述功能需求、验收标准、成功标准
Planplan.md基于 Spec 生成技术方案,包含架构决策、组件划分、依赖关系
Taskstasks.md将 Plan 拆解为有序的实施任务列表,每个任务有明确的输入输出
Implement代码按 Tasks 逐个实现,每个任务完成后校验是否符合规范

2.1 Constitution:项目宪法

Constitution 是 speckit 最有特色的设计。它扮演"项目宪法"的角色:

  • 所有后续阶段产物必须遵守 Constitution 中定义的原则
  • speckit.plan 命令会加载 constitution.md 做合规检查
  • speckit.analyze 命令将 Constitution 冲突自动标记为 CRITICAL 级别
  • 通过 Governance 章节规定修订流程,版本语义化管理

这个设计的出发点很好——给 LLM 一个"不可违背的约束集合",防止 AI 在生成方案和代码时偏离项目的核心架构原则。

2.2 阶段顺序约束:双层保障

speckit 通过脚本前置检查 + 命令模板内流程约束两层机制,确保阶段不被跳过:

脚本层:不同阶段使用不同的前置脚本。/speckit.specify 使用 create-new-feature.sh 创建分支和目录;/speckit.plan 使用 setup-plan.sh 初始化方案模板;/speckit.tasks/speckit.implement/speckit.analyze 通过 check-prerequisites.sh 检查前序产物是否存在。

命令模板层:每个命令明确要求加载前序产物作为输入:

命令必须加载的前序产物
/speckit.specifyspec-template.md
/speckit.planconstitution.md + spec.md
/speckit.tasksspec.md + plan.md(+ 可选产物)
/speckit.implementtasks.md + plan.md(+ 可选产物)
/speckit.analyzespec.md + plan.md + tasks.md + constitution.md

值得注意的是,Implement 阶段并不直接加载 spec.md 和 constitution.md——需求和原则约束仅通过 tasks.md 和 plan.md 间接传递,这意味着信息衰减不可避免。

2.3 三个核心理念

speckit 代表的 SDD 方法论可以归纳为三个核心理念:

  • 规范即代码:Spec 文档的详细程度接近代码本身,是系统行为的权威描述
  • 宪法最高权威:Constitution 是不可违背的约束,所有阶段产物必须与之对齐
  • 强制线性:五个阶段通过脚本前置检查强制顺序执行

三、上下文窗口:speckit 绕不开的物理极限

speckit 的每个阶段都通过 command(命令模板)实现——本质上是一段注入 LLM 对话的 Markdown 指令。每次调用阶段命令时,命令模板 + 前序产物会被注入到 LLM 的上下文中,与用户输入、项目代码共同竞争有限的上下文窗口

3.1 窗口里到底装了什么?

/speckit.implement 为例:

graph TB
    subgraph CTX["LLM 上下文窗口(固定容量)"]
        direction TB
        A["命令模板(~200 行)<br/>阶段指令 + 执行步骤 + 校验规则"]
        B["必需产物<br/>tasks.md + plan.md"]
        C["可选产物<br/>data-model.md + contracts/<br/>+ research.md + quickstart.md"]
        D["项目代码上下文<br/>需要读取和修改的源文件"]
        E["对话历史<br/>本轮交互的累积上下文"]
    end

    style A fill:#ff9999
    style B fill:#ffcc99
    style C fill:#ffcc99
    style D fill:#99ccff
    style E fill:#cccccc

红色是"约束开销"——每次必须占用;橙色是"产物开销";蓝色才是"有效信息"——真正帮助 LLM 做出正确决策的代码上下文。约束和产物占据的空间越大,留给实际代码的空间越小。

3.2 阶段推进,窗口压力递增

graph TD
    S1["Constitution<br/>命令模板 + constitution 模板<br/>窗口占用:低"]
    S2["Specify<br/>命令模板 + spec-template<br/>窗口占用:低"]
    S3["Plan<br/>constitution + spec.md<br/>窗口占用:中高"]
    S4["Tasks<br/>spec.md + plan.md + 可选产物<br/>窗口占用:中高"]
    S5["Implement<br/>tasks.md + plan.md + 可选产物<br/>+ 大量代码读写<br/>窗口占用:高"]

    S1 --> S2 --> S3 --> S4 --> S5

    style S1 fill:#c8e6c9
    style S2 fill:#c8e6c9
    style S3 fill:#ffcc80
    style S4 fill:#ffcc80
    style S5 fill:#ef9a9a

Implement 阶段的窗口压力最大,原因有二:一是 tasks.md 通常比 spec.md 更长(展开的详细任务列表),二是 implement 还需要大量读写实际代码文件。

3.3 窗口溢出的四个症状

现象原因
AI 生成的代码不符合 Constitution 原则Implement 阶段不加载 constitution.md,原则约束仅通过 plan.md 间接传递,信息衰减不可避免
Implement 阶段产出与 Spec 不一致Implement 不直接加载 spec.md,需求信息仅通过 tasks.md 间接传递,细节丢失
多步骤流程后期质量下降执行多个 task 时对话历史累积,命令模板中的执行规则在窗口中的"权重"逐轮稀释
复杂项目几乎无法使用仅"理解现有代码"就需要大量窗口,留给约束和产物的空间不够

四、speckit 的价值与局限

值得借鉴的设计

  1. Constitution 机制:给 AI 一个不可违背的约束集合,这个思路在任何 AI 辅助开发场景都有价值
  2. 阶段门控:通过脚本 + 模板双层机制确保流程不被跳过,降低了 AI"跳步"的风险
  3. Analyze 命令:提供了一个独立的质量审查阶段,可以对全部产物做一致性检查

核心局限

  1. 上下文窗口是物理极限:再精妙的流程设计,也无法绕开 LLM 上下文窗口的容量限制。当产物 + 约束占据过多窗口空间时,留给实际代码的空间不足,AI 输出质量必然下降
  2. 信息间接传递导致衰减:Implement 不加载 spec 和 constitution,需求和原则通过 plan/tasks 间接传递,细节丢失是结构性问题
  3. 强制线性 vs 真实开发的非线性:speckit 假设需求稳定、方案一次成型。虽然提供了 /speckit.clarify 处理歧义,但一旦进入 Plan 阶段就没有回头修正 spec 的机制
  4. 缺少"理解现有系统"的阶段:对于存量项目,每个需求的第一步都是"摸清现状",speckit 没有这个阶段

五、总结

speckit 是一个有思想的工具。它试图用"规范文档"来驯服 LLM 的不确定性,用"强制线性流程"来保证工程质量。在新项目、需求清晰、复杂度可控的场景下,它确实能带来结构化的开发体验。

但 LLM 的上下文窗口是一个硬约束。speckit 的"全量加载前序产物"策略,在复杂项目中会导致约束和产物挤占代码上下文的空间,最终反而降低 AI 输出质量。这不是 speckit 的 bug,而是当前 LLM 架构下所有"重文档"方法论都会面临的结构性矛盾。

理解这个矛盾,才能更好地在实践中取舍。