资讯动态

多Agent系统通信与上下文共享:架构设计与实战避坑指南

发布时间:2026/10/22 0:23:21 来源:尧图企业网站定制
多Agent系统这两年热度一直居高不下但很多人搭完Demo之后会发现一个很尴尬的事Agent一多大家各说各话A辛辛苦苦算出来的中间结果B根本看不到最后汇总出来的东西驴唇不对马嘴。问题就出在一件事上——Agent之间的通信和上下文共享没做好。这不是选哪个框架的问题而是整个多Agent系统能不能真正跑起来的地基。这篇文章就把我实际做过的几个多Agent项目里关于通信协议、上下文传递、消息时序、状态一致性这些事的经验和坑一次说清楚。1. 为什么多Agent系统绕不开通信与上下文共享1.1 单体Agent的边界与“分身困境”先抛一个问题一个Agent能干所有事为什么要拆成多个很多人第一反应是“多个Agent更酷”但实际上真正的驱动力是资源边界。单个Agent的上下文窗口有限有Token成本有响应时延。你让一个Agent既做意图识别又做工具调用又做长文档总结又做结果校验它会在两个地方卡死一个是上下文被中间产物塞满还没干正事Token就快烧完了另一个是职责太杂之后系统提示词变得无比臃肿模型反而不知道该听哪条指令。拆开之后问题就来了每个Agent都是独立调用大模型它们本身没有记忆也没有“看到别人在干什么”的能力。A说“帮我查到订单号是12345”B说“好的”但B根本不知道12345是从哪张表里查出来的、筛选条件是什么、有没有经过清洗。信息在Agent之间不是自动流动的你必须主动设计它们的通信方式和共享空间否则多Agent就是多个单Agent的简单拼盘甚至比单体更差。1.2 通信与上下文共享的真正含义很多刚接触的人会把“通信”和“上下文共享”当成一回事其实它们是两个层次。通信解决的是“消息怎么传到对方手里”核心是路由、协议、时序——A怎么把消息给BB怎么知道这条消息是给自己的消息阻塞了怎么办。上下文共享解决的是“各方对同一件事的理解是一致的”核心是状态存储、可见性、一致性——B在干活的时候能不能拿到A已经处理过的数据各个Agent对“当前任务进行到哪一步”有没有共识。打个比方通信是快递员上下文共享是仓库。快递员负责把货从这个仓库送到那个仓库但如果两个仓库的货物清单对不上收到货的人还是不知道怎么干活。我之前看过不少团队的做法是用消息队列把数据发来发去消息倒是没丢但下游Agent拿到的是过期版本的数据或者拿到一堆原始数据还要重新解析一遍这种“能通信但没共享”的状态系统复杂度上去了效率反而下降了。所以真正健康的架构是通信负责触发和通知上下文共享负责提供事实。两者配合才能让多个Agent像一个团队一样协作而不是像多个外包员工各做各的。2. 主流通信模式与选型思路2.1 三种基础通信模式我在不同项目里用过三种模式各有各的适用场景没有绝对的好坏。第一种是点对点直连。Agent A直接调用Agent B的接口传参、拿结果。这种模式最简单调试也方便但缺点很明显Agent之间的关系是写死的加一个新Agent就要改一堆调用关系而且A在等B的时候整个链路是阻塞的。它适合两个Agent之间稳定的一问一答比如“意图识别Agent把结果发给执行Agent”。第二种是发布/订阅。Agent只管往消息中心发事件不关心谁在听订阅方按自己的需求接收感兴趣的事件。这种模式好处是解耦新Agent上线不用改老代码只需要订阅它关心的事件就行。坏处是排查问题的时候责任链不清晰你不知道这条消息到底被谁消费了处理顺序是什么样的。它适合广播类场景比如“任务状态有变化通知所有关心这个任务的Agent”。第三种是共享存储/黑板模式。所有Agent都往一个共享空间里读写状态谁需要什么数据自己去拿谁更新了什么直接写进去。这是上下文共享最直接的一种落地方式。它的问题在于并发写入时的数据一致性以及读写冲突。实际项目里这三种模式不是互斥的。我之前做过一个客服工单处理系统整体是共享存储为核心的每个工单的状态和中间结果都放在共享上下文里各Agent按需读写但在某些关键节点上用的是发布/订阅——比如“新工单进来了负责分类的Agent请处理一下”。2.2 模式选型我的一点实战建议选型的时候别只看技术时髦度先问自己三个问题第一Agent之间的调用关系是否固定如果是固定的点对点就是最高效的不要为了“解耦”而解耦把简单的流程复杂化。第二一个任务的执行是线性链路还是多路并行线性链路可以用点对点或简单队列真正复杂的并行协作才需要发布/订阅或者黑板模式。第三Agent之间共享的数据量级有多大如果只是传递几个状态字段没必要上重型存储如果共享的是长文本、多轮对话历史、业务对象快照那就要认真设计共享存储了。还有一个容易被忽略的点Agent通信的触发方式是同步还是异步。很多场景下下游Agent希望上游处理完马上通知自己但这不代表要阻塞等待。异步触发配上共享上下文是目前综合体验最好的组合——触发靠事件数据靠共享。我用这个组合做过几个项目代码改动灵活性很高后面加Agent基本不用推翻重来。3. 上下文共享的落地设计3.1 上下文的分层会话、工作记忆与长期记忆“共享上下文”这个词听起来抽象落地之前首先要解剖它。我习惯把上下文分成三层这三层的存储方式、生命周期和访问权限完全不一样。会话上下文是最基础的一层相当于一次任务执行过程中的“聊天记录”。包括用户的原始输入、Agent A的中间输出、Agent B的反馈等等。这层的特点是生命周期短——任务结束基本就可以丢了。但因为它的内容天然是长文本直接全部传给每个Agent要么让Token爆炸要么让上下文窗口溢出。工作记忆是任务执行中的关键状态比如当前任务进行到第几步、有哪些待办分支、关键变量值是什么。这层的特征是结构化适合用KV、JSON或数据库字段来存。工作记忆才是真正需要跨Agent共享的核心因为这是协作的基础。长期记忆是Agent系统积累下来的经验库。比如历史工单的处理方式、哪些工具调用经常失败、用户偏好等等。这层不一定在每个任务里都用得到但它是让系统越用越聪明的关键。之前做过一个系统把过去成功处理相似请求时的消息模式存下来新请求进来先检索类似历史作为参考片段注入到规划Agent的提示词里效果比单纯堆参数好得多。共享上下文设计最常见的一个错误就是把三层混在一起全塞进一个大JSON里。看起来什么问题都解决了实际上维护几天就想删库重来。会话上下文放Redis里做短时缓存工作记忆放数据库或者独立的状态服务里长期记忆放向量库或文档存储里各司其职才能定位问题的时候不抓瞎。3.2 共享存储的技术选型选型之前先看团队熟悉什么再看场景需要什么最后才看技术本身。如果只是单机Demo级别的多Agent协作用一个全局字典或者最简单的SQLite也够了。但我做过一个要真正跑业务的项目三个Agent并行处理一批工单共享上下文的数据要同时给多个进程读这时候至少得用Redis因为要处理并发读写和过期策略。如果是需要事务性更新的场景还得考虑数据库。我之前踩过一个坑两个Agent同时更新同一个任务的状态字段最后总有一个更新丢掉了。后来改成数据库行锁加版本号控制才把一致性问题压下去。很多文章不会跟你提这个但真实环境里并发写入就是会出现的。再往上走服务多了之后需要的是统一的状态访问服务。共享存储本身不如“共享访问层”重要——你不希望各个Agent直接拼各种连接串去读写数据源而是让它们都走一个统一的上下文服务。服务内部可以对接Redis、MySQL或者对象存储但对外暴露的就只有“读上下文”“写上下文”“订阅变更”这几个接口。3.3 消息体里的“上下文引用”设计这里我要说一个我认为很关键、但很多人没意识到的细节跨Agent传递消息的时候不要传整个上下文快照而是传一个上下文引用。什么意思呢就是消息里不携带完整的业务数据而是带一个上下文ID比如ctx_20241108_0001下游Agent拿到这个ID之后去共享上下文服务里查真正的数据。这样做有几个好处一是减少消息体体积。你要知道Agent之间的消息如果走消息队列消息太大不管是序列化成本还是传输成本都会让你肉疼。二是避免数据过期问题。A传给B的消息是某个时间点的快照等B真正开始处理这个快照可能已经过时了。带着引用去查B拿到的是当前最新的数据。三是方便追踪。出了问题时你只要看消息里的上下文引用就能回放整个执行链路快速定位是哪个环节的数据不对。当然引用设计要配合缓存和过期策略一起做不然每次都查底层存储性能也扛不住。我们一般会在引用上挂一个TTL比如任务执行期间有效、任务结束就失效既保证协作需要又不至于让垃圾数据堆在存储里。4. 一个最小可复用的实战示例4.1 场景设定光讲理论太虚我拿一个实际做过的简化版场景来演示一下整套链路是怎么跑起来的。场景是一个“智能工单处理”系统包含三个Agent意图识别Agent接收用户工单判断工单类型咨询、投诉、售后。处理Agent根据意图执行对应动作如果是售后就查订单信息如果是投诉就生成升级通知。汇总Agent收集前面Agent的中间结果生成最终响应给用户。这三个Agent在物理上是三个独立服务各自调用大模型。它们之间的协作就完全依赖通信和共享上下文。4.2 消息结构定义先定义统一的消息结构。实践下来最少要包含这几个字段{ message_id: msg_20241108_001, msg_type: ticket.created, source_agent: intent_agent, target_agent: handler_agent, ctx_ref: ctx_ticket_20241108_001, timestamp: 1731052800000, payload: { ticket_id: TK-20241108-001, intent: after_sale } }message_id用于幂等处理和追踪链路msg_type是事件类型让订阅方快速判断是否跟自己相关source_agent和target_agent在点对点模式下用于路由ctx_ref是上下文引用真正完整的数据都挂在共享上下文服务里。4.3 共享上下文服务核心逻辑共享上下文服务不需要很复杂核心能力就两个读和写。用Python写一个简化版示意class SharedContext: def __init__(self): self._storage {} def write(self, ctx_id, key, value, ttlNone): if ctx_id not in self._storage: self._storage[ctx_id] {} self._storage[ctx_id][key] { value: value, updated_at: time.time() } # 实际项目中这里可以额外发布一个事件触发订阅方 def read(self, ctx_id, keyNone): if ctx_id not in self._storage: return None if key is None: return self._storage[ctx_id] return self._storage[ctx_id].get(key) def snapshot(self, ctx_id): # 给需要完整上下文的Agent提供一次性快照 return dict(self._storage.get(ctx_id, {}))实际项目里肯定要加锁、加持久化、加分布式但接口形态基本就是这个样子。Agent之间不直接传数据都是通过这个服务读写。4.4 两个Agent的协作循环意图识别Agent处理完工单往共享上下文里写入识别结果然后发布事件# 意图识别Agent内部逻辑 intent llm_analyze(ticket_text) ctx.write(ctx_ticket_20241108_001, intent, intent) publish(ticket.created, {ticket_id: TK-20241108-001, intent: intent}, targethandler_agent)处理Agent订阅到事件后先从上下文里读出完整数据再干活def on_ticket_created(msg): ctx_id msg[ctx_ref] ticket ctx.read(ctx_id, ticket) intent ctx.read(ctx_id, intent) if intent after_sale: order_info query_order(ticket[order_id]) ctx.write(ctx_id, order_info, order_info) publish(ticket.processed, {ticket_id: ticket[ticket_id]}, targetsummary_agent)汇总Agent最后把所有中间状态读出来生成回复。整个过程里每个Agent只关心自己要写的和要读的不关心其他Agent的内部实现。这个结构的好处是再来十个Agent也能往里加不需要大改。5. 协议、序列化与流式场景的细节处理5.1 为什么消息要比普通JSON多带几个字段很多人写Agent通信传的还是那种只有业务字段的裸JSON比如{ticket_id: 123, intent: 售后}。单看一个消息确实够用但一旦消息多了、Agent多了就会遇到三个问题顺序乱了不知道先处理哪个消息重复投递不知道是不是同一件事出问题之后没法回溯链路。所以消息里必须带上上面示例中的那几个元信息字段。message_id不是为了好看它是幂等处理的基础——消费者拿到消息先查这个ID有没有处理过处理过就跳过这在消息队列的重复投递场景下特别关键。timestamp也很重要尤其是在多个Agent异步处理的时候。它帮你在排查问题时还原事件顺序。我遇到过这样的情况汇总Agent收到的处理结果和意图识别结果不是同一个时间点产生的业务上出现了逻辑矛盾。没有时间戳的话你根本看不出来是谁先谁后。5.2 序列化选择与流式推送Agent之间的消息序列化我用的最多的还是JSON人类可读、调试方便、生态兼容好。但如果你对性能和体积实在敏感可以考虑MessagePack或者Protobuf。我的建议是项目初期没必要上重型序列化JSON足够等流量真上来了再优化也不迟因为序列化替换是相对可控的差异隔离。流式场景稍微特殊一点。大模型输出本身就是流式的如果下游Agent需要边接收边处理再走“积攒完整消息再发”的路线就太慢了。这时候消息类型里要单独定义流式事件比如ticket.updated.partial每次只推一个增量片段。对应地接收方要做片段缓存和按序拼接最后等一个ticket.updated.complete事件来确认整段数据收齐了。流式推送还有一个陷阱顺序问题。网络传输里后发的片段可能先到。所以流式片段消息里务必带上序号片段的起止标识接收方做重排时要用到。这个细节我一开始没注意排查了半天才发现是乱序拼接导致的结果错乱。还有一个关乎体验的细节如果消息量很大注意控制推送频率。不是推得越频繁越好有些Agent根本不需要实时看到每一个token它只需要在关键节点知道结果。我之前把一个工具状态更新从“每次过程都推”改成“只在开始、完成、失败三个节点推”消息量降了80%对业务毫无影响。6. 影响范围分析通信与上下文共享改变了什么6.1 对开发者的影响从写业务逻辑到设计协作协议以前写单体Agent核心工作是写提示词、调参数、设计工具调用。但多Agent系统一旦引入通信和上下文共享开发者的工作重心就变了——你得开始思考“消息类型怎么设计”“谁负责更新状态”“状态冲突怎么解决”这些原来后端系统才考虑的事。这带来一个技能迁移问题。很多做AI应用的同学一开始对并发、状态一致性、消息队列并不熟悉而这些东西恰恰是多Agent稳定运行的关键。我见过不少项目Agent单跑都挺好一组合就各种串状态、丢消息、重复调用工具根本不是模型能力的问题而是通信基础设施没跟上。这个趋势其实对开发者是好事。多Agent系统让它从“调大模型”变成了“设计分布式协作系统”工程含量更高也更值得深入。只会写提示词的红利期正在过去懂消息设计、懂状态管理、懂系统架构的人会越来越有优势。6.2 对团队与产品架构的影响对团队来说上下文共享模式直接改变了分工方式。以前做一个AI功能一个人从头写到尾现在按Agent分层之后有人专门维护共享上下文服务有人专注意图识别Agent有人专注工具执行Agent彼此通过消息结构对齐不用所有事情都去打扰别人。对产品架构的影响更明显。通信与上下文共享做得好整个系统是“可插拔”的——新增一个能力Agent只要声明自己订阅哪些事件、读写哪些上下文就能接入现有流程。做得不好每次加需求都要动主干逻辑产品迭代速度就会被拖死。还有一个对业务的影响容易被忽略多Agent系统的可观测性直接决定了你能不能上线。你有五个Agent在协作用户说“结果不对”你连是哪个Agent搞错的都定位不了这就不是模型问题而是管理问题了。所以通信层和共享层的日志设计要从一开始就做别等上线之后再补。上下文ID贯穿全链路日志里处处带ctx_ref这是最基本的可观测性要求。7. 常见故障与排查实录7.1 我实际踩过的几个坑第一个坑上下文被覆盖。两个并行Agent同时写同一个上下文键最后一个写入的覆盖了前面的。解决方案是给键加上Agent标识或者阶段前缀比如handler_a.order_info和handler_b.order_info分开存需要合并时再由汇总Agent统一处理。第二个坑消息风暴。A处理完发事件B收到后更新上下文又发新事件C收到后又发一旦有循环依赖整个系统就在疯狂刷消息。我的排查办法是在每个Agent的出口加一个节流和去重同时用message_id做链路追踪很快就能发现是谁在循环触发。第三个坑共享上下文无限膨胀。任务一多共享上下文里的数据就不清理最后存储里堆了几百万条过期状态。解决方案是给上下文加生命周期任务结束就归档归档之后只能读不能写再配合定期清理问题就解决了。第四个坑大模型幻觉数据写进上下文。Agent在处理过程中可能会“认为”某个状态是某值然后写进去但这个值根本没经过验证。后来我们要求Agent写入关键状态之前必须先引用数据来源的上下文键否则写入失败。这就逼着Agent的每一步输出都有据可依。7.2 排查工具与套路多Agent系统排查问题的核心思路是“选一个上下文ID走完整个链路”。我们的做法是用户每次任务生成一个trace_id贯穿所有消息和上下文操作。出问题时按trace_id查所有相关记录就能看到每个Agent在哪个时间点读写了什么。实际操作中我会按优先级排查先看有没有消息丢失发送记录在消费记录不在再看有没有状态覆盖同一上下文键被多次写入且来源不同最后看有没有提示词层面的问题Agent读到了正确数据但没用对。建议每个Agent都打两类日志一类是业务日志记录输入输出和关键决策另一类是通信日志记录消息收发、上下文读写。有了这两层日志大部分问题都能快速定位到具体环节。最后说点实在的做了几个多Agent项目的通信层之后我最大的感受是这个系统的复杂度和Agent数量根本就是指数关系而通信与上下文共享的设计决定了这个指数增长是可控还是失控。别急着堆Agent先把消息结构定义清楚、共享上下文分层设计好、日志链路打通比什么技巧都管用。如果你刚起步哪怕用最简单的Redis加JSON消息先跑通一套闭环也比一开始就纠结用哪个消息中间件要实际得多——通信架构的升级可以后做协作逻辑和上下文设计才是真正难改的部分。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑