最近在思考一个问题: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) 什么时候停下来?
自动迭代 没有明确的完成标准 单元测试驱动(测试通过即完成) 如何生成有意义的测试?
测试驱动 AI 难以凭空生成有意义的测试 规范驱动(从需求生成测试) 不适合多系统环境
单应用规范驱动 单应用视角,无法处理服务间协作 系统行为层(BDD) 如何串联全流程?
BDD 各层独立,缺乏端到端串联 三层 Agent 架构

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

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

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

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

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

类比:印刷术的发明不是让抄书匠失业,而是让知识的传播者从"复制者"升级为"创作者"。SDD 的意义与此相同——它不是让 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)
↓ 单元测试驱动开发
↓ 方法/函数/类级别
↓ 产出:通过的单元测试

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 个应用

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

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

三层 Agent 模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌─────────────────────────────────────────────┐
│ PRD 分析 Agent(ATDD 层) │
│ 输入:PRD 需求文档 │
│ 输出:用户行为 Gherkin(PM 可读可确认) │
│ 价值:PM ↔ 研发的协作契约 │
└──────────────────────┬──────────────────────┘


┌─────────────────────────────────────────────┐
│ 技术方案设计 Agent(BDD + UTDD 层) │
│ 输入:用户行为 Gherkin │
│ 输出:接口契约 + 各应用系统行为 Gherkin │
│ + 任务分配清单 │
│ 价值:研发 ↔ 研发的协作规范 │
└──────────────────────┬──────────────────────┘


┌─────────────────────────────────────────────┐
│ 代码开发 Agent(执行层) │
│ 输入:系统行为 Gherkin + 接口契约 │
│ 输出:可编译运行的代码 + 通过的单元测试 │
│ 模式:TDD 红绿重构循环,逐场景执行 │
└─────────────────────────────────────────────┘

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

协作成本的前置解决

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

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

落地:数据流与目录约定

三层 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 的内部实现。

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

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

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

1
2
3
4
5
while 未满足完成条件:
执行编译检查(mvn compile)
执行测试(mvn test)
如果任何检查失败 → 继续修复
如果全部通过 → 退出循环

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

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

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

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

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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌─────────────────────────────────────────────┐
Level 0: 语义注册表 │
│ (Skill 名称 + 简短描述 + 参数 Schema) │
│ Token 消耗:极低 | LLM 角色:Router │
└──────────────────────┬──────────────────────┘
│ 路由选择

┌─────────────────────────────────────────────┐
Level 1: 渐进式加载器 │
│ (按需加载选中 Skill 的完整 Prompt/文档) │
│ Token 消耗:中等 | LLM 角色:Planner │
└──────────────────────┬──────────────────────┘
│ 执行决策

┌──────────────────────┬──────────────────────┐
Level 2A: LLM 生成 │ Level 2B: 确定性脚本 │
│ (非结构化、创意任务) │ (结构化、逻辑严密任务) │
│ 概率性输出 │ 精确执行,零概率误差 │
└──────────────────────┴──────────────────────┘

关键洞察: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 是工兵。不要让指挥官去挖战壕,也不要让工兵去制定战略。

七、三大设计原则

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

原则一:上下文最小化(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 的完整流程。

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 场景都有对应的通过测试。

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

案例小结

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

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

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

九、总结

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

1
2
3
4
5
6
哲学层:  人 → 高层决策,AI → 低层执行
问题层: Vibe Coding 优化个人效率,SDD 优化团队协作效率
方法论层:已解决的问题 → AI,新问题 → 人
工程层: PRD → 用户行为 Spec → 技术方案 → 系统行为 Spec → Code
架构层: 注册表(路由)→ 按需加载(规划)→ 脚本(执行)
实践层: 目录约定(解耦)→ Ralph Loop(防偷懒)→ 服务目录(归属判断)

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

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

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