最近在思考一个问题:AI 编程工具的真正价值是什么?不是"让机器替代人",而是让人工作在更高的抽象层次上。这个认知转变,带出了一系列关于人机协作、Agent 架构设计的思考。

一、从 Vibe Coding 到 SDD:一个被误解的问题

2024-2025 年,AI 编程助手的爆发带来了一个新词汇——Vibe Coding(基于感觉的编程)。开发者与 AI 对话,AI 即时生成代码,看起来效率惊人。

但这里有一个被普遍忽视的根本矛盾:

Vibe Coding 优化的是"个人编码效率",但工程的真正瓶颈是"团队协作效率"。

一个人写代码快 10 倍,但团队沟通成本不变,整体效率提升极为有限。更糟的是,Vibe Coding 在协作层面制造了新的麻烦:

  • PM ↔ 研发:对话历史无法作为契约,验收时各执一词,“这不是我要的”
  • 前端 ↔ 后端:各自 vibe,联调时才发现接口格式对不上,浪费 1-2 天
  • 后端 ↔ 后端:订单服务调用 POST /inventory/deduct,库存服务只有 PUT /stock/reduce,集成测试时 404

这些问题不是工具不够好,而是 Vibe Coding 从根本上缺少一样东西:共同语言

AI 编程的演进链条

理解 SDD 的必要性,需要先看清 AI 编程工具的演进轨迹——这是一条"问题→解决方案→新问题"的链条:

阶段 核心问题 解决方案 遗留问题
Vibe Coding 推一步走一步,依赖大量人工精力 自动迭代循环(Ralph Loop) 什么时候停下来?
自动迭代 没有明确的完成标准 单元测试驱动(测试通过即完成,即 Ralph Loop:编译→测试→修复的自主迭代循环) 如何生成有意义的测试?
测试驱动 AI 难以凭空生成有意义的测试 规范驱动(从需求生成测试) 不适合多系统环境
单应用规范驱动 单应用视角,无法处理服务间协作 系统行为层(BDD) 如何串联全流程?
BDD 单独使用时各层独立,缺乏跨系统端到端串联 三层 Agent 架构

这个演进揭示了一个关键洞察:端到端是一个软件工程管理问题,不是纯粹的研发问题。只停留在研发领域(代码生成、测试生成),永远无法做到端到端。必须向上延伸到需求分析,向外扩展到多系统协作。

SDD 的本质:规范先行,协作优先

SDD 的核心逻辑:在写代码前,先用一种"AI 易读、人类可维护"的结构化语言定义系统的每一个细节。

规范驱动开发(Spec Driven Development,SDD)的核心不是"AI 写代码",而是在写代码之前,先用结构化的方式定义"系统应该做什么",让这份规范成为:

  • 人类与 AI 之间的契约
  • 代码实现的验收标准
  • 团队协作的共同语言

这个思想并不新鲜。早在 2000 年代初,Kent Beck 提出 TDD(测试驱动开发)时就包含了"先定义预期,再实现代码"的核心。今天,这一思想在 AI 编程的语境下获得了新生——而且有了更丰富的工程含义。

类比:印刷术的发明不是让抄书匠失业,而是让知识的传播者从"复制者"升级为"创作者"。SDD 的意义与此相同——它不是让 AI 替代人,而是让人从低层级的编码工作中解放出来,去处理更高层的问题。

这就是"超级个体"的由来:不是一个人变得更聪明,而是一个人拥有了原本需要一个团队才能覆盖的能力边界。

超级个体:能力边界的重新定义

"超级个体"这个概念,值得在此多展开一些。

传统意义上,一个软件工程师的能力边界是清晰的:他擅长某个技术栈,熟悉某个业务领域,在团队中承担特定角色。跨越这个边界,需要学习、需要时间、需要经验积累——这是人类认知带宽的自然限制。

AI 工具的出现,并没有消除这个限制,但它大幅降低了跨越边界的摩擦成本。一个后端工程师,借助 AI,可以在不深入学习前端框架的情况下,产出质量可接受的 React 组件;一个研发,借助 AI,可以在不成为产品专家的情况下,将模糊的用户反馈转化为结构化的需求文档。

这不是"万能",而是**“够用”**——在特定场景下,AI 能把一个人的能力从"不会"提升到"够用",从"够用"提升到"熟练"。这个提升,在某些场景下足以让一个人独立完成原本需要 2-3 人协作的工作。

但超级个体的真正价值,不在于"一个人干多个人的活",而在于减少协作中的信息损耗。当一个人能同时理解产品意图、技术实现和测试验收,他就不需要在三个角色之间反复传递信息、对齐理解——而这种对齐成本,往往是团队效率的最大杀手。

SDD 正是超级个体的工程基础设施:它提供了一套结构化的语言(Gherkin、OpenAPI、Spec),让一个人能够在不同抽象层次之间自如切换,同时保持各层之间的一致性。没有这套基础设施,超级个体只是"一个人同时做多件事";有了它,才是"一个人在统一的认知框架下驱动多个层次的工作"。

二、正确的使用姿势:AI 代替已解决的问题

在讨论具体的使用姿势之前,需要建立一个核心认知框架:

软件工程效果 = 模型能力(基础) × 上下文质量(决定性因素)

其中,上下文包含领域知识、编码规范、历史经验——这些知识需要显性化。构建上下文是 AI 软件工程的核心活动。

这个公式揭示了一个常被忽视的事实:模型能力只是基础,真正决定输出质量的是上下文的丰富度和准确性。没有准确上下文的 AI,就像一个拥有超高智商但缺乏领域知识的新手——能快速学习,但容易犯错。

基于上述认知,AI 的正确使用姿势变得清晰:

不是让 AI 代替自己,而是让 AI 代替那些已经被解决的、重复的、昂贵的问题。

更进一步,有一个更激进但也更务实的原则:

凡是 AI 已能稳定胜任的,原则上都应优先交由 AI 完成。

这不是对 AI 的盲目信任,而是对人机协作效率的理性计算。当 AI 能够稳定、一致地完成某项任务时,继续由人工介入只会引入不必要的延迟和人为错误。人类的精力应该集中在那些真正需要判断力、创造力和跨领域整合的工作上——而不是与 AI 争夺那些它已然擅长的领域。

这里有一个关键区分:

类型 特征 应该由谁处理
已解决的问题 有明确答案、可重复执行、规则清晰 AI
新问题 边界模糊、需要判断、涉及权衡

AI 的价值在于稳定、一致地输出——它不会因为疲劳而出错,不会因为情绪而走神。当 AI 稳定地处理已知领域,人就可以把精力投入到拓展工作场域上,去解决那些还没有答案的问题。

这是一种正向循环:AI 处理旧问题 → 人解决新问题 → 新问题被解决后成为旧问题 → AI 接管 → 人继续探索更新的问题。

三、Spec 的理论根基:TDD 家族

SDD 的"规范先行"思想,有一套完整的理论谱系支撑——TDD 家族。理解这个谱系,才能理解 SDD 为什么有效,以及如何在不同层次上落地。

TDD 家族的分层体系

这四个方法论并非互斥,而是在不同抽象层次上相互补充:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
用户行为层(ATDD)
↓ 验收测试驱动开发
↓ 三方协作:PM + 研发 + 测试
↓ 产出:用户故事的验收标准

系统行为层(BDD)
↓ 行为驱动开发(Dan North, 2003-2006)
↓ 引入 Gherkin DSL:Given-When-Then
↓ 产出:可执行的规范文档

代码单元层(UTDD)
↓ 单元测试驱动开发
↓ 方法/函数/类级别
↓ 产出:通过的单元测试

产物驱动:每层的输出是下一层的输入

这里有一个关键洞察,值得单独点出:TDD 家族的三层不只是"并列的方法论",而是一条产物驱动的流水线——每一层的输出文档,就是下一层的输入上下文。

这也是近两年不少 SDD 实践会采用的工作流:

1
2
3
4
5
6
7
8
ATDD 层(用户行为)
产物:用户故事 Gherkin(Given-When-Then 场景)
↓ 作为输入
BDD 层(系统行为)
产物:接口契约(OpenAPI)+ 各服务系统行为 Gherkin + 任务分配清单
↓ 作为输入
UTDD 层(代码单元)
产物:通过的单元测试 + 可编译运行的代码

为什么 ATDD 和 BDD 都产出 Gherkin?

细心的读者可能注意到:ATDD 层和 BDD 层都产出"Gherkin(Given-When-Then 场景)",这有什么区别?

关键区别在于视角和抽象层次:

层级 视角 Gherkin 描述的对象 主角是谁
ATDD 用户视角(黑盒) 用户与系统的交互行为 用户
BDD 系统视角(白盒) 系统内部各模块的协作行为 服务/模块

具体来说:

  • ATDD 层的 Gherkin(用户行为):描述的是用户故事,主角是"用户",关注的是"用户看到什么、做什么、得到什么"。PM 可以直接阅读并确认,不需要了解系统内部结构。

    1
    2
    3
    4
    5
    # ATDD 层:用户行为 Gherkin
    Scenario: 成功提交订单
    Given 用户已登录,购物车中有商品
    When 用户点击"提交订单"
    Then 用户应该看到订单号
  • BDD 层的 Gherkin(系统行为):描述的是服务间协作,主角是"服务/模块",关注的是"哪个服务做什么、服务间如何协作"。需要了解系统的技术架构才能编写。

    1
    2
    3
    4
    5
    # BDD 层:系统行为 Gherkin
    Scenario: 订单服务调用库存扣减
    Given 订单服务收到创建请求
    When 调用库存服务的 POST /inventory/deduct 接口
    Then 库存服务返回 200,库存数量减少

两者都使用 Gherkin 语法,但抽象层次不同——ATDD 是"黑盒视角"(用户不知道系统内部),BDD 是"白盒视角"(知道系统由哪些服务组成、如何协作)。这就是为什么它们需要分两个阶段、由不同角色的 Agent 来处理。


Augment Code 的研究将这一流程总结为五个阶段:Specify → Plan → Tasks → Implement → Debug,与上述三层有较强的对应关系。也有一些业界分析把 SDD 的重点概括为"将规划阶段(生成 spec)和实现阶段(生成代码)分离"——而分离的介质,就是这些层层传递的结构化文档。

这个机制的价值在于:每一层的产物都是对上一层意图的精确化和可验证化。用户故事 Gherkin 把模糊的 PRD 变成可确认的场景;系统行为 Gherkin 把单一的用户故事拆解为多个服务的职责边界;单元测试把系统行为变成可自动执行的验证。每一步都在减少歧义,每一步都在增加可验证性。

BDD 的核心创新在于:规范不仅是文档,还是可直接执行的测试。Gherkin 语法让 PM 能读懂、研发能执行、测试能自动化:

1
2
3
4
5
6
7
8
9
10
11
12
Feature: 用户下单

Scenario: 成功提交订单
Given 用户已登录,购物车中有可售商品
When 用户确认收货地址并点击"提交订单"
Then 订单应该创建成功,系统生成订单号
And 用户跳转到支付页面

Scenario: 库存不足无法下单
Given 用户购物车中商品库存为 0
When 用户尝试提交订单
Then 系统提示"库存不足,无法下单",订单不创建

这份 Gherkin 是 PM 与研发的共同契约:PM 可以直接阅读确认,研发以此为开发目标,测试将其转化为自动化用例。验收时,双方对着同一份文档检查,而不是各执一词。

四、企业级挑战:Spec 无法独立生成代码

理解了 TDD 家族之后,还需要面对一个现实:现有的 Spec 驱动工具(Spec-Kit、OpenSpec、Kiro 等)都有一个共同的隐含假设——

一个 Spec 对应一个应用。

但企业级开发的现实是:一个需求需要多个职责分明的应用协同完成。

以"用户下单后自动扣减库存"为例,这个看似简单的用户故事,实际上涉及一系列无法从 Spec 直接得出的决策:

问题 需要决策
谁负责扣减? 订单服务同步调用?库存服务异步处理?
失败怎么办? 重试?补偿?人工处理?
如何保证一致性? 分布式事务?最终一致性?
前端需要感知吗? 立即反馈?后台通知?

这些决策不是 Spec 能回答的,而是需要技术方案设计。这正是现有工具缺失的关键环节:

1
2
3
4
5
6
7
8
9
单体应用:  PRD → Spec → Code

企业级应用:PRD → Spec(用户行为)

技术方案设计(判断归属 + 定义协作)

Spec(系统行为)× N 个应用

Code × N 个应用

存量知识:proposal 质量的天花板

在理解了"一个需求需要多个应用协同"这个挑战之后,还有一个更深层的问题值得正视:即使有了完整的 Spec 驱动流程,生成的 proposal 质量仍然受制于一个先决条件——知识库里的存量有多准确。

这里的"知识库"不局限于某种特定形式,可以是 project.mdAGENTS.mdservice-catalog.yaml,也可以是 specs/ 目录下的历史规范——凡是 AI 在生成 proposal 之前会读取的上下文,都属于存量知识。

存量知识的作用链条是这样的:

1
2
3
4
5
存量知识(系统现状)
↓ 与 PRD 需求对齐
proposal(变更方案)
↓ 驱动实现
Code

存量设计的偏差会在这条链条上逐级放大。如果 service-catalog.yaml 里记录的库存服务能力已经过时,AI 生成的 proposal 就会基于错误的前提做出功能归属判断;如果 specs/ 里的历史规范与代码实际行为不符,AI 生成的接口契约就会与现实脱节。这不是 AI 的问题,而是 GIGO(Garbage In, Garbage Out)在 AI 工程中的具体表现。

这个认知带来一个实践结论:在大规模工程开始之前,维护准确的存量知识,比优化 prompt 更重要。 存量知识是 proposal 质量的天花板——天花板不够高,再好的 AI 也只能在低处徘徊。

五、分层 Agent 架构:按工程流程拆分 SDD

解决上述矛盾的方案,是按 TDD 家族的层级关系拆分 Spec 驱动流程,每一层由专门的 Agent 负责。

三层 Agent 模型

flowchart TB
    subgraph L1["🔍 PRD 分析 Agent(ATDD 层)"]
        A1["输入:PRD 需求文档"]
        A2["输出:用户行为 Gherkin(PM 可读可确认)"]
        A3["价值:PM ↔ 研发的协作契约"]
        A1 --> A2 --> A3
    end

    subgraph L2["🏗️ 技术方案设计 Agent(BDD + UTDD 层)"]
        B1["输入:用户行为 Gherkin"]
        B2["输出:接口契约 + 各应用系统行为 Gherkin + 任务分配清单"]
        B3["价值:研发 ↔ 研发的协作规范"]
        B1 --> B2 --> B3
    end

    subgraph L3["⚙️ 代码开发 Agent(执行层)"]
        C1["输入:系统行为 Gherkin + 接口契约"]
        C2["输出:可编译运行的代码 + 通过的单元测试"]
        C3["模式:TDD 红绿重构循环,逐场景执行"]
        C1 --> C2 --> C3
    end

    L1 -->|"用户行为 Gherkin"| L2
    L2 -->|"系统行为 Gherkin + 接口契约"| L3

    style L1 fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style L2 fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style L3 fill:#fff3e0,stroke:#ff9800,stroke-width:2px

关键洞察:Agent 不只是"代码生成器",更是"协作规范生成器"。分层架构的核心价值,是让团队在开发前就对齐预期,而不是在联调时才发现问题。

协作成本的前置解决

协作关系 问题根源 分层 Agent 的解决方案
PM ↔ 研发 需求理解不一致 PRD 分析 Agent 生成 Gherkin,双方共同确认
前端 ↔ 后端 接口定义不一致 技术方案 Agent 生成接口契约,开发前对齐
后端 ↔ 后端 服务协作不明确 技术方案 Agent 定义服务间协作规范

与其在联调时发现问题并返工,不如在开发前就通过 Spec 对齐预期。

端到端工程实践:从阶段到接口

理解了三层 Agent 模型之后,还需要一套具体的工程实践来支撑落地。以下是一个前后端端到端交付项目的完整工程流程。

四阶段交付流程

一个完整的端到端项目,通常经历四个阶段:

阶段 输入 产出 方式
阶段一:需求分析 PRD + 历史需求 结构化需求文档 AI 做结构化分析 → 人工确认修正
阶段二:UI 设计 需求文档 UI 原型 AI 生成 → Iteration 反馈迭代
阶段三:详细设计 需求 + UI 稿 接口契约 + 领域模型 + 数据模型 AI 生成 → 人工评审关键决策
阶段四:代码生成(ATDD 驱动) 设计文档 + 参考代码 可运行代码 + 测试用例 先测试(红灯)→ 代码(绿灯)

这四个阶段与三层 Agent 架构高度对应:需求分析对应 PRD 分析 Agent,详细设计对应技术方案设计 Agent,代码生成对应代码开发 Agent。UI 设计作为前端专属阶段,在详细设计之前完成,为接口契约提供前端视角的输入。

小步快跑:接口级迭代循环

在代码生成阶段,坚持小步快跑的节奏——每一轮只实现一个接口,完成后才进入下一轮:

flowchart LR
    START(["🚀 开始新接口"]) --> IMPL
    IMPL["⚙️ 实现接口\n(含单元测试)"] --> TEST
    TEST["🧪 测试验证\nRalph Loop 通过"] --> REVIEW
    REVIEW["👀 Code Review\n人工审查"] --> CONFIRM
    CONFIRM{"✅ 确认通过?"}
    CONFIRM -->|"是"| NEXT["➡️ 进入下一个接口"]
    CONFIRM -->|"否"| FIX["🔧 修复问题"]
    FIX --> TEST

    style START fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style IMPL fill:#e3f2fd,stroke:#2196f3
    style TEST fill:#e3f2fd,stroke:#2196f3
    style REVIEW fill:#fff3e0,stroke:#ff9800
    style CONFIRM fill:#f3e5f5,stroke:#9c27b0
    style NEXT fill:#e8f5e9,stroke:#4caf50
    style FIX fill:#fce4ec,stroke:#e91e63

为什么要小步快跑? 每个接口都是一个可验证的交付单元。接口粒度的迭代让问题暴露得更早、修复成本更低,同时也让 Review 的认知负担保持在可控范围内——审查一个接口的实现,远比审查一个功能模块的全量代码更容易发现问题。

测试八问:接口级质量门禁

每个接口开发时,遵循测试八问作为质量门禁——这八个问题覆盖了接口可能遇到的所有典型场景,确保测试覆盖不留盲区:

# 问题 必须有测试覆盖
1 正常路径是否可走通? 创建成功、查询有数据
2 必填参数缺失会如何? 返回参数错误
3 参数格式错误会如何? 类型不匹配、超长、负数
4 关联数据不存在会如何? 父资源不存在时的处理
5 重复操作会如何? 幂等性验证
6 边界值会如何? 0、-1、空、最大值
7 状态流转是否正确? 非法状态转换拒绝
8 并发操作会如何? 同时操作不冲突

测试八问与 Ralph Loop 形成互补:Ralph Loop 保证"测试通过才算完成",测试八问保证"测试本身是有意义的"。没有测试八问的约束,AI 可能生成只覆盖正常路径的测试,让 Ralph Loop 在一个不完整的测试集上通过——这是一种更隐蔽的"偷懒"。

领域驱动分工与外部记忆

在团队协作层面,由领域资深工程师牵头,按以下顺序组织工作:

1
2
3
4
5
6
7
划分领域(Domain)

拆分模块(Module)

分层实现(Layer)

纵横切分任务(Task Decomposition)

纵横切分的含义:

  • 纵切:按业务功能切分(订单、库存、支付各自独立)
  • 横切:按技术层次切分(接口层、服务层、数据层分别实现)

两个维度的切分共同作用,确保每个 Agent 的单次任务粒度足够小,避免上下文过载——这是 AI 协作中最常见的失败模式之一。

基于文件的外部记忆是应对上下文限制的关键机制。在工作过程中,将关键决策、进度状态、接口契约持久化到文件系统,而不是依赖对话上下文:

场景 外部记忆的价值
快速恢复上下文 新开一个 Agent 会话时,读取文件即可还原工作状态
多人协作 不同开发者的 Agent 通过共享文件同步进度,避免重复工作
上下文超限 即使对话历史被截断,关键信息仍保存在文件中,不丢失

这正是本章目录约定的深层价值:.specs/ 目录不只是"规范存放处",更是团队协作的外部记忆载体——每个 Agent 的输出都写入文件,每个 Agent 的输入都从文件读取,上下文通过文件而非对话历史传递。


落地:数据流与目录约定

三层 Agent 之间通过约定好的目录结构传递数据,无需额外的编排层:

1
2
3
4
5
6
7
8
项目根目录/
├── .specs/ # Spec 数据流转
│ ├── prd/ # 输入:PRD 文档
│ ├── user-behavior/ # 第一层输出:用户行为 Gherkin
│ ├── system-behavior/ # 第二层输出:系统行为 Gherkin
│ │ └── contracts/ # 接口契约(OpenAPI 格式)
│ └── service-catalog.yaml # 服务目录(多系统环境定义)
└── src/ # 第三层输出:代码

其中,服务目录是技术方案设计 Agent 的核心依赖——它描述了当前环境有哪些服务可用,以及每个服务的能力边界,Agent 据此做出功能归属判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# .specs/service-catalog.yaml
services:
- name: order-service
description: 订单服务,负责订单创建、状态管理
capabilities:
- 订单创建
- 订单查询
- 订单状态变更

- name: inventory-service
description: 库存服务,负责库存管理
capabilities:
- 库存查询
- 库存扣减
- 库存预占

这个约定的价值在于:Agent 之间通过文件系统解耦,每个 Agent 只需读取上一层的输出文件,写入自己的输出文件,无需了解其他 Agent 的内部实现。

工具链落地:OpenSpec 完整实操指南

理解了目录约定之后,一个自然的问题是:这些 Spec 文件由谁来管理?格式是否有要求?能否借助工具自动生成?

OpenSpec 可以看作这类规范管理工具中的一个轻量实现。它的核心理念与本文的 SDD 思想相当接近:在写代码之前,先让人类与 AI 就规范达成共识(align before code)

OpenSpec 是一个轻量级的 SDD 工具链,通过标准化的目录结构和 CLI 命令,让开发者在写代码之前先与 AI 就需求规范达成共识。它解决了 AI 辅助编程中的三个核心问题:如何让 AI 理解项目上下文、如何规范需求描述格式、如何沉淀已实现的功能知识。OpenSpec 的核心机制包括项目知识库(project.md)、变更提案(proposal.md)、需求规范(spec.md)和实现任务清单(tasks.md),通过 initnewapplyarchive 四个核心命令,实现了从需求到代码的完整闭环。

更详细的实战教程:如果你希望了解 OpenSpec 的完整实操步骤(包括安装、初始化、核心概念详解、目录结构详解、完整工作流程等),请参考独立文章 OpenSpec 实战教程:从入门到精通,那里包含了从零开始使用 OpenSpec 的完整示例和最佳实践。

工具机制选择:Skills vs Slash Commands vs MCP vs Hooks

在构建 SDD 工作流时,一个关键问题是:生成脚手架、单元测试、集成测试、Mock、实现记忆等任务,应该使用哪种工具机制来实现?

这涉及 AI 编程工具生态中的四种核心机制:

机制 触发方式 典型用途 特点
Skills 自动激活(基于描述匹配) 领域知识注入、工作流自动化 上下文感知,零摩擦触发
Slash Commands 手动调用 可重复工作流、参数化任务 显式控制,适合标准化流程
MCP 外部服务集成 数据库、API、文件系统访问 突破沙箱,连接真实世界
Hooks 事件驱动 质量门禁、自动化检查 在特定时机自动执行,不可绕过

核心决策框架

选择哪种机制,取决于三个维度:

  1. 触发模式:自动触发(Skills/Hooks)vs 手动触发(Slash Commands)
  2. 上下文需求:需要丰富上下文(Skills)vs 需要外部资源(MCP)
  3. 执行确定性:概率性输出(Skills 调用 LLM)vs 确定性执行(MCP/脚本)
flowchart TB
    Q1{"需要自动触发?"}
    Q2{"需要外部资源?<br/>(数据库/API/文件系统)"}
    Q3{"需要概率性推理?<br/>(创意/判断/模糊匹配)"}
    Q4{"需要在特定时机强制执行?"}

    Q1 -->|"是"| Q3
    Q1 -->|"否"| Q2

    Q3 -->|"是"| SKILL["🎯 <b>Skills</b><br/>自动激活 + LLM 推理"]
    Q3 -->|"否"| Q4

    Q4 -->|"是"| HOOK["🔒 <b>Hooks</b><br/>事件驱动 + 强制执行"]
    Q4 -->|"否"| SCRIPT["⚙️ <b>确定性脚本</b><br/>自动触发 + 精确执行"]

    Q2 -->|"是"| MCP["🔌 <b>MCP</b><br/>外部服务集成"]
    Q2 -->|"否"| SLASH["📝 <b>Slash Commands</b><br/>手动触发 + 可重复工作流"]

    style SKILL fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style MCP fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style SLASH fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style HOOK fill:#fce4ec,stroke:#e91e63,stroke-width:2px
    style SCRIPT fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px

六项任务的具体分析

1. 生成脚手架 → Slash Command

  • 理由:脚手架生成是显式触发的任务,需要用户指定项目名称、模板类型等参数,属于"可重复工作流"
  • 实现/scaffold <template> <project-name>,支持参数化配置
  • 为什么不选 Skill:脚手架生成不需要自动触发,用户明确知道何时需要创建新项目

2. 生成单元测试 → Skill

  • 理由:单元测试生成是 TDD 工作流的自然组成部分,应该在检测到新代码或代码变更时自动激活
  • 实现:Skill 描述包含"检测到新增函数/类时,自动生成对应的单元测试框架"
  • 为什么不选 Slash Command:测试驱动开发的核心是"测试先行"或"测试同步",不应该要求用户手动触发

3. 生成集成测试 → Skill + MCP

  • 理由:集成测试需要了解服务间依赖关系,可能需要访问服务目录、API 定义等外部资源
  • 实现:Skill 负责推理"测试什么、如何测试",MCP 负责获取服务目录和接口定义
  • 协作模式:Skill 调用 MCP 工具获取上下文,再基于上下文生成测试

4. 生成 Mock → Skill + 确定性脚本

  • 理由:Mock 生成分为两个阶段:决策(哪些接口需要 Mock、返回什么数据)和执行(生成 Mock 文件)
  • 实现:Skill 负责决策(概率性推理),脚本负责生成 Mock 文件(确定性执行)
  • 原则:遵循"概率与确定性分离"原则——LLM 决定"What",脚本执行"How"

5. 实现记忆 → CLAUDE.md + PKB Skill

  • 理由:记忆分为两类:持久化规范(存放在 CLAUDE.md/AGENTS.md)和动态知识(通过 PKB Skill 管理)
  • 实现
    • CLAUDE.md:项目级规范,如编码风格、架构决策(极低频变更)
    • PKB Skill:管理个人/团队级的品味、规范、规则,支持冷热分层和自动归档
  • 协作模式CLAUDE.md 提供静态上下文,PKB Skill 提供动态知识注入

6. 特定代码生成 → 视情况而定

  • 模板化代码(CRUD、DTO):确定性脚本,效率优先
  • 业务逻辑代码:Skill,需要领域知识注入
  • 涉及外部 API 的代码:Skill + MCP,需要获取 API 定义

SDD 工作流的 Skill 化架构

将上述决策应用到三层 Agent 架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PRD 分析 Agent
├── Skill: prd-analysis(自动激活)
│ ├── 领域模型注入
│ └── Gherkin 模板约束
└── 输出:用户行为 Gherkin

技术方案设计 Agent
├── Skill: technical-design(自动激活)
│ ├── 架构模式注入
│ └── 服务目录读取(MCP)
├── Slash Command: /scaffold(手动触发)
│ └── 生成新服务脚手架
└── 输出:系统行为 Gherkin + 接口契约

代码开发 Agent
├── Skill: test-generator(自动激活)
│ └── 单元测试生成
├── Skill: mock-generator(自动激活)
│ └── Mock 决策 + 脚本执行
├── Hook: write-time-lint(强制执行)
│ └── 代码写入前的质量门禁
└── 输出:通过测试的可运行代码

理论支撑:近两年的常见实践

这一决策框架,与近两年 AI 编程工具社区里常见的分工思路大体一致:

  • Anthropic 官方文档:Skills 用于"上下文增强和自动触发",MCP 用于"外部服务集成",两者互补而非替代
  • Claude Code 最佳实践:Write-Time Hooks(如 plankton)证明"强制执行"比"事后检查"更有效
  • Cursor 社区:Slash Commands 适合"可重复的复杂工作流",Skills 适合"零摩擦的自动化"

核心洞察:机制选择不是"非此即彼",而是"各司其职"。正确的做法是:

  • 让 Skills 处理"什么时候该做什么"(自动感知)
  • 让 Slash Commands 处理"用户明确要求的重复任务"(显式控制)
  • 让 MCP 处理"需要外部资源"(连接真实世界)
  • 让 Hooks 处理"强制执行的质量门禁"(不可绕过)

代码开发层:Ralph Loop 防偷懒机制

我们正在进入这样一个时代:10 倍开发者(10x Developer)的核心技能不再是解决复杂 Bug 的能力,而是设计自动化测试体系与反馈循环的能力——这些机制能让模型的十六个并行实例替他们解决问题。

代码开发 Agent 面临一个特殊挑战:AI 模型在 TDD 场景下容易"偷懒"——声称"测试已通过"但实际没运行,或跳过 Red 阶段直接写实现。

解决方案是引入 Ralph Loop(由 Geoffrey Huntley 提出)——一种自主迭代机制:

1
2
3
4
5
while 未满足完成条件:
执行编译检查(mvn compile)
执行测试(mvn test)
如果任何检查失败 → 继续修复
如果全部通过 → 退出循环
flowchart TD
    START(["🚀 开始:Agent 接收场景任务"]) --> COMPILE

    COMPILE["⚙️ 执行编译检查\nmvn compile"]
    COMPILE -->|"编译失败 ❌"| FIX_COMPILE["🔧 修复编译错误"]
    FIX_COMPILE --> COMPILE

    COMPILE -->|"编译通过 ✅"| TEST

    TEST["🧪 执行单元测试\nmvn test"]
    TEST -->|"测试失败 ❌"| FIX_TEST["🔧 修复实现代码"]
    FIX_TEST --> COMPILE

    TEST -->|"测试通过 ✅"| LINT

    LINT["📋 代码规范检查\ncheckstyle / spotbugs"]
    LINT -->|"规范不符 ❌"| FIX_LINT["🔧 修复代码风格"]
    FIX_LINT --> COMPILE

    LINT -->|"规范通过 ✅"| DONE

    DONE(["✅ 完成:所有检查通过\nAgent 声明本场景完成"])

    style START fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style DONE fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style COMPILE fill:#e3f2fd,stroke:#2196f3
    style TEST fill:#e3f2fd,stroke:#2196f3
    style LINT fill:#e3f2fd,stroke:#2196f3
    style FIX_COMPILE fill:#fff3e0,stroke:#ff9800
    style FIX_TEST fill:#fff3e0,stroke:#ff9800
    style FIX_LINT fill:#fff3e0,stroke:#ff9800

关键在于 Backpressure(反压)机制:用编译结果和测试结果验证 AI 的输出,防止自欺欺人。只有当所有检查都通过时,Agent 才能声明完成。

验证手段 作用
编译检查 语法正确性
单元测试 逻辑正确性
代码规范检查 代码质量
类型检查 契约一致性

这套机制的本质,是把"完成"的定义权从 AI 手中夺回来,交给客观的验证标准。

从源头约束:Shift Left 与 Write-Time Quality Gates

Ralph Loop 解决的是"生成后验证"的问题,但在 SDD 的多步骤流水线中,一个更深层的挑战是:迭代后半程的输出量太大,Code Review 压力过重。几百行 Spec 可能产生几千行代码,问题发现越晚,修复成本越高。

这个问题的解决思路是 Shift Left(左移)——将质量约束从 Review 阶段前移到代码生成阶段,甚至生成之前。

Plan/Spec Mode:生成前的意图对齐

Claude Code 的 Plan Mode(Shift+Tab 切换)提供了一个非破坏性的规划阶段:

  • 只读探索:Plan Mode 下禁止写入文件,AI 只能读取代码、分析依赖、输出规划
  • 意图显式化:人类确认规划无误后,再进入执行阶段
  • 避免返工:在生成代码前对齐预期,而不是在 Review 时发现问题

OpenAI Codex 团队也在探索类似能力(GitHub Discussion #7355),核心设计问题是:模态 vs 非模态、持久化 vs 临时、访谈式 vs 自由形式。社区反馈强烈倾向于硬模态切换——明确的 Plan Mode 能提供安全感和可预测性。

Write-Time Quality Gates:写入时强制检查

plankton 项目(GitHub: alexfazio/plankton)将 Shift Left 推向极致:

“Code quality gate enforcement at write-time — The agent is blocked from proceeding until its output passes your checks”

其核心是 Claude Code Hooks 的三阶段流水线:

1
2
3
4
5
6
7
8
9
10
11
12
13
文件编辑触发

Phase 1: Auto-format(自动格式化)
- ruff, shfmt, biome, taplo — 静默修复风格问题

Phase 2: Violation Collection(违规收集)
- 20+ linters 输出结构化 JSON

Phase 3: AI Fix(智能修复)
- 专用 Claude 子进程推理修复剩余问题

全部通过 → 允许写入
任何失败 → 阻塞并重试

关键机制

  • PreToolUse Hook:在工具调用前拦截,阻止不符合规范的代码写入磁盘
  • Config Tamper-Proof:禁止 AI 修改 lint 配置来绕过检查
  • Model Routing:简单问题用小模型,复杂问题用大模型,节省 Token

这套机制的价值在于行为塑造——AI 在生成代码时就知道约束存在,会主动避免违规,而不是生成后再被动修复。

分层 Agent 中的约束映射

将 Shift Left 思想应用到三层 Agent 架构:

层级 约束目标 机制
PRD 分析 Agent Gherkin 完整性 Skill 约束:必须使用 Given-When-Then,覆盖正常+异常路径
技术方案 Agent 架构合理性 Skill 约束:明确服务边界、幂等性、失败策略
代码开发 Agent 代码质量 Write-Time Gates:编译检查 → 静态分析 → 单元测试

核心洞察:约束不是限制 AI 的能力,而是将人类的工程经验编码为可执行的质量门禁。与其在 Review 时反复指出同类问题,不如让 Skill 在生成时就避免这些问题。

这与 Ralph Loop 形成互补:

  • Ralph Loop:生成后验证,确保输出正确
  • Shift Left + Write-Time Gates:生成前/生成中约束,减少错误产生

两者结合,才能从根本上缓解 SDD 流水线后半程的 Review 压力。

六、上下文管理:Skills 渐进披露机制

分层 Agent 架构还需要解决一个技术层面的根本限制:LLM 的上下文窗口是有限的

当 Agent 拥有大量 Skill(技能)时,会遇到一个矛盾:

  • Skill 越多,Agent 能力越强
  • 但把所有 Skill 的完整内容都加载进上下文,Token 消耗巨大,且注意力会被稀释(无关信息越多,模型对关键指令的遵循能力越弱)

这就是上下文拥挤问题(Context Crowding)

解决方案:声明层 + 实现层的分离

聪明的做法是将 Agent 的能力库分为声明层实现层,通过多趟调度实现按需加载:

这里还有一个更深层的协作原则值得强调:

对话优于僵硬指令,协作上下文优于单纯追求更强模型。Spec 的正确性,会直接影响项目成败。

这意味着:

  • 对话优于指令:与其给 AI 一长串静态指令,不如通过多轮对话逐步澄清意图、修正理解。对话是动态的、可迭代的,能够暴露假设、消除歧义。
  • 上下文优于模型:与其一味追求更强大的模型,不如投入在更精确的协作上下文(Spec)上。一个准确的 Spec 能让普通模型表现出色,而一个错误的 Spec 即使交给更强模型,也可能南辕北辙。

Spec 的正确性是项目的质量天花板——天花板不够高,再好的 AI 也只能在低处徘徊。

flowchart TB
    L0["🗂️ <b>Level 0: 语义注册表</b><br/>Skill 名称 + 简短描述 + 参数 Schema<br/>Token 消耗:极低 | LLM 角色:Router"]
    L1["📖 <b>Level 1: 渐进式加载器</b><br/>按需加载选中 Skill 的完整 Prompt/文档<br/>Token 消耗:中等 | LLM 角色:Planner"]
    L2A["🤖 <b>Level 2A: LLM 生成</b><br/>非结构化、创意任务<br/>概率性输出"]
    L2B["⚙️ <b>Level 2B: 确定性脚本</b><br/>结构化、逻辑严密任务<br/>精确执行,零概率误差"]

    L0 -->|"路由选择"| L1
    L1 -->|"执行决策"| L2A
    L1 -->|"执行决策"| L2B

    style L0 fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px
    style L1 fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style L2A fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style L2B fill:#fff3e0,stroke:#ff9800,stroke-width:2px

关键洞察:LLM 不需要知道所有 Skill 的细节,只需要知道"有哪些 Skill 可用"(注册表)。一旦选定 Skill,再加载细节。这就像操作系统的动态链接库——程序启动时不加载所有库,只在调用时才链接。

在实践中,Skills 使用标准化的目录结构组织业务知识:

1
2
3
4
5
6
7
8
9
10
11
.claude/skills/
├── prd-analysis/ # PRD 分析 Agent 的领域知识
│ ├── SKILL.md # 技能描述(入口,极低 Token)
│ ├── domain-model.md # 领域模型(按需加载)
│ └── gherkin-examples.md
├── technical-design/ # 技术方案设计 Agent 的领域知识
│ ├── SKILL.md
│ ├── architecture-patterns.md
│ └── service-catalog.md
└── shared/
└── business-rules.md # 共享业务规则

这套机制的核心思想:不是一次性加载所有背景,而是按需分批加载。就像程序员需要时查阅文档,而不是先背诵所有文档一样。

为什么要引入确定性脚本(Script)?

这是架构中最精妙的一层。LLM 是概率模型,它的输出本质上是"最可能正确的答案",而不是"一定正确的答案"。对于精确计算、严格的格式转换、数据库查询、文件系统操作,让 LLM 去"模拟"这些操作,既昂贵又不可靠。

正确的做法是:LLM 决定调用哪个脚本,脚本负责精确执行

维度 LLM 确定性脚本
擅长 意图理解、模糊处理、创意生成 精确计算、严格逻辑、一致输出
不擅长 精确计算、完全一致的重复输出 理解自然语言、处理歧义

LLM 是指挥官,Script 是工兵。不要让指挥官去挖战壕,也不要让工兵去制定战略。

七、三大设计原则

阅读说明:本章的三条原则聚焦于 Agent 架构设计层面——如何构建高效的 AI Agent 系统(上下文管理、概率与确定性分离、规范先行)。第九章的五条原则则聚焦于 SDD 工程实践层面——如何在团队中落地规范驱动开发(规范先行、分阶段验证、规范即上下文、警惕 Spec 瀑布、Bug 是 Spec 缺口)。两套原则视角不同、互为补充,共同构成 AI 时代人机协作的完整工程哲学。

从上述架构模式中,可以提炼出构建高效 AI Agent 的三条设计原则。

graph LR
    P1["🎯 原则一<br/><b>上下文最小化</b><br/>Minimal Context Exposure<br/>摘要·索引·注册表作为入口<br/>细节按需披露"]
    P2["⚖️ 原则二<br/><b>概率与确定性分离</b><br/>Probabilistic vs Deterministic<br/>LLM 负责意图与变化<br/>Script 负责精确与可靠"]
    P3["📋 原则三<br/><b>规范先行</b><br/>Specification First<br/>Human 定义 What & Why<br/>AI 处理 How"]

    P1 -->|"降低 Token 消耗<br/>提升注意力集中度"| P2
    P2 -->|"LLM 调用 Script<br/>Function Call 机制"| P3
    P3 -->|"规范驱动上下文<br/>最小化加载"| P1

    style P1 fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style P2 fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style P3 fill:#fff3e0,stroke:#ff9800,stroke-width:2px

原则一:上下文最小化(Minimal Context Exposure)

“The model should only know what it needs to know to make the next immediate decision.”

永远不要把所有知识一次性灌输给 LLM。上下文是稀缺资源,过多的无关信息会产生两个副作用:

  1. Token 浪费:直接的成本问题
  2. 注意力稀释(Attention Dilution):LLM 的注意力机制会被无关内容分散,导致对核心指令的遵循能力下降

实践:使用摘要(Summary)、索引(Index)和注册表(Registry)作为入口,细节按需披露。

原则二:概率与确定性分离(Separation of Probabilistic and Deterministic Logic)

“Use LLMs for intent and variability; use Scripts for precision and reliability.”

实践:通过 Function Call(工具调用)机制实现——LLM 输出结构化的调用意图,运行时将其路由到对应的确定性代码。

原则三:规范先行(Specification First)

“Humans define the ‘What’ and ‘Why’; AI handles the ‘How’.”

这是对整篇文章人机协作哲学的技术化表达:

  • Human:定义接口(Interface)、约束(Constraints)、验收标准(Acceptance Criteria)
  • AI:填充实现细节(Implementation)

人类从"写代码(Coding)"升级为"设计系统(System Designing)“和"审查(Reviewing)”。这不是降低了人的价值,而是提升了人工作的抽象层次,让人能够统摄更大的系统复杂度。

八、完整案例演练:用户下单功能

理念最终要落地。以"用户下单"这个经典场景为例,走一遍三层 Agent 的完整流程。

flowchart LR
    subgraph Input["📄 输入"]
        PRD["PRD 需求文档\n用户下单功能"]
    end

    subgraph Step1["🔍 Step 1: PRD 分析 Agent"]
        G1["生成用户行为 Gherkin\n成功下单 / 库存不足场景"]
        PM["✅ PM 确认契约"]
        G1 --> PM
    end

    subgraph Step2["🏗️ Step 2: 技术方案设计 Agent"]
        SC["读取服务目录\norder-service / inventory-service"]
        SG["生成系统行为 Gherkin\n× 各服务职责边界"]
        TA["输出任务分配清单\n开发顺序建议"]
        SC --> SG --> TA
    end

    subgraph Step3["⚙️ Step 3: 代码开发 Agent"]
        RED["🔴 RED\n写失败测试"]
        GREEN["🟢 GREEN\n最小实现通过"]
        NEXT["➡️ 下一场景"]
        RED --> GREEN --> NEXT --> RED
    end

    subgraph Output["✅ 输出"]
        CODE["可编译代码\n+ 通过的单元测试"]
    end

    PRD --> G1
    PM -->|"用户行为 Gherkin"| SC
    TA -->|"系统行为 Gherkin\n+ 接口契约"| RED
    NEXT -->|"所有场景完成"| CODE

    style Input fill:#f5f5f5,stroke:#9e9e9e
    style Step1 fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style Step2 fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style Step3 fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style Output fill:#fce4ec,stroke:#e91e63,stroke-width:2px

Step 1:PRD 分析 Agent → 用户行为 Gherkin

输入.specs/prd/user-order.md):

1
2
3
4
5
6
7
8
## 功能描述
1. 用户可以将商品加入购物车
2. 用户可以提交订单
3. 下单成功后库存自动扣减

## 业务规则
- 下单时检查库存,库存不足则拒绝
- 订单创建成功后生成唯一订单号

输出.specs/user-behavior/user-order.feature):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@用户行为 @ATDD
Feature: 用户下单
作为一个已登录用户
我想要能够提交订单
以便购买我选中的商品

Background:
Given 用户已登录

Scenario: 成功提交订单
Given 购物车中有以下商品
| SKU | 名称 | 数量 |
| PHONE-001 | 智能手机 | 1 |
And 商品库存充足
When 用户提交订单
Then 订单应该创建成功
And 用户应该看到订单号
And 库存应该扣减相应数量

Scenario: 库存不足无法下单
Given 购物车中有商品 "PHONE-001" 数量 10
And 商品 "PHONE-001" 库存只有 3
When 用户提交订单
Then 应该提示"库存不足,当前库存: 3"
And 订单不应该创建

这份 Gherkin 是 PM 与研发的共同契约,PM 可以直接阅读确认,无需理解任何技术细节。

Step 2:技术方案设计 Agent → 系统行为 + 接口契约

Agent 读取服务目录,分析每个场景涉及的能力点,匹配到对应服务,然后输出:

功能归属判断

用户行为步骤 匹配能力 归属服务
“用户提交订单” 订单创建 order-service
“库存应该扣减” 库存扣减 inventory-service
“用户应该看到订单号” 用户界面展示 frontend-app

输出:订单服务系统行为.specs/system-behavior/order-service.feature):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@系统行为 @BDD @订单服务
Feature: 订单服务

Scenario: 成功创建订单
Given 收到创建订单请求,包含有效的用户 ID 和商品列表
When 调用库存服务扣减接口
And 库存服务返回成功
Then 创建订单记录,状态为 "CREATED"
And 返回 201 和订单详情

Scenario: 库存不足创建失败
Given 收到创建订单请求
When 调用库存服务扣减接口
And 库存服务返回库存不足
Then 不创建订单记录
And 返回 409 和错误信息

输出:任务分配清单.specs/system-behavior/task-assignment.md):

服务 任务 依赖
库存服务 实现 POST /inventory/deduct
订单服务 实现 POST /orders 库存服务接口
前端 实现下单页面 订单服务接口

开发顺序建议:库存服务(无依赖)→ 订单服务 → 前端。

Step 3:代码开发 Agent → TDD 实现

Agent 按 Red-Green-Refactor 循环逐场景实现,Ralph Loop 在后台持续验证:

Round 1 - RED:先写失败的测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
void should_create_order_when_stock_sufficient() {
// Given
CreateOrderRequest request = CreateOrderRequest.builder()
.userId("user_123")
.items(List.of(new OrderItem("PHONE-001", 1)))
.build();
when(inventoryClient.deduct(any())).thenReturn(DeductResponse.success());

// When
OrderResult result = orderService.createOrder(request);

// Then
assertThat(result.isSuccess()).isTrue();
assertThat(result.getOrder().getStatus()).isEqualTo("CREATED");
verify(orderRepository).save(any(Order.class));
}

运行测试 → 编译失败,OrderService 不存在 ❌

Round 2 - GREEN:写最小实现,测试通过 ✅

Round 3:继续下一个场景,直到所有 Gherkin 场景都有对应的通过测试。

flowchart LR
    subgraph TDD["🔄 TDD Red-Green-Refactor 循环"]
        RED["🔴 RED\n先写失败的测试\n编译失败 / 断言失败"]
        GREEN["🟢 GREEN\n写最小实现\n让测试通过"]
        REFACTOR["🔵 REFACTOR\n重构代码\n保持测试通过"]

        RED -->|"实现代码"| GREEN
        GREEN -->|"优化结构"| REFACTOR
        REFACTOR -->|"下一个场景"| RED
    end

    subgraph RALPH["🔁 Ralph Loop 外层保障"]
        CHECK["编译 + 测试 + 规范检查\n全部通过才能退出"]
    end

    REFACTOR -->|"场景完成,进入验证"| CHECK
    CHECK -->|"有失败 → 回到修复"| GREEN
    CHECK -->|"全部通过 ✅"| NEXT["➡️ 下一个 Gherkin 场景"]
    NEXT --> RED

    style RED fill:#ffebee,stroke:#f44336,stroke-width:2px
    style GREEN fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style REFACTOR fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style CHECK fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style NEXT fill:#f3e5f5,stroke:#9c27b0

整个过程中,Ralph Loop 持续运行编译和测试检查。只有当所有检查都通过时,Agent 才能退出循环,声明完成。

案例小结

这个案例展示了三层 Agent 的核心价值:

  • PRD 分析 Agent:把模糊的需求文档转化为 PM 和研发都能确认的 Gherkin 契约
  • 技术方案设计 Agent:把单一的用户故事拆解为多个服务的职责边界和协作规范
  • 代码开发 Agent:在 Ralph Loop 的约束下,确保每一行代码都有对应的测试覆盖

三层之间通过文件系统传递数据,每一层的输出都是下一层的输入,形成一条从 PRD 到代码的完整流水线。

九、SDD 的五项核心原则

如果说第七章讨论的是 Agent 架构怎么设计,那么这里要收束的是 SDD 在工程实践中如何落地。下面五条原则更偏交付、协作与质量控制,而不是再重复一次前面的架构讨论。

原则一:规范先行,而非文档补写

"先定义预期,再实现代码"——不是写完代码后的文档补充,而是驱动实现的前置契约。

传统软件开发中,文档往往扮演着"事后说明"的角色:代码写完后,再补一份设计文档或接口说明。这种模式下,文档与代码脱节是常态,"文档过时"成为永恒的抱怨。

SDD 彻底反转这一顺序:

传统模式 SDD 模式
Code → Document → 维护时文档已过时 Spec → Code → Spec 即验收标准
验收时各执一词 双方对着同一份 Gherkin 确认
接口变更靠口头同步 接口契约变更需更新 Spec

规范先行的本质,是将"意图"从隐性的对话历史中提取出来,固化为可验证、可传递的结构化知识。 这正是 OpenSpec 工作流中 proposal.mdtasks.mdspec.md 的核心价值——在写第一行代码之前,人类与 AI 必须先就"要做什么"达成共识。

原则二:分阶段验证,拒绝模糊推进

每一层都有明确的完成标准和验证机制,拒绝"差不多行了"的模糊推进。

Vibe Coding 的最大风险在于进度幻觉——AI 声称"完成了",但实际上只是输出了看起来合理的代码,并未经过客观验证。SDD 通过分层验证机制解决这一问题:

1
2
3
4
5
6
7
PRD 分析层:Gherkin 是否覆盖所有场景?PM 是否确认?
↓ 验证通过
技术方案层:接口契约是否完整?服务边界是否清晰?
↓ 验证通过
代码实现层:Ralph Loop 是否全部通过?测试是否覆盖?
↓ 验证通过
完成

关键机制

层级 验证手段 拒绝模糊的方式
PRD 分析 PM 人工审查 Gherkin 未确认不进入下一层
技术方案 服务目录匹配 + 架构评审 功能归属不明确不分配任务
代码实现 Ralph Loop 强制检查 编译/测试/规范任一失败即阻塞

这种**分阶段门控(Stage-Gate)**机制,将"完成"的定义权更多交给客观可验证的标准。实践里未必每个团队都会采用同样严格的门禁,但核心思想是一致的:不要让未经验证的产物一路向下游扩散。

原则三:规范即上下文,赋能多 AI 协同

Spec 不仅是人与 AI 的契约,更是多 Agent 协同的"共同语言"和上下文载体。

当多个 Agent 协作完成一个需求时,最大的挑战是上下文传递——如何让 Agent B 理解 Agent A 的输出,并在此基础上继续工作?

SDD 的解决方案是:让 Spec 成为上下文本身

1
2
3
4
5
6
7
项目根目录/
├── .specs/
│ ├── prd/user-order.md # Agent A 的输入(人工编写)
│ ├── user-behavior/user-order.feature # Agent A 的输出 = Agent B 的输入
│ ├── system-behavior/order-service.feature # Agent B 的输出 = Agent C 的输入
│ └── system-behavior/contracts/openapi.yaml # 接口契约(共享上下文)
└── src/ # Agent C 的输出

规范作为上下文的三重价值

  1. 契约价值:人与 AI 之间的承诺——“你按这个规范实现,我按这个规范验收”
  2. 验收价值:代码实现的客观标准——“测试通过即符合规范”
  3. 协作价值:团队共同语言——PM、研发、测试对着同一份文档工作

这也回到了文章开篇的主线:Vibe Coding 最大的问题不是代码写得快不快,而是缺少可共享、可传递、可验证的共同语言;Spec 的价值,恰恰在于把这种共同语言显式化。

原则四:警惕 Spec 瀑布,拒绝 Markdown 怪兽

规范是必要的,但过度的规范是负担。警惕 Spec 瀑布,不要制造 Markdown 怪兽。

SDD 强调"规范先行",但这不意味着要写无穷无尽的文档。实践中存在一个危险的陷阱:为了规范而规范,最终产生大量无人阅读、无人维护的 Markdown 文件,成为项目的累赘而非资产。

Spec 瀑布的表现

反模式 症状 后果
过度设计 一个简单需求产出 50 页 Spec 维护成本超过实现成本
文档膨胀 每个变更都要更新 5 个文件 开发者逃避更新,文档迅速过时
形式重于内容 追求完美的格式而非清晰的意图 Spec 成了表演,而非协作工具

健康的 Spec 应该遵循"刚好足够"原则

  • 长度:能说明白即可,不追求篇幅
  • 格式:工具可解析即可,不追求排版
  • 维护:变更时顺手更新,不成为额外负担

记住:Spec 的价值在于减少沟通成本,而不是增加文档工作量。 当你发现写 Spec 的时间超过了写代码的时间,就是 Spec 瀑布的警告信号。

原则五:Bug 是 Spec 缺口,而非代码问题

很多值得长期修复的 Bug,最终都应该回到源头——在 Spec 文档中补上缺口。

传统观念认为 Bug 是代码写错了,但在 SDD 的视角下,Bug 的本质是 Spec 的缺口——要么是 Spec 没有覆盖这个场景,要么是 Spec 的描述不够精确,导致实现偏离了预期。

Bug 根因分析

Bug 类型 传统视角 SDD 视角
边界条件未处理 代码遗漏 Spec 未定义边界行为
异常流程报错 异常处理缺失 Spec 未覆盖异常场景
功能与需求不符 实现错误 Spec 描述模糊,理解有歧义
性能不达标 算法优化不足 Spec 未定义性能验收标准

在源头闭合缺口意味着:

  1. 发现 Bug 时,先问 Spec:这个场景在 Spec 中有定义吗?定义清晰吗?
  2. 修复 Bug 时,先改 Spec:补充缺失的场景描述,明确预期行为
  3. 验证修复时,对照 Spec:确保实现与更新后的 Spec 一致

这不是在推卸代码质量的责任,而是尽量把质量保障左移到更便宜的阶段——越早发现问题,修复成本通常越低。

一个无法回写到 Spec 的 Bug 修复,往往还不算完整。 只有把缺口补回规范层,团队才更有机会避免它以别的形式再次出现。


把这五条放在一起看,它们更像一组彼此制衡的工程准则:

graph TB
    P1["📋 原则一<br/>规范先行<br/>定义 What"]
    P2["✅ 原则二<br/>分阶段验证<br/>确保 Quality"]
    P3["🤝 原则三<br/>规范即上下文<br/>赋能 Collaboration"]
    P4["⚠️ 原则四<br/>警惕 Spec 瀑布<br/>保持 Lightweight"]
    P5["🐛 原则五<br/>Bug 是 Spec 缺口<br/>源头闭合"]

    P1 -->|"驱动"| P2
    P2 -->|"验证"| P3
    P3 -->|"反馈"| P1
    P1 -.->|"约束"| P4
    P2 -.->|"约束"| P4
    P3 -.->|"约束"| P4
    P4 -->|"保障"| P5

    style P1 fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style P2 fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style P3 fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style P4 fill:#fce4ec,stroke:#e91e63,stroke-width:2px
    style P5 fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px
  • 规范先行回答了"做什么"
  • 分阶段验证约束了"什么时候算完成"
  • 规范即上下文支撑了"如何协作传递"
  • 警惕 Spec 瀑布提醒我们不要把规范本身做成负担
  • Bug 是 Spec 缺口则要求把经验真正沉淀回体系

它们共同指向一个更务实的目标:让规范既能驱动实现,又不反过来拖垮实现。

十、总结

这几个层次的思考,实际上是同一个核心洞见在不同尺度上的展开:

1
2
3
4
5
6
哲学层:  人 → 高层决策,AI → 低层执行
问题层: Vibe Coding 优化个人效率,SDD 优化团队协作效率
方法论层:已解决的问题 → AI,新问题 → 人
工程层: PRD → 用户行为 Spec → 技术方案 → 系统行为 Spec → Code
架构层: 注册表(路由)→ 按需加载(规划)→ 脚本(执行)
实践层: 目录约定(解耦)→ Ralph Loop(防偷懒)→ 服务目录(归属判断)
graph TB
    L1["🧠 哲学层<br/>人 → 高层决策 | AI → 低层执行"]
    L2["❓ 问题层<br/>Vibe Coding 优化个人效率<br/>SDD 优化团队协作效率"]
    L3["📐 方法论层<br/>已解决的问题 → AI<br/>新问题 → 人"]
    L4["⚙️ 工程层<br/>PRD → 用户行为 Spec → 技术方案<br/>→ 系统行为 Spec → Code"]
    L5["🏗️ 架构层<br/>注册表(路由)→ 按需加载(规划)<br/>→ 脚本(执行)"]
    L6["🔧 实践层<br/>目录约定(解耦)→ Ralph Loop(防偷懒)<br/>→ 服务目录(归属判断)"]

    L1 -->|"指导"| L2
    L2 -->|"落地为"| L3
    L3 -->|"实现于"| L4
    L4 -->|"支撑于"| L5
    L5 -->|"约束于"| L6

    style L1 fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px
    style L2 fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
    style L3 fill:#e3f2fd,stroke:#2196f3,stroke-width:2px
    style L4 fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style L5 fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style L6 fill:#fce4ec,stroke:#e91e63,stroke-width:2px

AI 的演进方向,是从"生成器"转变为"调度器"和"决策器"。而人的演进方向,是从"操作员"晋升为"架构师"。

Vibe Coding 时代,我们关注"如何让 AI 更快地写出代码"。SDD 时代,我们关注"如何让团队更高效地协作"。理念落地的关键,是把三层 Agent 架构从概念变为可运行的实现——而这需要的不只是工具,更是一套工程约定。

这不是零和游戏,而是一场认知升维的协作。而这一切的核心,仍然是那个从 Kent Beck 时代就开始的理念:先定义预期,再实现代码