Skip to main content

用途

新增功能不是“让 Codex 写几段代码”,而是把一个业务结果安全地放进已有系统。可靠的顺序是:先把需求说成可判定的行为,再读懂项目已有的做法,随后确认接口、数据、错误和兼容性,拆成可验证的小步骤,最后实现、测试、审查和交付。 本页只讲“开发新功能”这一类任务。修复已有故障,重点是复现和根因;重构,重点是行为不变;新增功能,重点是新行为与旧行为同时成立。如果需求还不清楚,先不要让 Codex 修改文件。 本页使用一个具体案例贯穿全文:给已有的任务管理 API 增加“标记任务完成”功能。假设系统已经有任务列表和创建接口,但还没有完成状态。案例中的路径、语言和命令是示意,实际项目必须以仓库里的路由、模型、测试和脚本为准。
本页中的命令、界面文案和参数可能随 Codex 版本变化。请以本机 codex --help、项目说明和官方文档为准。参考资料:参考/codex/14-workflows.md、参考/codex/34-capstone.md、参考/codex/13-prompting.md。

一张流程图

一个完整的新功能任务,可以压缩成下面九个阶段:
每个阶段都应该有看得见的产出。没有产出,就容易从“讨论需求”直接跳到“改代码”,最终只能依靠人工猜测来验收。 原则:先让 Codex 观察和提问,再让它计划,最后才让它编辑。 越是跨文件的功能,越需要先建立上下文,否则代理会把“项目惯例”替换成自己的通用想象。

01 开工前:确认工作区和安全边界

先在正确的仓库根目录操作。不要在生产目录、包含真实客户数据的目录或错误分支中试做功能。
预期输出至少能回答三件事:当前目录确实是目标项目;当前分支适合开发;工作区原本有哪些改动。 如果 git status 已经显示修改,不要让 Codex 顺手覆盖它们。把现有修改记下来,并在提示中明确“保留任务开始前已有改动”。如果当前分支不是任务分支,先按团队流程建立分支或工作副本。

先写非目标

新功能很容易不断扩张。开始前明确本次不做什么,例如:
  • 不重新设计任务列表接口。
  • 不迁移到新的 ORM 或 Web 框架。
  • 不增加第三方依赖。
  • 不改变已有创建和查询接口的响应结构。
  • 不自动批量完成历史任务。
  • 不提交、推送或部署,除非交付阶段明确批准。
非目标为变更画边界。它还能帮助 Codex 在发现“顺便优化”的机会时停下来报告,而不是自行扩大范围。

启动只读探索

探索阶段推荐让 Codex 只读。不同版本的权限选项可能不同,使用当前版本的帮助确认;核心要求是这一轮只允许读取文件、搜索文本和运行低风险检查,不允许编辑。
预期输出不是代码,而是一份依据文件路径的地图。如果 Codex 一开始就提出修改而没有指出它读过什么,先要求它补充证据。

02 需求澄清:把一句话变成可验收行为

“增加标记完成功能”还不是开发需求。它没有说明谁能操作、任务不存在时怎样、重复操作是否幂等、列表是否显示新状态,也没有说明是否需要数据库迁移。 可以用“目标、范围、约束、验证”四件套整理需求:

先确认名词和状态

要求 Codex 把模糊名词列成问题,而不是自行选择实现:
如果业务方尚未决定,可把选项写清楚后再确认。例如“完成”可以是布尔值 completed,也可以是状态枚举 pending/completed/archived。选择应由已有模型、未来状态和查询需求决定,而不是由 Codex 方便与否决定。

案例的澄清结果

经过确认,案例采用以下定义:
  • 已登录用户调用 PATCH /api/tasks/{id}/complete。
  • 只有任务创建者可以操作该任务。
  • 成功返回 200 和更新后的任务。
  • 任务不存在返回 404。
  • 任务属于其他用户时返回 403,不泄露额外敏感信息。
  • 已完成任务再次调用仍返回 200,结果保持已完成,接口幂等。
  • 创建接口继续接受原有请求,默认新任务为未完成。
  • 列表接口在原有字段基础上增加 completed;如果客户端严格校验响应,先检查兼容策略。
  • 不在本次功能中增加“取消完成”、批量操作、通知或筛选参数。
这份结果已经比“加一个完成按钮”更接近可实现的契约,也明确了失败处理,避免实现完成后才争论状态码。

把验收写成是或否

好的验收标准能由测试、命令或人工步骤给出明确答案:

03 探索现有模式:复用,不发明平行体系

新增功能最常见的返工原因,不是语法错误,而是没有遵循已有项目模式:重复造一个认证中间件、使用另一种错误格式、绕过服务层直接写数据库,或用新库解决已有工具能解决的问题。

推荐的探索顺序

按“从面到线”的顺序阅读:
  1. 读 README、AGENTS.md、包配置和测试脚本,确认运行方式与硬性约定。
  2. 找任务资源的路由、控制器、服务、模型、迁移和测试文件。
  3. 找一个已有的“更新资源”或“权限检查”功能,逐层追踪调用链。
  4. 找同类错误响应、事务处理、日志和测试夹具。
  5. 读相关提交历史或注释,确认某些看似奇怪的兼容逻辑是否有原因。
可直接交给 Codex 的只读提示:

如何判断“复用”是对的

看到一个相似函数,不要只按名字复制。检查四个维度: 如果项目已经有 update_task,完成接口可能应调用同一个服务方法,而不是再写一套 SQL。若现有服务只支持允许字段白名单,就把 completed 纳入白名单并补测试;不要在控制器里绕过它。

预期的探索报告

如果输出只有“我会创建路由、模型和测试”,说明它还没有完成探索,应继续追问。

04 接口设计:先定契约,再接实现

接口是客户端、服务端和测试之间的共同边界。先写出请求、响应、状态码和错误格式,能减少“后端完成了但客户端接不上”的返工。

案例接口契约

本例不需要请求体。如果项目约定所有 PATCH 必须带 JSON,也应使用空对象 {},并遵循已有约定,不要自行另创形式。 成功响应示例:
错误响应应与项目既有格式一致。若项目使用以下结构,案例可以这样表达:

接口设计检查表

  • HTTP 方法是否符合项目惯例。
  • 路径参数的类型和非法值如何处理。
  • 是否需要请求体;空体和缺字段是否有不同含义。
  • 成功状态码是否与同类更新接口一致。
  • 错误响应是否包含稳定的机器可读错误码。
  • 是否会暴露资源存在性或其他敏感信息。
  • 重试是否安全,重复请求是否幂等。
  • 是否需要权限、限流、审计日志或事务。
不要让 Codex 用“行业惯例”替代项目证据。提示中应写“对照现有更新接口保持一致”,并要求它指出参考文件。

05 数据设计:默认值、迁移和旧数据

新增功能经常意味着新增字段或表。数据设计不能只看新代码能否编译,还要回答旧记录、部署顺序和回滚问题。

案例的数据变更

任务表增加 completed 字段,旧记录默认 false。设计时确认:
  • 字段类型是布尔值还是项目既有状态枚举。
  • 数据库默认值和应用层默认值是否都需要。
  • 旧数据迁移是一次完成,还是需要分阶段。
  • 字段是否允许为空;如果允许,业务层如何解释 null。
  • 是否需要索引;完成状态是否用于高频筛选。
  • ORM 模型序列化是否会自动暴露该字段。
  • 回滚迁移会不会丢失已写入的数据。
推荐提示:

向后兼容的迁移顺序

对已有线上数据,常见顺序是:
  1. 先增加可选或带默认值的字段,让旧版本程序仍能读取。
  2. 发布能写入新字段、同时兼容旧记录的应用版本。
  3. 回填历史数据,并监控失败记录。
  4. 确认所有读取路径不再依赖空值后,再收紧约束。
实际顺序必须结合数据库和部署系统。不要让 Codex 擅自执行生产迁移;它可以生成迁移和本地验证命令,但执行生产变更需要单独审批、备份和回滚方案。

数据层失败处理

如果“更新成功响应”发出前数据库写入失败,应该返回项目规定的 5xx 错误,不要返回成功。若写入包含多个表,使用已有事务边界;没有事务时,先要求 Codex 说明部分成功如何恢复。 预期的失败测试至少包括数据库约束失败、并发更新(如果系统支持并发)、迁移后读取旧记录。不要只测试内存对象被改成 true。

06 错误处理:把失败当成产品行为

新功能的质量主要体现在失败路径。让 Codex 先画错误表,再实现:

错误分类

输入错误:任务 ID 不是合法格式、请求体字段类型错误。应尽早返回,不能访问不必要的数据,也不能产生写入。 身份错误:没有凭据、凭据过期或用户不存在。沿用认证中间件的状态码和结构,不在功能路由中重复解析令牌。 权限错误:用户已登录但不是任务所有者。调用既有策略函数;不要只在前端隐藏按钮。 资源错误:任务不存在。确认项目对“查询不到”和“无权访问”的信息披露策略,避免通过响应差异泄露敏感信息。 依赖错误:数据库、队列或外部服务暂时失败。遵循项目的超时、重试和日志约定;不要让客户端重复请求造成非幂等副作用。

错误处理的反例

这种写法把所有错误压成一个结果,丢失状态码、错误码和日志上下文,也可能掩盖编程错误。应复用项目的异常类型和错误转换层,让不同失败保持可诊断。

失败时的代理行为

如果 Codex 报告“测试通过”但没有命令、退出码或测试数量,要求它补充证据。没有证据的“通过”只是摘要,不是验收结果。

07 分步计划:每一步都能审、能测、能回滚

跨文件功能不应一次性实现。先用 /plan 或普通提示要求计划;是否使用具体命令取决于本机版本。

案例计划

计划要足够具体,但不必把每一行代码都预先决定。实现中如果发现已有模式与假设不同,应暂停并更新计划,而不是悄悄扩大改动。

什么时候需要重新规划

  • 发现状态字段其实由事件表驱动。
  • 权限策略不允许按任务所有者判断。
  • 旧客户端会因新增响应字段失败。
  • 数据迁移需要停机或分阶段发布。
  • 一个接口需要同时改动公共 SDK、后台任务和文档。
这些是需求边界发生变化的信号。让 Codex 报告影响范围,并由你确认新方案。

08 先写契约和测试:给新行为上锁

测试不是实现之后的装饰。先写测试可以固定需求,也能让 Codex 在实现中自我验证。测试应遵循项目已有测试框架、夹具、命名和数据库清理方式。

测试矩阵

先让测试失败

在功能尚未实现时,允许契约测试先失败,但要确认失败原因是“路由或字段尚不存在”,而不是测试环境坏了。失败测试应具有明确的预期:
如果 Codex 提议通过放宽断言、跳过测试或把测试改成“只要不是 500 就算成功”,应拒绝。测试必须锁定业务行为,而不是迎合当前实现。

09 实现:从数据层到入口逐步接线

实现顺序应服从项目架构。常见顺序是数据模型和迁移、业务服务、路由控制器、序列化和文档;有些项目先由接口契约驱动,按已有模式调整即可。

第一步:数据和模型

让 Codex 只完成数据层,并立即运行数据层测试。检查:
  • 新字段默认值是否覆盖旧记录。
  • ORM 的创建和更新白名单是否同步。
  • 序列化字段名是否与 API 契约一致。
  • 迁移是否可重复执行或由工具正确标记。
  • 回滚迁移是否有明确的数据损失说明。
预期结果:旧的创建和查询测试仍通过,模型可以保存和读取 completed。

第二步:业务服务

服务层负责业务规则,不应依赖 HTTP 请求对象。它应接收用户身份和任务 ID,执行资源查找、权限判断、幂等更新,并返回项目规定的结果或异常。
预期结果:服务层测试覆盖所有者、重复操作、其他用户、不存在任务和数据库失败。

第三步:路由和响应

路由只负责解析参数、调用认证和服务、转换响应。检查它是否错误地把权限判断移到了控制器,是否把异常吞掉,是否返回了与其他接口不同的 JSON 结构。 预期成功输出:
预期失败输出:
实际字段和消息必须服从项目现有格式。示例中的“预期”是行为说明,不是要求复制文本。

第四步:客户端或界面

如果项目包含前端,再接按钮、状态展示和加载错误。界面按钮不是权限边界;即使按钮被隐藏,服务端仍必须拒绝越权请求。 检查三种状态:
  • 成功后按钮、标签和列表状态同步更新。
  • 请求进行中禁止重复提交或明确显示处理中。
  • 401、403、404 和 5xx 显示符合产品约定的消息,并保留重试入口或刷新路径。
如果 UI 需要新增 API 字段,先确认类型定义、客户端缓存和 mock 响应同步更新。不要只改界面让类型检查失去意义。

10 跨文件变更:维护影响清单

跨文件很正常,但“跨文件”不等于“可以随便改”。维护影响清单,逐项说明为什么要改: 要求 Codex 在每次阶段结束时汇报:
如果出现未计划的新文件,先问“为什么需要它”。尤其注意临时脚本、生成物、锁文件和配置文件是否真的属于交付。

11 兼容性:新功能不能破坏旧用户

兼容性检查要覆盖接口、数据、客户端和部署,而不只是“旧测试全绿”。

API 兼容

  • 旧请求是否仍被接受。
  • 旧响应字段和类型是否保持不变。
  • 新增字段是否会让严格解析客户端失败。
  • 状态码是否改变了已有错误语义。
  • 是否需要版本化路径或能力协商。

数据兼容

  • 旧记录读取是否安全。
  • 新旧应用版本短暂并存时是否互相可用。
  • 回滚应用后,新字段写入如何处理。
  • 数据库迁移失败时是否有停止条件和恢复步骤。

行为兼容

  • 默认新任务仍是未完成。
  • 列表排序和分页不因新增字段改变。
  • 权限边界与既有更新操作一致。
  • 重试不会生成重复事件、通知或审计记录。

12 验证:从小到大运行检查

按成本和反馈速度从小到大:
  1. 格式化和静态检查。
  2. 新增服务或组件的单元测试。
  3. 路由或 API 集成测试。
  4. 相关模块回归测试。
  5. 类型检查和生成代码检查。
  6. 全量测试和构建。
  7. 必要时在临时环境做人工接口或 UI 验证。

预期验证报告

数量和格式会随项目变化。关键是报告可复核,且没有把“没有运行”写成“通过”。

验证失败怎么办

测试失败:保留完整错误、定位到断言或堆栈,判断是实现错误、测试夹具错误还是环境问题。实现错误应修代码;测试假设错误要先说明并确认;环境问题要给出重现命令。 类型失败:先检查公共类型、序列化和 mock 是否同步,不要直接加 any 或关闭严格检查。 构建失败:确认生成步骤、依赖和环境版本。未经确认不要升级依赖或改锁文件。 迁移失败:停止应用层扩大改动,保存数据库错误和迁移状态,按项目回滚文档处理。不要手工删除迁移记录。 接口手测失败:记录请求、响应码、响应体和服务端日志关联 ID;不要只说“按钮没反应”。

13 Diff 审查:看代码之外的变化

测试全绿仍需审查 diff。Codex 可以帮忙总结,但最终要自己查看实际差异:
重点审查:
  • 是否只修改了计划中的文件。
  • 是否出现无关格式化、重命名或依赖升级。
  • 是否把密钥、令牌、真实数据或本地路径写入文件。
  • 错误路径是否真的没有写入。
  • 权限检查是否在服务端执行。
  • 重复请求是否幂等。
  • 迁移默认值是否覆盖旧数据。
  • 测试是否测试行为,而不是只测试 mock 被调用。
  • 公共接口的响应、类型和文档是否一致。
  • 日志是否包含足够上下文但没有敏感信息。
预期审查输出应区分“必须修复”和“可后续改进”。不要因为审查报告很长就自动接受,也不要因为没有报告就认为没有风险。

14 交付:让别人能运行、审查和恢复

交付不是一句“已完成”。应提供足够信息,让接手者知道改了什么、怎么验证、怎样发布和怎样回滚。

提交边界

默认让 Codex 停在交付摘要,不自动提交、推送或部署。若团队允许提交,也要先看 git status 和 git diff,再确认暂存范围与提交信息。提交前检查是否混入任务开始前已有改动。
如果明确授权提交,仍应只暂存相关文件;如果授权发布,先确认目标环境、迁移顺序、监控指标和回滚开关。生产操作需要单独审批和凭据管理,不能把本地测试通过当成发布授权。

15 完整案例:从“加个完成按钮”到交付

下面把前面的步骤合成一段可以改写后使用的任务提示。它不是让 Codex 跳过探索,而是把目标和边界写清楚。

案例的阶段性预期输出

探索阶段:列出任务路由、更新服务、权限策略、模型、迁移和测试夹具,并指出复用哪个现有更新操作。若无法确认响应兼容性,列为问题。 计划阶段:至少包含迁移、服务、路由和测试四个边界,每步有可执行验证。计划不应出现“重写整个任务模块”之类无边界描述。 实现阶段:测试从“路由不存在”或“字段不存在”失败,到正确行为通过;旧测试不应无理由变化。每一阶段的 diff 文件都与计划相符。 最终阶段:成功请求得到 200 和 completed=true;不存在、无权、未登录分别得到稳定错误;重复请求不会产生重复副作用;全量检查通过。

案例的失败处理

如果迁移工具不允许安全默认值,停止实现路由,先补迁移方案和旧数据策略。 如果列表接口的严格客户端因新增字段失败,停止前端接线,确认是否要版本化、使用已有扩展字段机制,或先更新客户端。 如果权限测试显示“其他用户”能完成任务,优先修服务层权限边界,不要只禁用前端按钮。 如果重复请求创建了两条完成事件,保留失败测试,检查幂等键、状态转换和事务边界;不要把第二次请求简单改成静默返回而不确认副作用语义。 如果全量构建失败但相关测试通过,按构建错误定位类型、生成文件或打包入口;不能以“功能测试通过”交付一个无法构建的版本。 如果发现代理修改了计划外的配置、锁文件或其他模块,先停止,查看完整 diff,说明每项是否必要;不要覆盖任务开始前已有的用户修改。

16 可复用提示词模板

需求澄清模板

现有模式探索模板

计划模板

实现模板

最终审查模板

17 常见失误与纠正

18 小结

开发新功能的核心不是提示词更长,而是每一步都减少一个未验证的假设:
  1. 用目标、范围、约束、验证把需求变成可判定行为。
  2. 先读项目规则和相似功能,复用入口、权限、错误、数据和测试模式。
  3. 在实现前确定接口契约、状态、默认值、迁移、失败处理和幂等语义。
  4. 把跨文件任务拆成每步有文件、有命令、有预期输出和回滚点的计划。
  5. 先用测试固定正常路径、边界路径、权限路径、持久化和旧行为。
  6. 从数据层到服务、路由、客户端逐步接线,每步都检查 diff 和验证结果。
  7. 用兼容性清单审查旧请求、旧数据、并存版本和回滚影响。
  8. 交付时给出变更、接口、测试、未验证项、风险和回滚,而不是只说“完成”。
可以把整页压缩成一句工作指令:先问清要做成什么,再证明项目通常怎么做;先定契约和失败行为,再分步实现;先看证据和测试,再交付。 下一页 05-重构与补测试 会转向“行为不变”的改造任务;完成新功能后,如果发现重复逻辑或测试薄弱,再用重构流程处理,不要把两类目标混在同一次无边界修改里。