news 2026/10/2 10:12:53

Codex CLI多Agent协同实战:Planner、Executor、Verifier三Agent架构与调度

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Codex CLI多Agent协同实战:Planner、Executor、Verifier三Agent架构与调度

1. 单Agent的瓶颈:为什么"一个人包打天下"越来越吃力

刚开始用 Codex CLI 那阵子,我确实觉得一个 Agent 就够了。写个函数、补个测试、解释一段报错,它都能接住。但项目一旦超过几千行、涉及多语言栈、还要同时改前端和后端,问题就来了:上下文窗口被塞满、任务边界模糊、改完 A 文件忘了 B 文件的依赖,最后变成"它很努力,但方向全错"。

这不是模型能力的问题,而是单 Agent 架构的固有天花板。一个 Agent 同时扮演需求理解者、架构设计者、编码实现者、测试验证者四个角色,每个角色对上下文的需求是冲突的。写代码需要大量局部细节,做架构需要全局视野,验证又需要独立的批判视角。把这些塞进一个上下文里,必然互相挤占。

我踩过最典型的一次坑:让 Codex 一次性重构一个 Express 项目的路由层,它改得很漂亮,但完全没注意到有个中间件依赖旧的路由命名。跑起来直接 500。它"看到"了那个中间件文件,但在长上下文里那个信息被稀释了。这就是单 Agent 的注意力衰减问题。

多 Agent 协同要解决的核心,就是把冲突的角色拆开,让每个 Agent 只背自己那份上下文。下面这张表是我实测下来单 Agent 和多 Agent 在几个维度上的差异:

维度单 Agent多 Agent 协同
上下文占用所有信息挤在一个窗口每个 Agent 只加载职责相关上下文
任务边界模糊,容易越界改动明确,通过接口契约约束
错误发现自己写自己验,盲区大独立验证 Agent 能抓出实现者的盲区
并发能力串行,一个任务一个任务来可并行处理无依赖的子任务
调试成本出错后难定位是哪一步每个 Agent 有独立日志,定位快

需要说明的是,多 Agent 不是"越多越好"。我见过有人一上来就搞七八个 Agent,结果协调开销比干活还大。Agent 数量应该由任务的自然边界决定,而不是拍脑袋定的。

2. 拆角色的艺术:我的三Agent最小可用组合

多 Agent 协同最容易犯的错,是按"技术栈"拆——一个前端 Agent、一个后端 Agent、一个数据库 Agent。听起来合理,实际很糟,因为技术栈之间是强耦合的,拆开后沟通成本极高。我试过几轮之后,稳定下来的拆法是按职责阶段拆,最小可用组合是三个:

2.1 Planner:只做拆解,不碰代码

Planner 的职责非常纯粹:读需求,输出一份结构化的任务清单,每个任务包含目标、涉及文件、验收标准、依赖关系。它绝对不写代码,这是纪律。

为什么不让 Planner 顺手把代码也写了?因为一旦它开始写代码,它的上下文就会被具体实现细节污染,后续拆解任务时就会不自觉地"迁就"自己已经写的那部分,失去全局视角。我实测过,让 Planner 只输出 JSON 格式的任务清单,拆解质量比让它"边想边写"高出一大截。

Planner 的输出我固定成这个结构:

{ "tasks": [ { "id": "T1", "goal": "为 /api/users 增加分页参数校验", "files": ["src/routes/users.js", "src/validators/userValidator.js"], "acceptance": "传入 page<1 或 pageSize>100 时返回 400", "depends_on": [] }, { "id": "T2", "goal": "补充分页参数的单元测试", "files": ["tests/users.test.js"], "acceptance": "覆盖边界值 0、1、100、101", "depends_on": ["T1"] } ] }

depends_on这个字段是多 Agent 并行的关键。没有它,Executor 就不知道该等谁,只能全部串行,多 Agent 的意义就没了。

2.2 Executor:按任务清单干活,一次只做一个

Executor 拿到单个任务,加载任务指定的文件,改完就退出。它不关心其他任务,也不做计划。这种"短生命周期"设计是刻意的——每个任务一个干净的上下文,避免长会话里的注意力衰减。

我一开始让 Executor 常驻,连续处理多个任务,结果发现它会把前一个任务的假设带到后一个任务里。比如 T1 里它假设了某个工具函数存在,T2 里就默认这个函数可用,但实际 T1 根本没创建它。改成"一个任务一个 Executor 实例"之后,这类串味问题基本消失。

2.3 Verifier:专职找茬,且必须独立

Verifier 是最容易被省略、但价值最高的角色。它拿到 Executor 的产出后,不看 Executor 的思路,只看结果和验收标准。它的提示词里我会明确写:"你的任务是找出这个实现不满足验收标准的地方,如果找不到,明确说明你验证了哪些边界。"

独立性的关键:Verifier 不能复用 Executor 的上下文。我见过有人为了省 token,让同一个会话里先写后验,结果 Verifier 满脑子都是"我刚才为什么这么写",根本挑不出毛病。必须开新会话,这是硬要求。

三个角色的分工用一张表说清楚:

角色输入输出上下文策略禁止事项
Planner需求描述任务清单 JSON全局,不加载具体代码禁止写代码
Executor单个任务代码改动只加载任务相关文件禁止改任务范围外的文件
Verifier改动+验收标准验证报告全新会话,只看结果禁止参考实现思路

3. 用 Codex CLI 把协同跑起来:目录结构与调度脚本

理论说完了,落地才是关键。Codex CLI 本身是个命令行工具,它不内置多 Agent 调度,所以调度逻辑得我们自己写。我用的是最土但最稳的办法:一个 shell 脚本 + 三个提示词模板 + 一个共享的任务目录。

3.1 目录结构设计

project/ ├── .agents/ │ ├── prompts/ │ │ ├── planner.md │ │ ├── executor.md │ │ └── verifier.md │ ├── tasks/ │ │ ├── pending/ # Planner 产出的任务 │ │ ├── running/ # 正在执行的任务 │ │ └── done/ # 已完成的任务 │ └── logs/ │ ├── planner.log │ ├── executor.log │ └── verifier.log └── src/

这个结构的好处是状态全部落在文件系统上,任何一步崩了都能从文件恢复,不用维护内存里的状态机。任务在pending里就是待办,被 Executor 拿走就移到running,Verifier 通过后移到done。简单粗暴,但极其可靠。

3.2 Planner 的调用

Planner 只需要跑一次,把需求喂进去:

codex exec \ --prompt-file .agents/prompts/planner.md \ --input "需求:给用户列表接口加分页和参数校验" \ > .agents/tasks/planner_output.json

然后写个小脚本把planner_output.json拆成一个个任务文件丢进pending/:

import json, os, pathlib with open(".agents/tasks/planner_output.json") as f: data = json.load(f) pending = pathlib.Path(".agents/tasks/pending") pending.mkdir(parents=True, exist_ok=True) for task in data["tasks"]: (pending / f"{task['id']}.json").write_text( json.dumps(task, ensure_ascii=False, indent=2) )

3.3 Executor 的调度循环

Executor 的调度核心是依赖检查。一个任务只有在它所有depends_on都进了done/之后才能执行:

#!/bin/bash while true; do for task_file in .agents/tasks/pending/*.json; do [ -e "$task_file" ] || break task_id=$(basename "$task_file" .json) deps=$(jq -r '.depends_on[]?' "$task_file") ready=true for dep in $deps; do [ -f ".agents/tasks/done/$dep.json" ] || ready=false done if [ "$ready" = true ]; then mv "$task_file" ".agents/tasks/running/$task_id.json" codex exec \ --prompt-file .agents/prompts/executor.md \ --input "$(cat .agents/tasks/running/$task_id.json)" \ >> .agents/logs/executor.log 2>&1 mv ".agents/tasks/running/$task_id.json" ".agents/tasks/done/$task_id.json" fi done sleep 2 done

这段脚本我用了很久,sleep 2是防止空转烧 CPU。如果你要并行跑多个 Executor,把for循环里的执行部分丢到后台加&就行,但要注意同一文件不能被两个任务同时改,这个约束得在 Planner 拆任务时就保证。

3.4 Verifier 的触发

Verifier 在任务进done/之后触发,开全新会话:

codex exec \ --prompt-file .agents/prompts/verifier.md \ --input "任务:$(cat .agents/tasks/done/T1.json) 改动文件:$(git diff --name-only HEAD~1)" \ > .agents/logs/verify_T1.log

注意:Verifier 的输入里我特意只给"任务定义"和"改动文件列表",不给 Executor 的对话记录。这是保证独立性的关键,宁可多花点 token 重新读文件,也不要让 Verifier 被实现思路带偏。

4. 提示词模板:三个角色各写什么

多 Agent 协同的效果,八成取决于提示词。我调了很多版,下面这三份是当前稳定在用的,直接可以抄。

4.1 Planner 提示词

你是一个任务拆解专家。你的唯一职责是把需求拆成可独立执行的任务清单。 规则: 1. 每个任务必须能由一个不了解其他任务的执行者独立完成 2. 每个任务必须指定明确的文件范围 3. 每个任务必须有可验证的验收标准 4. 用 depends_on 标注任务依赖,无依赖的任务会被并行执行 5. 你绝对不写任何代码,只输出 JSON 输出格式: {"tasks": [{"id": "T1", "goal": "...", "files": [...], "acceptance": "...", "depends_on": [...]}]}

第 1 条规则是灵魂。它逼着 Planner 把任务拆到"自包含"的程度,而不是"你懂的"那种模糊描述。

4.2 Executor 提示词

你是一个代码执行者。你只处理分配给你的这一个任务。 规则: 1. 只修改任务 files 字段列出的文件,绝不越界 2. 严格按 acceptance 字段实现,不多做也不少做 3. 如果发现任务描述有歧义,停下来输出 "BLOCKED: 原因",不要猜 4. 完成后输出改动摘要,不要输出完整代码 任务: {{TASK_JSON}}

第 3 条"BLOCKED"机制特别有用。Executor 遇到歧义时硬猜,往往就是 bug 的来源。让它主动阻塞,把问题抛回给 Planner 或人,比它自作聪明强得多。

4.3 Verifier 提示词

你是一个独立的验证者。你没有参与实现,也不应该假设实现是正确的。 规则: 1. 逐条对照 acceptance 字段验证 2. 主动构造边界用例,不要只跑 happy path 3. 如果发现不满足,明确指出文件和行号 4. 如果全部通过,列出你验证了哪些边界 任务定义: {{TASK_JSON}} 改动文件: {{CHANGED_FILES}}

Verifier 提示词里"你没有参与实现"这句话是刻意写的,它会显著提升挑刺的积极性。实测下来,加了这句话之后,Verifier 抓出的边界问题多了将近一倍。

5. 实测中的坑:协同不是免费的午餐

多 Agent 跑起来之后,我踩的坑比单 Agent 时期还多,只是坑的类型变了。下面这几个是最值得说的。

5.1 任务粒度太粗,Executor 直接摆烂

第一次拆任务,我让 Planner 拆得"粗一点",结果它给出一个"实现用户模块"的任务,涉及 12 个文件。Executor 拿到之后,改了两个文件就输出"完成"。为什么?因为上下文塞不下 12 个文件,它只能挑重点改,剩下的它"以为"不用改。

任务粒度的经验值:单个任务涉及文件不超过 3 个,改动行数预期不超过 150 行。超过这个量级,Planner 就该继续拆。这个数字不是拍脑袋的,是我统计了二十多个任务后,Executor 完成质量开始明显下降的临界点。

5.2 依赖环:Planner 也会犯糊涂

有一次 Planner 拆出 T1 依赖 T2、T2 又依赖 T1 的循环。调度脚本直接死锁,两个任务永远在pending里等对方。后来我在调度脚本里加了个检测:

def has_cycle(tasks): graph = {t["id"]: t["depends_on"] for t in tasks} visited, stack = set(), set() def dfs(node): if node in stack: return True if node in visited: return False visited.add(node); stack.add(node) for dep in graph.get(node, []): if dfs(dep): return True stack.remove(node) return False return any(dfs(n) for n in graph)

Planner 输出后先跑一遍这个检测,有环就打回重拆。别指望模型永远不犯错,用代码兜底比用提示词祈祷靠谱。

5.3 Verifier 太宽松,形同虚设

早期 Verifier 经常输出"看起来没问题"。我分析了一下,原因是它的提示词里"验证"这个词太温和。改成"你的任务是找出这个实现不满足验收标准的地方"之后,它变得挑剔多了。措辞对模型行为的影响,比我想象的大得多。

还有一个技巧:给 Verifier 一个"必须列出至少一个潜在风险"的硬性要求,哪怕实现完全正确。这会逼它认真思考边界,而不是敷衍通过。

5.4 上下文串味:共享文件是重灾区

多个 Executor 并行时,如果两个任务都碰了同一个工具文件,后写的会覆盖先写的。我的解法是在 Planner 阶段就做文件级互斥:同一个文件只能出现在一个任务的files里。如果确实需要多个任务改同一文件,就强制串行,用depends_on串起来。

这个约束听起来很严,但它把并发冲突从"运行时随机出现"变成了"拆解时就能发现",排查成本天差地别。

6. 并发与成本:多 Agent 到底值不值

聊到这儿肯定有人问:多 Agent 是不是更费钱?答案是看任务类型。我拿同一个重构任务做了对比测试:

方案Token 消耗耗时一次通过率
单 Agent 串行约 45k12 分钟60%
三 Agent 协同约 78k7 分钟88%

Token 多了七成,但耗时少了四成,一次通过率从 60% 提到 88%。关键在那个一次通过率——单 Agent 方案里,40% 的情况要人工返工,返工的时间成本远超多花的 token。

所以我的判断标准是:任务越复杂、验收标准越明确,多 Agent 越划算。反过来,如果只是改个变量名、加个日志,单 Agent 直接上,别搞协同,纯属浪费。

6.1 并发度的控制

并行不是越多越好。我实测下来,同时跑 3 个 Executor 是甜点。超过 3 个之后,文件冲突概率上升,而且 Codex CLI 的调用本身有速率限制,排队反而更慢。这个数字跟你的机器配置和账号额度有关,可以自己压测找平衡点。

6.2 成本优化的几个实操点

  • Planner 只跑一次,别每个任务都重新规划,那是纯浪费。
  • Verifier 只验证改动文件,不要让它读整个仓库。
  • 任务清单用 JSON 而不是自然语言,模型解析 JSON 比解析散文省 token。
  • 失败的验证报告要缓存,同一个问题别让 Verifier 反复发现。

7. 从三 Agent 到更多:什么时候该扩展

三 Agent 能覆盖大部分场景,但有些任务确实需要更多角色。我扩展过的两个场景:

场景一:需要外部知识时加 Researcher。比如任务涉及一个我不熟的第三方库,Planner 拆出来的任务里 Executor 老是猜 API 用法。加一个 Researcher,专门去查文档、输出 API 用法摘要,Executor 拿着摘要干活,准确率明显提升。

场景二:需要长期维护时加 Reviewer。如果项目要持续迭代,加一个 Reviewer 定期扫描done/里的改动,检查是否有技术债累积、命名是否一致。它不阻塞流程,只在后台跑,输出改进建议。

但我要泼盆冷水:每加一个 Agent,协调复杂度是平方级上升的。三 Agent 的交互路径是 3 条,四 Agent 就是 6 条,五 Agent 是 10 条。我建议先用三 Agent 跑顺,真的遇到瓶颈了再加,别一上来就堆角色。

7.1 一个判断该不该加 Agent 的土办法

问自己:这个新角色能不能用一句不带"和"的话描述它的职责?能,就加;不能,说明职责还没想清楚,加了也是添乱。比如"Researcher 负责查文档并输出 API 摘要"——可以。"Reviewer 负责检查代码质量和命名规范并给出建议"——这里有个"并",说明它其实是两个角色,得再拆。

8. 我踩过的那些具体报错和修法

最后分享几个实操中真实遇到的报错,都是热词里高频出现的,估计不少人也卡过。

unable to locate the codex cli binary:这个基本是 PATH 没配好。装完之后which codex确认一下,没有的话把 npm 全局 bin 目录加进 PATH。别急着重装,九成是路径问题。

cc switch local proxy failed while handling codex endpoint:这类报错通常跟本地网络配置有关,检查一下是不是有别的进程占了端口,或者配置文件里的地址写错了。我遇到过一次是配置文件里多了个空格,排查了半小时。

npm: 无法加载文件:Windows 上 PowerShell 的执行策略问题。用管理员权限跑一次Set-ExecutionPolicy RemoteSigned就好,但改完记得心里有数,这是系统级设置。

Codex 无法发送消息:先看是不是上下文超了。多 Agent 场景下特别容易超,因为每个 Agent 都往会话里塞东西。我的做法是给每个 Agent 设一个 token 预算,超了就强制截断,宁可信息少点也别整个会话崩掉。

这些报错看着杂,但规律是一样的:先确认环境,再确认配置,最后才怀疑模型。我见过太多人一报错就重装,其实问题根本不在安装上。

多 Agent 协同这套东西,说到底不是技术炫技,而是把"一个人扛所有"变成"每个人扛自己那份"。Codex 是个好工具,但让它一个人包打天下,它累,你也累。拆开之后,每个环节都简单了,出问题也好定位了。我现在做稍大一点的项目,基本都会先花十分钟搭好这套骨架,后面省下的返工时间远不止十分钟。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 10:11:45

5G NR UCI 配置与验证实战:从参数规划到日志排查

简介&#xff1a;这份文档面向5G网络优化工程师及无线通信学习者&#xff0c;系统梳理NR网络中上行控制信息&#xff08;UCI&#xff09;的承载机制与PUCCH设计要点&#xff0c;帮助读者理解调度请求、HARQ ACK/NACK及CSI等控制信令如何在物理上行控制信道上传输。资源为1个doc…

作者头像 李华
网站建设 2026/10/2 10:11:07

论文AI率过高?9款降AI工具实测:原理、流程与避坑指南

2026年的继续教育圈&#xff0c;几乎没有比“AI率”更能让人失眠的词了。毕业论文、课程作业、开题报告、思想汇报&#xff0c;提交之前都要先过一遍AI检测&#xff0c;不少憋了两个月的同学&#xff0c;被一份红色标满的检测报告打回原地。更扎心的是&#xff0c;很多人根本不…

作者头像 李华
网站建设 2026/10/2 10:10:50

LeetCode 739每日温度:从暴力到单调栈的完整拆解

我刚开始刷单调栈这个专题的时候&#xff0c;也被“每日温度”这道题卡过一阵。LeetCode 739这个题号在算法圈里几乎是“必刷清单”里的常客&#xff0c;题目本身看起来平平无奇——给你一组每日温度&#xff0c;让你算每个位置要等几天才有更高的温度。但就是这道easy难度的题…

作者头像 李华
网站建设 2026/10/2 10:09:04

金蝶KIS云采购模块实操指南:从采购订单到入库发票的全流程解析

1. 采购模块的整体定位与业务流程1.1 采购模块在KIS云供应链中的角色接触金蝶KIS云之前&#xff0c;我一直在传统单机版进销存软件里折腾&#xff0c;最大的痛点就是数据孤岛。仓库管仓库的账&#xff0c;财务管财务的账&#xff0c;采购部自己拿个Excel登记到货情况&#xff0…

作者头像 李华
网站建设 2026/10/2 10:08:57

Java运算符从易错到精通:练习路线与自测方案

学Java有一段时间的人&#xff0c;基本都会在某个阶段对自己产生灵魂拷问&#xff1a;语法书翻了三遍&#xff0c;视频课也刷完了&#xff0c;为什么一到手写代码就卡壳&#xff1f;尤其是运算符这部分&#xff0c;看似一个晚上就能翻完&#xff0c;可真到刷题、写项目、面试的…

作者头像 李华