JOTO
Contact us
← AI 智库
技术前沿

第 13 篇 · 多 Agent:协作原理与任务委派实现

2026 年 8 月 8 日

多 Agent 协作的实现

前面的章节我们已经为 Agent 加上了工具、Skill、MCP、上下文压缩和跨会话记忆。这些能力都运行在同一个 Agent 循环中。

当Agent需要处理的任务变复杂后,单个 Agent 既要理解目标、拆分任务,又要检索资料、调用工具、检查结果和组织答案。

所有步骤共用同一份 messages 消息数组、同一组工具和同一个执行状态,就很容易出现上下文膨胀、注意力分散和局部失败相互影响等问题。

多 Agent 系统提供了另一种组织方式,把复杂目标交给多个相对独立的 Agent 执行单元,通过明确的分工、通信协议和协调机制共同完成任务。

我们假设用户提出一个任务:

找出最近一周修改过 services/ 这个目录下面代码 的所有 PR,并逐个总结改动与风险,最后生成一份统一报告。

多 Agent系统可以让一个协调者Agent负责拆解与汇总,让多个执行者Agent分别分析 PR,每个执行者只处理自己的局部上下文,最后把标准化结论交回协调者。

本文分成两部分:

  1. 先介绍什么是多 Agent、为什么需要多 Agent、常见实现方式和关键工程问题
  2. 再沿着源码说明 mini-openclaw 如何用 主 Agent 委派子 Agent 实现一种具体的多 Agent 架构。

第一部分:多 Agent 的原理

什么是多 Agent

多 Agent 系统包含多个能够独立运行的 Agent 执行单元,它们围绕同一个目标分工协作。

一个 Agent 执行单元通常包含以下几个部分:

  • 自己的任务或角色
  • 独立的上下文或状态
  • 可调用的模型、工具与 Skill
  • 接收任务和返回结果的通信接口
  • 明确的启动、运行和终止条件

Agent 可以使用不同模型,也可以复用同一个模型配置。判断一个系统是否属于多 Agent, 关键在于它是否包含多个边界清晰、可自主循环运行的 Agent,以及这些 Agent 是否具备彼此通信、协同推进任务的能力。

第 13 篇 · 多 Agent:协作原理与任务委派实现

为什么需要多 Agent

多 Agent 关注的是复杂任务的组织方式,即使单个Agent有能力完成任务,拆分执行仍可能让流程更可靠、更容易控制。

1. 分解复杂任务

复杂目标往往包含检索、分析、实现、测试和总结等不同阶段。把它们拆成输入和输出明确的子任务,可以降低每个 Agent 单次决策的难度。

2. 隔离上下文

假设分析 5 个 PR,每个 PR 的 diff 和工具结果占 4,000 token。最终报告只需要每个 PR 的结论,不需要把所有原始 diff 长期保留在协调者的 messages 中。

独立 Agent 可以在自己的上下文中处理大量中间材料,只把摘要、证据和风险返回给协调者。这种做法控制了各执行单元的上下文规模,但整个系统的 token 总消耗未必会减少。

3. 专业化能力

不同 Agent 可以使用不同的 system prompt、模型、工具或 Skill。例如:

  • 检索 Agent 只负责查找资料并给出来源
  • 代码 Agent 只负责修改指定目录
  • 审查 Agent 不写代码,只检查风险
  • 汇总 Agent 不访问外部系统,只整合已有结果

专业化可以减少无关工具和指令对模型的干扰。

4. 并发执行

相互独立的子任务可以同时运行,处理 10 个互不依赖的文件时,fan-out 并行通常比一个 Agent 依次处理更快。

多 Agent 也可能串行执行,异步调度、并发执行和结果汇聚机制共同决定了这类任务能否获得时延收益。

5. 故障与权限隔离

一个局部任务失败时,协调者可以单独重试、降级或跳过,主流程的其他状态仍然保留。每个 Agent 也可以只获得完成任务所需的最小权限,降低误操作范围。

多 Agent 同样有代价,它会增加模型调用、通信和调度开销,还会引入结果冲突、重复劳动、共享状态一致性和错误传播等新问题。使用多 Agent 前,需要确认分工收益足以覆盖这些成本。

多 Agent 系统由什么组成

一个可工作的多 Agent 系统通常包含五个层面:

层面
核心问题
角色与能力
每个 Agent 负责什么,可以使用哪些模型、工具和 Skill?
任务分解
谁把总目标拆成子任务,依赖关系如何表示?
通信与状态
Agent 之间传递消息、结构化结果,还是读写共享工作区?
调度与编排
任务按顺序、并行、条件分支还是动态方式运行?
治理与观测
如何限制权限、预算、轮数,处理失败并追踪执行过程?

只创建多个模型调用还不够。没有任务边界、通信协议和终止条件,多个 Agent 很容易重复工作或互相覆盖结果。

常见的多 Agent 实现方式

多 Agent 没有唯一架构。下面几种方式可以单独使用,也可以组合。

1. Supervisor–Worker:监督者与执行者

一个 Supervisor 理解总目标、拆分任务、选择 Worker 并汇总结果。Worker 只处理被分配的局部任务。

第 13 篇 · 多 Agent:协作原理与任务委派实现 配图 2

它的优点是控制关系和用户入口清晰,便于统一权限、预算和最终输出。缺点是 Supervisor 可能成为上下文、性能和决策瓶颈。

2. Pipeline:流水线

任务按照固定阶段传递,前一个 Agent 的输出成为后一个 Agent 的输入:

检索 Agent → 分析 Agent → 写作 Agent → 审查 Agent

流水线适合步骤稳定、依赖关系明确的任务,容易测试和重放。缺点是上游错误会沿链路传播,流程也不擅长处理动态变化。

3. Router–Experts:路由器与专家

Router 先判断任务类型,再把请求交给一个或多个专业 Agent。例如把问题路由给代码、数据、法务或客服 Agent。

这种方式的重点是选择合适的执行者,有些请求会被完整交给一个专家处理。它适合请求类型多、专家边界清晰的系统。主要风险是路由错误,以及跨领域任务被分给单一专家。

4. Fan-out / Fan-in:并行分发与汇聚

调度器把同类或互相独立的任务同时发给多个 Agent,等待结果后统一聚合。例如并行分析多个 PR,或让多个 Agent 独立提出方案,再由评审 Agent 比较。

它可以降低批量任务的总时延,也能用多份独立答案提高覆盖率。代价是调用成本更高,并且需要处理超时、部分失败、重复结果和冲突合并。

5. Peer-to-Peer / Shared Workspace:对等协作或共享工作区

这种架构不设唯一的 Supervisor。各 Agent 通过消息、事件队列、黑板或共享工作区协作:一个 Agent 发布任务,其他 Agent 认领任务或继续处理。

这种方式适合开放式、动态协作,但工程复杂度最高。系统必须处理并发写入、状态一致性、任务抢占、死锁、重复消费和全局终止等问题。

6. Hierarchical Teams:分层团队

顶层 Agent 管理多个组长,组长继续管理各自的执行者。它适合规模较大的任务树,但链路越深,信息损失、预算失控和故障定位就越困难。

Agent 之间如何通信

Agent 协作常见有三种通信方式:

  1. 消息传递:一个 Agent 把任务或结果直接发送给另一个 Agent;
  2. 结构化任务与结果:通过固定 schema 传递状态、证据、风险和下一步建议;
  3. 共享状态:多个 Agent 读写同一个数据库、文件工作区、任务队列或记忆系统。

直接把原始对话全文交给另一个 Agent,通常会带入无关信息、扩大上下文,也让接收方难以区分事实、指令和中间推理。

一般可以按照下面这个格式来处理:

字段
回答的问题
task
要完成什么局部目标?
context
完成任务必须知道哪些事实?
tools
可以使用哪些工具?
skills
可以采用哪些技能流程?
expected_output
返回什么格式才算完成?

返回结果也应尽量结构化,至少包含状态、结论、证据或发现、风险、缺失信息和下一步建议。结构化协议让协调者可以判断成功与失败,也便于持久化、观测和自动评估。

多 Agent 的关键工程问题

上下文边界

上下文太少,执行者无法完成任务,上下文太多,又会失去隔离意义。通常只传递任务必需事实、输入引用、约束和验收标准,不直接复制协调者的完整 messages。

权限边界

委派不能成为权限升级通道,层级委派中通常要求:

Worker 权限 ⊆ Supervisor 权限

并进一步按照最小权限原则,只分配本次子任务需要的能力。

调度与状态

系统需要知道任务处于等待、运行、成功、失败、取消还是超时状态。并行任务还要处理结果顺序、部分成功和重试幂等性。

终止与预算

每个 Agent 都可能重复搜索或调用工具。系统应限制单 Agent 轮数、总委派数、递归深度、token、费用和执行时间,并定义全局完成条件。

结果可信度

多个 Agent 不会自动带来正确答案,系统仍要校验证据、处理相互冲突的结论,并防止下游把上游的猜测当成事实。常见做法包括 schema 校验、评审 Agent、规则校验和外部测试。

可观测性

一次用户请求可能产生多条 Agent 运行链路。事件与 Trace 至少要能回答:

  • 谁创建了哪个任务
  • 每个 Agent 收到了什么上下文和权限
  • 调用了哪些模型与工具
  • 结果如何传递
  • 哪个步骤失败、超时或消耗过高

什么时候不需要多 Agent

以下任务通常留在单 Agent 中更合适:

  • 问题简单,一次模型循环即可完成
  • 子任务高度耦合,需要频繁共享不断变化的状态
  • 无法写清子任务的输入、边界和验收标准
  • 委派出去的 context 几乎等于完整父对话
  • 多次调用和协调成本高于分工收益

可以先问两个问题:

任务能否拆成 输入明确、输出明确 的独立单元?

拆分带来的隔离、专业化或并发收益,是否大于通信与调度成本?

如果答案是否定的,不必为了使用多 Agent 而增加 Agent。

第二部分:mini-openclaw 如何实现多 Agent

前面介绍的是通用原理。下面回到 mini-openclaw,沿着一次 delegate_task 调用实际经过的顺序阅读源码。

源码结构与完整调用链

相关代码分散在多个文件中,每个文件负责委派流程的一部分:

文件
职责
chat_service.py
给主 Agent 注入编排规则、注册工具并执行主模型循环
delegate_task_tools.py
定义模型可见的委派参数,并把调用转交给服务层
schemas/delegation.py
定义委派请求和结果的数据结构
delegation_service.py
校验权限、构造子 Agent、执行子模型循环并整理结果
tool_builder.py
为主 Agent 和子 Agent 分别构造工具定义与执行 registry
tool_executor.py
把主、子 Agent 发出的函数调用分发到具体工具
task_service.py
在任务树中创建子任务并更新状态
conversation_logger.py
记录委派、模型和工具事件

一次委派的主调用链如下:

chat_service.stream_chat()
    → 主模型返回 tool__delegate_task
    → tool_executor.dispatch()
    → delegate_task_tools.execute()
    → delegation_service.delegate_task()
    → delegation_service._run_delegated_task()
    → delegation_service._execute_child_agent()

子 Agent 如果需要调用工具,会在 _execute_child_agent() 内运行自己的工具循环:

子模型返回 tool call
    → tool_executor.dispatch()
    → 具体工具或 Skill
    → 工具结果追加到子 messages
    → 再次调用子模型

子模型不再返回工具调用时,结果沿原路径返回:

子模型最终文本
    → _normalize_child_result()
    → DelegateTaskResult
    → 序列化为 JSON 字符串
    → 成为主 Agent 的 tool result
    → 主模型继续生成最终答复

后面的代码讲解按这三段展开:主 Agent 发起委派、服务层创建并运行子 Agent、结果回到主 Agent。

把上面三段调用链合在一起,可以得到一次委派的完整流程:

第 13 篇 · 多 Agent:协作原理与任务委派实现 配图 3

delegate_task_tools.execute() 是工具层与委派服务层的边界,_execute_child_agent() 是委派准备阶段与子 Agent 独立循环的边界。后面逐步阅读源码时,可以用这两个位置判断当前代码仍在主循环中,还是已经进入子循环。

第一步:让主 Agent 知道何时可以委派

backend/app/services/delegation_service.py 定义了 ORCHESTRATION_SYSTEM_PROMPT,告诉主 Agent:

  • 哪些情况适合或不适合使用子 Agent
  • 创建子 Agent 时应该提供哪些字段
  • 子权限不能超过父权限
  • 子 Agent 不直接回复最终用户
  • 主 Agent 必须整合结果后再回答

backend/app/services/chat_service.py 的 get_agent_system_prompt() 会把这段规则加入主 Agent 的 system prompt:

sections.append(ORCHESTRATION_SYSTEM_PROMPT)

提示词只负责告诉模型“什么时候适合委派”,模型还需要在本轮请求的 tools 中看到委派工具,才能发起调用。

delegate_task_tools.py 把该工具声明为默认可用的系统工具:

"id": "delegate_task",
"is_system": True,
"configurable": False,
"default_available": True,

chat_service.stream_chat() 调用 build_tool_definitions() 时,系统工具会进入 openai_tools,工具构建器统一添加 tool__ 前缀,所以模型看到的函数名是:

tool__delegate_task

主 Agent 同时拿到了编排规则和工具定义,前者说明使用条件,后者说明工具调用参数。

第二步:主模型发起 delegate_task 工具调用

backend/app/tools/delegate_task_tools.py 定义了五个参数:

{
    "task": "子 Agent 要完成的具体任务",
    "context": "必要上下文",
    "tools": ["允许的工具"],
    "skills": ["允许的技能"],
    "expected_output": "期望输出格式"
}

schema 只强制要求 task,其余字段都有默认值。缺少 context 或 expected_output 时,请求仍能进入服务层,子 Agent 获得的信息也会相应减少。

主模型返回这个函数调用后,chat_service.stream_chat() 先交给统一分发器:

result = dispatch(
    func_name,
    args,
    registry,
    session_id=session_id,
    execution_context=execution_context,
    tool_call_id=tc["id"],
)

registry 把 tool__delegate_task 映射回工具 ID delegate_task,随后调用链进入 delegate_task_tools.execute()。

工具的 execute() 不直接运行模型,只把参数和当前执行上下文交给 delegation_service.delegate_task():

return delegate_task(
    args,
    session_id=kwargs.get("session_id"),
    execution_context=kwargs.get("execution_context"),
    tool_call_id=kwargs.get("tool_call_id"),
)

这里的三项附加参数用途如下:

  • session_id:记录事件、创建子任务和确定文件输出目录;
  • execution_context:保存父 Agent 的 ID 及权限配置;
  • tool_call_id:关联主 Agent 的这次工具调用与整条委派链路。

第三步:校验请求并登记委派

backend/app/schemas/delegation.py 定义:

class DelegateTaskRequest(BaseModel):
    task: str
    context: str = ""
    tools: list[str] = Field(default_factory=list)
    skills: list[str] = Field(default_factory=list)
    expected_output: str = ""

delegate_task() 先执行:

request = DelegateTaskRequest.model_validate(args)

参数类型不合法时,服务直接返回 Error: delegate_task 参数不合法,不会启动子模型。当前模型没有为 task 设置 min_length,所以空字符串仍能通过 Pydantic 校验。随后还会检查当前执行上下文是否包含 agent_id,因为子 Agent 需要继承父 Agent 的模型配置。

校验通过后,delegate_task() 生成 delegation_id。通常直接复用主模型生成的 tool_call_id;没有该 ID 时才创建 UUID。

如果存在 session_id,系统接着做两项登记:

  1. 写入 delegation_start 事件,保存任务、上下文、工具、Skill 和父 Agent ID;
  2. 在根任务下创建一个状态为 running 的子任务。

子任务保存 delegation_id、tool_call_id,并在 attributes 中记录 expected output、工具和 Skill。后面的Trace 和任务看板据此关联主 Agent 的工具调用与子 Agent 的执行记录。

创建任务记录的代码包在 try/except 中。任务树写入失败时,child_task_id 会变成 None,子 Agent 仍会继续运行。任务记录属于观测能力,不参与子任务的业务执行。

登记完成后,delegate_task() 调用 _run_delegated_task()。后续的权限校验、运行环境构造和子模型循环都从这里开始。

第四步:从父权限中解析子权限

4.1 计算父 Agent 的有效权限

_collect_parent_permissions() 使用父执行上下文重新构建工具 registry:

_, registry = build_tool_definitions(
    execution_context.tool_ids,
    execution_context.skill_ids,
)

随后从 registry 中提取 tool ID 和 skill ID。build_tool_definitions() 会把系统工具、强制工具和 Agent 配置中的工具一起加入 registry,权限校验以这份结果为准。

这里需要区分“配置权限”和“有效权限”。父 Agent 配置文件中的 tool_ids 只是一部分,系统工具和强制工具也会进入主 Agent 的 registry。因此,子权限的上限以父 Agent 实际能够调用的工具为准。

立即咨询 JOTO

JOTO 提供覆盖企业智能体规划与搭建、AI 平台私有化部署、RAG 知识工程、AI 安全治理、FDE 驻场共创及持续运营优化的全周期 AI 落地服务,帮助企业把验证中的 AI 能力转化为安全、可控、可持续迭代的生产力。 联系 JOTO 获取 AI 落地咨询

想把这些做法用到你的业务里?

留下你的场景和痛点,我们帮你判断从哪一步开始。

联系我们
Contact Us

Start your enterprise AI rollout

Tell us your industry, team, and current pain points. We'll get back to you within one business day to help you decide what to tackle first, what data to prepare, and which platform fits.

WeChat
Scan to add us for a 1:1 chat
JOTO WeChat consultation QR code

Tell us what you need

Once we receive your details, we'll be in touch within one business day.