[经验] Codex 子代理优化指南:增加效率 & 降低 50% Token 消耗

Viewed 1

1. 为什么 Codex 子代理这么费额度

众所周知,Codex 的子代理调度极其辣鸡,而且 GPT 非常喜欢过度工程化,再加上发布 Astra 后额度大幅降低。这就导致调用子代理时,你会花好几倍的 Token,效率提升却非常有限。

最近仔细研究了下,发现 Codex 其实还是可以抢救一下的。消耗了20多个20x的周限,最后发现 Codex 的低效主要有3个原因:

  1. 默认配置不合理,比如默认派发子代理时会带上主对话全部上下文,即 fork_turns 默认为 "all";不主动指定模型和思考强度,还可能直接继承主对话的配置。子代理角色提示词里写死的模型和思考强度,也会覆盖主对话派发时的选择。
  2. 任务派发不合理,主对话喜欢只派发阶段性任务。这样就导致一个任务要派发好几次,浪费时间的同时产出大量乱七八糟的中间文件。此外,子代理完成后,主对话可能不信任,喜欢重复验证,尤其喜欢算哈希值。
  3. 通讯机制不合理。主代理喜欢疯狂轮询子代理进度,而子代理喜欢屁大点事都向主对话汇报。明明可以像 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] 中的默认配置 > 主对话的配置。

所以,想让主对话每次主动选择模型和思考,就不能在角色文件里写死 modelmodel_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 管理系统,因此给出关键要点供大家参考:

  1. 每次派发必须显式指定模型和思考强度,禁止继承主对话全部上下文。必须使用 fork_turns: "none",建议加个门禁检查。
  2. 重写子代理的角色提示词,让子代理负责完整任务,自行完成调查、实现、测试、修正,以及外部工具调用和结果回收。不要屁大点事就跟主对话汇报,需要子代理间协调时,先找其他子代理。
  3. 主代理派发时,把目标、输入、工作目录和交付要求给清楚。主对话核对关键结果并集成,不重复已经完成的调查和整轮验证,不增加乱七八糟的哈希和额外门禁。
  4. 子代理只在实际阻塞、需要共同决定或影响其它任务时发消息。主对话耐心点,不催促、不反复查询,有依赖的子代理直接沟通。
  5. **优先等完成通知。**需要轮询时,子代理按1、2、4、8、16分钟递增,长命令按2、4、8、16、30分钟递增,达到上限后保持。
  6. 同一任务的延续优先复用原代理,中断后优先恢复已有成果,禁止主对话因为等不及就重复执行。

3. 通过浏览器调用 Pro 模型

有 Pro 订阅的,建议把每周的200次 6 Pro 用完。

大概的实现方案是:在 Chrome 和 Codex 内置浏览器登录网页 GPT,然后通过规范让它自己发问题、上传材料、等待和回收。更进一步,由于网页 GPT 连接 GitHub 插件后可以查看你的私有库代码,因此可以把规划和审查都交给 6 Pro。

具体有几个要点:

  1. 如果你用 GitHub 插件的方式让 Pro 看你的文件,最好直接在仓库中准备个专门给 Pro 看的规范文档
  2. 跑一次最少几十分钟,因此最好把问题和材料一次性给完整,建议规范化。
  3. 网页 Pro 的后台并发很高,实测同时运行10个 Pro 对话都没问题。但同时打开的 ChatGPT 网页数量有限制,打开多了会报网络错误,甚至中止思考。

4. 总结

此经验只针对高消耗/长时间无人值守任务,比如我需要几乎7×24小时运行。普通开发任务或者短期任务没必要使用子代理。其实还有很多细节没说,要是感兴趣的人多再写吧。

马上进入 AGI 时代,以后绝大多数的脑力劳动都会变成 spec 的管理和设计,建议每个人都应该积极研究并维护一套自己的 AI 工作流。希望本文能为大家提供参考。

0 Answers
Related