过去两周我一直在折腾一件听起来有点绕的事:让 Codex 给 Claude Code 发任务。
起因很现实。我手头一个中型项目,同时开着几个 AI 编程代理,有的擅长拆需求、出整体方案,有的适合在小范围里改代码、补测试,还有的只用来跑文本生成和文档整理。问题是它们各自为政,上下文完全隔离,我本人成了它们之间的“人肉消息队列”,天天把 A 生成的计划复制粘贴给 B,再把 B 的产物转回给 A。这显然不是正确的姿势。
后来我把一个叫 Termexo 的 MCP 服务器接进来,用一套统一的协议把 5 种 Agent 全部纳管,最终实现了“Codex 做调度器,Termexo 做接线员,Claude Code 等 5 个 Agent 做执行端”的多智能体协作链路。这篇文章把整条链路拆开讲:先从为什么需要跨 Agent 发任务说起,然后记录 Termexo 的安装与 5 种 Agent 的接入差异,再带你追踪一条委派指令从 Codex 出发到 Claude Code 跑完任务的完整旅程,最后是三种任务交接模式、踩坑清单和一些调优心得。如果你正从“单 Agent 干活”迈向“多 Agent 编排”,这篇能帮你省掉不少摸索时间。
1. 为什么非要让一个 Agent 给另一个 Agent 发任务
1.1 任务错配是日常,工具链却是割裂的
我越来越觉得,编程代理不是一个万能执行体,更像是一个“能力偏科”的协作者。用 Codex 做主控的时候,它的优势在于把一个大需求拆成若干子任务、保持全局上下文、按计划推进;而 Claude Code 在实际操作中给我的印象是,它在一个具体代码库里做小步重构、补测试、写局部说明文档非常稳,跟项目的耦合度更低,更“听话”。
于是真实项目里我不会只开一个代理,而是哪块活儿适合谁就让谁上手。听起来很合理,对吧?问题在于,每个代理的上下文是彼此隔离的,它们之间不存在“通信”这个能力。你没有办法在 Codex 的会话里直接说“再把这份任务转给 Claude Code 做一下”,因为 Codex 根本不知道 Claude Code 的存在。
你可以说,那就手动复制粘贴,当中间商。短任务还行,任务一多,整个工作流就变成一坨乱麻。我试过最崩溃的一次,是某个 Agent 认真完成了上一步,却把最终结果写在了对话中间位置,输出一长,前面的结论就被上下文窗口挤掉了,我又得从头核对一遍。在这个场景里,人成了不可靠的缓存,成了系统的瓶颈。
1.2 MCP 正好补上了这块缺口
MCP(Model Context Protocol)这套协议,原本解决的是“让 Agent 能调用外部工具”的问题。它的工具注册、参数校验、结果回传机制,几乎就是为“把另一个 Agent 变成工具”量身准备的。现在很多编程代理已经支持配置 MCP 客户端,Codex 里只要声明好 server,它就能自动发现一组工具,并在合适的时机调用它们。
所以这个标题可以拆成一句话:Termexo 是一个把“终端命令”翻译成 MCP 工具的服务器。Codex 是主控客户端,Claude Code 是执行端 CLI,Termexo 坐中间做协议翻译和路由。
这里最妙的一点是,目标 Agent 不需要做任何改造。只要它能用非交互方式跑任务——也就是能在命令行里一次性接收任务文本并输出结果——它就能被纳管。这意味着不管是闭源商业代理,还是本地小模型跑出来的工具脚本,只要有一个可调用的 CLI,都能被装进同一套调度体系。
当然,这种设计也不是没有代价。最直接的问题是:每一次跨 Agent 调用都是进程级的开销,Termexo 必须处理超时、日志、错误码、空输出这些脏活。如果你的 Agent 启动特别慢,体验就会很难受。这个我放到后面踩坑部分细讲。
2. 把 5 种 Agent 接进 Termexo:安装、配置与两种接入姿势
2.1 Termexo 在整套架构里到底扮演什么
用一句话定位:Termexo 是“MCP 世界”和“Agent CLI 世界”之间的桥。它向上用 MCP 协议给 Codex 暴露工具,向下维护一个 Agent 目录,里面记录每个 Agent 的命令行、工作目录、模型偏好、权限边界。
当 Codex 决定把一个任务派给某个 Agent 时,它会向 Termexo 发一个 tool call。Termexo 拿到参数后,按agent_id找到对应命令,启动子进程,把任务文本作为 prompt 传进去,然后捕获 stdout 和 stderr,再按照预设规则把结果转换回 MCP 响应。整个流程对 Codex 来说就像调用一个普通函数,只是这个“函数”背后站着的是一整个 Agent。
我在自己环境里的物理拓扑是这样的:
- 最上层:Codex,负责接收用户需求、拆解任务、决定用哪个 Agent、验收结果;
- 中间层:Termexo MCP 服务器,暴露
dispatch_agent工具; - 底层:5 个 Agent CLI,各自绑定独立的工作目录和权限边界。
这套结构的好处是层次分明。主控只操心“派什么活”,执行端只操心“怎么把活干完”,至于它们之间的通信细节、输出解析、超时重试,全部收敛在 Termexo 这一层。
2.2 安装与最小配置:从零到跑通
Termexo 这类工具在社区里已经有现成实现,我用的版本是 Python 写的,安装比较简单:
pip install termexo-mcp termexo --init--init会在~/.termexo/下生成一份默认配置。要在 Codex 里启用 Termexo,只需要在 MCP 配置文件中注册:
{ "mcpServers": { "termexo": { "command": "termexo-server", "args": ["--config", "~/.termexo/agents.json"], "env": {} } } }真正有信息量的是agents.json。这是一份 Agent 目录,告诉 Termexo 外部有哪些 Agent 可以用、怎么调用、在哪个目录下执行、超时多久。我拿其中一个 entry 举例:
{ "agents": { "claude": { "command": "claude", "args": ["-p"], "cwd": "/workspace/code", "timeout": 300, "env": { "MAX_THINKING_TOKENS": "8000" } } } }这里的-p是 Claude Code 的非交互模式参数,意思是“把任务文本作为参数传入,执行完直接输出结果,不进入交互对话框”。cwd是执行 Agent 时的工作目录,这一步相当关键,它决定了这个 Agent 能看到哪些文件、会在哪个仓库里操作。timeout是单次任务的最长执行时间,超过就会被 Termexo 杀掉并返回超时错误。
2.3 5 种 Agent 的接入差异与名单
我在配置里挂了 5 个 Agent,它们能力互补,同时也代表了几种不同的“接口形态”。这里直接给出我环境里的名单,名字是我自己起的,你完全可以根据手头有什么替换成别的:
| 序号 | agent_id | 底层命令 | 典型用途 | 接入时的特殊点 |
|---|---|---|---|---|
| 1 | claude | claude -p "task" | 局部重构、补测试、写文档 | 流式输出,需要等完整结束标志 |
| 2 | local_reasoner | local-agent --json | 本地小模型做轻量推理 | 输出较慢,但适合不需要大上下文的子任务 |
| 3 | fix_agent | fix-agent --diff-only | 生成代码补丁,不直接改文件 | 输出是 diff 文本,需要保留完整格式 |
| 4 | doc_agent | doc-agent | 生成 README、注释、changelog | 输入可以是目录路径,不必给代码正文 |
| 5 | review_agent | review-agent --auto | 按预设规则做代码审查 | 输出是 JSON 数组,需要结构化解码 |
为什么要凑这 5 种?我不是为了凑数,而是为了覆盖不同的“返回类型”。Claude Code 返回的是自然语言描述,local_reasoner返回 JSON,fix_agent返回 diff 文本,review_agent返回结构化 JSON 数组,doc_agent返回的是长文档。Termexo 的解析层需要针对不同返回类型做不同的后处理,我的做法是在每个 Agent entry 里加一个response_parser字段:
{ "agents": { "review_agent": { "command": "review-agent", "args": ["--auto"], "cwd": "/workspace/code", "timeout": 120, "response_parser": "json_array" } } }> 提示:如果你的目标 Agent 只支持交互式终端,不能通过 `-p` 这类参数直接接受任务文本,建议先在外面包一层薄薄的 CLI 适配脚本,把 stdin 接住再转成 Agent 能理解的输入。没必要为了接入 MCP 去改 Agent 本体代码。3. 一条委派指令的完整旅程:从 Codex 到 Claude Code
3.1 工具调用链路的每一跳
搞清楚了配置,我们需要理解一条委派指令究竟是怎么穿行整条链路的。我拆成 7 个环节:
- Codex 根据当前对话判断需要做某事,比如“补一个回归测试”;
- Codex 的 MCP client 把
dispatch_agent工具调用发给 Termexo; - Termexo 校验
agent_id是否在目录里,参数是否齐全; - Termexo 根据配置构造子进程命令,在工作目录中启动对应 Agent CLI;
- 目标 Agent 执行任务,输出结果到 stdout;
- Termexo 捕获 stdout/stderr,按
response_parser做结构化解码; - 解码后的结果返回给 Codex,Codex 把它当作一次普通工具调用的返回值继续推理。
从 Codex 的视角看,它就是调用了一个函数;
从 Termexo 的视角看,它做了一次进程编排;
从目标 Agent 的视角看,它只是安静地完成了一次命令行任务。
整条链路最容易被忽略的其实是第二步到第三步之间的参数校验。MCP 协议本身对参数是有类型约束的,但 Codex 在自由发挥时经常会把一些附加说明塞进task字段之外的参数里。所以我在 Termexo 的配置里开了strict_schema: true,只允许工具定义里声明过的字段传入,其他字段一律忽略。这一手帮我挡掉了不少“Agent 突然多收了一个不认识参数”的诡异问题。
3.2 一次真实的跨 Agent 任务:补回归测试
我拿一个具体场景来说明。假设主任务是这样的:修正用户表查询里的空指针问题,并补充回归测试。Codex 的规划能力会让它选择这么拆:核心修复它自己做,回归测试派给 Claude Code。
于是 Codex 内部生成的一个工具调用大概长这样:
{ "tool": "dispatch_agent", "arguments": { "agent_id": "claude", "task": "在 /workspace/code 的 tests/ 下新增 test_user_repository.py,覆盖空指针回归场景,运行 pytest 并报告结果。验收标准:新增测试能稳定通过。", "cwd": "/workspace/code", "timeout": 300 } }Termexo 收到后实际执行的命令是:
cd /workspace/code && claude -p "在 /workspace/code 的 tests/ 下新增 test_user_repository.py,覆盖空指针回归场景,运行 pytest 并报告结果。验收标准:新增测试能稳定通过。"Claude Code 干完活之后,会在 stdout 输出一段总结,通常包含它改了哪个文件、测试覆盖了哪些分支、测试结果如何。Termexo 会尽可能干净地把这段话捕获,然后作为工具调用的返回值交还给 Codex。
这一步里有一个容易掉进去的坑:Codex 会把返回值当作“既成事实”,如果 Claude Code 只是嘴上说“测试通过”,但没真正运行 pytest,Codex 也分辨不出来。所以我的习惯是在任务描述里明确要求“必须贴出 pytest 的实际输出末尾三行”,让结果里带上可验证的实证信息。
3.3 结果回传的两种模式
Termexo 支持两种结果回传方式,我分别用在不同场景:
| 模式 | 实现方式 | 适用场景 | 我的经验 |
|---|---|---|---|
| 全量回传 | 直接把 stdout 前 N 个字符作为结果返回 | 目标 Agent 会输出描述性结论 | 限制 N 一般在 8000 以内,避免撑爆主控上下文 |
| 结构化回传 | 配置response_parser,从输出中提取指定字段 | 目标 Agent 输出 JSON 或 diff | 必须给出示例解析规则,否则解析器会猜 |
结构化回传对 review_agent 特别重要。它输出的原始 JSON 可能有一大堆,但如果 Codex 只需要错误列表,那 Termexo 可以预先提取出errors[]数组回传。这样主控 Agent 拿到的数据量小、信噪比高,后续决策也更快。
4. 跨 Agent 任务交接的三种实战模式
4.1 RPC 模式:一问一答
RPC 模式是最直观的一种,Codex 发起一次调用,同步等待结果,就像调函数一样。适合单次、短小的任务,比如“让 doc_agent 给当前目录写一段 30 行的 README 快速开始”,或者“让 local_reasoner 把这个报错信息翻译成人话”。
这种模式的实现成本最低,Termexo 只需要同步阻塞地跑一个子进程,得到结果后返回。但它有一个天然限制:主控 Agent 在等待期间不能做任何事,如果目标 Agent 执行时间很长,整个推理过程会被卡住。所以长任务一定要慎用 RPC 模式。
4.2 Job 模式:异步派活与轮询
我试过最典型的场景是:“让 fix_agent 在几百个文件里统一改 import 路径”。这种任务耗时可能超过 10 分钟,如果同步等待,Codex 很可能会因为上下文过长而开始胡言乱语。
解决办法是让 Termexo 支持异步工具。它在dispatch_agent的 schema 里声明了一个额外字段:async: true。Codex 第一次调用时,Termexo 立刻返回一个job_id,然后后台慢慢跑;Codex 拿着job_id再调用job_status查询进度,直到返回completed。
{ "tools": [ { "name": "dispatch_agent", "async": true }, { "name": "job_status", "description": "查询异步任务状态", "inputSchema": { "job_id": "string" } } ] }这里的关键点是:MCP 工具本身并不区分同步和异步,区分方式完全取决于返回结果里有没有job_id。Codex 看到返回里有job_id,就会自然地把这个工具当作异步任务来处理。Termexo 只需要在工具定义里把返回 schema 声明清楚。
4.3 Pipeline 模式:多 Agent 接力
三种模式里我玩得最上头的是 Pipeline 模式。简单说,就是把多个 Agent 按顺序串成一条流水线,前一个 Agent 的输出直接作为后一个 Agent 的输入。Codex 担任编排者,不需要自己动手做中间加工。
举个例子,我有一条写 changelog 的流水线:
- doc_agent 读 git log,生成 changelog 初稿;
- review_agent 审查初稿,挑出措辞含糊、缺版本号的地方;
- claude 根据审查意见润色,输出最终版本。
在 Codex 里,我给它一个伪代码级的提示就能完成这种编排:
pipeline = [ ("doc_agent", "生成 changelog 初稿,基于 git log 最近 20 条"), ("review_agent", "审查初稿,输出需要修改的点"), ("claude", "根据审查意见润色最终版并保存") ] for agent_id, task in pipeline: result = dispatch(agent_id, task)Codex 读到这段代码,就会照着顺序依次调用 Termexo 暴露的工具。真正让我意外的是,它在流水线中间遇到 review_agent 返回“初稿太薄,缺结构”这样的结果时,会主动回去让 doc_agent 补充内容,而不是把错误结果往后传。这种“编排者的判断力”是 Pipeline 模式能成立的前提。
5. 踩坑清单:提示词污染、权限边界和上下文穿越
5.1 最先爆的坑:权限边界
我的第一个教训出在权限上。刚开始我图省事,所有 Agent 的cwd都设置成同一个项目目录,想着它们都在同一个仓库里干活,应该没啥问题。结果发现 fix_agent 和 claude 同时开工时,会互相覆盖对方刚刚生成的文件。
这其实不是 Agent 的问题,而是“多个执行者共享同一个工作区”的天然冲突。解决办法是在 Termexo 里给每个 Agent 划分独立的工作目录,比如:
- claude:
/workspace/code/workspaces/claude - fix_agent:
/workspace/code/workspaces/fix - doc_agent:
/workspace/code/workspaces/doc
主控 Codex 看到的是整个项目,但具体到每个执行 Agent,它们只拥有自己那份工作区的写权限。跨目录的合并操作由 Codex 统一决定,而不是让 Agent 自己去乱碰。这相当于在 Agent 之间画了清晰的边界,很多莫名其妙的问题都消失了。
> 注意:Termexo 里还有一个 `allowed_paths` 字段,用来限制目标 Agent 能读取的目录列表。哪怕 Agent 本身能力再强,也建议在这个字段上做收紧,而不是交给 Agent 自己自律。5.2 提示词污染:错误信息被主控 Agent 当素材
第二个坑非常隐蔽,属于“系统性设计缺陷”。当 Termexo 执行的子进程报错时, stderr 里会有大量堆栈信息、 Python traceback、各种环境变量。Termexo 如果把这些东西原封不动地回传给 Codex,Codex 会把这些内容当成“新的任务素材”来解读,于是它有可能基于一段错误堆栈编造出一个看似合理的修复方案。
我遇到过一次很经典的:Claude Code 跑测试时因为环境变量没设好失败了,Termexo 把整个 traceback 传给 Codex,Codex 没意识到这是执行失败,反而在那里分析 traceback 里某个无关变量名,最后得出一个完全跑偏的结论。
解决方式很简单,在 Termexo 配置里限制错误回传的字符数:
{ "max_error_chars": 2000, "error_prefix": "[EXECUTION FAILED]" }加上[EXECUTION FAILED]前缀后,Codex 会被明确告知“这是失败信号”,而不是普通输出。只回传最后 2000 字符,也防止了堆栈信息把主控的上下文窗口撑爆。
5.3 上下文穿越:不要把你的会话心得塞给执行 Agent
第三个坑,我管它叫“上下文穿越”。Codex 在执行委派时,容易把当下对话里的上下文,连同自己的推理过程、中间草稿、历史尝试,一股脑塞进task字段里。
这会导致什么问题?目标 Agent 收到的是掺杂了大量无关信息的任务描述,它会分不清哪些是最终指令、哪些只是主控的思考过程,结果就是产出偏离预期。我见过最离谱的一次,是目标 Agent 把主控的思考过程当成了用户需求,直接照着那个思路去改代码,改出了一个完全没用的版本。
我的经验是,在 task 描述里坚守隔离原则:只写四样东西——
- 明确的目标指令;
- 验收标准;
- 可用工具和工作目录;
- 输出格式要求。
不要写主控自己的推理过程,不要写“我本来想怎样怎样”,也不要把对话历史里那些来回尝试的过程转述过去。给执行 Agent 的信息越干净,它的执行力就越强。这个原则后来被我写成了 Termexo 的任务描述模板,Codex 派活之前必须按模板渲染,效果立竿见影。
5.4 长任务的超时与空输出
最后一个坑是运维层面的。目标 Agent 执行超过timeout后会被 Termexo 杀掉,此时 stdout 可能是空的,退出码非零。如果不做特殊处理,Codex 拿到一个空字符串,大概率会当成“任务完成了,但没有任何结果”——然后它就开始编造结果。
我的处理方式是在 Termexo 里对“超时且空输出”这个组合返回一个特殊的结构化错误码:
{ "error": "TIMEOUT_EMPTY_OUTPUT", "message": "agent claude 执行超时,未产生任何输出", "job_id": "xxx" }当 Codex 看到error字段,它就会意识到必须重新规划,比如增加 timeout、缩小任务范围,或者换个 Agent 来干。这里如果只是回传“超时”两个字,Codex 也可能搞不明白该怎么处理,所以一定要给出明确的原因和建议动作。
排查这类问题,我的标准链路是三步:先看 Termexo 的日志确认子进程是否被启动;再看目标 Agent 的日志确认它是否卡在某个环节;最后看 Codex 的调用记录确认它传进来的task是否合理。哪一个环节看起来正常,就说明问题出在下一个环节。
6. 方案取舍与调优:为什么我最后选了 Termexo 这类终端桥
6.1 三种接线方案对比
在做这套东西之前,我其实对比过三种接线方案:
| 方案 | 实现思路 | 优点 | 缺点 |
|---|---|---|---|
| 直连模式 | 两个 Agent 通过读写同一个项目文件来间接协作 | 不需要额外中间层 | 需要大量人工中转,上下文割裂严重 |
| MCP 终端桥 | 用 Termexo 这类工具把 Agent CLI 封装成 MCP 工具 | 目标 Agent 零改造,天然适配现有 MCP 生态 | 每次调用都有进程开销,需要处理超时和解析 |
| 自建 HTTP API | 给每个 Agent 包一层 HTTP 服务,主控调用 REST 接口 | 灵活、可控、可加鉴权 | 工作量大,每个 Agent 都要单独写服务 |
我最后选了 MCP 终端桥,最主要的原因就是“目标 Agent 零改造”。我不需要维护一堆常驻的 HTTP 服务,也不用担心某个 Agent 的 API 变了导致全线崩溃,Termexo 把整个差异遮挡在配置层后面。当然它的代价也很明显:每次调用都是冷启动一个子进程,启动慢的 Agent 会很拖累体验。这个我靠后面的常驻会话优化解决了一部分。
6.2 让这套链路变稳的 4 个优化点
如果你打算照着这个思路搭一套多 Agent 协作链路,我建议一开始就加上下面这 4 个优化,能帮你躲开大部分坑:
第一,优先选支持会话复用模式的 Agent。有些 Agent CLI 支持--session或类似参数,可以在多次调用中复用同一个进程,避免每次都重新加载模型、重新读上下文。Termexo 里可以配置session_id字段,把连续任务导向同一个会话。实测下来,单次调用冷启动要 5 秒的话,复用会话能压到 1 秒以内。
第二,给每个 Agent 挂一个专用工作目录,绝对不要共享。多个执行者共享一个目录,等于允许它们互相踩踏。只要把目录分开,大部分“文件被改了但不知道是谁改的”的问题自动消失。
第三,把任务描述模板化。不要让 Codex 每次自由发挥写 task 描述,而是在 Termexo 侧定义好模板,比如task_template,Codex 只需要填变量,模板负责控制格式。这样既能保证执行 Agent 收到的指令结构一致,也能有效防止上下文穿越问题。
第四,给工具调用加上 precheck 钩子。Termexo 可以在真正启动目标 Agent 之前,先执行一条快速检查命令,比如确认目标目录存在、目标文件没被其他 Agent 锁定、git 状态是否干净。如果检查失败,直接返回错误给 Codex,省得把一个注定失败的任务发下去。
这套体系我实际跑了两周,最大的感受是:多 Agent 协作真正难的不是技术接线,而是“任务边界”的划分。Termexo 帮我把 Agent 之间的通信变成了干净的函数调用,但真正决定这条链路稳不稳的,是每个 Agent 拿到手的任务是否清晰、权限是否收敛、输出是否可验证。建议你按我上面说的顺序先把一个最小闭环跑通——让 Codex 通过 Termexo 给 Claude Code 派一个补测试的小任务——再逐步加 Agent、加流水线,你会比我当初少走很多弯路。