ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

多人多AI协同架构设计:代理层、消息总线与角色编排实战

多人多AI协同架构设计:代理层、消息总线与角色编排实战 AI代理替人跑腿这件事最近一年从玩具变成了工程。我最早接触多智能体协同是在一个内部知识库问答项目里当时只是想让几个Agent分工查资料、写摘要、做校验结果一上手就发现单个Agent跑得挺欢一旦让它们互相通信、共享上下文、按角色协作各种问题全冒出来了——消息乱序、上下文爆炸、某个Agent卡死拖垮整条链路、输出内容踩合规红线。后来我把这套东西逐步抽象成一套多人多AI协同的架构核心思路是人不再直接操作每个AI而是由一个代理层代为交互人只在关键节点做决策和审核。这套架构我反复迭代了几轮踩过的坑足够写一篇长文今天就把设计思路、关键取舍和实操细节完整摊开讲。这篇文章适合两类人看一类是正在做多智能体系统、想让多个AI协同干活的工程师另一类是对AI代理代为交互这个概念感兴趣、想知道背后到底怎么落地的人。我会从架构分层讲到消息总线、从角色编排讲到合规拦截尽量把每个为什么这么设计讲透而不是只丢一堆名词。1. 先搞清楚代理代为交互到底代理了什么很多人一听到AI代理代为交互第一反应是不就是让AI帮我点按钮吗。这个理解太窄了。在我这套架构里代理层代理的是三件事交互动作、上下文维护、决策预筛。这三件事的难度是递增的很多人只做了第一件就以为大功告成结果系统一上规模就崩。1.1 交互动作代理最表层但最容易做歪交互动作代理指的是人不再直接对每个AI发指令而是把意图交给代理层由代理层拆解、分发、汇总。举个具体场景用户说帮我调研一下多智能体协同在电网调度里的应用出一份带引用的报告。在传统模式下用户得自己开好几个对话窗口分别让AI查资料、写大纲、润色。在代理模式下用户只说一句话代理层负责把任务拆成检索—筛选—撰写—校验—引用核对几个子任务分给不同的Agent。这里第一个坑就来了任务拆解的粒度。拆得太粗单个Agent负担过重容易跑偏拆得太细Agent之间通信开销爆炸一个简单任务要来回几十条消息。我实测下来的经验是单个子任务的预期输出控制在300到800字之间比较合适超过1000字就该考虑再拆低于200字就没必要单独开一个Agent合并处理更划算。第二个坑是意图歧义。用户说调研一下到底是只要事实罗列还是要带分析观点代理层如果不在分发前做一次意图澄清后面所有Agent都会基于各自的猜测干活最后汇总出来的东西四不像。我的做法是在代理层加一个轻量的意图确认环节对于模糊指令先返回一个任务拆解预览让用户确认确认后再执行。这一步看似多了一次交互但省下的返工成本远超这点开销。1.2 上下文维护代理真正决定系统上限的部分如果说交互动作代理是手脚那上下文维护代理就是记忆和判断。多智能体系统里最要命的问题不是算力而是上下文的一致性。Agent A基于版本1的资料写了初稿Agent B基于版本2的资料做了修改Agent C又基于版本1做了校验——最后三份东西对不上你还得人工去比对。我的解法是引入一个共享上下文仓库所有Agent的读写都走这个仓库而不是各自维护私有上下文。仓库里每条信息带版本号和来源标记Agent在读取时能知道这条信息是谁在什么时候写的、基于什么依据。写入时走乐观锁版本冲突就重试。这套机制听起来像数据库事务本质上就是——多智能体协同的上下文管理和分布式系统的数据一致性是同一类问题。提示共享上下文仓库不要存原始大文本存摘要加指针。原始资料放对象存储仓库里只放谁引用了哪份资料的哪一段。否则上下文仓库会迅速膨胀到无法维护。1.3 决策预筛代理把人的注意力用在刀刃上人在这套系统里的角色不是操作员而是决策者。但人的注意力是稀缺资源如果每个Agent的每个中间结果都要人确认那还不如自己干。所以代理层要做的第三件事是决策预筛把大量低风险的、可自动化的决策直接放行只把高风险的、模糊的、涉及合规红线的决策推给人。预筛的规则怎么定我一般分三档自动放行格式转换、摘要生成、事实检索、抽样复核内容改写、观点归纳按比例抽检、强制人工确认涉及对外发布、涉及敏感表述、涉及金额或承诺。这个分档不是拍脑袋定的而是根据历史出错率和出错后果的严重程度来调的。跑一段时间后把出错率高的环节往上升一档把长期零出错的环节往下降一档系统会越跑越顺。2. 消息总线多智能体协同的血管怎么铺多智能体系统里Agent之间怎么通信直接决定了系统的吞吐、延迟和可维护性。我见过太多项目一上来就搞全连接——每个Agent都能直接调每个Agent结果就是一张蜘蛛网加一个Agent要改一堆代码排查问题像大海捞针。2.1 为什么我最终选了总线主题订阅而不是点对点点对点通信的优点是简单直接A调B一个函数调用就完事。但它的致命伤是耦合。当你有5个Agent时点对点还能忍到10个以上调用关系就变成了一团乱麻。更麻烦的是点对点很难做广播和聚合——你想让所有Agent都收到资料更新了这个事件点对点就得挨个通知。总线模式的核心是发布订阅Agent不直接互相调用而是往总线上发消息谁关心谁订阅。这样一来新增一个Agent只需要让它订阅相关主题完全不用改其他Agent的代码。我用的主题划分大致是这样的主题发布者订阅者消息类型task.dispatch代理层执行类Agent任务指令context.update任意Agent上下文仓库、相关Agent上下文变更result.ready执行类Agent汇总Agent、校验Agent子任务结果compliance.flag校验Agent代理层、人工复核队列合规告警human.decision人工界面代理层人工决策回传这张表是我实际项目里用的你可以根据自己的场景调整但核心原则不变主题按事件语义划分不按Agent名称划分。按Agent名划分主题比如agentA.output会导致主题数量随Agent数量线性增长很快就失控。2.2 消息的幂等与顺序两个必须提前想清楚的问题总线模式带来两个新问题消息可能重复投递消息可能乱序到达。这两个问题在点对点模式下不明显但在总线模式下是常态。幂等怎么保证我的做法是每条消息带一个全局唯一的消息ID接收方维护一个已处理消息ID的滑动窗口重复ID直接丢弃。这个窗口不用太大保留最近1000条就够因为重复投递通常发生在短时间内。顺序怎么保证严格全局有序代价太高也没必要。我的做法是按任务ID保证局部有序同一个任务下的消息带递增序号接收方按序号处理序号跳跃就等待或请求重发。不同任务之间的消息可以并行互不影响。这样既保证了正确性又保留了并发能力。注意不要试图用时间戳来排序消息。分布式环境下各节点的时钟不可能完全同步时间戳排序在跨节点场景下会出错。用逻辑序号别用物理时间。2.3 背压与熔断别让一个慢Agent拖垮全局多智能体系统里最隐蔽的故障是慢节点拖垮全局。某个Agent因为模型响应慢或者卡在某个循环里它订阅的主题消息越积越多最终把总线堵死所有Agent都受影响。我在总线上加了两道防线。第一道是背压每个Agent的待处理队列有上限超过上限就拒绝新消息并返回忙信号发布方收到忙信号后可以选择重试或降级。第二道是熔断如果某个Agent连续多次超时或报错总线暂时把它从订阅列表里摘掉等它恢复后再加回来。这两道防线加上之后系统的稳定性提升非常明显——以前一个Agent卡死会导致整个任务链停摆现在最多是那个子任务失败其他部分照常推进。3. 角色编排让多个AI各司其职而不是各说各话多智能体系统里Agent不是越多越好。我见过一个项目开了十几个Agent结果大部分时间在互相等待和重复劳动。角色编排的核心是用最少的Agent覆盖任务所需的能力并且让每个Agent的职责边界清晰。3.1 我常用的四类角色及其职责边界经过几轮迭代我稳定下来的角色划分是四类检索者、撰写者、校验者、汇总者。这四类不是随便定的而是对应了信息获取—内容生产—质量把关—结果整合这条完整链路。检索者负责从各种来源拉取原始资料它的输出是带来源标记的素材片段不做任何加工和判断。撰写者负责把素材组织成连贯的内容它的输入是素材片段输出是草稿。校验者负责检查草稿的事实准确性、逻辑一致性和合规性它的输出是问题清单而不是修改后的稿子——这一点很关键校验者如果直接改稿就和撰写者的职责重叠了出了问题分不清是谁的责任。汇总者负责把各方的输出整合成最终结果并处理格式和引用。这四类角色的边界必须写死在系统提示里不能让Agent自由发挥。我踩过的坑是早期没限制撰写者的行为结果它自己去检索了新资料和检索者的输出冲突最后汇总时两份资料对不上。后来我在撰写者的系统提示里明确写了你只能使用输入中提供的素材不得自行检索或引入外部信息问题才解决。3.2 角色之间的交接协议比角色本身更重要角色定好了接下来是交接。Agent A把结果交给Agent B这个交不是简单地把文本丢过去而是要带上一组元信息任务ID、来源标记、置信度、待确认事项。没有这组元信息接收方就不知道该怎么处理这份输入。我定义的交接协议大致包含这几个字段task_id任务唯一标识用于串联整条链路source_refs这份结果引用了哪些原始资料带定位信息confidence产出方对这份结果的置信度高/中/低open_questions产出方不确定、需要下游注意的点compliance_status合规检查状态通过/待查/拦截这套协议看起来繁琐但它解决了一个大问题下游Agent能基于上游的置信度和待确认事项做差异化处理。比如校验者看到置信度低的结果就会重点核查看到高的结果就做常规抽检。这比无差别处理效率高得多。3.3 什么时候该加Agent什么时候该合并判断标准很简单如果两个角色的输入输出格式不同、或者对失败的容忍度不同就该分开如果只是同一类工作的不同实例就该合并。举个例子检索学术资料和检索新闻资料看起来是两件事但它们的输入输出格式一样都是查询→素材片段失败容忍度也一样检索不到就换关键词重试所以应该合并成一个检索者Agent通过参数区分检索源而不是开两个Agent。反过来撰写和校验虽然都处理文本但撰写要创造性、校验要批判性两者的提示词和失败模式完全不同就必须分开。我见过最离谱的设计是给每个数据源开一个Agent结果十个数据源十个Agent光调度逻辑就写了几百行。后来合并成一个检索者加数据源配置表代码量降到原来的五分之一效果反而更好。4. 内容合规多智能体系统里最不能省的一环多智能体系统有个特性Agent之间会互相放大内容。一个Agent产出的轻微偏差经过几个Agent的转述和加工可能被放大成严重问题。所以合规检查不能只在最后做一次而要嵌入到链路的关键节点。4.1 合规检查应该放在哪几个位置我的做法是在三个位置设检查点输入检查、中间检查、输出检查。输入检查针对用户指令拦截明显不当的请求。中间检查针对Agent之间的交接内容重点查是否引入了未经核实的信息和是否出现了不该出现的表述。输出检查针对最终结果做全面的合规扫描。这三个检查点的严格程度是递增的输入检查可以宽松一些避免误伤正常请求中间检查中等严格主要防放大输出检查最严格因为这是最终对外的东西。4.2 规则引擎和模型判断怎么配合纯规则引擎的问题是覆盖不全纯模型判断的问题是可能漏判和误判。我的做法是规则引擎做第一道粗筛模型判断做第二道细筛。规则引擎负责拦截明确的红线词和模式这部分用正则和关键词表就能搞定速度快、零漏判对已知模式而言。模型判断负责处理规则覆盖不到的语义层面问题比如这段话虽然没有敏感词但整体倾向有问题。两道筛子串行规则引擎拦下的直接拦截规则引擎放行的再过模型判断。提示规则引擎的词表要定期更新但不能频繁大改。频繁大改会导致行为不稳定今天能过的明天过不了用户会困惑。我的做法是词表分稳定层和实验层实验层的新规则先跑一段时间观察误伤率稳定后再并入稳定层。4.3 被拦截之后怎么办不能只是简单报错合规拦截之后如果只是给用户返回一个内容不合规用户体验很差而且用户不知道该怎么改。我的做法是拦截时给出可操作的反馈指出哪一部分触发了拦截、触发的是哪类规则、建议怎么修改。比如用户让Agent写一段营销文案文案里出现了夸大表述拦截时不应该只说不合规而应该说第三段的绝对领先属于绝对化表述建议改为在某某维度表现突出。这样用户知道问题在哪也知道怎么改体验就好很多。对于中间检查拦截的情况处理方式又不一样不是返回给用户而是回退给上游Agent重新生成。比如撰写者产出的草稿在中间检查时被拦截系统会自动把拦截原因附在提示里让撰写者重新生成一版。重试次数设上限我一般设2次超过上限就升级到人工处理。5. 本地模型与代理层的配合什么时候该用本地什么时候该用云端最近AI代理助手加本地模型这个方向很热我实际跑过几套组合说说真实感受。本地模型的价值主要在数据不出域、响应延迟低、成本可控这三点但它的能力上限确实比云端大模型低一截。所以关键不是用本地还是用云端而是怎么分工。5.1 我实际用的分工策略我的分工原则是高频、低复杂度、涉及敏感数据的任务走本地低频、高复杂度、需要强推理的任务走云端。具体到角色上检索者的查询改写和素材初筛可以走本地因为这部分任务模式固定、对创造力要求低撰写者的初稿生成走云端因为需要较强的语言组织能力校验者的事实核查走云端因为需要较强的推理和判断汇总者的格式整理走本地因为这部分基本是规则性工作。这套分工跑下来本地模型承担了大约60%的调用量云端只承担40%成本降了一半多而最终质量几乎没有下降。关键是本地和云端之间的接口要统一Agent不需要知道自己在调本地还是云端代理层根据任务类型路由就行。5.2 本地模型的上下文窗口限制怎么绕本地模型普遍上下文窗口偏小这是硬约束。我的绕法是分块处理加摘要传递长文档先分块每块单独处理处理结果汇总成摘要摘要再传给下游。这样每个环节处理的上下文都不超过窗口限制。但分块会带来一个新问题块与块之间的信息丢失。比如一份文档的前半部分定义了某个术语后半部分用了这个术语分块处理后后半部分的Agent不知道这个术语的含义。我的解法是在分块时保留一个全局上下文头把文档的关键定义和背景信息提取出来附在每个块的前面。这个头不用太长几百字就够但能显著减少块间信息丢失。5.3 本地模型的稳定性问题本地模型还有一个容易被忽视的问题长时间运行后的性能衰减。我遇到过本地模型跑几个小时后响应变慢、输出质量下降的情况重启后又恢复正常。后来排查发现是显存碎片和缓存累积导致的。我的应对是定期重启加健康检查本地模型服务每隔一段时间我设的是4小时自动重启一次重启前把待处理任务排空。同时加一个健康检查接口代理层在路由前先探一下本地服务是否健康不健康就临时切到云端。这套机制加上之后因为本地模型不稳定导致的任务失败率降到了可以忽略的水平。6. 实测中那些文档不会写的坑前面讲的都是架构层面的东西这一节讲几个具体到操作层面的坑都是我在实际跑系统时踩出来的常规文档里基本不会提。6.1 Agent的过度自信问题大模型有个通病不知道自己不知道。检索者没检索到相关资料它不会说我没找到而是会基于训练数据里的记忆编一段看起来很像那么回事的内容。这个问题在多智能体系统里会被放大因为下游Agent倾向于信任上游的输出。我的解法是强制检索者标注来源每条素材必须带来源引用没有来源的素材一律标记为未经核实下游Agent看到这个标记就必须做额外核查。同时在检索者的提示里明确写如果检索不到相关资料必须明确返回未找到不得基于记忆编造。这条规则加上之后编造问题减少了八成以上。6.2 上下文仓库的脏读问题共享上下文仓库在并发写入时会出现脏读Agent A正在写一条记录Agent B同时读到了写了一半的内容。这个问题在低并发时不明显一旦Agent数量上去就会频繁出现。我的解法是写入原子化加版本号每条记录的写入是原子的要么全写进去要么完全不写读取时带版本号如果读到的版本和预期不符就重读。这套机制和数据库的MVCC多版本并发控制是一个思路实现起来不复杂但能彻底解决脏读。6.3 任务链路的断头问题多智能体系统跑长任务时偶尔会出现某个环节的Agent没有响应导致整条链路卡住。如果没做超时处理这个任务就会永远挂在那里。我的解法是每个环节设超时加兜底每个Agent处理任务有超时限制超时后总线把任务标记为失败并触发兜底逻辑。兜底逻辑分两种可重试的比如检索超时自动重试不可重试的比如校验发现严重问题升级到人工。同时整条链路有一个总超时超过总超时就整体终止并通知用户避免用户无限等待。6.4 日志和可观测性出事之后能查才是关键多智能体系统出问题时最难的不是修复而是定位。一条任务链路经过五六个Agent每个Agent又调了若干次模型没有完善的日志根本查不出问题出在哪。我的做法是全链路追踪每个任务从创建到结束所有环节的输入输出、耗时、状态都记录在案用task_id串联。日志分两级一级是摘要日志记录每个环节的关键信息用于快速定位二级是详细日志记录完整的输入输出用于深入排查。摘要日志常开详细日志按需开启比如某个任务失败时自动开启该任务的详细日志。这套日志体系加上之后排查问题的平均时间从小时级降到了分钟级。我强烈建议在系统设计初期就把日志和追踪考虑进去后期补的代价要大得多。7. 从单机Demo到生产系统中间隔着什么最后聊聊规模化的问题。很多多智能体项目在Demo阶段跑得很好一上生产就各种问题。我总结下来中间主要隔着三样东西并发控制、故障恢复、成本控制。并发控制方面Demo阶段通常只有一两个任务在跑生产环境可能几十上百个任务并发。这时候上下文仓库的锁竞争、总线的消息堆积、模型服务的限流都会成为瓶颈。我的做法是分层限流总线层面限制总消息速率Agent层面限制单Agent并发数模型服务层面限制调用速率。三层限流配合系统在高并发下也能保持稳定。故障恢复方面Demo阶段挂了重启就行生产环境不能随便重启。我的做法是状态外置Agent本身无状态所有状态存在上下文仓库和任务队列里。Agent挂了直接重启从队列里重新拉任务继续跑。这样单点故障不会导致任务丢失。成本控制方面多智能体系统的模型调用量是单Agent的好几倍不加控制很容易超预算。我的做法是按任务设预算上限每个任务预估一个模型调用次数上限超过上限就降级比如从云端切到本地或终止。同时监控各Agent的调用量异常增长的及时排查。这套东西跑下来我的体会是多智能体协同系统的难点从来不在让AI干活而在让AI可靠地、可控地、可负担地干活。架构设计的大部分精力应该花在后三个词上而不是第一个。我见过太多项目把精力全花在提示词调优上结果系统一上规模就崩就是因为忽略了可靠性、可控性和成本这三个维度。如果你正在做类似的东西我的建议是先把单Agent的边界和职责定清楚再考虑多Agent协同先把消息总线和上下文仓库搭起来再往里填Agent先把合规检查和日志追踪做好再追求功能丰富度。顺序反了后面返工的代价会很大。
返回列表