为什么需求规格决定实现质量
这几年用 AI 写代码以后,我越来越觉得:Java 项目里真正拉开差距的,不是“让 AI 多写几行代码”,而是“让 AI 在写代码前先把需求理解对”。尤其是订单、库存、结算、报表、权限这类业务系统,表面上只是加一个接口,背后可能牵扯状态机、事务边界、幂等、消息补偿、历史数据兼容和测试数据准备。
更准确地说,OpenSpec 安装完成后,主要使用的是 /opsx:* 这一组命令,而不是单独的 /openspec。常用链路是:/opsx:propose 先提出变更并生成规格,/opsx:apply 按规格实现,/opsx:sync 把变更规格同步回主规格,最后用 /opsx:archive 归档完成的 change。
这篇记录一下我会怎么在 Java 项目里使用 OpenSpec/OPSX,重点是怎么让 /opsx:propose 先匹配项目、怎么写变更输入、怎么检查生成的 artifacts,以及怎么用 /opsx:apply 进入后续编码。
OpenSpec 在开发流程中的职责
Spec Coding 的核心不是“多写文档”,而是把模糊需求变成可验收条件。对 Java 后端项目来说,一个可用的 spec 至少要回答这些问题:
业务目标:这次到底解决哪个业务问题,不解决哪些问题。
项目位置:需求落在哪个服务、哪个模块、哪几类包结构里。
接口变化:新增还是修改接口,请求参数、响应字段、兼容性如何。
数据变化:是否新增表、字段、索引、枚举值,是否涉及历史数据迁移。
流程变化:正常流程、异常流程、回滚流程、补偿流程。
工程约束:权限、幂等、事务、锁、消息、日志、监控、告警。
验收标准:什么场景下算完成,哪些测试必须通过。
如果这些内容没有先写清楚,Codex 再强也只能根据上下文去猜。猜对了是效率,猜错了就是返工。
OpenSpec 常用指令
OpenSpec 的新流程里,最常用的是下面这些命令:
1 | /opsx:propose # 创建变更并生成规划 artifacts |
还有一些辅助命令:
1 | /opsx:explore # 需求还不清楚时,先讨论和探索 |
对日常开发来说,我最常用的是这条主线:
1 | /opsx:propose add-partial-shipment |
/opsx:propose 会在 openspec/changes/<change-name>/ 下生成变更相关文档。不同配置下 artifacts 可能略有差异,但通常会包含 proposal.md、design.md、tasks.md 和 specs/ 目录。后面的 /opsx:apply 就是按这些文档实现,不是让 AI 凭空写代码。
如果你输入 /opsx:propose 也提示没有命令,通常说明 OpenSpec 没有正确初始化到当前 AI 工具里。可以先检查项目里是否有:
1 | openspec/ |
也可以重新确认是否执行过 openspec init,以及当前工具是否加载了 OpenSpec 生成的 slash commands。
先让 propose 匹配项目
很多人用 /opsx:propose 时只写一句“帮我设计一下”,这样很容易得到一份看起来完整、但和项目完全对不上的文档。正确做法是先让 Codex 读取项目规则,再生成 change artifacts。
我一般会让它先看这些内容:
项目规则:AGENTS.md、README.md、团队开发规范、接口规范。
构建配置:pom.xml、父子模块关系、Spring Boot 版本、依赖版本。
代码结构:src/main/java 下的 controller、service、repository、mapper、domain、dto、vo。
同类功能:已经存在的订单、库存、报表、审批、结算接口。
数据层:MyBatis XML、JPA Entity、Flyway 或 Liquibase 脚本、表结构说明。
测试方式:src/test/java、MockMvc、JUnit、Testcontainers、集成测试脚本。
运行命令:mvn test、mvn -pl xxx test、项目自带的脚本。
把这些信息读完,/opsx:propose 输出的内容才会贴近当前项目,而不是空泛地讲“新增 controller、service、dao”。
一个比较实用的项目匹配提示词是:
1 | /opsx:propose add-partial-shipment |
这段提示词的关键是“先读项目,再生成 artifacts”。如果不加这个约束,AI 很可能会按照通用 Java 项目想象出一套不存在的架构。
例子一:订单支持部分发货
假设需求是“订单支持部分发货”。不要直接让 Codex 改代码,可以先这样用:
1 | /opsx:propose add-partial-shipment |
我希望它生成的 OpenSpec artifacts 至少包括这些内容:
1 | 1. 业务定义 |
这份 change 不是最终代码,但它能让后续实现少走很多弯路。确认 artifacts 没问题以后,再进入实现:
1 | /opsx:apply add-partial-shipment |
实现完成并验证后,再同步和归档:
1 | /opsx:sync add-partial-shipment |
例子二:库存预占和释放
库存类需求更适合先走 /opsx:propose,因为它经常涉及并发和补偿。提示词可以这样写:
1 | /opsx:propose inventory-reservation |
这里我会特别检查 artifacts 是否写清楚三件事:
第一,库存数量字段怎么定义。比如 available_qty、locked_qty、sold_qty 各自代表什么。
第二,状态和消息如何流转。下单预占、支付成功确认、支付超时释放、取消订单释放,每个动作都要有幂等判断。
第三,并发怎么处理。是用数据库条件更新 where available_qty >= ?,还是用版本号乐观锁,还是结合 Redis 锁。不能只写“加锁保证并发安全”这种空话。
例子三:ERP 报表统计
报表需求看起来只是查 SQL,其实最容易变成慢查询。用 /opsx:propose 时可以这样限制:
1 | /opsx:propose supply-chain-fulfillment-report |
这类 spec 必须明确数据口径。比如“履约率”的分母是订单数、订单明细数,还是商品数量;缺货数是下单时缺货,还是发货时缺货;跨天订单归属到下单日期还是发货日期。口径不清楚,代码写得再快也没有意义。
从 spec 进入编码计划
/opsx:propose 生成 artifacts 后,不要马上 /opsx:apply。我更推荐先让 Codex 复核 tasks.md 是否已经能映射到项目内的修改计划:
1 | 请根据 openspec/changes/add-partial-shipment 下的 proposal、design、tasks、specs,先复核实现计划,不要改文件。 |
如果计划里出现项目没有的目录、框架、命名方式,就让它回去重读项目:
1 | 这个计划里出现了项目不存在的 Repository 风格。 |
这个过程看起来多了一步,实际上是在编码前做了一次轻量 review。越是复杂需求,越值得这样做。
我会怎么检查 propose 的输出
一组 OpenSpec artifacts 看起来长,不代表它有用。我一般按下面这个清单检查:
是否引用了真实项目文件:比如具体模块、类名、表名、接口路径,而不是泛泛地说“新增服务层”。
是否区分目标和非目标:这次不做的事情要写出来,避免需求边界无限扩大。
是否有异常流程:库存不足、重复提交、权限不足、状态不允许、下游失败都要覆盖。
是否有幂等设计:尤其是支付、库存、发货、结算、消息消费。
是否有事务边界:哪些操作必须一致,哪些可以异步补偿。
是否有数据兼容:新增字段默认值、历史数据迁移、旧接口响应兼容。
是否有测试和验收:单元测试、集成测试、SQL 解释计划、接口回归都要能落地。
如果这些都没有,说明 spec 还只是“文章”,不是工程规格。
规格驱动开发的常见误区
第一个坑,是把 /opsx:propose 当成魔法命令。它只是帮助整理上下文和规格,不能替代业务判断。关键口径还是要人来确认。
第二个坑,是不让它读项目。没有项目匹配的 spec 往往很漂亮,但落到 Java 工程里会出现错误包名、错误框架、错误事务模型。
第三个坑,是 spec 只写正常流程。真实系统最容易出问题的是异常流程,比如库存不足、重复请求、事务失败、部分写入、消息重复消费。
第四个坑,是 spec 和实现脱节。写完 spec 后,每轮实现都要让 Codex 对照 spec 和 diff,而不是写完一大堆代码再说“差不多”。
第五个坑,是一次 spec 太大。一个大需求可以拆成多个 spec,比如“状态流转 spec”“库存扣减 spec”“发货单 spec”“报表口径 spec”。每个 spec 能独立验收最好。
总结
OpenSpec/OPSX 的价值,是让 Codex 在写 Java 代码前先把需求说清楚,并且说成当前项目能执行的规格。它适合处理订单、库存、结算、权限、报表这类业务边界复杂的需求。
我的使用顺序是:先用 /opsx:propose 生成 change artifacts,再检查它是否匹配项目规则和同类代码,然后用 /opsx:apply 实现,完成后 /opsx:sync 同步规格,最后 /opsx:archive 归档。
当 spec 能清楚描述接口、数据、流程、异常、幂等、事务和验收时,后面的 coding 才会更准确。否则 Codex 只是更快地写出一批可能不符合业务的代码。