Codex 联动 OpenSpec 提效方法论

一、这套方法解决什么问题

在需求开发中,最容易低效的地方不是写代码,而是:

  • 需求还没想清楚就开始改代码
  • 讨论结论散落在聊天里,后面实现时忘掉
  • Codex 根据不完整上下文"猜实现"
  • 代码改完后才发现老数据、新数据、边界条件没对齐

Codex + OpenSpec 的正确用法,是先把讨论沉淀成可执行的变更文档,再让 Codex 按文档实现。

简单说:

text 复制代码
先讨论清楚 -> 写入 OpenSpec -> 再实现代码 -> 最后归档

OpenSpec 是"需求和设计的锚点",Codex 是"帮你分析、补文档、落代码的执行者"。

二、核心工作流

1. 先用 propose 创建变更

当你有一个新需求或改造点时,先不要直接让 Codex 改代码,而是先创建 OpenSpec change。

示例:

text 复制代码
/opsx:propose batch-download-store-connector-search
RPA 文档列表支持店铺/连接器切换搜索。
连接器搜索最终按 connector_id 查。
RobotReportFileDTO 只有 connectorId,没有 connectorName。
connectorName 需要在落库前通过 connectorId 补齐。
老数据 connector_id / connector_name 允许为空,第一期不回填。

生成后会得到类似目录:

text 复制代码
openspec/changes/batch-download-store-connector-search/
├── proposal.md
├── design.md
├── tasks.md
└── specs/
    └── rpa-documents/
        └── spec.md

这些文件分别负责:

  • proposal.md:说明为什么要做、做什么、不做什么
  • design.md:说明技术方案、关键决策、风险和取舍
  • tasks.md:拆成可执行任务
  • spec.md:沉淀可验证的行为要求

2. 讨论中不断修正 OpenSpec

OpenSpec 不是一次性写完的,它应该随着讨论变准。

比如这次我们讨论连接器搜索时,最开始容易误以为:

text 复制代码
RobotReportFileDTO 和 RobotReportFileParam 都有 connectorId / connectorName

但看代码后发现真实情况是:

text 复制代码
RobotReportFileDTO 有 connectorId,没有 connectorName
RobotReportFileParam 有 connectorId,也有 connectorName

这时就应该让 Codex 修正 OpenSpec:

text 复制代码
把 batch-download-store-connector-search 里的结论修正一下:
RobotReportFileDTO 只有 connectorId,没有 connectorName。
connectorName 需要在 convertFile 前基于 connectorId 补齐。
老数据第一期允许为空,不通过 job_uuid 粗暴反推。

这个动作非常关键。

如果文档不修正,后面 /opsx:apply 时 Codex 可能会按照错误前提实现。

3. 文档确认后再 apply 实现

当你觉得 proposal.mddesign.mdtasks.mdspec.md 已经把需求说清楚了,再开始实现。

示例:

text 复制代码
/opsx:apply batch-download-store-connector-search

这时 Codex 会读取 OpenSpec 里的文档,按任务改代码。

你也可以限制范围:

text 复制代码
/opsx:apply batch-download-store-connector-search
先只实现后端,不动前端。

或者:

text 复制代码
/opsx:apply batch-download-store-connector-search
只做 connector_id / connector_name 落库链路,查询接口下一步再做。

4. 实现后检查和补充

实现过程中,你可以继续追问:

text 复制代码
这个 connectorName 为什么放在 manager 层补?
text 复制代码
老数据 connector_id 为空时会不会被连接器搜索命中?
text 复制代码
帮我 review 这次改动有没有破坏店铺搜索。

如果发现设计还要调整,先回到 OpenSpec 补文档,再继续实现。

三、什么时候用 OpenSpec

适合用 OpenSpec 的场景:

  • 涉及多个文件、多层架构、多端联动
  • 有新老数据兼容问题
  • 有查询语义、边界条件、互斥规则
  • 需要后续别人接手或 review
  • 你担心 Codex 改代码时跑偏

不一定要用 OpenSpec 的场景:

  • 改一个错别字
  • 简单补日志
  • 明确的一行 bug fix
  • 纯粹查代码、解释代码

一个简单判断:

text 复制代码
如果这个改动需要先解释"为什么"和"边界是什么",就先用 OpenSpec。
如果这个改动一句话能说清楚,直接让 Codex 改代码即可。

四、推荐提问模板

1. 创建变更

text 复制代码
/opsx:propose <change-name>
我要做 <功能/改造>。

背景:
- ...

目标:
- ...

非目标:
- ...

关键约束:
- ...

已知边界:
- ...

示例:

text 复制代码
/opsx:propose batch-download-store-connector-search
我要让 RPA 文档列表支持店铺/连接器切换搜索。

背景:
- 当前主表 qymall_robot_report_file 有 store_name
- 当前主表没有 connector_id / connector_name
- RobotReportFileDTO 有 connectorId,没有 connectorName

目标:
- 店铺模式只按 storeName 查
- 连接器模式最终按 connector_id 查
- 列表返回 connectorName

非目标:
- 第一期不回填历史数据
- 不用 job_uuid 粗暴反推历史 connectorId

关键约束:
- connectorName 需要在落库前通过 connectorId 补齐

2. 修正文档

text 复制代码
把 <change-name> 里的 OpenSpec 文档修正一下:
<指出错误前提>
<给出新结论>
<要求同步修改 proposal/design/tasks/spec>

示例:

text 复制代码
把 batch-download-store-connector-search 修正一下:
RobotReportFileDTO 没有 connectorName。
connectorName 不能认为是上游已经传了。
需要在 robotManager.robotReportFile(param) 里、convertFile 前通过 connectorId 查询补齐。
老数据第一期允许为空。

3. 开始实现

text 复制代码
/opsx:apply <change-name>

或者限制范围:

text 复制代码
/opsx:apply <change-name>
只实现后端落库链路,不动前端。

4. 让 Codex 解释实现

text 复制代码
请按链路解释 connectorId 从请求到落库怎么流转。
text 复制代码
请说明 connectorName 为什么要在 convertFile 前补齐。
text 复制代码
请说明老数据为什么第一期不建议回填。

5. 让 Codex 做 review

text 复制代码
review 这次 batch-download-store-connector-search 的改动,重点看:
- 新数据 connectorId 是否能落库
- connectorName 是否能补齐
- 老数据是否会误命中
- 店铺搜索是否被影响

五、一个完整例子:连接器搜索

1. 先讨论事实

先让 Codex 查代码:

text 复制代码
帮我确认 RobotReportFileDTO、RobotReportFileParam、QymallRobotReportFileDO 里有没有 connectorId 和 connectorName。

得到事实:

text 复制代码
RobotReportFileDTO:有 connectorId,没有 connectorName
RobotReportFileParam:有 connectorId,有 connectorName
QymallRobotReportFileDO:当前没有 connectorId / connectorName

2. 再沉淀设计

把事实写进 OpenSpec:

text 复制代码
新数据 connectorId 来自 /robot/reportFile 上报参数。
connectorName 当前不能从 DTO 直接获得。
落库前需要基于 connectorId 查连接器名称并补齐。
老数据 connector_id / connector_name 允许为空。

3. 再实现

实现时的核心链路应该是:

java 复制代码
RobotReportFileDTO robotReportDTO = request.parseReqParam();
RobotReportFileParam param = robotDomainConverter.convert(robotReportDTO);
param.setTenantId(tenantId);
return robotManager.robotReportFile(param);

进入 manager 后:

java 复制代码
fillConnectorName(robotReportFileParam);
QymallRobotReportFileDO robotReportFileDO = robotConverter.convertFile(robotReportFileParam);
reportFileDAO.save(robotReportFileDO);

这里的关键点是:

  • connectorId 由 DTO 转 Param,再转 DO
  • connectorName 需要在 Param 转 DO 前补齐
  • 如果先 convertFile 再补 Param,就晚了

4. 老数据策略

老数据以前没有保存连接器字段,第一期策略应该是:

text 复制代码
允许 connector_id 为空
允许 connector_name 为空
连接器搜索不命中 connector_id 为空的老数据
不通过 job_uuid 粗暴反推连接器归属
历史回填后续单独评估

六、常见误区

误区 1:把 Param 有字段当成 DTO 也有字段

这次我们就遇到了。

RobotReportFileParamconnectorName,不代表 RobotReportFileDTO 也传了 connectorName

正确做法是沿着链路确认:

text 复制代码
DTO -> Param -> DO -> 表字段

每一层都要确认字段是否存在、是否有值、是否会自动映射。

误区 2:只补 DO 字段就以为能落库完整

只给 QymallRobotReportFileDOconnectorName 不够。

如果 Param 里的 connectorName 是空的,MapStruct 也只能映射出空值。

所以要么上游补传,要么后端查表补齐。

误区 3:用 job_uuid 推老数据 connectorId

job_uuid 只能说明任务或计划关系,不能稳定证明某条结果文件来自哪个连接器。

如果一个计划关联多个连接器,强行用 job_uuid 回填会有误命中风险。

误区 4:文档错了还继续 apply

OpenSpec 文档是 Codex 实现时的输入。

如果文档里写错了,Codex 很可能按错的方向实现。

所以讨论中发现结论变化,要先修文档,再实现。

七、你可以怎么和 Codex 配合

比较推荐的协作方式是:

text 复制代码
你负责指出业务事实和疑问。
Codex 负责查代码、找证据、补 OpenSpec、实现代码。

你可以多问这种问题:

  • "这句话有代码依据吗?"
  • "这个字段是从哪里来的?"
  • "老数据会不会受影响?"
  • "这个结论要不要写进 OpenSpec?"
  • "现在是改文档还是改代码?"

这些问题都很有价值,因为它们能阻止需求跑偏。

八、执行前检查清单

/opsx:apply 前,建议检查:

  • proposal.md 是否说清楚为什么做
  • design.md 是否说清楚关键技术决策
  • tasks.md 是否能直接指导实现
  • spec.md 是否覆盖了新数据、老数据、异常场景
  • 是否明确哪些不做
  • 是否明确字段来源
  • 是否明确老数据策略

如果这些都清楚,再让 Codex 实现,效率会高很多。

相关推荐
过期动态1 小时前
【RabbitMQ基础篇】RabbitMQ从入门到实战
java·jvm·数据库·分布式·spring·rabbitmq·intellij-idea
上弦月-编程1 小时前
Java编程:跨平台开发利器
java·开发语言
AI人工智能+电脑小能手1 小时前
【大白话说Java面试题】【Java基础篇】第38题:两个对象的hashCode()相同,则 equals()是否也一定为 true?
java·开发语言·后端·面试·hash-index
java1234_小锋1 小时前
什么是可重入锁ReentrantLock?
java·开发语言
csbysj20201 小时前
XSLFO 区域
开发语言
江南十四行1 小时前
Java并发编程中的锁机制:synchronized与Lock详解
java·开发语言
SamDeepThinking1 小时前
所有的框架源码,最怕的就是被debug
java·后端·程序员
道剑剑非道1 小时前
FFmpeg + Qt 实现摄像头采集与 MP3 背景音乐 RTSP 推流
开发语言·qt·ffmpeg
吴声子夜歌1 小时前
Java——字符编码
java·字符编码·char