Codex 多智能体机制深度分析 · 下篇:治理与实践

代码来源 : github.com/openai/code... · Rust 工作区 codex-rs · commit 8c07694(2026-10-18 克隆)

分析范围:本文只分析 V2 实现(工具命名空间 collaboration)。仓库中另有 V1 实现;V1 与普通 ReAct 执行模式的对比已单独成文《Codex 多智能体机制·执行模式对比》,本文不再展开。

篇目结构 :全文分上下两篇。上篇(第 0--6 章,另见《Codex 多智能体机制分析_上篇_机制与架构》 )讲机制与架构;下篇(本篇,第 7--14 章)讲治理与实践。两篇章节编号接续,本篇多处引用上篇的机制章节(均标注"上篇");阅读门槛为了解 spawn_agent 派生流程与消息投递路径。


7. 并发与资源治理:真正的工程难点

多智能体的难点从来不是"如何派发",而是"派发过多会怎样"。Codex 在这里叠了五层防线(7.1--7.5)。 图 7:派生过程中的资源治理闸门。该图表达 spawn 请求到达后依次经过的树关停检查、执行容量、驻留槽位、路径与昵称预约、线程创建各道闸门,以及回合执行期的树级 token 预算约束;右侧为各拒绝出口,紫色为槽位满员时的驱逐旁路。

7.1 防线一:执行容量(Execution Capacity)

只限制子 Agent。根 Agent 必须始终可执行------否则整个系统将无法运行。这个限定条件很讲究:限流的目的是防止单棵 Agent 树耗尽机器资源,而根 Agent 是用户直接对话的对象,限制它等于让产品不可用。

容量上限来自 max_concurrent_threads_per_session,默认 4(含根),实际可派的子 Agent 数是它减一(根占一个)。

7.2 防线二:驻留与驱逐(Residency / Eviction)

在允许深层嵌套的情况下,如果每个子 Agent 都常驻内存,20 个 Agent × 每个数万 token 上下文,内存占用将急剧膨胀。因此引入"驻留槽位"概念:逻辑上可以存在很多 Agent,物理上只有少数几个真正装载在内存中。 图 8:驻留状态机。该图表达「驻留中 ↔ 未装载」的迁移条件,以及驱逐的四个前提与重新加载的四项校验。

把图 8 的迁移条件展开成表:

迁移 触发条件 守卫与前提 结果
装载 派生流程创建线程,或唤醒型消息到达未装载目标 驻留槽预约成功(槽位不足时先 LRU 驱逐腾位) 线程进入注册表,计入驻留槽
驻留中 → 未装载(驱逐) 新派生需要驻留槽而槽位已满 候选须空闲:状态为 PendingInit/Completed/Errored/Interrupted 之一,无活跃回合,无 durable sleep,无待触发邮箱项;并能抢到目标线程的驻留写闸(抢不到则本次驱逐返回 Busy,稍后重试) 停止回合调度 → 邮箱搬入树级邮箱 → 环境选择存入注册表 → 摘除注册表条目 → 释放驻留槽
未装载 → 驻留中(重载) followup_task 等唤醒型消息到达,或冷恢复的子 Agent 收到任何消息 校验父线程所有权、历史 V2 标记、记录中的 parent 一致性 从磁盘恢复历史 → 重建线程 → 树级邮箱中的积压消息一次性取回输入队列 → 开新回合
终态后保持 回合到达终态(Completed/Errored/Interrupted) 线程空闲即可被选为驱逐候选 不主动销毁;消息仍可进入树级邮箱,等待下次重载

驱逐候选按 LRU 选择(最近使用过的移到队尾),并跳过两类线程:本次派生受保护的线程,以及尚未启动(PendingInit)的线程------后者是容量驱逐的既有策略:保留未启动的线程。

驱逐子Agent不是"杀掉",是"换出":历史在磁盘上、邮箱在内存里、环境选择记在注册表里,下次需要时按原样重新展开。重新加载时会校验父线程所有权、历史中的 V2 标记、记录里的 parent 一致性。

这套机制让 Codex 能做到"逻辑上容纳 20 个 Agent,物理上 4 个在内存中运行",用户感知不到差异。

7.3 防线三:不设深度上限,用并发间接约束

V2 不设嵌套深度上限,只累加深度不做判断。这一判断基于现实考量:用户真正在意的不是"套了几层",而是"同时有多少在消耗资源"。控制并发数,深度自然被间接限制(一层派两个,两层就 4 个,很快逼近容量上限)。

7.4 防线四:共享 token 预算

预算记录在树级共享运行时上,整棵树共享。这解决了一个真实痛点:3 个子 Agent 并行运行时,每个都认为"我还剩 80% 预算可用",合计便会超支。共享记账让"树的总额"成为硬约束,超限时回合直接终止于 SessionBudgetExceeded。

7.5 防线五:关停可追踪、不悬挂

所有树成员(spawn、完成监听器、清理任务)都记在一个任务跟踪器里,关停时等全部退出,并收集失败报告(最多保留 64 条,防止长生命周期树把失败记录无限堆积)。

同时,所有"应该在完成后标记完成"的操作都由一个关停守卫覆盖:如果任务意外退出而未能标记完成,会被记为显式失败。这是将"静默泄漏"转为"显式告警"的典型手法。


8. 角色与模型分层:默认继承,显式窄化

子 Agent 派生出来的瞬间,有两件事必须当场定下来:它是"谁"------角色决定它的指令与能力面;它用哪个"大脑"------使用哪个大模型与推理强度决定它的智力与成本。本章讲解这两个决定的规则,一句话可以概括:默认全部跟随父 Agent;任何例外都必须显式设置,且只能收窄、不能放大。 这条哲学同时照顾能力与成本:子 Agent 默认不会比父弱,也不会悄悄换成一个更贵的模型;所有差异化入口都带着明确边界。

8.1 角色:一层有界的「减配覆盖」

角色是什么。 角色是一份打包好的差异配置,模型在 spawn_agent 时通过 agent_type 参数按名选用。它能改的项有一个白名单:开发者指令、模型、推理强度、推理摘要、输出详细度、人格、服务档位,以及一组功能开关与技能。

模型如何知道有哪些角色。 模型并不靠猜------spawn_agent 的工具描述里固有一段 Available roles: 清单:用户角色排在前,内置角色排在后,每个角色附带定位描述;配置文件锁定了模型或推理强度的角色,还会附带一句 "This role's model is set to X and cannot be changed."。选用哪个角色是模型的决定,而清单的措辞是运行时影响这个决定的方式。

解析顺序:用户优先,内置兜底。 角色名先查用户角色,再查内置角色,同名时用户角色覆盖内置角色。用户角色来自 $CODEX_HOME/agents/ 目录(递归扫描其中的 toml 文件),也可在配置文件中显式声明。省略 agent_type 时使用内置的 default 角色------它不带任何覆盖,等同于纯继承。当前内置角色有三个:default(无覆盖)、worker(定位是执行与生产工作,描述中强调必须明确文件所有权,并提醒"你不是唯一在改这个代码库的人")、explorer(定位是快而权威的代码库问答;它虽带一个嵌入式配置文件,但当前内容为空,不产生实际覆盖)。另一个 awaiter(长命令守候)已从内置列表移除。角色名不存在时报 "unknown agent_type ''";应用失败时返回固定文案 "agent type is currently not available",细节只进日志------面向模型的错误要可读,面向调试的错误走日志。

为什么叫减配。 白名单中的功能开关只包含五个可关闭项(shell 工具、apps、插件、记忆工具、权限请求工具),技能同样只能关闭:角色可以让子 Agent 比父弱,不可能比父强。其动机与安全论证见上篇 3.5------如果角色可以提权,一个被 prompt injection 影响的子 Agent 就能给自己开更宽的沙箱。测试同样印证了这条边界:角色应用后,权限、模型提供商、MCP 服务器、通知等父级配置原样保留,只有白名单内的项发生变化。

什么时候角色根本不生效。 V2 全历史 fork 不指定角色时,连 default 都不应用,子 Agent 整体继承父配置;只有 V2 全历史 fork 且显式指定角色时,角色才参与配置合成。

8.2 模型:默认继承,覆盖受提示词引导、受运行时校验

默认规则。 子 Agent 默认使用父 Agent 当前这一轮正在使用的模型与推理强度------不是会话启动时那份静态配置,而是调用 spawn_agent 这一刻的生效值;父会话中途切换模型,随后派生的子 Agent 跟上新模型。配置层还可以给所有子 Agent 预设默认(agent_default_subagent_model 与 agent_default_subagent_reasoning_effort)。

提示词立规矩。 V2 的使用提示(注入在 multi_agent_role 指令中)原文是:

Full-history forks (fork_turns omitted or "all") inherit the parent model and reasoning effort and do not accept overrides. Only set model or reasoning_effort when explicitly requested by the user, applicable AGENTS.md instructions, or skill instructions; when doing so, set fork_turns to "none".

译成大白话:继承了父的全部上下文,就老老实实用父的模型;确有必要换,只有用户、AGENTS.md 或技能明确要求时才换,并且要用 fork_turns="none" 明示"我主动放弃了上下文继承"。

关键区分:这是提示词的规矩,不是运行时的拦截。 上文 "do not accept overrides" 约束的是模型的行为,不是程序的执行。运行时测试专门覆盖了 fork_turns="all" 加显式 model 的组合,断言子 Agent 照样使用请求的模型(测试名 spawned_full_history_v2_child_uses_model_precedence_without_dropping_context)------模型不守规矩时,程序并不会拒绝执行。提示词负责防患于未然,运行时负责的是另一类兜底:

运行时真正强制三件事。

  1. 模型名必须在候选列表内。 候选只收录"在模型选择器中可见、且支持多智能体后端"的模型,最多 5 个。不在名单内会直接报错,并把可用模型列出来给模型看:"Unknown model X for spawn_agent. Available models: ..."。
  2. 推理强度必须是该模型支持的档位,否则同样报错。
  3. 角色锁定的模型优先于调用参数。 工具参数里的模型先应用、角色后应用,因此角色自带的模型会盖住调用时传入的 model。

这三条合起来正是"用工具 schema 做约束"的范例:与其在运行时报一堆难以理解的错误,不如让不合法的选项根本不出现在候选列表里。


9. Guardian:第二类多智能体

Codex 中还有一套多智能体用法,容易被忽略但很有参考价值:评审型 Agent。

Guardian 的职责不是执行任务,而是在动作执行前由另一个模型评估其危险性 。它通过线程管理器启动隔离的评审会话来运行,而非简单地调用一次模型。它具有独立的工具策略,只能读取父会话的受限视图。

这套设计有三点值得借鉴:

  1. 评审 Agent 与被评审 Agent 不共享控制权,只共享"只读视图"------评审者不能修改被评审者的状态;
  2. 评审是异步/同步双路径:一路边走边打分(工具调用级别),一路在需要决策时同步介入;
  3. 失败即拒绝(fail-closed) :评审器不可用时不是"放行",而是"拒绝"------安全机制的默认值必须是保守的。

未验证说明:Guardian V2 的采样器数量、连接池上限、抢占式调度等实现参数,本快照中未能逐项核对,上文仅描述机制,不引用数值。


10. 可观测性:一棵树如何被记录

多智能体的调试难度很高:出现问题时,面对的是树形结构而非单线流程。Codex 用四种粒度记录。

粒度一:线程级。每个线程有独立 rollout 文件,记录完整对话与工具调用。

粒度二:树级。rollout-trace 把派生关系还原成运行时节点与信息流边:

记录项 来源 含义
AgentThread 子线程派生 子线程在 trace 里的节点
ToolCall 5 个协作工具 根侧发起的协作工具调用
ConversationItem 子 Agent 面向模型的消息 子 Agent 看到的历史
InteractionEdge spawn / task / result / close 父子之间的信息流

粒度三:事件级。SubAgentActivityItem(Started / Completed,带线程 ID、路径、模型)会作为父回合的正式条目发出,所以 TUI 里能实时看到"某个分支开始了/完成了"。

粒度四:指标级。埋点包括派生计数(带角色、版本标签)、结果投递(queued / failed 分开统计)、工具级调用记录。

值得借鉴的一点:result_delivery 将"入队成功"与"投递失败"分开统计。消息系统中"已发送"与"已送达"是两件事,混合统计会在故障排查中导致错误结论。


11. 功能清单(可作为配置手册使用)

11.1 协作工具面

工具 必填参数 一句话语义 关键限制
spawn_agent task_name, message 派生子 Agent 执行单项任务 task_name 只能小写字母/数字/下划线;fork_turns 只能是 none/all
send_message target, message 给某个 Agent 留言,不唤醒 目标是路径或 ID
followup_task target, message 派后续任务,空闲则唤醒 不能指向根
wait_agent 无 等任意 Agent 有状态更新 超时 10s~1h,默认 30s;只回摘要不回内容
list_agents 无(可选 path_prefix) 列出树里的活 Agent 支持子树前缀过滤
interrupt_agent target 打断目标当前回合 不销毁线程

11.2 关键配置项

配置 默认 作用
enabled --- 开启多智能体工具面
max_concurrent_threads_per_session 4 树内线程总数上限(含根),可派 = N-1
min_wait_timeout_ms / default_wait_timeout_ms / max_wait_timeout_ms 10s / 30s / 1h wait_agent 超时约束
tool_namespace collaboration 工具命名空间,可避免与宿主工具命名冲突
hide_spawn_agent_metadata true 只返回 task_name,不暴露线程 UUID
expose_spawn_agent_model_overrides true 是否暴露 model / reasoning_effort 字段
wait_agent_enabled true 是否暴露 wait_agent
disable_native_tools false 隐藏原生工具但保留多智能体运行时(给宿主自定义工具用)
disable_direct_message false 关掉 Agent 间直接私聊,只保留派生和结果回流
preserve_fork_prefix false 全量 fork 时是否保留父级 prompt 前缀(影响缓存命中)
message_board_in_memory / message_board_remote false / 空 消息板内存模式 / 远端板
root_agent_usage_hint_text / subagent_usage_hint_text 空 直接覆盖注入给根/子的行为准则
subagent_developer_instructions 空 覆盖没有专属角色的子 Agent 的开发者指令

hide_spawn_agent_metadata = true 是个很有想法的默认值:不把 UUID 暴露给模型。模型不需要它(路径就够了),给了反而可能被幻觉编造。


12. 两个完整例子:一次复杂任务是如何执行完成的

前面各章介绍的是各个组成机制,本章将它们组合为完整流程。两个例子覆盖两类最典型的复杂任务:

  • 例一是"一对多并行":一条主任务拆分出三条互不依赖的支线,考察派生、并行、结果回流;
  • 例二是"多层级联 + 动态纠偏":任务在执行中才暴露出深层结构,考察嵌套派生、容量驱逐、重载、中断纠偏、预算熔断。

再次提醒:例子的流程与资源行为严格对应代码机制;模型每轮的具体措辞是示意。横轴是逻辑时间,不追求真实耗时比例。

12.1 例一:三平台 webhook 签名调研 + 对比汇总

用户请求 :"调研 Stripe、PayPal、PayID 三个支付平台的 webhook 签名验证机制,汇总成对比表。" 图 9:例一执行推演(甘特图)。该图表达三条边车任务并行派生、根 Agent 全程未阻塞、结论经终态监听异步回流的完整过程。

分步讲解:

阶段 谁在做什么 背后机制
① 任务分析 根 Agent 读取请求并判断:三条支线互不依赖 → 边车任务;"汇总成表"卡在三条结论上 → 关键路径,由根 Agent 自行处理 编排策略在 prompt 层(上篇 3.1);阻塞任务由根 Agent 自行处理,不派发给子 Agent
② 派生 ×3 根 Agent 连续发起三次 spawn_agent,task_name 分别取 stripe / paypal / payid,message 里写明"只结论、带出处、按统一字段返回" 每次派生都走完整的运行时流程(上篇第 5 章):准入 → 容量 → 槽位 → 路径注册 → fork 历史 → 建线程 → 写 Open 边 → 完成监听
③ 路径就位 三个子 Agent 分别获得 /root/stripe、/root/paypal、/root/payid,UUID 对模型不可见 路径规划(上篇 2.1);hide_spawn_agent_metadata
④ 并行执行 三个子 Agent 各自搜索文档、读规范、交叉验证。每个的上下文只有自己的任务,互不污染 同构副本(上篇 3.3);上下文隔离是场景三的解法
⑤ 根不等待 根 Agent 获得三个 task_name 后即返回,继续搭建汇总表骨架(列名、评分维度),未调用 wait_agent 异步回流是主路径,wait_agent 是兜底机制(上篇 6.4)
⑥ 终态回流 三个子 Agent 先后 Completed。完成监听器把每条结论渲染成 FINAL_ANSWER 消息,作为根回合的正式条目注入,role = "assistant",带 Task name 溯源 终态映射(上篇 2.2);回流格式(上篇 6.3)
⑦ 汇总交付 根 Agent 收齐三条结论,填进骨架,输出对比表;子 Agent 空闲后被 LRU 换出,树随根会话结束整体关停 驻留驱逐(7.2);关停跟踪(7.5)

本例的核心认知 :根 Agent 全程未发生阻塞 。派发任务后它继续处理自身任务,三条结论由子 Agent 自动回流。多智能体在此换来的是墙钟时间(实际耗时)的缩短,代价是三份并行的 token 消耗。

12.2 例二:跨模块 bug 修复(Safari 导出 CSV 乱码)

用户请求:"用户反馈在 Safari 里导出 CSV 文件名和内容都乱码,帮忙定位并修复。"

这个任务的复杂之处在于:结构是在执行过程中才暴露的 ------先要定位,定位后才发现链路跨前后端,需要再拆分;中途还会出现执行方向偏离、容量达到上限、Agent 被换出后重载等情况。 图 10:例二执行推演(甘特图)。该图表达嵌套派生、容量驱逐、中断纠偏、预算熔断与按需重载在一条时间轴上的动态过程。

分步讲解:

阶段 谁在做什么 背后机制
① 本地定位 根 Agent 首先自行读取 issue、复现步骤、查看导出入口代码。"到底是不是编码问题"卡在后续所有步骤上 → 阻塞任务,由根 Agent 自行完成 说明书明确约束:阻塞关键路径自行处理(上篇 3.1)
② 派生两个边车 确认是编码链路问题后,根 Agent 派 /root/repro(写最小复现脚本)和 /root/trace(排查"前端 Blob 构造 → 传输 → 后端响应头"全链路)。两者互不依赖,且都不阻塞根 Agent 继续读代码 场景一并行;fork 历史让子 Agent 携带"用户提出了什么",但不携带父级的中间推理过程(上篇 5.3)
③ 嵌套派生 trace 发现链路跨前后端,派孙 Agent /root/trace/fe(查 Blob 构造与 charset)和 /root/trace/be(查 Content-Disposition 头) 不设深度限制,路径自然长成 /root/trace/fe(7.3)
④ 容量与驱逐 孙 Agent 同样计入执行容量(子 Agent 派生的也一样受限)。槽位不够 → 运行时驱逐最久未用的空闲子 Agent------repro 刚执行完毕正好空闲,被换出:历史落盘、邮箱搬进 Mailboxes、环境选择留在注册表 执行容量只限子 Agent(7.1);先搬邮箱再释放守卫(7.2)
⑤ 结果回流 repro 的复现脚本结论先流回根 Agent;fe/be 的结论流回 trace,由它汇总成"链路结论"再流回根 结果回流是消息而非返回值(上篇 6.3);中间层自然承担汇总与压缩职责
⑥ 发现方向偏离 → 纠偏 根 Agent 发现 trace 正在排查一个无关的转码逻辑。先 interrupt_agent 中止其当前回合(不销毁线程),再 followup_task 带上纠偏指令唤醒它重新排查 send_message 只入队不唤醒,纠偏必须用 followup_task(上篇 6.2);中断不算结果,不产生回流消息(上篇 2.2)
⑦ 预算熔断 孙 Agent 大批量读源码时把整棵树的 token 预算推到上限,某个回合直接终止于 SessionBudgetExceeded,错误作为 Errored 结果回流给根 树级共享记账(7.4):防止"每个分支都认为仍有余量,合计就会超支"
⑧ 按需重载 根 Agent 想找 repro 补充一个细节,但它已被驱逐。运行时从磁盘重载:校验父线程所有权、历史 V2 标记、parent 一致性 → 通过 → 邮箱里积压的消息一次性取出进输入队列 懒驻留换来的能力(7.2);"逻辑上存在,物理上未装载"
⑨ 修复交付 根 Agent 汇总:前端补 BOM/charset、后端补响应头、附复现脚本与回归测试。各 Agent 陆续终态,树随根会话关停 RAII 回滚守护全程待命,均未触发------治理机制的价值在于:未发生故障时其持续生效

本例的核心认知 :多智能体系统真正的考验不是"能否派发",而是执行过程中状态不断变化时系统仍能保持自洽------容量不够就换出、方向错了就纠偏、预算超了就熔断、要对话的 Agent 不在内存就重载。这些全是运行时职责,模型只负责在合适的时机发起对应的工具调用。

12.3 例子与机制对应表

例子里的动作 机制 章节
判断"这个能并行、这个不能" prompt 层编排策略 上篇 3.1
task_name → /root/trace/fe 路径规划 上篇 2.1
派生时复制配置与历史 同构副本 + 有损 fork 上篇 3.3 / 5.3
三个/五个 Agent 同时跑也不触限 执行容量 + 驻留槽 + LRU 驱逐 7.1 / 7.2
结论自动回流 终态监听 + FINAL_ANSWER 回流 上篇 6.3
留言不唤醒、派发任务才唤醒 MessageDeliveryMode 两态 上篇 6.2
打断偏离方向的回合 interrupt_agent 上篇 6.2
整棵树 token 不超支 树级共享预算 7.4
被驱逐的 Agent 还能对话 按需重载 + 所有权校验 7.2
出事不留"半棵树" RAII 回滚 + 关停跟踪 上篇 3.7 / 7.5

13. 设计取舍与批判

以上为设计优势,本节讨论其代价。以下是借鉴前必须充分考虑的问题。

① 编排质量完全依赖模型。 没有可复用的编排 DSL,没有"任务图编译期检查"。同一个任务,换模型、换 reasoning effort、甚至换一次采样,拆分方式可能完全不同。生产环境中这意味着行为不可复现------对需要审计的行业(金融、医疗)是严重障碍。

② 结果消息的信任边界被弱化。 子 Agent 的结论以 role = "assistant" 注入父上下文,形式上等同于"父自己的判断"。如果子 Agent 被注入攻击或产生了幻觉,父 Agent 缺少"这是外部输入,需要核验"的警觉。这是本分析中最值得讨论的一处设计(不少实践者也会自行改造:将子 Agent 结论放入 role = "user" 或添加显式的"未经核验"标记)。

③ 路径寻址对模型的分支推理能力有要求。 /root/task1/task_3 这类绝对路径在小树中很好用,树较深时(4 层、十余个分支)模型容易拼接错误路径。Codex 的缓解手段是 list_agents(path_prefix) + 相对名解析,但仍然依赖模型主动查询。

④ 驱逐/重载的语义对用户不透明。 "逻辑上存在的 Agent 可能已不在内存",重载要校验父所有权、历史 V2 标记、parent 一致性。这套校验完备,但代价是恢复失败时的错误信息对用户不友好。对 CLI 场景可以接受,对产品化场景需要额外封装。

13.1 与常见多智能体方案的对比

下表只对比模式类型(业界常见做法的归类),不对任何具体框架的版本下结论------具体框架的实现随版本变化很快,需要以各自最新文档为准。

维度 中心编排器(supervisor / 图 DSL) 纯 prompt 委派 Codex:模型决策 + 运行时治理
编排决策者 框架代码(预定义任务图/状态机) 模型自主决策 模型(prompt 层),运行时只做硬约束
子 Agent 形态 图节点 / 受限工具调用 另开一段对话 同构线程(同工具、同沙箱、可再派)
身份与寻址 图节点 ID / 队列名 弱(靠对话历史) 规范路径 /root/a/b
资源治理 框架统一管(队列/并发) 基本没有 容量 + 驻留槽 + 树级预算 + 原子回滚
可复现性 强(图是代码,可测试) 弱 弱(编排不可复现,治理可复现)
灵活度 低(改行为要改图、发版) 高 高(改行为改 prompt)
典型风险 过度工程;为简单任务付架构税 失控、重复派发任务、无法排障 依赖模型能力;治理参数需调

Codex 的选择落在第三列:用 prompt 的灵活性换取架构的简单性,再以运行时的硬约束为这种灵活性设定边界。这个交换是否值得,取决于你的场景对"可复现"和"灵活"的权重。

13.2 明确的不适用场景

  • 不适用于需要严格复现、逐笔审计的批处理流水线------编排不可复现是结构性属性,调参无法消除;
  • 不适用于子任务间有大量细粒度共享状态的场景------消息是唯一耦合,没有共享内存/黑板,高频状态同步会淹没在消息里;
  • 不适用于需要跨会话常驻的"专家 Agent"------Agent 树随根会话消亡,常驻需求应交给外部服务或 AgentMessageBoard;
  • 不适用于轻量单轮任务------派生有固定开销(建线程、fork 历史、写图谱边),任务本身几十秒能做完时,多智能体得不偿失;
  • 不适用于根 Agent 模型能力弱的场景------编排质量完全依赖根模型,ExplicitRequestOnly 模式下至少不会主动拆分错误,但用户明确要求拆分时仍可能错误地拆分任务。

14. 如果要借鉴,落地清单

按重要程度排序:

必做(缺了就不算多智能体)

  1. 定义"Agent 的物理载体" :一条有独立上下文/工具/持久化的线程。不宜将"一次函数调用"视为 Agent。
  2. 把"派生"做成原子操作:占槽 → 建线程 → 注册身份 → 写拓扑 → 投递任务,任何一步失败都要能回滚(RAII 守护是最稳妥的实现方式)。
  3. 给 Agent 一个稳定身份:使用路径或命名,不宜使用 UUID。模型友好的身份比机器友好的身份更重要。
  4. 消息是唯一耦合:不要共享可变状态。有共享状态,就无法做懒加载、无法做驱逐、无法做独立恢复。

强烈建议(决定上限)

  1. 两层容量治理:逻辑并发数(能派几个)+ 物理驻留数(同时几个在内存)。两者分离才能实现"逻辑上无上限,物理上可控"。
  2. 树级预算记账:token 预算挂在树根,不挂在单个 Agent。
  3. 权限单调不增:角色/子配置只能关闭能力,不能开启。
  4. 结果回流用"消息"而不是"返回值" :让父 Agent 能在不阻塞的情况下继续工作。

加分项(决定体验)

  1. 把编排策略写成 prompt,并给出"何时不该做" 。多数实现仅说明"能做什么",Codex 则以大量篇幅说明"不该做什么",这才是行为稳定的关键。
  2. 模式闸门:用模型档位/用户设置控制"是否允许主动拆解",成本低于事后纠错。
  3. 可观测性分层齐备:线程级日志 + 树级 trace + 事件级 UI 通知 + 指标级埋点。

附录 关键常量与事实核对

事实 值 出处
默认线程上限 4(可派 3 个) config/mod.rs
默认工具命名空间 collaboration config/mod.rs
wait_agent 超时 最小 10s / 默认 30s / 最大 1h multi_agents_common.rs
默认角色名 default agent/role.rs
模型覆盖候选上限 5(仅收录选择器可见且支持多智能体后端的模型) agent/child_config.rs
全量 fork 的默认值 fork_turns 缺省即 all multi_agents_v2/spawn.rs
默认隐藏 Agent 元数据 true MultiAgentV2Config::defaults_for_max_concurrency
相关推荐
梦醒江南1 小时前
RAG 证据链验收:别只测答案像不像,要证明它从哪里来
前端·agent·ai编程
桦说编程2 小时前
别再追“最强模型”了,先想清楚你要什么
人工智能·llm·agent
武子康3 小时前
HunyuanVideo-1.5 首帧视频怎么做提示词对照?先查清 rewrite 是否生效
人工智能·后端·agent
玩泥巴的4 小时前
一份声明,多份产物:飞书 SDK 的 AI 工具面是怎么生成的
ai·.net·飞书·agent
掘黄金的打工人4 小时前
AI-Agent python
agent·ai编程
小七-七牛开发者5 小时前
从 GLM 到 GPT,HarnessPro 如何用 RSI 降低 Agent 成本
ai·大模型·agent·ai coding·harnesspro
lyai0076 小时前
garak 入门:别急着扫,先看懂一条数据是怎么被判“命中”的
aigc·agent
梦醒江南6 小时前
别让模型每次 CI 都重跑:混合式 e2e 怎么拆步骤
开源·agent·测试