惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Y
Y Combinator Blog
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
M
MIT News - Artificial intelligence
博客园 - Franky
V
Visual Studio Blog
I
InfoQ
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
博客园 - 司徒正美
L
LangChain Blog

博客园 - 咸着的鱼25

环境才是 Agent 的核心基础设施 OpenCode + OpenSpec + Oh-My-OpenCode 联合 SDD/ATDD 开发指南 在线服务数据压缩算法比较 延迟深度链接 搭建wiki系统后端存储-来自大模型 广告投放名词 java spring IoC原理 面试题1 c++ 代码技巧 c++ 性能分析 粗排治理之性能优化 MMR 算法优化 core 基本操作 聊天室开发心得 Docker 学习笔记 Airflow 使用简介 lua转换etcd应答 修改系统参数 https学习笔记 openresty: nginx worker不同请求之间共享数据
AI 驱动开发工作流:OpenCode + Oh-My-OpenCode + SDD + ATDD
咸着的鱼25 · 2026-03-26 · via 博客园 - 咸着的鱼25

目录

  1. 背景与动机
  2. 工具链概览
  3. OpenCode 核心使用
  4. Oh-My-OpenCode 增强
  5. SDD:规格驱动开发
  6. ATDD:验收测试驱动开发
  7. OpenSpec:规格阶段的守门员
  8. 五者协同工作流
  9. 完整案例:用户订单服务
  10. 团队规范建议
  11. 常见问题

1. 背景与动机

为什么要改变?

传统开发流程中,我们面临几个核心痛点:

  • 需求到代码的鸿沟:产品文档到可运行代码之间存在大量人工翻译成本
  • 测试滞后:测试往往在代码写完后才补,而不是指导开发
  • 上下文丢失:AI 辅助编码时,AI 不了解项目规范、架构约束,产出物良莠不齐
  • 并行能力受限:单人单线程工作,无法充分利用 AI 的并行能力

新工作流的目标

需求文档 → 规格 → 测试 → 实现 → 验证
    ↑                              |
    └──────── AI 全程参与 ──────────┘
  • SDD(Specification-Driven Development):先写规格,再让 AI 生成代码
  • ATDD(Acceptance Test-Driven Development):先写验收测试,代码必须让测试通过
  • OpenCode:AI 编码主力,执行具体代码修改
  • Oh-My-OpenCode:增强 OpenCode,提供多模型编排、并行子 agent、更强工具链

2. 工具链概览

各工具职责

工具 职责 阶段
Oh-My-OpenCode 多模型编排,Sisyphus 主 agent 协调规划 全程
OpenCode (Plan 模式) 分析需求、生成规格、制定实现计划 规格阶段
OpenCode (Build 模式) 编写代码、重构、修复 bug 实现阶段
SDD 将需求转化为机器可读的 API 规格(OpenAPI/ADR) 设计阶段
ATDD 将验收条件转化为可执行测试(Cucumber/JUnit) 测试阶段
OpenSpec 规格阶段的流程框架,物理隔离规格与代码,防止 AI 提前写代码 规格阶段

工具安装

# 安装 OpenCode
curl -fsSL https://opencode.ai/install | bash
# 或
npm install -g opencode-ai

# 安装 Oh-My-OpenCode
npm install -g oh-my-opencode

# 在 opencode.json 中启用插件
# ~/.config/opencode/opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-20250514",
  "plugin": ["oh-my-opencode"]
}

3. OpenCode 核心使用

3.1 两种核心模式

┌─────────────────────────────────────────────────┐
│  Tab 键切换                                      │
│                                                  │
│  [Plan 模式]          [Build 模式]               │
│  - 只分析,不修改     - 完整工具权限              │
│  - 生成规格/计划      - 执行实际代码变更           │
│  - 安全探索代码库     - 运行命令/测试              │
└─────────────────────────────────────────────────┘

使用原则

  • 不确定怎么做时,先用 Plan 模式 探索,确认方向后切换 Build 模式
  • 复杂任务一定先 Plan,再 Build,避免 AI 走弯路

3.2 AGENTS.md:给 AI 的项目说明书

在项目根目录创建 AGENTS.md,这是 AI 了解项目的核心入口:

# 初始化(AI 自动扫描项目生成)
/init

# 然后手工完善
# 项目名:订单服务 (order-service)

## 技术栈
- Java 17 + Spring Boot 3.x
- Maven 构建
- MySQL 8.0(通过 JPA/Hibernate 访问)
- Redis(缓存层)
- Cucumber + JUnit 5(验收测试)

## 项目结构
- `src/main/java/com/example/order/` - 主代码
  - `controller/` - REST 控制器
  - `service/` - 业务逻辑
  - `repository/` - 数据访问
  - `domain/` - 领域对象/实体
  - `dto/` - 请求/响应 DTO
- `src/test/` - 测试代码
  - `java/.../acceptance/` - Cucumber 验收测试
  - `resources/features/` - .feature 文件

## 代码规范
- 所有公开方法必须有 Javadoc
- Service 层统一抛出自定义 BusinessException,不允许直接抛 RuntimeException
- Controller 层只做参数校验和 DTO 转换,不含业务逻辑
- 字段验证使用 Jakarta Validation 注解
- 禁止在 Service 层直接使用 HttpServletRequest

## 接口规范
- 统一响应格式:`{ "code": 200, "message": "success", "data": {} }`
- 错误码定义在 `ErrorCode` 枚举中
- 分页接口使用 `PageRequest` 参数

## 测试规范
- 每个新功能必须有对应的 .feature 文件(ATDD)
- 验收测试覆盖正常流程 + 至少 2 个边界/异常场景
- 单元测试使用 Mockito,不依赖真实数据库

## Git 规范
- 分支命名:feature/xxx、fix/xxx、refactor/xxx
- commit message 格式:`type(scope): description`

提交到 Git,让团队所有成员的 OpenCode 都读到相同的上下文。

3.3 子 agent 调用

# 在消息中 @mention 子 agent
@explore 帮我找所有实现了 OrderService 接口的类

@general 并行检查以下三个文件的代码规范符合情况:
  - OrderController.java
  - OrderService.java  
  - OrderRepository.java

4. Oh-My-OpenCode 增强

4.1 核心能力

Oh-My-OpenCode(npm 包:oh-my-opencode,GitHub:code-yeongyu/oh-my-openagent)是 OpenCode 的增强插件,提供:

能力 说明
Sisyphus 主 agent 智能编排器,自动分解任务、并行调度子 agent
Prometheus 规划师 采访模式,在动手前深度规划,适合 SDD 阶段
ultrawork 命令 一键启动全量 agent,推进任务直到完成
Hash 锚定编辑 每行代码有内容 hash,杜绝过期行错误
Background Agents 同时运行 5+ 个专项 agent
LSP + AST-Grep IDE 级别的代码重构和搜索

4.2 关键命令

# 启动后在 OpenCode TUI 中输入:

/start-work      # 调用 Prometheus,采访式规划,适合 SDD 阶段
ultrawork        # 或 ulw,一键全力推进任务
/init-deep       # 为项目所有子目录生成层级 AGENTS.md

4.3 多模型编排策略

Oh-My-OpenCode 会自动根据任务类型路由到最合适的模型:

任务类型           → 模型
─────────────────────────────────────
架构设计/复杂推理  → claude-opus 或 kimi-k2.5
代码实现/重构     → gpt-5.x-codex
前端/UI           → visual-engineering 专项模型
快速单文件修改    → 轻量快速模型

无需手动切换模型,Sisyphus 自动判断。

4.4 安装配置

安装后,~/.config/opencode/opencode.json 会自动更新。项目级配置放在 .opencode/oh-my-opencode.jsonc

{
  // 项目级 Oh-My-OpenCode 配置
  "agents": {
    "sisyphus": {
      // 覆盖默认模型(可选)
      "model": "anthropic/claude-opus-4-6"
    }
  },
  "background_tasks": {
    "max_concurrent": 3  // 最多同时运行 3 个后台 agent
  }
}

5. SDD:规格驱动开发

5.1 什么是 SDD?

SDD(Specification-Driven Development)的核心理念:

代码是规格的实现,而不是需求的直接翻译

工作流:

产品需求文档
    ↓  (Plan 模式 + Prometheus)
API 规格(OpenAPI YAML)+ 架构决策记录(ADR)
    ↓  (Build 模式)
代码实现
    ↓
与规格对齐验证

5.2 AI 辅助生成规格

Step 1:用 Plan 模式 + /start-work 生成规格草稿

# 切换到 Plan 模式(Tab 键)
# 输入:

我需要设计一个订单创建接口。业务需求:
- 用户可以提交包含多个商品的订单
- 需要校验库存是否充足
- 订单金额需要计算折扣
- 支持多种支付方式(微信、支付宝、银行卡)
- 订单提交成功后异步发送确认邮件

请用 /start-work 采访我,然后生成 OpenAPI 规格。

Prometheus 会问你:

  • 是否有幂等性要求?
  • 库存不足时是部分成功还是全部失败?
  • 折扣逻辑的优先级规则是什么?
  • ……

Step 2:规格文件落地

AI 生成后保存为 docs/api/order-api.yaml

openapi: 3.0.0
info:
  title: Order Service API
  version: 1.0.0

paths:
  /api/v1/orders:
    post:
      summary: 创建订单
      operationId: createOrder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: 订单创建成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        '400':
          description: 参数校验失败
        '409':
          description: 库存不足

components:
  schemas:
    CreateOrderRequest:
      type: object
      required: [userId, items, paymentMethod]
      properties:
        userId:
          type: string
          description: 用户 ID
        items:
          type: array
          items:
            $ref: '#/components/schemas/OrderItem'
          minItems: 1
        paymentMethod:
          type: string
          enum: [WECHAT, ALIPAY, BANK_CARD]
        couponCode:
          type: string
          description: 优惠券码(可选)
    # ... 其他 schema 定义

5.3 用规格驱动 AI 生成代码

有了规格,对 AI 的指令变得精确:

# 切换到 Build 模式
# 输入:

根据 @docs/api/order-api.yaml 中的规格,
实现 POST /api/v1/orders 接口,包括:
1. CreateOrderRequest DTO(带 Jakarta Validation 注解)
2. OrderController(只做参数校验,业务逻辑委托给 Service)
3. OrderService 接口及实现(包含库存校验逻辑)
4. 统一响应格式封装

遵循 @AGENTS.md 中的代码规范。

6. ATDD:验收测试驱动开发

6.1 什么是 ATDD?

ATDD(Acceptance Test-Driven Development):

先写验收测试,再写实现代码,以测试通过作为完成标志

使用 Gherkin 语言(.feature 文件)描述业务场景,让业务人员、测试、开发共同理解需求:

Feature: 创建订单
  作为一个已登录用户
  我想要提交订单
  以便购买商品

  Scenario: 正常创建订单
    Given 用户 "user001" 已登录
    And 商品 "SKU001" 库存为 10
    When 用户提交包含 2 件 "SKU001" 的订单
    Then 返回状态码 201
    And 订单状态为 "PENDING_PAYMENT"
    And 商品 "SKU001" 库存减少为 8

  Scenario: 库存不足时拒绝创建
    Given 用户 "user001" 已登录
    And 商品 "SKU001" 库存为 1
    When 用户提交包含 5 件 "SKU001" 的订单
    Then 返回状态码 409
    And 错误信息包含 "库存不足"

6.2 AI 辅助生成 Feature 文件

# Plan 模式下输入:

基于 @docs/api/order-api.yaml 的 createOrder 接口,
帮我生成完整的 Cucumber feature 文件,要覆盖:
1. 正常流程(单商品、多商品)
2. 库存不足场景
3. 无效优惠券场景
4. 无效支付方式场景
5. 并发下单场景(幂等性)

保存到 src/test/resources/features/order/create-order.feature

6.3 AI 辅助生成 Step Definitions

有了 .feature 文件,让 AI 生成对应的 Step 实现:

# Build 模式下输入:

根据 @src/test/resources/features/order/create-order.feature,
生成对应的 Cucumber Step Definitions,要求:
- 使用 Spring Boot Test + MockMvc
- 使用 @MockBean 模拟 OrderService
- 每个 Step 方法要简洁,复杂逻辑抽取到 helper 方法
- 保存到 src/test/java/com/example/order/acceptance/OrderStepDefs.java

6.4 红绿循环

写 .feature 文件(红)
    ↓
生成 Step Definitions(红)
    ↓
AI 生成业务代码(绿)
    ↓
运行验收测试
    ↓
全部通过 → 完成
失败 → 让 AI 修复(迭代)

运行测试的提示词

运行 mvn test -Dtest=AcceptanceTest,
如果有失败的用例,分析原因并修复,直到全部通过。

7. OpenSpec:规格阶段的守门员

7.1 为什么需要 OpenSpec?

在实践 SDD 时,一个常见问题是:AI 不等规格确认就开始写代码。Plan 模式的 ask 权限只是弹出确认框,并不强制阻止。当团队成员有时候直接在 Build 模式下开始工作,规格文档就很容易被跳过。

OpenSpec 解决这个问题的方式是:用目录结构和 agent 权限,在物理层面隔离规格阶段和实现阶段

OpenSpec 不是 OpenCode 的竞争者,而是 SDD 的流程框架,与 OpenCode 互补。

7.2 核心概念

OpenSpec 为每个功能维护一个独立目录:

openspec/
└── changes/
    └── create-order/           # 每个功能一个目录
        ├── proposal.md         # 功能提案(需求描述)
        ├── design.md           # 架构/设计决策
        ├── tasks.md            # 拆解的实施任务
        └── specs/
            ├── api.yaml        # OpenAPI 规格
            └── events.yaml     # 领域事件规格(如需要)

三个核心命令:

命令 作用
/opsx:propose 开启新功能规格流程,AI 采访后生成 proposal.md
/opsx:apply 规格确认后,解锁代码文件权限,开始实现
/opsx:archive 功能完成后,归档规格文档

7.3 opencode-plugin-openspec:与 OpenCode 的集成

opencode-plugin-openspec(GitHub: Octane0411/opencode-plugin-openspec)是专门为 OpenCode 打造的 OpenSpec 插件,提供一个名为 openspec-plan 的专用 agent。

与 Plan 模式的关键区别

对比项 Plan 模式 openspec-plan agent
对文件写入的控制 ask 权限(弹确认框) deny 权限(物理禁止写代码文件)
强制性 低,人可以绕过 高,连 AI 自己也无法绕过
适用场景 个人探索、快速迭代 团队协作、有规范要求的项目

7.4 安装与配置

# 安装 OpenSpec CLI
npm install -g @fission-ai/openspec

# 安装 OpenCode 插件(可选,但推荐)
# 在 opencode.json 的 plugin 数组中添加:
{
  "$schema": "https://opencode.ai/config.json",
  "model": "anthropic/claude-sonnet-4-20250514",
  "plugin": ["oh-my-opencode", "opencode-plugin-openspec"]
}

初始化项目:

# 在项目根目录
openspec init

这会创建 openspec/ 目录和基础配置。

7.5 典型工作流:以"创建订单"为例

阶段一:提案(Propose)

# 在 OpenCode 中,使用 openspec-plan agent
# 此时 AI 无法修改任何业务代码

/opsx:propose create-order

我要实现创建订单功能:
- 用户提交多商品订单
- 校验库存
- 支持优惠券
- 异步发送确认邮件

AI 采访并生成 openspec/changes/create-order/proposal.md

# Proposal: 创建订单功能

## 背景
用户需要能够一次性提交包含多个商品的订单。

## 业务规则
- **原子性**:多商品订单中任一商品库存不足,整单取消
- **优惠券**:每单限用一张,固定金额减免
- **邮件**:异步发送,失败不影响订单主流程

## 接口设计决策
- 幂等键:通过 `X-Idempotency-Key` 请求头实现
- 错误策略:409 表示库存不足,404 表示商品/优惠券不存在

## 未解决问题
- [ ] 并发下单时的库存锁定策略(乐观锁 vs 悲观锁)?

人工 Review proposal.md,确认无误后继续。

阶段二:生成规格

# 仍在 openspec-plan agent 中(仍无法写业务代码)

根据 proposal.md,生成:
1. OpenAPI 规格到 openspec/changes/create-order/specs/api.yaml
2. 架构决策记录到 openspec/changes/create-order/design.md
3. 任务拆解到 openspec/changes/create-order/tasks.md

人工 Review,若 Review 通过:

/opsx:apply create-order

这一步将规格文件复制到 docs/api/同时解锁业务代码文件的写入权限,后续可切换回普通 Build 模式继续工作。

阶段三:实现(接续 ATDD 流程)

/opsx:apply 之后,流程与不使用 OpenSpec 的 ATDD 流程完全相同:

  1. AI 根据 specs/api.yaml 生成 Cucumber .feature 文件
  2. 生成 Step Definitions 骨架
  3. Build 模式实现业务代码
  4. 运行测试直到全绿

7.6 是否需要引入 OpenSpec?

情况 建议
团队 ≤ 2 人,文档纪律好 可以不用,Plan 模式 + 人工自律即可
团队 3+ 人,需要流程保障 推荐引入,防止规格被跳过
AI 经常在规格未确认时就开始写代码 强烈推荐,openspec-plan agent 物理阻断
需要规格文档可追溯、可归档 推荐,/opsx:archive 提供完整归档机制

8. 五者协同工作流

完整工作流图

┌──────────────────────────────────────────────────────────────┐
│                     一个功能的完整流程                         │
└──────────────────────────────────────────────────────────────┘

1. 需求澄清(Oh-My-OpenCode Prometheus + Plan 模式)
   ├─ /start-work 采访模式,明确需求边界
   ├─ 生成功能说明文档
   └─ 确定接口契约

2. 规格设计(SDD + OpenSpec + openspec-plan agent)
   ├─ /opsx:propose 开启规格流程(物理禁止写业务代码)
   ├─ AI 采访生成 proposal.md
   ├─ AI 生成 OpenAPI YAML 到 openspec/changes/<feature>/specs/
   ├─ 人工 Review 规格,确认无误
   ├─ /opsx:apply 解锁代码权限,规格复制到 docs/api/
   └─ 提交规格文件到 Git

3. 验收测试先行(ATDD + Build 模式)
   ├─ AI 生成 .feature 文件
   ├─ 人工 Review 场景覆盖度
   ├─ AI 生成 Step Definitions 骨架
   └─ 此时测试全部为红(失败)

4. 并行实现(Oh-My-OpenCode ultrawork)
   ├─ Sisyphus 分解任务
   ├─ 多个 Background Agent 并行工作:
   │   ├─ Agent A:实现 Controller + DTO
   │   ├─ Agent B:实现 Service + 业务逻辑
   │   └─ Agent C:实现 Repository + 数据层
   └─ 各 Agent 完成后合并

5. 验证(Build 模式)
   ├─ 运行验收测试(Cucumber)
   ├─ AI 修复失败用例
   └─ 测试全绿 → 功能完成

6. 代码 Review(explore subagent)
   └─ @explore 检查是否符合 AGENTS.md 规范

7. 归档(OpenSpec)
   └─ /opsx:archive 归档规格文档,保留可追溯记录

关键原则

  1. 规格先于代码:没有 OpenAPI 规格,不开始写代码
  2. 测试先于实现:没有 .feature 文件,不开始写 Service
  3. Plan 后再 Build:复杂功能必须先在 Plan 模式中确认方向
  4. AGENTS.md 是唯一真相:所有规范都在这里,AI 和人都遵循
  5. OpenSpec 守门:3+ 人团队中,用 openspec-plan agent 物理隔离规格与代码阶段

9. 完整案例:用户订单服务

场景:为电商平台实现"创建订单"功能

Step 1:需求澄清(10 分钟)

打开 OpenCode,切换到 Plan 模式,输入:

我要实现一个订单创建功能。
请用 /start-work 采访我,完成后给出功能规格摘要。

基本需求:
- 用户选择商品和数量,提交订单
- 要检查库存
- 要支持优惠券
- 成功后发邮件通知

Prometheus 会问:

  • Q: 如果多个商品中有一个库存不足,是全部取消还是部分成功?
  • A: 全部取消,保持原子性
  • Q: 优惠券是按金额减免还是按折扣?同一订单可以用多张吗?
  • A: 固定金额减免,每单只能用一张
  • Q: 邮件发送失败是否影响订单创建成功?
  • A: 不影响,邮件异步发送,失败自动重试

Step 2:生成 OpenAPI 规格

# Plan 模式继续:

根据以上澄清,生成完整的 OpenAPI 3.0 规格,
保存到 docs/api/create-order.yaml

AI 生成的 docs/api/create-order.yaml

openapi: 3.0.0
info:
  title: Order Service
  version: 1.0.0

paths:
  /api/v1/orders:
    post:
      summary: 创建订单
      operationId: createOrder
      tags: [orders]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
            example:
              userId: "user_123"
              items:
                - skuId: "SKU_001"
                  quantity: 2
              paymentMethod: "ALIPAY"
              couponCode: "SAVE10"
      responses:
        '201':
          description: 订单创建成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse'
        '400':
          description: 请求参数不合法
        '404':
          description: 商品不存在或优惠券不存在
        '409':
          description: 库存不足

components:
  schemas:
    CreateOrderRequest:
      type: object
      required: [userId, items, paymentMethod]
      properties:
        userId:
          type: string
          minLength: 1
        items:
          type: array
          minItems: 1
          items:
            type: object
            required: [skuId, quantity]
            properties:
              skuId:
                type: string
              quantity:
                type: integer
                minimum: 1
                maximum: 99
        paymentMethod:
          type: string
          enum: [WECHAT, ALIPAY, BANK_CARD]
        couponCode:
          type: string

    OrderResponse:
      type: object
      properties:
        orderId:
          type: string
        status:
          type: string
          enum: [PENDING_PAYMENT, PAID, CANCELLED]
        totalAmount:
          type: number
        discountAmount:
          type: number
        finalAmount:
          type: number
        createdAt:
          type: string
          format: date-time

    ApiResponse:
      type: object
      properties:
        code:
          type: integer
        message:
          type: string
        data:
          $ref: '#/components/schemas/OrderResponse'

人工 Review 后,提交到 Git。

Step 3:生成验收测试

切换回 Plan 模式(或保持 Plan 模式),输入:

根据 @docs/api/create-order.yaml 和以下业务规则:
- 库存不足时全部取消(原子性)
- 每单只能用一张优惠券(固定金额减免)
- 邮件异步发送,不影响主流程

生成 Cucumber feature 文件,覆盖:
1. 正常创建(无优惠券)
2. 使用有效优惠券
3. 商品库存不足(全部回滚)
4. 部分商品库存不足(全部回滚)
5. 优惠券不存在
6. 无效的支付方式

保存到 src/test/resources/features/order/create-order.feature

生成的 create-order.feature

Feature: 创建订单
  作为一个已注册用户
  我希望能够提交包含多个商品的订单
  以便完成购买流程

  Background:
    Given 商品库存数据如下:
      | skuId   | stock |
      | SKU_001 | 10    |
      | SKU_002 | 5     |

  Scenario: 正常创建订单(无优惠券)
    When 用户 "user_123" 提交以下订单:
      | skuId   | quantity |
      | SKU_001 | 2        |
    And 支付方式为 "ALIPAY"
    Then 返回状态码 201
    And 订单状态为 "PENDING_PAYMENT"
    And 商品 "SKU_001" 库存变为 8

  Scenario: 使用有效优惠券创建订单
    Given 优惠券 "SAVE10" 面值为 10 元,状态为可用
    When 用户 "user_123" 提交以下订单:
      | skuId   | quantity |
      | SKU_001 | 1        |
    And 支付方式为 "WECHAT"
    And 使用优惠券 "SAVE10"
    Then 返回状态码 201
    And 响应中 discountAmount 为 10

  Scenario: 单个商品库存不足时全部回滚
    When 用户 "user_123" 提交以下订单:
      | skuId   | quantity |
      | SKU_001 | 20       |
    And 支付方式为 "ALIPAY"
    Then 返回状态码 409
    And 错误信息包含 "库存不足"
    And 商品 "SKU_001" 库存保持为 10

  Scenario: 多商品中有一个库存不足时全部回滚
    When 用户 "user_123" 提交以下订单:
      | skuId   | quantity |
      | SKU_001 | 2        |
      | SKU_002 | 10       |
    And 支付方式为 "ALIPAY"
    Then 返回状态码 409
    And 商品 "SKU_001" 库存保持为 10
    And 商品 "SKU_002" 库存保持为 5

  Scenario: 优惠券不存在
    When 用户 "user_123" 提交以下订单:
      | skuId   | quantity |
      | SKU_001 | 1        |
    And 支付方式为 "ALIPAY"
    And 使用优惠券 "INVALID_CODE"
    Then 返回状态码 404
    And 错误信息包含 "优惠券不存在"

  Scenario: 无效支付方式被拒绝
    When 用户 "user_123" 提交以下订单:
      | skuId   | quantity |
      | SKU_001 | 1        |
    And 支付方式为 "BITCOIN"
    Then 返回状态码 400

Step 4:生成 Step Definitions 骨架

# 切换到 Build 模式

根据 @src/test/resources/features/order/create-order.feature,
生成 Cucumber Step Definitions:
- 使用 Spring Boot Test
- 使用 @SpringBootTest + MockMvc 做集成测试
- 数据用 @Sql 注解初始化
- 保存到 src/test/java/com/example/order/acceptance/CreateOrderStepDefs.java

生成的 Step Definitions 骨架(节选):

@SpringBootTest
@AutoConfigureMockMvc
@CucumberContextConfiguration
public class CreateOrderStepDefs {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private InventoryRepository inventoryRepository;

    private ResultActions result;
    private CreateOrderRequest.Builder requestBuilder;

    @Given("商品库存数据如下:")
    public void 商品库存数据如下(DataTable dataTable) {
        List<Map<String, String>> rows = dataTable.asMaps();
        rows.forEach(row -> {
            Inventory inv = new Inventory();
            inv.setSkuId(row.get("skuId"));
            inv.setStock(Integer.parseInt(row.get("stock")));
            inventoryRepository.save(inv);
        });
    }

    @When("用户 {string} 提交以下订单:")
    public void 用户提交以下订单(String userId, DataTable dataTable) {
        requestBuilder = CreateOrderRequest.builder().userId(userId);
        List<OrderItem> items = dataTable.asMaps().stream()
            .map(row -> OrderItem.builder()
                .skuId(row.get("skuId"))
                .quantity(Integer.parseInt(row.get("quantity")))
                .build())
            .collect(Collectors.toList());
        requestBuilder.items(items);
    }

    @And("支付方式为 {string}")
    public void 支付方式为(String paymentMethod) throws Exception {
        CreateOrderRequest request = requestBuilder
            .paymentMethod(PaymentMethod.valueOf(paymentMethod))
            .build();
        result = mockMvc.perform(
            post("/api/v1/orders")
                .contentType(MediaType.APPLICATION_JSON)
                .content(objectMapper.writeValueAsString(request))
        );
    }

    @Then("返回状态码 {int}")
    public void 返回状态码(int statusCode) throws Exception {
        result.andExpect(status().is(statusCode));
    }

    @Then("订单状态为 {string}")
    public void 订单状态为(String status) throws Exception {
        result.andExpect(jsonPath("$.data.status").value(status));
    }

    // ... 其他 Step 实现
}

此时运行测试,全部为红(因为业务代码还没写)。

Step 5:并行实现业务代码

切换到 Build 模式,使用 ultrawork:

根据 @docs/api/create-order.yaml 和 @AGENTS.md 的规范,
实现创建订单功能。

要求:
1. CreateOrderRequest DTO(带完整 Bean Validation)
2. OrderController(委托给 Service,不含业务逻辑)
3. OrderService 接口 + OrderServiceImpl(包含库存事务性扣减)
4. 邮件异步发送(Spring @Async)
5. 全局异常处理器(BusinessException → 标准响应格式)

测试在 @src/test/resources/features/order/create-order.feature

ultrawork

Sisyphus 自动分解为多个并行子任务,Background Agents 同时工作。

生成的 OrderServiceImpl.java(核心逻辑节选):

@Service
@Slf4j
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {

    private final InventoryRepository inventoryRepository;
    private final OrderRepository orderRepository;
    private final CouponService couponService;
    private final EmailService emailService;

    @Override
    @Transactional
    public OrderResponse createOrder(CreateOrderRequest request) {
        // 1. 验证并锁定库存(悲观锁,原子性保证)
        List<InventoryLock> locks = lockInventory(request.getItems());

        // 2. 计算金额
        BigDecimal totalAmount = calculateTotal(request.getItems());
        BigDecimal discountAmount = BigDecimal.ZERO;

        // 3. 处理优惠券
        if (StringUtils.hasText(request.getCouponCode())) {
            Coupon coupon = couponService.validateAndUse(request.getCouponCode());
            discountAmount = coupon.getDiscountAmount();
        }

        // 4. 创建订单
        Order order = Order.builder()
            .userId(request.getUserId())
            .status(OrderStatus.PENDING_PAYMENT)
            .totalAmount(totalAmount)
            .discountAmount(discountAmount)
            .finalAmount(totalAmount.subtract(discountAmount))
            .paymentMethod(request.getPaymentMethod())
            .build();

        order = orderRepository.save(order);

        // 5. 异步发送确认邮件(失败不影响订单)
        emailService.sendOrderConfirmationAsync(order);

        return OrderResponse.from(order);
    }

    /**
     * 锁定库存,任一商品不足则抛出异常触发回滚
     */
    private List<InventoryLock> lockInventory(List<OrderItem> items) {
        return items.stream()
            .map(item -> {
                Inventory inventory = inventoryRepository
                    .findBySkuIdWithLock(item.getSkuId())
                    .orElseThrow(() -> new BusinessException(
                        ErrorCode.PRODUCT_NOT_FOUND,
                        "商品不存在: " + item.getSkuId()
                    ));

                if (inventory.getStock() < item.getQuantity()) {
                    throw new BusinessException(
                        ErrorCode.INSUFFICIENT_STOCK,
                        "库存不足: " + item.getSkuId()
                    );
                }

                inventory.setStock(inventory.getStock() - item.getQuantity());
                inventoryRepository.save(inventory);
                return new InventoryLock(item.getSkuId(), item.getQuantity());
            })
            .collect(Collectors.toList());
    }
}

Step 6:运行验收测试,修复到全绿

运行 mvn test -Dtest="**/acceptance/**"
如果有失败的测试,逐一分析并修复,直到全部通过。

AI 自动运行测试、分析失败原因、修复代码,循环直到全绿。

✓ 正常创建订单(无优惠券)
✓ 使用有效优惠券创建订单
✓ 单个商品库存不足时全部回滚
✓ 多商品中有一个库存不足时全部回滚
✓ 优惠券不存在
✓ 无效支付方式被拒绝

Tests run: 6, Failures: 0, Errors: 0

Step 7:代码规范检查

@explore 检查新增的代码是否符合 @AGENTS.md 中的规范,
特别检查:
1. Service 层是否直接抛了 RuntimeException(应该用 BusinessException)
2. Controller 是否包含了业务逻辑
3. 公开方法是否都有 Javadoc

10. 团队规范建议

10.1 文件目录规范

project/
├── AGENTS.md                    # AI 项目说明书(必须提交 Git)
├── .opencode/
│   ├── oh-my-opencode.jsonc     # Oh-My-OpenCode 项目级配置
│   └── skills/                  # 项目自定义 Skills
│       └── java-conventions/
│           └── SKILL.md
├── openspec/                    # OpenSpec 规格目录
│   └── changes/
│       └── create-order/        # 每个功能一个目录
│           ├── proposal.md
│           ├── design.md
│           ├── tasks.md
│           └── specs/
│               └── api.yaml
├── docs/
│   └── api/                     # 已 apply 的 OpenAPI 规格(SDD 产物)
│       ├── order-api.yaml
│       └── user-api.yaml
└── src/
    └── test/
        └── resources/
            └── features/        # Cucumber feature 文件(ATDD 产物)
                └── order/
                    └── create-order.feature

10.2 开发流程检查清单

每个功能开发前:

  • 是否已用 /opsx:propose 开启规格流程(3+ 人团队)?
  • 是否已在 Plan 模式中澄清需求?
  • 是否已生成 OpenAPI 规格并提交?
  • 是否已运行 /opsx:apply 解锁代码权限?
  • 是否已生成 .feature 文件并 Review?

每个功能开发中:

  • Step Definitions 骨架是否已生成?
  • 是否优先让测试驱动实现?

每个功能完成后:

  • 验收测试是否全部通过?
  • 是否用 @explore 做了规范检查?
  • AGENTS.md 是否需要更新?
  • 是否运行 /opsx:archive 归档规格文档?

10.3 AGENTS.md 维护规范

  • 新增架构约束 → 更新 AGENTS.md 的"代码规范"部分
  • 新增公共组件 → 更新"项目结构"部分
  • 每个 Sprint 开始前 Review 一次 AGENTS.md

10.4 禁止事项

  • 禁止在 Build 模式下直接写代码,跳过 Plan 确认(复杂功能)
  • 禁止在未生成 .feature 文件的情况下完成功能开发
  • 禁止让 AI 修改 AGENTS.md 中的规范部分(只有人工修改)
  • 禁止在 3+ 人团队中跳过 /opsx:propose,直接进入 Build 模式

11. 常见问题

Q:OpenSpec 和 Plan 模式有什么本质区别,必须两者都用吗?
A:Plan 模式的文件写入控制是"弹确认框"(ask),人可以绕过。openspec-plan agent 使用 deny 权限,物理禁止写业务代码文件,AI 自身也无法绕过。小团队(1-2 人)靠自律用 Plan 模式即可;3+ 人团队推荐加 OpenSpec 作为流程护栏。两者不是非此即彼,而是深度互补。

Q:OpenSpec 的 /opsx:apply 后,规格还能改吗?
A:可以,/opsx:apply 只是复制规格文件并解锁权限,openspec/changes/<feature>/specs/ 目录仍然存在。改动规格后需要手动同步到 docs/api/,建议通过 PR 记录规格变更。

Q:Plan 模式下 AI 能修改文件吗?
A:默认情况下修改操作会弹出确认框(ask 权限),而非直接禁止。可以在 opencode.json 中将 plan agent 的 edit 权限设为 deny 实现完全只读。

Q:Oh-My-OpenCode 的 ultrawork 命令会不会乱改代码?
A:不会,它仍然受 OpenCode 的权限体系约束。可以在 .opencode/oh-my-opencode.jsonc 中配置 background_tasks.max_concurrent 控制并发度。

Q:AGENTS.md 写多少内容合适?
A:不宜过长(超过 500 行会占用大量 context window),核心规范放 AGENTS.md,细节规范通过 opencode.jsoninstructions 字段引用外部文件。

Q:Cucumber 测试跑得很慢怎么办?
A:验收测试(/acceptance/)和单元测试(/unit/)分开执行。验收测试走真实 Spring 上下文,慢是正常的,可以配 CI 并行执行。

Q:AI 生成的代码质量不稳定怎么办?
A:AGENTS.md 写得越详细,输出越稳定。另外可以创建团队专属的 Skill,把编码规范以 Skill 形式注入:.opencode/skills/java-conventions/SKILL.md


参考资料