当 Codex 从生成零散代码转向直接修改项目时,模糊的任务描述会迅速放大风险:改动可能越界,测试虽然通过,实际行为却未必符合预期。要稳定处理复杂任务,关键是先定义清晰的完成状态、修改边界和验证依据,让编码代理能够在执行过程中判断每一步是否达标。
用 Codex 一段时间之后,很多人会撞上同一个瓶颈:简单任务很好用,稍微复杂一点就开始跑偏——改了不该改的文件、顺手引入新依赖、把测试改绿了但行为变了、最后给出一个几百行的 diff 没法 review。
于是得出一个结论:这东西只适合写小脚本。
但把跑偏的几次任务翻出来看,原因往往不在模型,而在任务描述。编码代理的工作方式是固定的:读你给的上下文 → 规划 → 改文件 → 跑命令 → 看结果 → 继续改。它每一步都依赖你给的信息。信息越模糊,它就越要自己补全,而补全出来的东西大概率不是你要的。
所以使用 Codex 的核心能力,不是"会写提示词",而是会写规格:把一件事写成"完成时是什么样子、允许动哪些文件、不许做什么、用什么证明做完了"。
这篇文章拆解一套可以直接抄用的任务规格模板,以及它在多轮任务、长任务和 review 阶段的具体用法。

先区分两种期待。
一种是"给我一段能用的代码":把需求描述清楚,等它输出,复制到项目里,自己调试。这种用法在写工具函数、处理脚本时没问题,但它把验证成本留给了你。
另一种是"给我一个可验收的变更":它进入仓库、读相关文件、改代码、跑测试、把结果汇报成一份可以检查的交付。你验收的是结果,不是代码片段。
第二种用法才是代理式工具的价值所在,而它有一个硬性前提:你得能让它自己判断做对没有。
这个判断依据很少是"我觉得写得不错",而是一个具体的东西——一条能跑的命令、一个能复现的用例、一份能对比的基线。任务描述里没有这个东西,它就只能靠猜。
模糊的目标是跑偏的第一来源:
帮我优化一下订单模块的性能。
"优化"没有验收标准。它可以改缓存、改索引、改并发、重写查询、甚至顺手把目录结构也整理一遍,最后你面对一个巨大的 diff,很难判断哪些是必要的。
把目标改成"完成时的可观察状态":
目标:
订单列表接口 P95 响应时间从 800ms 降到 300ms 以内,
且返回结果与优化前完全一致。
这句话把三件事钉死了:改什么、改到什么程度、什么不能变。
一个可用的判断标准是:如果这个目标无法被写成一个断言,它就还不是目标。"响应时间 < 300ms"可以断言,"性能更好"不行。
编码代理最容易引发争议的地方,是它顺手改了范围外的东西。加个参数体验一下,顺手升级了依赖;改一个函数,顺手统一了整个模块的命名风格。每一次"顺手"都让 review 变难。
所以在任务里显式写出边界:
范围:
允许修改:
- src/orders/service.py
- src/orders/repository.py
- tests/test_orders.py
不要修改:
- 公开 API 的请求/响应结构
- 数据库表结构
- 其它模块
- 依赖清单
范围写清楚之后,还有一个额外好处:diff 的大小会自己收敛。当它知道只能在三个文件里动手,就不会去做大规模重构。
如果确实需要它先了解全局,就分两轮:第一轮只读不写,让它输出一份代码地图;第二轮再限定范围修改。第一轮的任务可以这样写:
先不要修改任何文件。
请阅读订单相关的代码和测试,输出:
1. 请求入口在哪个文件、哪个函数;
2. 业务逻辑分布在哪几处;
3. 数据库写入位置;
4. 现有的异常处理方式;
5. 相关测试文件;
6. 你认为风险最高的三处代码,并说明原因。
每条结论给出文件路径和函数名。
约束是任务描述里最容易被忽略、也最值钱的部分。它对应的是工程里的隐性知识,你不写,它不知道。
常见的约束值得固化成一段常驻文本:
约束:
- 不新增第三方依赖,需要新库先说明理由;
- 不修改公开接口签名;
- 不改动现有测试的断言,除非明确说明原因;
- 保持与现有代码相同的错误处理风格;
- 不做与本次目标无关的重构、格式化、重命名;
- 涉及数据库变更时,必须先给出迁移方案再执行。
这几条看起来琐碎,但它们把"什么算越界"定义清楚了。没有这段约束,代理会按"最优解"行事;有了约束,它会按"你团队的解"行事。这两者经常完全不同。
最后一块拼图,是让它自己验证。
验收:
1. 先写一个能复现问题的失败测试,运行并贴出失败输出;
2. 做最小修复;
3. 运行:
pytest tests/test_orders.py -q
4. 运行完整测试套件,确认没有回归:
pytest -q
5. 最后汇报:修改了哪些文件、每条命令的实际输出、遗留风险。
两个细节值得注意。
第一,先失败,再修复。要求它先给出失败用例,等于要求它证明"问题真的存在"。很多"修复"失败的原因是问题被理解错了,而一个写不出来的失败用例会立刻暴露这一点。
第二,要求贴出真实输出,而不是结论。"测试通过"是一句断言,"12 passed in 3.42s"才是证据。要求原文输出,能过滤掉相当一部分幻觉。
把四个要素拼起来,就是一份可以直接复制使用的任务模板:
目标:
<完成时的可观察状态,可断言>
背景:
<相关文件、涉及模块、相关历史决策>
范围:
允许修改:<文件列表>
不要修改:<文件/接口/结构>
约束:
- <不允许做的事>
验收:
1. <证明问题存在的命令或测试>
2. <修改后要跑的命令>
3. <回归验证命令>
4. 汇报格式:修改文件、命令输出、遗留风险
第一次写会觉得啰嗦。但对比一下成本:写这 20 行大概两分钟,而一次跑偏的修改,你要花二十分钟去分辨哪些 diff 是必要的。写规格是省时间的做法。

除了写规格,第二个决定质量的变量是上下文。
常见误区是"给得越多越好"——把整个仓库丢进去。实际上无关文件会稀释注意力,还会让它产生错误的联想:看到别的模块有某种模式,就以为这里也该那样写。
推荐的做法是按任务类型给最小充分上下文:
| 任务类型 | 需要给的文件 |
|---|---|
| 修 bug | 报错栈涉及的函数 + 相关测试 |
| 加功能 | 同类功能的一个完整实现 + 接口定义 |
| 重构 | 目标模块全部文件 + 调用方列表 |
| 改测试 | 被测函数 + 测试文件 + fixture 定义 |
| 排查 CI | 失败日志 + 相关测试 + 依赖清单 |
还有一条经验:让它自己去找文件,比你替它贴文件更好。给它一条线索("订单创建逻辑在 src/orders 下"),让它自己定位,它建立的上下文通常更准确——因为路径是它自己验证过的。
一个任务涉及超过三个文件、或者需要多轮修改时,直接一次做完风险很高。更稳的做法是固定拆成三段,每段单独验收:
第一段(只读):
分析问题,输出根因假设和修改方案,不写代码。
第二段(只写):
按确认的方案做最小修改,跑相关测试,贴出输出。
第三段(只验):
跑完整测试套件,检查 diff 是否只包含方案内改动,
给出回归风险和回滚方式。
三段式的价值在于它把"分析错了"和"改错了"这两类问题分开暴露。一次性任务里,这两种错误会混在一个巨大的 diff 里,很难定位。
如果任务确实很长,还可以在第二段内部再拆:先改数据层,跑测试;再改业务层,跑测试;最后改接口层。每完成一小步就跑一次测试,比全部改完再跑要快得多——因为出问题时你知道是刚改的那一步引起的。

代理给出的 diff,检查顺序建议固定下来,避免被无关细节带走注意力:
1. 范围:改动文件是否都在允许列表内?
2. 语义:行为变化是否符合目标?有没有顺带改变别的行为?
3. 边界:异常路径、空值、并发、超时是否被处理?
4. 测试:新增测试是否真的会在旧代码上失败?
第四点最容易被跳过,但它是判断"测试有没有意义"的唯一方法。**一个在修复前也能通过的测试,等于没有测试。**验证方式很简单:让它解释这个测试为什么在修复前会失败;说不清楚,就要求重写。
把上面这套方法用起来之后,会有一个明显的变化:任务跑偏的次数下降,单次任务处理的范围变大。以前只敢让它改一个函数,现在可以放心让它处理一个模块的重构加测试补全。
这个变化会带来一个新的现实问题——使用强度上去了。
当 Codex 只用来写零散脚本时,用量是波动的;但当它进入日常流程,成为接手项目、修 bug、补测试、审查 diff 的常规工具之后,用量会变得稳定且持续:任务更长、涉及文件更多、多轮迭代更频繁。这时候最容易出现的不是"不够聪明",而是在任务中途被打断——上下文断了,前面的分析要重来一遍,那才是最消耗时间的部分。
所以判断自己该用哪个档位,比较靠谱的方式不是看套餐介绍,而是记录一周真实使用情况:
日期 | 任务数 | 长任务数 | Review 次数 | 主要仓库
周一 | 12 | 3 | 4 | backend/frontend
周二 | 9 | 2 | 3 | backend
周三 | 15 | 5 | 6 | backend/infra
一周以后看两件事:任务是否已经贯穿大部分开发时间;长任务是否频繁中断。如果两条都成立,说明你需要的不是"更会写提示词",而是减少高频开发过程中的中断——这才是更高用量档位真正解决的问题。反过来,如果一周只启动两三次,那先把任务描述和拆分练熟,收益比换档位大得多。
如果你正在了解 Pro 的开通方式与套餐选择,可以参考 gptupcn.com,具体权益、价格与功能范围请以官方页面为准。本文只讨论 Codex 的使用方法,不涉及共享账号、代充或账号交易。