Featured image of post 多Agent 系统架构设计(三):从单 Agent 到多 Agent,什么情况该拆?

多Agent 系统架构设计(三):从单 Agent 到多 Agent,什么情况该拆?

如果你正在搭一个 Agent 系统,你一定经历过这个纠结时刻:

「我的系统,要不要拆成多 Agent?」

一边是单 Agent 的简单美好——一个循环、一个上下文、一个入口,调试起来清清楚楚。但上下文窗口就那么大,模型处理能力就那么多,用户需求一复杂,它就开始「忘了之前说过什么」。

另一边是多 Agent 的灵活强大——各司其职、可以并行、可以专业分工。但一拆开,协调成本飞升、调试变得像大海捞针、状态一致性变成了噩梦。

这不是一个「选哪个」的问题,而是一个 「什么时候该拆,拆了以后怎么应对新问题」 的问题。

这篇文章是这个系列的第三篇。前两篇讲了编排模式和通信层,那是「假设你已经决定拆了」。这一篇我们回到原点:你真的需要拆吗?如果需要,怎么拆?拆了以后,那些新问题怎么应对?

决策框架:什么时候该拆?

先给一个简单的判断标准。

单 Agent 够用的情况:

条件 说明
任务线性的 一个任务接一个任务,没有并发需求
上下文能在窗口内 所有信息塞进一个 LLM 上下文窗口就够了
不需要专业角色 你不需要一个 Agent 专门查数据库、另一个专门做分析
权限不复杂 所有操作都在同一个安全边界内

必须拆成多 Agent 的情况:

条件 说明
超出上下文窗口 长期对话、多文档处理、需要持续记忆的场景
需要并行 同时查 5 个数据源、同时分析 3 份报告
需要专业分工 不同的 Agent 用不同的模型、不同的工具集、不同的 prompt
需要隔离权限 一个 Agent 只能读数据库,另一个只能写文件系统

这个决策框架的关键在于:不要为了「技术时髦」而拆。 我见过太多团队,系统只有 3 个 Agent 就上了 A2A + Kafka + 事件总线,最后花了两周调试通信问题,而单 Agent 加几个工具一天就能搞定同样的事。

核心原则:从单 Agent 出发,被一个具体问题逼到墙角了,再拆。不要预判性地拆。

拆分的三种粒度

当你确定需要拆了,下一个问题是:按什么维度拆?

按能力域(Skill Domain)

最常见的方式。每个 Agent 负责一类能力:搜索 Agent 只做搜索、分析 Agent 只做分析、生成 Agent 只做生成。

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  搜索 Agent  │     │  分析 Agent  │     │  生成 Agent  │
│  工具: 搜索  │     │  工具: 计算  │     │  工具: 写作  │
│  Model: 轻量 │     │  Model: 强  │     │  Model: 创意 │
└─────────────┘     └─────────────┘     └─────────────┘

优点:职责清晰,每个 Agent 的 prompt 和工具集可以针对性优化。 缺点:Agent 之间需要频繁传递数据,通信开销大。

按数据域(Data Domain)

每个 Agent 负责处理一个数据源或一个数据流。常见于数据管道类系统。

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│ 订单数据Agent │    │ 用户数据Agent │    │ 库存数据Agent │
│  只读订单表   │    │  只读用户表   │    │  只读库存表   │
└──────────────┘    └──────────────┘    └──────────────┘

优点:数据隔离性好,每个 Agent 的数据源清晰。 缺点:跨数据源的查询需要多步协调,延迟高。

按安全域(Security Domain)

每个 Agent 运行在不同的权限边界内。这是最容易被忽视但最重要的拆分维度。

┌──────────────────────────────────────┐
│         公共域 Agent                   │
│  权限: 只读公开数据, 无敏感操作        │
└──────────────────────────────────────┘
          │
          ▼
┌──────────────────────────────────────┐
│         内部域 Agent                   │
│  权限: 读写业务数据, 需认证调用        │
└──────────────────────────────────────┘
          │
          ▼
┌──────────────────────────────────────┐
│         敏感域 Agent                   │
│  权限: 支付/财务/个人数据, 强审计      │
└──────────────────────────────────────┘

优点:安全隔离,一个 Agent 被攻破不会波及全系统。 缺点:跨域通信需要认证和审计,增加了延迟。

实际系统中通常是混合拆分

一个真实的 Agent 系统不会只用一种粒度。比如一个客服系统:按安全域拆出「公开咨询 Agent」和「账户操作 Agent」;后者内部再按能力域拆出「订单查询 Agent」和「退款处理 Agent」;订单查询 Agent 内部再按数据域拆出「MySQL 查询 Agent」和「Redis 缓存 Agent」。

拆分粒度没有标准答案,但有指导原则:先按安全域拆(最刚性),再按能力域拆(最灵活),最后按数据域拆(最细化)。

拆了以后的新问题

拆完以后,你以为问题解决了?才刚开始。多 Agent 系统引入的新问题,比单 Agent 时代多得多。

协调开销(Token 成本 + 延迟)

这是最直观的代价。单 Agent 时代,一个 LLM 调用完成所有推理。多 Agent 时代,每个 Agent 各调用一次,再加上协调 Agent 的调用,Token 消耗翻倍甚至翻三倍。

实测数据: 一个三 Agent 系统(Orchestrator + 2 Workers)完成一个简单任务,总 Token 消耗是单 Agent 的 2.5-3 倍。其中 30-40% 的 Token 消耗在协调本身(任务分解、结果汇总、状态同步),而不是在「干活」上。

应对策略:

  • 不要什么任务都走多 Agent。简单的「查一下天气」这种问题,单 Agent 直接返回,不需要走完整编排流程。只有复杂任务才走多 Agent 路径。
  • 用缓存减少重复协调。同一个任务类型,协调 Agent 的分解策略可以缓存,不需要每次都重新推理。
  • 选择轻量协调协议。MCP 的请求-响应比 A2A 的任务状态机更轻量,因为后者需要维护任务状态。如果 Agent 之间只需要「你给我一个结果」,用 MCP 就够了。

调试困难(因果链断裂)

单 Agent 时代,debug 就是看一个 LLM 的完整推理日志。「为什么它返回这个结果?」——看完整对话就知道了。

多 Agent 时代,一个结果经过了 Agent A → Agent B → Agent C,中间还有三个队列、两个超时重试、一个降级策略。你看到最终结果错了,但根本不知道是哪个环节出了问题。

这就是多 Agent 系统最致命的可观测性问题。

应对策略:

  • 每个 Agent 请求都带 Trace ID。这是分布式 Tracing 101,但在 Agent 系统里经常被忽略。每个用户请求生成一个 Trace ID,贯穿所有 Agent 调用。
  • 记录每个 Agent 的「输入 + 输出 + 推理过程」。不只是日志,而是结构化的追踪数据——Agent 收到了什么、想了什么、做了什么、返回了什么。
  • 用事件总线做审计日志。所有 Agent 之间的通信都写入审计 Topic,出了问题可以回放整个调用链。这比查分散的日志文件高效得多。

状态一致性问题

多个 Agent 共享状态时,一切分布式系统的坑都会出现:

  • 竞态条件:Agent A 和 Agent B 同时更新同一个状态,谁覆盖谁?
  • 过期读:Agent A 读到的状态已经被 Agent B 更新了,但 A 不知道。
  • 部分失败:Agent A 成功了,但 Agent B 失败了,整个任务的状态怎么算?

应对策略:

  • 限制共享状态范围。不是所有 Agent 都需要访问所有状态。按数据域拆分的好处就在这里——每个 Agent 只处理自己的数据,不需要共享。
  • 用事件驱动代替状态共享。A2A 的 Task 状态机是一种不错的方案——Agent A 把任务交给 Agent B 后,不再关心 Agent B 的内部状态,只关心任务的最终状态(Completed / Failed / Cancelled)。
  • 接受最终一致性。大多数 Agent 场景不需要强一致性。一个 Agent 晚了几秒看到最新状态,通常不会导致灾难性后果。不要为了强一致性去引入分布式事务,那会复杂得让你怀疑人生。

攻击面扩大

每个 Agent 都是一个潜在的攻击入口。单 Agent 时代,你只需要保护一个入口。多 Agent 时代,N 个 Agent 就有 N 个入口。

安全风险清单:

  • Agent 冒充:攻击者伪装成合法 Agent 发送恶意请求
  • Prompt 注入跨 Agent 传播:一个 Agent 被注入后,通过通信把恶意 prompt 传给其他 Agent
  • 数据泄露:Agent A 没有权限访问的数据,通过 Agent B 的返回间接泄露
  • 拒绝服务:一个 Agent 被大量请求压垮,导致依赖它的其他 Agent 也超时

应对策略:

  • 网关层做认证和审计(见第二篇关于网关层的讨论)。所有 Agent 之间的通信经过网关,网关验证身份、记录日志、做限流。
  • 最小权限原则。每个 Agent 只拥有完成任务所需的最小权限。不要在 Agent 间共享 API Key。
  • 通信加密。Agent 之间的所有通信使用 mTLS 或类似机制加密。
  • 输入输出过滤。每个 Agent 在接收输入和发送输出时,做基本的 prompt 注入检测。

对比分析:从开源项目中学习

前几个月我拆解了好几个开源 Agent 项目,现在回头看,它们各自展示了「单 Agent 到多 Agent」演进过程中的不同解法。

Pi Agent 的双队列:单 Agent 内部的并行

《Pi Agent 深度拆解》 中我详细分析了它的 Steering Queue + Follow-up Queue 设计。

Pi Agent 本质上是单 Agent 架构,但通过双队列在单 Agent 内部实现了类似多 Agent 的并行能力:

  • Steering Queue:处理高优先级任务(用户当前指令)
  • Follow-up Queue:处理低优先级任务(后台分析、上下文补充)
           ┌────────────────────────────────┐
           │        Pi Agent (单 Agent)      │
           │                                  │
           │  ┌─────────┐    ┌──────────────┐│
           │  │Steering │    │Follow-up     ││
           │  │ Queue   │    │   Queue      ││
           │  └────┬────┘    └──────┬───────┘│
           │       │                │         │
           │       ▼                ▼         │
           │  ┌──────────────────────────┐   │
           │  │      LLM 推理循环         │   │
           │  └──────────────────────────┘   │
           └────────────────────────────────┘

这个设计的启示不是所有「并行」都需要拆成多 Agent。 如果你的并行需求只是「不同优先级任务的调度」,单 Agent 内部用队列就能解决,完全不需要引入多 Agent 的协调复杂度。

Nanobot 的 MessageBus:轻量级多 Agent 编排

《Nanobot 源码深度拆解》 展示了一个完全不同的思路——用 Python 异步 MessageBus 做轻量级 Agent 编排。

Nanobot 的核心是 MessageBus——一个内存中的事件总线,Agent 通过发布/订阅模式通信:

# Nanobot 的简化模型
class MessageBus:
    def __init__(self):
        self.subscribers = {}  # event_type -> [handlers]

    def publish(self, event_type, payload):
        for handler in self.subscribers.get(event_type, []):
            handler(payload)  # 异步执行

    def subscribe(self, event_type, handler):
        self.subscribers.setdefault(event_type, []).append(handler)

这个设计的启示轻量级事件总线可以解决大部分多 Agent 的协调问题,不需要上 Kafka。 如果你的 Agent 数量在 10 个以内,且都在同一个进程内,Nanobot 的 MessageBus 模式比 Kafka 简单 100 倍。

但 MessageBus 的局限也很明显:没有持久化、没有分区、不支持跨进程通信。一旦 Agent 需要跨机器部署,MessageBus 就不够用了。

OpenTag 的双运行时:协议驱动的多 Agent 架构

《CopilotKit 开源了 OpenTag!》 展示了一种更工程化的多 Agent 架构。

OpenTag 的核心是AG-UI 协议 + 双运行时

  • CopilotKit Runtime:负责聊天 UI、用户交互、会话管理
  • Agent Runtime:负责 Agent 推理、工具调用、任务执行
┌──────────────────────────────────────────────────┐
│                  OpenTag 架构                      │
│                                                    │
│  ┌────────────────────┐  ┌──────────────────────┐ │
│  │  CopilotKit Runtime │  │   Agent Runtime      │ │
│  │  (UI + 会话管理)    │  │   (推理 + 工具执行)   │ │
│  │                     │  │                       │ │
│  │  ┌───────────────┐  │  │  ┌───────────────┐   │ │
│  │  │ Slack/Web/Line │  │  │  │ Agent A      │   │ │
│  │  └───────────────┘  │  │  │ Agent B      │   │ │
│  │                     │  │  │ Agent C      │   │ │
│  └──────────┬──────────┘  │  └───────────────┘   │
│             │             └──────────────────────┘
│             │  AG-UI 协议 (JSON-RPC)
│             ▼
│  ┌──────────────────────────────────────────────┐
│  │          可替换的 Agent Runtime                 │
│  │  原生 Agent / OpenAI Assistants / Anthropic   │
│  └──────────────────────────────────────────────┘

这个设计的启示协议驱动 + 可替换运行时的模式,是「从单 Agent 到多 Agent」演进中最优雅的中间态。 你不需要一开始就决定用多个 Agent 还是一个 Agent——运行时是可替换的。今天用单 Agent 的原生运行时,明天换成多 Agent 的编排运行时,CopilotKit Runtime 完全不需要改。

对比总结

维度 Pi Agent Nanobot OpenTag
架构类型 单 Agent + 内部队列 轻量多 Agent + 事件总线 协议驱动 + 可替换运行时
解决的问题 单 Agent 内的优先级调度 多 Agent 的轻量协调 UI 与 Agent 逻辑的解耦
引入的复杂度 低(队列管理) 中(事件路由) 中(协议定义)
适用规模 1-2 Agent 2-10 Agent 1-50 Agent
可观测性 好(单进程日志) 中(事件追踪) 好(协议层拦截)
演进方向 可拆为多 Agent 可升级到 Kafka 可替换运行时实现多 Agent

核心差异点:Pi Agent 代表「单 Agent 内部优化」的极致,Nanobot 代表「轻量多 Agent」的实用主义,OpenTag 代表「协议驱动」的工程化——在 Agent 之间、在 UI 与 Agent 之间、在运行时与运行时之间,都用协议解耦。对于大多数从单 Agent 起步的团队,OpenTag 的「协议驱动 + 可替换运行时」模式是最值得参考的中间态。

演进路线图:别一步到位

这是我觉得最重要的部分。不要试图一步到位。 多 Agent 系统的复杂度是逐渐显现的,你的架构也应该是逐渐演进的。

阶段 1:单 Agent + 更多工具

状态:一个 Agent,通过 MCP 连接 5-10 个工具。 目标:把单 Agent 的能力推到极限。 关注点:工具选择、Prompt 优化、上下文窗口管理。

  ┌──────────────┐
  │   单 Agent    │
  │  (一个 LLM) │
  └──────┬───────┘
         │
    ┌────┼────┐
    │    │    │
    ▼    ▼    ▼
  工具1 工具2 工具3

什么时候可以进入下一阶段? 当你的 Agent 开始频繁「忘记」上下文,或者你发现一个 prompt 里塞了太多角色定义,导致模型在角色间切换时出错。

阶段 2:单 Agent + 子 Agent(局部并行)

状态:主 Agent 保持整体协调,局部任务委派给子 Agent。 目标:只拆必须拆的部分,保持整体架构简单。 关注点:子 Agent 的边界定义、结果汇总策略。

  ┌──────────────────────────────┐
  │        主 Agent               │
  │  (协调 + 简单任务自己做)       │
  └──────┬──────────────┬────────┘
         │              │
    ┌────▼────┐    ┌────▼────┐
    │ 子Agent 1│    │ 子Agent 2│
    │ (搜索)   │    │ (分析)   │
    └─────────┘    └─────────┘

什么时候可以进入下一阶段? 当子 Agent 数量超过 5 个,或者子 Agent 之间需要互相通信时,局部并行模式就撑不住了。

阶段 3:多 Agent 编排

状态:完整的 Ochestrator-Worker 或 Supervisor 模式。 目标:系统化地管理 Agent 生命周期。 关注点:编排模式选择、通信协议选择、状态管理策略。

这个阶段就是前两篇文章的内容了。选好编排模式(第一篇)、搭好通信层(第二篇),然后跑起来。

什么时候可以进入下一阶段? 当 Agent 数量超过 20 个,或者需要跨团队共享 Agent 时。

阶段 4:分层管理

状态:Supervisor 层级 + 事件总线 + 网关层。 目标:面向大规模、多团队、多环境。 关注点:网关治理、跨域通信、安全策略。

  ┌──────────────────────────────────┐
  │        顶层 Supervisor            │
  │   (策略下发 + 全局监控)           │
  └──────┬──────────────────┬───────┘
         │                  │
    ┌────▼────┐        ┌────▼────┐
    │ 域A Supv│        │ 域B Supv│
    │ (搜索)  │        │ (分析)  │
    └────┬────┘        └────┬────┘
         │                  │
    ┌────┼────┐        ┌────┼────┐
    │    │    │        │    │    │
    ▼    ▼    ▼        ▼    ▼    ▼
   W1   W2   W3       W4   W5   W6

关键原则每一个阶段都应该能独立运行,并且能回退到上一阶段。 如果你在阶段 3 发现「这个任务其实单 Agent 就够了」,你应该能轻松回退到阶段 2,而不是被自己的架构卡住。

实战建议

先跑通再拆

这是最务实的建议。先把整个流程用单 Agent 跑通,确认业务逻辑正确、数据流清晰。然后找出瓶颈点——是上下文不够用了?是响应太慢了?是某个工具调用太频繁了?——针对性地拆。

不要「先拆了再说」。拆完发现不是预期的问题,又费劲合并回来,是最大的浪费。

用可观测性兜底

不管你处在哪个阶段,可观测性是最重要的基础设施。没有它,你根本不知道拆了以后是变好了还是变坏了。

需要关注的三件事:

  1. Trace ID:贯穿所有 Agent 调用,能追踪一个请求的完整生命周期
  2. Token 成本追踪:每个 Agent 每次调用消耗了多少 Token,是评估「拆了值不值」的关键数据
  3. Agent 调用拓扑:谁调用了谁?调用频率如何?失败率如何?——这能帮你发现「这个 Agent 其实不需要」的证据

控制拆分的「度」

一个经验法则:一个 Agent 系统里,Agent 数量不应该超过人类团队规模。 如果你的系统有 10 个 Agent,但你们团队只有 3 个工程师,你大概率管不过来。

另一个经验法则:如果某个 Agent 的职责需要 3 句话以上才能说清楚,它应该被拆成两个。 Agent 的职责边界模糊,是系统混乱的第一信号。

写在最后

这篇文章我们讨论了从单 Agent 到多 Agent 的整个演进路径。核心观点其实很简单:

单 Agent 不是缺陷,多 Agent 不是目标。合适的复杂度才是。

从单 Agent 出发,被具体问题逼到墙角了再拆。拆的时候,先按安全域拆,再按能力域拆,最后按数据域拆。拆完以后,用可观测性来验证「拆了是否真的更好」。如果 Token 消耗翻倍了但响应质量只提升了 10%,那可能不值得拆。

这个系列走到第三篇,我们已经覆盖了编排模式、通信层、演进路径三个维度。下一篇是这个系列的收官篇,我们来聊聊未来的方向——Agent 即服务(Agent as a Service)和 Agent Mesh。

📌 本系列连载:一、《编排模式》 → 二、《通信层》 → 三、演进路径(本篇)→ 四、《Agent 即服务》

By AI博士 万戈