多智能体系统里存在多种通信范式:一对多广播、多对一汇聚、拉取模式、实时流式推送、高可靠错误消息。如果每种场景单独实现一套通信通道,会造成代码臃肿、维护成本高。本文介绍使用 EventBus(事件总线,发布-订阅模型) 收敛全部通信场景,同时解决 Agent 引擎内部通信,以及后端向前端实时推送状态两大核心问题。

一、多 Agent 系统两大通信难题

在多智能体项目中,通信可以归纳为两类核心问题:

  1. 引擎间通信:各个 Agent 模块之间如何交换事件、中间结果、状态变更。
  2. 前后端通信:后端 Agent 在后台长时间运行,如何把任务进度、思考过程实时推送到浏览器前端。

实际业务会拆解出 5 种典型通信场景,每种场景对通信模型、延迟、可靠性要求完全不一样:

通信场景 通信模型 特点 Agent 业务释义
研究进度广播 一对多 实时低延迟 某一个 Agent 输出任务进度,多个后端 Agent / 监控组件同时订阅观察
论坛摘要收集 多对一 异步、可缓冲 大量子 Agent 产出碎片化结果,汇总交给同一个聚合 Agent 处理,允许消息排队削峰
HOST 发言反馈 一对多、拉取模式 非实时 主 HOST Agent 产生思考输出,不主动推送;客户端按需主动拉取缓存数据,降低消息风暴压力
进度推送到前端 多对多 实时、支持断线重连 多个 Agent 产生实时事件,推送给多个浏览器用户;网页刷新断线后,可以恢复事件流
错误通知 多对一 实时、消息不可丢失 全部 Agent 抛出异常事件,统一交给错误处理模块;错误消息不能丢失,用于告警、重试、日志审计

如果针对上面每一种场景,独立实现一套通信通道,分别手写一对多广播、多对一队列、拉取缓存、推送流,会造成大量重复代码,架构臃肿,后续新增 Agent、新增业务场景维护成本急剧上升。

二、EventBus 事件总线:用一套发布-订阅承载全部场景

EventBus 的核心思路:统一抽象发布-订阅模型,把上面 5 种截然不同的通信场景收敛到同一套总线机制,避免多套通信基础设施

所有组件遵循统一范式:发布者发布事件,订阅者按需订阅自己关心的事件。不需要硬编码模块之间的调用关系。

1. 如何用 Pub-Sub 映射各类通信模式

  • 一对多(进度广播):单个 Agent 发布事件,多个 Agent 订阅同一个事件主题,实现广播。
  • 多对一(摘要收集):多个 Agent 向同一个 Topic 发布事件,仅一个聚合 Agent 订阅消费该事件,实现结果汇聚。
  • 多消费方复用:同一个事件 Topic,可以同时供给后端内部组件,也转发给 SSE 网关,一份事件多处消费。
  • 异步缓冲:摘要收集这类不需要立刻处理的任务,EventBus 支持异步派发,不会阻塞 Agent 主执行流程。
  • 拉取模式(HOST 发言反馈):事件产生时,先把数据写入缓存存储,总线不主动推送通知消费方;需要数据时,业务模块主动读取缓存,不走事件推送链路。

2. 内部引擎通信与前后端推送复用同一总线

这是非常关键的设计取舍:

SSE Router(向前端推送的网关)仅仅是 EventBus 的众多订阅者之一

  1. Agent 引擎只负责 publish 发布事件,完全感知不到前端浏览器的存在。Agent 只管产出事件,不需要关心谁会消费事件。
  2. SSE Router 订阅总线中指定类型事件,把内部事件格式转换为 SSE 流式协议,推送给浏览器。
  3. 后端内部组件通信、向前端推送,复用同一套事件来源,不用维护两套事件生产逻辑。

这样做的好处是:

  • 引擎层只关心“发生了什么”
  • 推送层只关心“如何把事件送到前端”
  • 两边通过 Topic / 事件类型对接,职责清晰

3. 模块解耦,提升扩展性

  • Agent 之间不存在直接函数调用依赖,只依赖事件定义。
  • 新增业务逻辑、新增 Agent,只需要新增事件订阅,不需要修改原有 Agent 业务代码。
  • 可以灵活插拔监控、日志、埋点组件,只需要订阅总线事件即可。

4. 支持断线重连配套能力

事件总线支持事件缓存、事件回放。当用户浏览器断开 SSE、刷新页面重连之后,可以回放历史事件流,恢复 Agent 任务进度,不会因为前端断连丢失中间执行状态。

实践上建议至少约定:

  1. 事件带唯一 ID 与时间戳
  2. 客户端记录最后消费位置(cursor / lastEventId)
  3. 重连时按位置请求回放,而不是整段重跑任务

三、整体设计总结

多 Agent 系统内部混合了一对多广播、多对一结果汇聚、拉取读取、前后端流式推送、高可靠错误通知等多种通信模式。如果每个场景单独实现通信通道会极度复杂。

EventBus 使用统一的发布-订阅模型,把全部通信场景收敛到一套机制,完成模块解耦;同时分离后端内部事件流转、向前端推送事件两条链路,降低整体架构复杂度。

可以把它理解成:

层级 职责
Agent / 业务模块 只负责 publish / subscribe
EventBus 负责路由、缓冲、回放、解耦
SSE Router 作为订阅者之一,负责前端推送

四、落地选型参考

  • 轻量原型阶段:内存 EventBus + Redis 缓存做拉取模式数据存储;适合单机多 Agent。
  • 分布式生产环境:Redis Streams / NATS 作为事件总线底层介质,实现持久化、消息不丢失,支撑分布式多 Agent 部署。
  • 前端侧:SSE 作为推送协议,配合总线实现事件流;断线重连依靠事件回放机制。

选型口诀:先统一“事件模型”,再换“底层介质”。原型阶段用内存总线验证通信语义,上线后再平滑替换成 Redis Streams / NATS,尽量少改业务代码。

五、可直接落地的实现清单

如果你准备动手,建议按这个顺序推进:

  1. 先定义事件清单:事件名、字段、谁发布、谁订阅
  2. 实现最小 EventBus:publish / subscribe / 异步派发
  3. 把进度广播、摘要汇聚接到总线上
  4. 让 SSE Router 只订阅前端需要的事件类型
  5. 为错误事件单独加持久化与告警通道
  6. 最后补齐事件缓存与断线回放

核心原则只有一句:

Agent 负责产出事实,EventBus 负责分发事实,前端只消费事实。