1. 为什么 Codex 子代理这么费额度
众所周知,Codex 的子代理调度极其辣鸡,而且 GPT 非常喜欢过度工程化,再加上发布 Astra 后额度大幅降低。这就导致调用子代理时,你会花好几倍的 Token,效率提升却非常有限。
最近仔细研究了下,发现 Codex 其实还是可以抢救一下的。消耗了20多个20x的周限,最后发现 Codex 的低效主要有3个原因:
- 默认配置不合理,比如默认派发子代理时会带上主对话全部上下文,即
fork_turns默认为"all";不主动指定模型和思考强度,还可能直接继承主对话的配置。子代理角色提示词里写死的模型和思考强度,也会覆盖主对话派发时的选择。 - 任务派发不合理,主对话喜欢只派发阶段性任务。这样就导致一个任务要派发好几次,浪费时间的同时产出大量乱七八糟的中间文件。此外,子代理完成后,主对话可能不信任,喜欢重复验证,尤其喜欢算哈希值。
- 通讯机制不合理。主代理喜欢疯狂轮询子代理进度,而子代理喜欢屁大点事都向主对话汇报。明明可以像 Claude Code 那样静默等子代理发消息回来。而且主对话耐心很差,喜欢催促,甚至直接自己又去干一遍,花你2倍+的额度。
好在这些问题基本可以优化。另外,如果有 Pro 订阅,也可以让 Codex 通过浏览器调用 6 Pro,负责规划和审查,从而节约大量额度。经过对工作流和规范的优化,实测能在提升效率的同时大约节约50%的额度。
2. 分析和解决
2.1 优化子代理配置
优化默认配置和规范,让主对话每次主动指定模型和思考强度。
经过大量对比,个人认为子代理值得用的只有2套:
| 模型 | 默认思考强度 | 结果不好返工时自动增加 |
|---|---|---|
| gpt-6-astra | low | medium → high |
| gpt-5.6-sol | high | xhigh → max |
如果你搭配了后面提到的 6 Pro 规划和复核,那么子代理建议用 5.6-sol high。
主对话建议用 Astra xhigh。不要用 Astra medium 或者 Astra low,实测会更加耗额度。猜测是因为 medium 和 low 运行太快了,用作主对话,就会极大增加触发问题2和3的频率(即更加疯狂的轮询)。
项目的 .codex/config.toml 可以先设一个默认值:
[agents]
default_subagent_model = "gpt-5.6-sol"
default_subagent_reasoning_effort = "high"
实际上,按本方法每次显式指定模型和思考强度的话,这两个默认值不会被实际采用。因为模型和思考强度的配置优先级为:
自定义角色文件中的配置 > 派发时显式传入的参数 > [agents] 中的默认配置 > 主对话的配置。
所以,想让主对话每次主动选择模型和思考,就不能在角色文件里写死 model 和 model_reasoning_effort。
然后在主对话规则里要求:每次派发都明确传模型和思考强度,禁止继承主对话上下文。
如果你的 AI 听话,那么它派发的子代理大概是这样(我这里的 spawn_agent 派发参数):
{
"task_name": "implement_feature",
"agent_type": "project_implement",
"model": "gpt-5.6-sol",
"reasoning_effort": "high",
"fork_turns": "none",
"message": "完成分配的功能,包括调查、实现、测试、修正和交付。任务要求、工作目录及必要材料见本次派发说明。"
}
其中 project_implement 是自定义的子代理角色。Codex 内置了三个:default(通用)、worker(执行和修复)、explorer(探索)。我使用的 Trellis 内置了另外3个:trellis-research(调研)、trellis-implement(实现)、trellis-check(检查)。
fork_turns 这个参数尤其要注意。 Codex 默认是 "all",即继承主对话上下文,同时强制继承主对话的模型和思考强度。这个参数必须改成 "none",只给子代理必要的任务说明和文件位置。
但是很遗憾,就算你把这个规定写入 AGENTS.md,AI 也经常不遵守(原因未知,可能子代理派发相关有内置提示词),依然派出 "fork_turns": "all"。我的方案是用 hook 做了个门禁,检测到 "fork_turns": "all" 就拒绝派发。
2.2 优化任务派发
主对话只当项目经理,不处理具体事务。主对话应该给子代理派发完整任务。
这样可以减少大量的重复工作和无效通讯。比如派发时应该规定:
- 最后要得到什么;
- 当前代码和输入材料在哪里;
- 改动范围,哪些是其它代理正在做的;
- 要做哪些必要检查;
- 中途不要汇报,除非遇到阻碍。
然后让它自己选具体做法,自己跑命令,自己等结果。主对话只负责协调子代理,处理阻碍和最后集成。
子代理需要调用 Pro 模型,也应该由它自己调用和回收。实测目前子代理无法调用内置浏览器,需要让它调用 Chrome,从而使用 Web 的 Pro 模型。
对主对话,还应该规定:
主对话应该信任子代理,收到交付后,不要重复测试一遍。只看测试结果,处理集成带来的新问题即可。不要把已经跑过的命令重跑,尤其不要给每个文件都算一遍哈希。
**充分利用子代理上下文处理相关的任务。**对于类似的问题,由于它已经读过代码、知道之前怎么改,让这个子代理继续执行比新开一个会更省 Token。但独立审查时必须开新的子代理。
2.3 降低无效通讯
主代理喜欢疯狂轮询子代理进度,而子代理喜欢屁大点事都向主对话汇报。这2个问题会增加非常多的 Token 消耗。
每次查进度、发消息,都会带来工具调用和模型响应。明明只用在任务结束时发一次消息就行,高频轮询进度纯属浪费。
而且子代理一汇报,主对话就容易开始看文件、检查结果、追加要求,甚至自己上手。子代理还没做完,主对话已经重复干了一遍。
所以对子代理应该规定:
子代理只在实际阻塞、需要决定、影响其它任务时主动发消息。普通进度禁止逐条报告,禁止收到消息后回复“收到”。
对主对话,还应该规定:
禁止连续轮询子代理进度,可先进行下个目标的准备,或者按以下时间间隔等待:1 → 2 → 4 → 8 → 16分钟,之后保持16分钟。
2.4 优化效果
以我最近实测的数据为例,一般我的每个对话都运行10到30个小时(用完一个20x的周限)。
- A组:优化了子代理配置,同时使用网页Pro规划和复核;
- B组:进一步优化了任务派发和无效通讯。
按说还应该加一个无任何优化的对照组,但实在不想浪费额度去测试。
由于运行时间和子代理数量不同,所以分别按主对话每小时、平均单个子代理每小时计算。
主对话每小时
| 指标 | A组 | B组 |
|---|---|---|
| 总 Token | 32.289 | 20.002 |
| 缓存输入 Token | 31.400 | 19.334 |
| 非缓存输入 Token | 0.803 | 0.597 |
| 输出 Token | 0.086 | 0.072 |
| 模型响应次数 | 206.03 | 119.72 |
| 主动发送消息次数 | 23.00 | 6.63 |
| 追加任务次数 | 1.83 | 0.19 |
| 查询代理列表次数 | 1.83 | 1.36 |
| 上下文压缩次数 | 2.47 | 1.95 |
| 浏览器操作次数 | 42.98 | 17.74 |
Token 单位为百万,次数为按小时平均值。
平均单个子代理每小时
| 指标 | A组 | B组 |
|---|---|---|
| 总 Token | 36.636 | 29.594 |
| 缓存输入 Token | 35.859 | 28.996 |
| 非缓存输入 Token | 0.669 | 0.526 |
| 输出 Token | 0.108 | 0.072 |
| 模型响应次数 | 255.00 | 193.34 |
| 主动发送消息次数 | 11.16 | 6.39 |
| 查询代理列表次数 | 0.92 | 0.38 |
| 上下文压缩次数 | 2.38 | 2.04 |
| 浏览器操作次数 | 0.00 | 34.11 |
主对话每小时 Token 降了约38.1%,单个子代理降了约19.2%(实际差距应该更大,因为测试中的B同时开的子代理更多,所以主对话 Token 应该更多)。
按运行24小时,平均同时开3个子代理估算:
| 指标 | A组 | B组 |
|---|---|---|
| 总 Token | 34.13亿 | 26.11亿 |
| 非缓存输入 Token | 6,748万 | 5,222万 |
| 输出 Token | 982万 | 692万 |
| 模型响应次数 | 23,305 | 16,794 |
| 主动发送消息次数 | 1,356 | 619 |
总 Token 降低约23.5%,模型响应次数减少约27.9%。注意,A的结果已经是优化了配置之后的,如果B跟Codex默认配置比,估计能降低超过50%。
此外,A的浏览器操作都由主对话进行,且子代理之间几乎没有消息,子代理之间的协调几乎都由主对话进行。而B的浏览器操作主要由每个子代理各自调用。B的子代理之间有79条消息(大部分主动发送的消息都是向其他子代理发的)。显然,无论是工具调用,还是通讯交互,昂贵的Astra主对话参与越少,就会越省额度。
2.5 优化方案
本质上这属于提示词工程,但把正确的提示词在正确的时间注入正确的对话并不简单。
目前我是自己维护了简化版本的 Trellis,通过 hook、skill、规范和工作流,让以上策略在全局和特定项目中发挥作用。相信大家都有自己的一套 spec 管理系统,因此给出关键要点供大家参考:
- 每次派发必须显式指定模型和思考强度,禁止继承主对话全部上下文。必须使用
fork_turns: "none",建议加个门禁检查。 - 重写子代理的角色提示词,让子代理负责完整任务,自行完成调查、实现、测试、修正,以及外部工具调用和结果回收。不要屁大点事就跟主对话汇报,需要子代理间协调时,先找其他子代理。
- 主代理派发时,把目标、输入、工作目录和交付要求给清楚。主对话核对关键结果并集成,不重复已经完成的调查和整轮验证,不增加乱七八糟的哈希和额外门禁。
- 子代理只在实际阻塞、需要共同决定或影响其它任务时发消息。主对话耐心点,不催促、不反复查询,有依赖的子代理直接沟通。
- **优先等完成通知。**需要轮询时,子代理按1、2、4、8、16分钟递增,长命令按2、4、8、16、30分钟递增,达到上限后保持。
- 同一任务的延续优先复用原代理,中断后优先恢复已有成果,禁止主对话因为等不及就重复执行。
3. 通过浏览器调用 Pro 模型
有 Pro 订阅的,建议把每周的200次 6 Pro 用完。
大概的实现方案是:在 Chrome 和 Codex 内置浏览器登录网页 GPT,然后通过规范让它自己发问题、上传材料、等待和回收。更进一步,由于网页 GPT 连接 GitHub 插件后可以查看你的私有库代码,因此可以把规划和审查都交给 6 Pro。
具体有几个要点:
- 如果你用 GitHub 插件的方式让 Pro 看你的文件,最好直接在仓库中准备个专门给 Pro 看的规范文档。
- 跑一次最少几十分钟,因此最好把问题和材料一次性给完整,建议规范化。
- 网页 Pro 的后台并发很高,实测同时运行10个 Pro 对话都没问题。但同时打开的 ChatGPT 网页数量有限制,打开多了会报网络错误,甚至中止思考。
4. 总结
此经验只针对高消耗/长时间无人值守任务,比如我需要几乎7×24小时运行。普通开发任务或者短期任务没必要使用子代理。其实还有很多细节没说,要是感兴趣的人多再写吧。
马上进入 AGI 时代,以后绝大多数的脑力劳动都会变成 spec 的管理和设计,建议每个人都应该积极研究并维护一套自己的 AI 工作流。希望本文能为大家提供参考。