1. 从“子代理”说起:这次更新到底改了什么
OpenAI 在深夜放出 Codex 的 Subagents 功能,消息传开之后,开发者圈子里讨论最多的不是模型又涨了多少参数,而是一个更实际的问题:这东西到底能不能让我少干点重复活。我第一时间在自己的环境里跑了一遍,结论是——它确实改变了我和 Codex 协作的方式,但和很多人想象的“全自动写代码”完全不是一回事。
先把概念说清楚。Subagents,直译过来就是“子代理”。在 Codex CLI 的语境里,它指的是一个主代理(main agent)在执行任务的过程中,可以派生出若干个子代理,每个子代理独立负责一块具体的子任务,各自拥有独立的上下文窗口,最后把结果汇总回主代理。这个机制解决的是一个老问题:当任务链条变长、涉及的文件变多时,单个代理的上下文会被塞满,注意力被稀释,越到后面越容易“忘事”。
你可以把它理解成一个施工队。以前是一个老师傅从头干到尾,水电、木工、油漆全包,干到后面脑子已经乱了。现在是老师傅当工头,把水电交给一个徒弟、木工交给另一个徒弟,每人只管自己那一摊,工头最后验收。子代理就是这些徒弟,它们各自有干净的上下文,不会被别的任务干扰。
这个功能对谁最有用?我的判断是三类人:一是经常用 Codex CLI 处理多文件重构的开发者;二是需要让 AI 帮忙做代码审查、测试生成这类“旁路任务”的工程师;三是把 Codex 接入自己工作流、想进一步做自动化编排的人。如果你只是偶尔让 AI 补个函数,这个功能对你感知不强,但一旦任务复杂度上来,差别就非常明显。
需要提前说明的是,Subagents 目前主要围绕 Codex CLI 这个命令行工具展开,不是网页版 ChatGPT 里的功能。所以下面所有的讨论,都建立在你能正常跑起 Codex CLI 的前提上。关于安装和配置,我会在后面的章节里结合常见坑一起讲。
2. 核心机制拆解:子代理为什么能提升效率
2.1 上下文隔离:解决“越写越糊涂”的根本问题
要理解子代理的价值,得先理解大模型在长任务里的一个硬伤:上下文污染。假设你让 Codex 重构一个模块,它需要读十几个文件,每读一个文件就占用一部分上下文窗口。读到第八个文件的时候,前面读过的内容可能已经被挤出窗口,或者虽然还在但权重被稀释。结果就是它开始重复读文件、忘记之前的约定、甚至改出前后矛盾的代码。
子代理的解法是物理隔离。主代理把“重构 A 模块”这个任务派给子代理 1,子代理 1 只加载 A 模块相关的文件,上下文干干净净。同时主代理把“更新对应的测试”派给子代理 2,子代理 2 只关心测试文件。两个子代理互不干扰,各自在自己的小窗口里把事做完,只把结论回传给主代理。
这个设计的好处是显而易见的:每个子代理的上下文利用率极高,不会因为任务庞杂而分心。我用一个实际例子说明差别。之前让 Codex 一次性重构三个相互依赖的 service 文件,它改到第二个文件时就开始引用第一个文件里已经不存在的旧方法名。换成子代理模式,每个 service 一个子代理,改完之后主代理做一次交叉检查,这类低级错误基本消失了。
2.2 并行与串行的取舍:不是所有任务都适合拆
很多人一听“子代理”就以为可以无限并行,这是误解。子代理之间可以是并行关系,也可以是串行关系,取决于任务之间有没有依赖。
并行适合的场景:几个子任务彼此独立,比如同时给五个不同的工具函数写单元测试,或者同时检查三个不相关模块的代码风格。这种情况下,子代理并行跑,总耗时接近最慢的那个子任务,而不是所有任务耗时之和。
串行适合的场景:子任务之间有先后依赖,比如先要子代理 1 分析出接口定义,子代理 2 才能根据接口写实现。这时候硬要并行,子代理 2 拿不到子代理 1 的产出,只能瞎猜,结果就是返工。
我的经验是,拆分子任务之前先问自己一句:这两个任务之间有没有数据依赖?有依赖就串行,没依赖才并行。这个判断做错了,子代理不但不省事,反而会制造更多需要人工介入的混乱。
2.3 主代理的角色转变:从执行者到调度者
子代理机制带来的一个深层变化,是主代理的定位变了。以前主代理是“干活的人”,现在它更像“派活和验收的人”。它需要做三件事:把大任务拆成合理的子任务、给每个子代理分配清晰的边界、在子代理返回结果后做一致性检查。
这个转变对使用者的要求其实更高了。因为主代理拆得好不好,直接决定子代理跑得顺不顺。如果主代理把一个本该串行的任务拆成并行,或者给子代理的指令含糊不清,子代理就会各自为政,产出互相打架的结果。所以用好这个功能的关键,不在于子代理本身多聪明,而在于你怎么引导主代理去拆解任务。
我踩过的一个坑是:一开始我给的指令太粗,比如“优化这个项目的性能”,主代理拆出来的子任务五花八门,有的去改数据库查询,有的去动缓存策略,最后合在一起反而引入了新的 bug。后来我改成“先分析出三个最耗时的接口,然后针对每个接口单独做优化”,子代理的产出就聚焦多了。
3. 实操落地:从安装到跑通第一个子代理任务
3.1 环境准备:Codex CLI 安装与常见报错处理
在聊子代理之前,得先保证 Codex CLI 能正常跑起来。这一步看起来简单,但实际卡住的人不少。我把自己和身边朋友遇到过的典型问题整理一下。
安装方式上,主流是通过包管理器或者官方提供的安装脚本。装完之后用codex --version验证,能打印出版本号说明二进制没问题。但很多人会遇到一种情况:命令行里codex --version正常,一进 Windows Terminal 或者某个特定终端就报找不到命令。这通常是 PATH 环境变量在不同终端会话里没生效导致的,重启终端或者手动把安装路径加进 PATH 就能解决。
另一个高频报错是codex auth token is unavailable。这个一般和登录态有关,需要重新走一遍认证流程。还有一种报错是配置文件里的 provider 名字对不上,比如提示model provider 'openai' not found,这时候要检查 config.toml 里的 provider 定义和实际调用时用的名字是否一致,大小写和拼写都要对上。
提示:配置文件改完之后,最好完全退出 Codex 再重新启动,有些配置是启动时读取一次的,热改不一定生效。
如果你在 Windows 上遇到failed to start. unable to locate the codex cli binary,基本可以确定是安装路径没被正确识别,检查一下安装目录是否存在、是否有执行权限。这类问题排查思路很朴素:先确认二进制在不在,再确认能不能被执行,最后确认调用方找的路径对不对。
3.2 配置要点:模型、provider 与参数选择
Codex CLI 的配置核心在 config.toml 这个文件。几个关键项需要搞清楚。
模型选择上,不同模型对 Codex 的支持程度不一样。有些模型在 Codex 场景下会直接报不支持,比如你可能会看到类似the 'gpt-5.6-sol' model is not supported when using codex的提示。遇到这种,换一个明确支持 Codex 的模型即可,不要硬扛。
provider 配置是另一个容易出问题的地方。如果你用的是兼容接口,base_url 和 api_key 要填对,provider 的名字要和调用时一致。我见过有人把 provider 定义成openai,但调用时写的是OpenAI,结果就是找不到。这种问题没有任何技术含量,但就是能耗掉你半小时。
参数方面,和子代理相关的主要是并发控制和超时设置。子代理并行跑的时候,如果并发数设得太高,可能触发接口的速率限制;设得太低,又体现不出并行的优势。我的建议是从小往大试,先设 2 到 3 个并发,观察稳定性和耗时,再逐步往上加。超时时间也要留够,子代理处理复杂任务时耗时可能比预期长,超时设太短会导致任务被中途掐断。
3.3 第一个子代理任务:让主代理拆解一个真实需求
配置跑通之后,可以试第一个子代理任务了。我建议从一个中等复杂度的真实需求开始,不要一上来就搞大重构。
我的第一个成功案例是这样的:项目里有一个数据处理模块,需要做三件事——补充输入校验、增加异常处理、更新对应的文档注释。这三件事彼此独立,非常适合拆成三个子代理。
我给主代理的指令大意是:把这个模块的改进拆成三个独立子任务,分别处理输入校验、异常处理、文档注释,每个子任务单独执行,最后汇总检查一致性。主代理接到指令后,派出了三个子代理,各自负责一块。跑完之后我检查产出,三块改动互不冲突,合并起来很顺。
这里的关键是“独立”两个字。我在指令里明确说了三个子任务彼此独立,主代理才会放心地并行拆解。如果我说“先做校验再做异常处理”,它就会按串行来。所以指令里的依赖关系描述,直接决定拆解方式。
3.4 观察与验收:怎么判断子代理干得好不好
子代理跑完之后,不能直接无脑合并,得做验收。我的验收习惯分三步。
第一步看边界。每个子代理有没有越界改动?比如负责文档注释的子代理,如果去动了业务逻辑,那就是越界了,需要回退。第二步看一致性。几个子代理的产出放在一起,有没有互相矛盾的地方?比如一个子代理把某个方法改名了,另一个子代理还在引用旧名字,这种就要修。第三步看整体。把所有改动合起来跑一遍测试,确认没有引入回归。
这三步里,第一步最容易被忽略,但恰恰最重要。子代理越界往往是因为主代理给的边界不够清晰。如果发现子代理频繁越界,回头去优化主代理的拆解指令,比事后一个个修要高效得多。
4. 进阶玩法:把子代理编进你的日常工作流
4.1 代码审查场景:让子代理当你的第二双眼睛
代码审查是子代理特别好用的一个场景。传统做法是你写完代码,自己再看一遍,或者等同事 review。现在可以派一个子代理专门做审查,它只关心“这段改动有没有明显问题”,上下文里只放 diff 和相关文件,注意力非常集中。
我的做法是:主代理负责实现功能,实现完之后派一个审查子代理,指令是“检查这次改动是否有逻辑错误、边界遗漏、命名不一致”。审查子代理返回问题列表,主代理根据列表决定要不要修。这个流程跑下来,能抓到不少我自己写代码时忽略的小问题。
要注意的是,审查子代理的指令要具体。如果你只说“审查代码”,它可能给你一堆风格建议,价值不大。说清楚你关心什么,比如“重点看空值处理和并发安全”,它才会往那个方向使劲。
4.2 测试生成场景:并行给多个模块补测试
给多个模块补单元测试,是并行子代理的经典用法。每个模块一个子代理,各自读自己的源码,生成自己的测试用例,互不干扰。
这里有个细节值得说:测试子代理最好能拿到模块的接口定义,而不是整个实现。因为测试关心的是行为,不是内部实现。如果子代理读了太多实现细节,它可能会写出过度耦合的测试,实现一改测试就挂。所以给测试子代理的上下文,应该聚焦在公开接口和预期行为上。
我实测下来,并行给五个模块补测试,总耗时大概是串行的三分之一左右。省下来的时间主要来自上下文切换的减少——每个子代理只干一件事,不用在多个模块之间来回跳。
4.3 多任务编排:主代理拆解的粒度怎么把握
拆解粒度是子代理用得好不好的分水岭。拆得太粗,子代理还是会被上下文压垮;拆得太细,子代理之间通信开销变大,主代理调度也累。
我的经验法则是:一个子代理的任务,应该能在一次上下文窗口内完成,且产出一个可以独立验收的结果。如果任务大到需要读几十个文件,就继续拆;如果任务小到只是改一行代码,就没必要单独派子代理,主代理顺手做了就行。
还有一个判断标准是“可验收性”。如果一个子任务的产出没法单独判断对错,那它就不适合独立成子代理。比如“优化代码风格”这种任务,产出好坏很主观,拆出来反而增加验收负担。相反,“给这个函数加上参数校验并写测试”就很适合,因为对错清晰。
5. 常见问题与排查技巧实录
5.1 子代理跑飞了怎么办
子代理跑飞,通常表现为产出和预期完全不符,或者改了一堆不该改的地方。遇到这种情况,先别急着骂工具,回头看看主代理的拆解指令。
最常见的原因是边界不清。比如你说“改进这个模块”,主代理可能理解成“随便改”,子代理就放飞了。改成“只在这个文件内,只改输入校验部分,不动其他逻辑”,子代理就老实了。
第二个原因是依赖没说明。如果两个子任务其实有依赖,但你没说,主代理按并行拆了,子代理就会各自基于不完整的信息做决策,结果互相打架。解决办法是在指令里显式说明依赖关系。
5.2 上下文还是不够用怎么办
有人会问:子代理不是隔离上下文吗,怎么还会不够用?答案是,如果单个子任务本身就很大,子代理的上下文照样会满。这时候要做的是继续往下拆,而不是指望子代理能扛住。
另一个技巧是给子代理“减负”。比如让它只读必要的文件,而不是整个目录。Codex CLI 支持指定文件范围,用好这个能省下大量上下文。我习惯在派子代理之前,先自己确认一下这个任务最少需要哪些文件,然后明确告诉主代理只加载这些。
5.3 并行任务互相干扰的排查
并行子代理理论上互不干扰,但实际中可能出现“看起来互相干扰”的情况。比如两个子代理都改了同一个文件,合并时冲突。这其实不是干扰,是拆解时没做好文件级隔离。
排查思路是:先看冲突发生在哪些文件,再看这些文件是不是被多个子代理同时改了。如果是,说明拆解时应该按文件边界来分,而不是按功能边界。功能边界和文件边界不一致的时候,优先按文件边界拆,能避免大部分合并冲突。
下面这张表是我整理的高频问题速查,遇到问题可以先对号入座。
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 子代理产出与预期不符 | 主代理拆解指令边界不清 | 细化指令,明确范围和禁区 |
| 合并时文件冲突 | 多个子代理改了同一文件 | 按文件边界重新拆解 |
| 子代理上下文仍不够 | 单个子任务过大 | 继续拆分子任务 |
| 并行耗时没减少 | 任务间存在隐性依赖 | 改为串行或调整拆解 |
| 子代理越界改动 | 未明确禁止改动的范围 | 指令中显式声明禁区 |
5.4 几个我踩过的坑
第一个坑是过度信任主代理的拆解。早期我给的指令很粗,主代理拆出来的子任务质量参差不齐,有的子代理甚至去做了我根本没要求的事。后来我养成了一个习惯:主代理拆解完之后,先看一遍它的拆解方案,确认合理再让它执行。多花这一分钟,能省下后面半小时的返工。
第二个坑是忽略验收。有一次几个子代理并行跑完,我看都没看就合并了,结果跑测试挂了一片。后来才知道其中一个子代理把某个公共方法的签名改了,另一个子代理还在用旧签名。从那以后,我合并前一定先做一致性检查。
第三个坑是并发数设太高。有一次我设了 8 个并发,结果触发了速率限制,一半子代理直接失败。后来改成 3 个,稳定多了。并发数不是越高越好,稳定压倒一切。
6. 我对这套机制的实际体会
用了一段时间之后,我对子代理的评价是:它是一个“放大器”。你的任务拆解能力越强,它放大出来的效率越高;你的指令越含糊,它放大出来的混乱也越多。它不会自动帮你把活干好,但它能让你在同样时间内处理更复杂的任务。
我现在的日常流程基本固定下来了:接到一个稍大的任务,先自己花两分钟想清楚能拆成几块、哪块和哪块有依赖,然后把这个思路写进给主代理的指令里。主代理按我的思路拆解,子代理各干各的,最后我做验收。这套流程跑顺之后,处理多文件改动的效率比之前高了不少。
如果你刚开始用,我的建议是从小任务练起,先熟悉主代理的拆解逻辑和子代理的行为模式,再逐步加大任务复杂度。别一上来就搞大重构,那样很容易被各种意外情况劝退。工具是好工具,但得先摸清它的脾气。