你让 Codex “把 auth module 重构到用新的 session API”。四十分钟后它中途停了:PR 改了 8 个文件,另外 6 个动过的文件还留着 // TODO: migrate this 注释。或者 transcript 结尾是 “Context window exceeded” 或 “Maximum tool calls reached”。Codex 干了真活,但中途预算耗尽,你的 branch 现在半新半旧。
这不是 Codex 的 bug——是任务跨的代码量超过了 model context + 它的 tool-call 预算。解药是开工前的范围纪律,加上几个 harness 层面的开关(选 model、把改动拆成多 PR plan、把要改的文件精确列出来)。
常见原因
1. 任务跨的文件太多,context 装不下
你要重构 auth module,30 个文件、8k 行。哪怕 context 有 200k token,Codex 要读每个文件、产生 edit。跑到一半,下一个文件的内容塞不进还在跑的 plan 旁边。
如何判断:transcript 结尾是 context_length_exceeded、Maximum context reached,或者跑了 N 个文件后干脆没下文。
2. Tool-call 预算用光
Codex harness 一般对每个 task 限 tool call 数(常见 50-200)。长 refactor 烧 call 飞快:read_file、apply_patch、再 read_file 验证、run_shell 跑 type check。任务还没做完就撞上限。
如何判断:transcript 结尾是 “tool calls exhausted”,或者明显还有活没干 agent 就不出 action 了。
3. patch 里某个文件巨大
5000 行的 generated 文件(lockfile、SVG、vendored 库)进了 diff。读和写它一次就吞掉一大块预算。
如何判断:git diff --stat 里某个文件改了几千行。或者 agent “卡” 在单个文件上不动。
4. Codex 重复读已经在 context 里的文件
Model 跟丢了它已经加载过什么,对同一个 path 调三次 read_file。每次都吃 token。最后一半 context 是重复的文件内容。
如何判断:transcript 里搜对同一 path 的重复 read_file。老 harness 没 memoization 的多见。
5. 任务太开放(“全部清理一遍”)
你写 “把 auth module 清理一下”。Codex 理解成 “重写 12 个文件”,但你本来只想 “把 auth module 里的 User.uid 全改名成 User.id”。开放任务的范围会一直膨胀直到撞预算。
如何判断:对比你的任务描述和 Codex 实际动的文件。它动了没关系的东西(“既然来了,顺便…”),就是范围没设界。
最短修复路径
Step 1:任务窄到一个动词 + 一个 module
差:「重构 auth module。」
好:「只在 src/auth/*.ts 里,把 User.uid 改名成 User.id。改所有 call site。Test 文件只做机械改名。」
好的 prompt 包含:
- 一个动词:rename、extract、replace、delete、add
- 一个范围:path glob 或文件列表
- 一个 non-goal:“不要碰 X、Y、Z”
# 推荐的 Codex 任务模板
GOAL: <一句话,一个动词>
SCOPE: <显式文件列表或 glob>
NON-GOALS: <哪些不要碰>
ACCEPTANCE: <测试通过 + 1 个具体检查>
Step 2:大改拆成多 PR plan
跨 >10 文件的改动,写 plan 让 Codex 每个 PR 跑一步:
# Auth 迁移 plan
PR 1:新增 `Session` API,和老的 `auth.cookie` 并存(caller 暂不动)
PR 2:迁移 `src/auth/login.ts` 和 `src/auth/logout.ts`
PR 3:迁移 `src/auth/middleware/`(3 个文件)
PR 4:迁移 `src/pages/api/` 的 caller(10 个文件,机械改)
PR 5:删除旧 `auth.cookie`,更新 README
每个 PR 都小到能在一次 Codex run 里塞下。Reviewer 也跟得上。
Step 3:prompt 里预先列出要改的文件
省掉 agent 自己 discover 的步骤:
要改的文件(仅限这些):
- src/auth/session.ts
- src/auth/cookie.ts
- src/auth/middleware/withAuth.ts
- tests/auth/session.test.ts
如果你需要改不在这个列表里的文件,停下来问。
既缩小 working set 又防 scope creep。
Step 4:让 agent 跳过 lockfile 和 generated 文件
AGENTS.md 里写:
## 规划时跳过的文件
除非明确要求,不要完整读这些:
- package-lock.json、pnpm-lock.yaml、yarn.lock
- 超过 200 行的 *.svg
- src/generated/**
- public/**
- *.min.js、*.min.css
要更新 lockfile,跑 `npm install`,不要手动编辑。
这些是预算大户。agent 一行一行读它们永远不值。
Step 5:大任务换大 context model
Codex CLI 之类的 harness 都能挑底层 model。真正跨多文件的任务,换成 harness 里最大 context 的 model:
# Codex CLI 例子
codex --model gpt-5.5 --max-tool-calls 200 "执行 PLAN.md 里的 plan"
harness 允许调高 tool-call 上限的话也调——但要先把范围切好。范围没切的任务,预算越大产生的烂摊子越大。
Step 6:让 Codex 停下来时写 resume note
AGENTS.md 里:
如果你的 context 或 tool call 不够用,停下来之前写一个文件
`.codex/resume.md`,包含:
- 哪些文件做完了
- 哪些文件改了一半(当前状态是什么)
- 哪些文件没动
- 下一个该做的具体动作是什么
把 `.codex/resume.md` 一起 commit 进 PR。
下一次 run 从这个 note 接着干,不用重新 discover 状态。
预防
- 每个任务窄到一个动词 + 一个 module + 显式文件列表
- 跨 >10 文件的改动拆成多 PR plan
AGENTS.md里列出要跳过的 path(lockfile、generated、public asset)- 实在需要大改,用 harness 里最大 context 的 model
- 让 Codex 写
.codex/resume.md以便中断后能续上 - 每次 agent 跑完,diff 一下 file 列表,多动了就把 prompt 收紧