☰
多人多AI协同系统架构:Agent编排、消息契约与工程落地方案
2026/10/6 6:22:09 网站建设 项目流程

最近在做一个内部预研课题,题目就是“基于AI代理代为交互的多人多AI协同系统架构”。说人话就是:一群人和一群AI代理,在同一套系统里互相协作,每个AI代理不是简单陪你聊天的对话框,而是代表某个角色去接任务、拆任务、调工具、和其他代理交涉,最后把结果回给你。这个方向技术圈讨论热度很高,但真动手搭架构时坑不少。这篇我把预研过程中踩过的坑、拆过的架构、做过的取舍完完整整整理出来,给正在做Agent编排、多智能体协同、或者企业内协同平台的朋友当参考。

1. 场景认知:为什么需要“多人+多AI”的协同架构

1.1 单AI交互的体验天花板

先讲一个我们预研时的痛点。团队里产品、研发、测试每天大量时间花在“对齐”上:产品写了一份需求,研发要解读,测试要理解,中间反复开会确认。大家现在都用AI助手,但实际使用方式是“个人私聊式”——产品问AI、研发也问AI,结果是两个人拿到的答案互相不承认,因为上下文对不上、角色视角不一致、约束条件缺失。这种单点AI交互方式解决不了协作问题。

单人单AI走到今天,体验天花板已经很明显了。它有三个结构性缺口:一是上下文割裂,每个人给AI喂的背景信息不同,AI产出自然不同;二是角色缺失,AI没有固定身份和边界感,今天像产品经理、明天又像开发,完全取决于你怎么问;三是协作无法被表达,你希望“AI代表你去和黄总那边的AI对接”,这在传统对话框形态里根本组织不起来。

所以核心不是把单AI变强,而是把AI放进一个“多角色共存”的系统里。系统里既有真人,也有各司其职的AI代理。真人不再是手工把信息从左边复制到右边,而是通过代理完成事务性交互。这个转变看着小,动起手来才意识到这是整个交互范式的事情。

1.2 “代为交互”到底解决了什么问题

“代为交互”这个词,是这套架构研究的切入点。它和传统AI交互最本质的区别在于:传统交互是“对话”,代理交互是“委托”。你告诉代理一个目标,代理自主去推进,过程中它可能需要查知识库、调用内部API、或者通过协议向其他AI代理发起协作请求。代理不是回答你的问题,而是替你跑活。

举我们预研里用的一个例子。假设产品经理的代理P和研发工程师的代理D,P收到指令“把这份会议记录整理成下周产品行动项,并让D确认排期”。过去要让真人做这件事:整理会议记录、提炼行动项、发消息给研发、研发再评估排期,来回两三天。在“代为交互”模式下,P代理先整理行动项,然后构造一条结构化消息发给D代理,D代理结合自己的任务上下文判断排期是否合理,合理就直接确认,不合理则回复修改建议。整个过程人只需要在关键节点复核,事务性流转由代理完成。

所以“代为交互”有四个可观察的特征:意图接管、自主规划、工具调用、结果回执。意图接管指用户只提目标不写步骤;自主规划指代理自己决定先做什么后做什么;工具调用指代理为了完成任务需要使用外部工具;结果回执指完成后必须把结果沉淀回系统,而不是飘在聊天里。这四件事,是后面整套架构设计的元需求。

1.3 适用场景与目标人群

这套架构的适用场景,不是“想炫技做个聊天机器人”的人,而是真实存在多角色协作压力的地方。我们整理过三类典型场景:

企业部门间协作是最大的一块。销售、产品、研发、客服各自有代理,代理之间传递报价单、需求文档、Bug报告、FAQ条目,人只在节点决策。多学科设计也很有意思,结构工程师、电气工程师、工艺工程师各用一套专业AI代理,在设计评审时自动交叉检查各自约束条件,比如“走线是否撞结构件”“散热是否影响装配”。还有具身智能与机器人场景,多个机器人本体和服务端AI代理协同,任务分发到各机器人的执行控制器,这点也是目前机器人操作系统生态里很热的关注方向。

目标人群我总结为三类:做Agent应用开发的工程师,他们更关心编排框架和消息协议;系统架构设计师,关注的是扩容、容错和权限边界;企业数字化负责人,更关心这套东西落地后能替换什么工作流、降低什么成本。无论哪个角色,这套架构研究对他们都有参考价值。

2. 总体架构设计:把“人-机-人”三角关系落地

2.1 分层架构总览:从一条消息讲起

我们最终采用的分层架构包含四层:接入交互层、网关调度层、代理执行层、记忆与数据层。我没画图,用一条消息的流动来说清楚这件事。

用户从接入层发起指令,可能是Web界面、企业即时通讯机器人或者API。这条指令带着用户身份、会话ID和原始自然语言,进入网关调度层。网关调度层是我的重点设计位置,它负责身份认证、消息路由、负载分配。打个比方,它像一个分布式交换机,核心工作就是“交换”——把正确的消息交换给正确的代理处理。交换逻辑不是简单的搬运,它要认身份、查权限、转协议,还要维护全系统状态。

消息到了代理执行层,才是真正的AI工作区。一个代理是一个逻辑单元,里面有系统提示词、工具集、上下文窗口和工作状态。多个代理之间通过网关交换消息,而不是直连,这样做的好处后面讲。记忆与数据层在底层,主要承担三件事:短期对话缓存、长期知识库、结构化任务记录。逻辑上就这么四层,理论上每层都可以独立扩容。

2.2 核心模块拆解:网关、任务引擎、上下文总线、记忆存储

网关调度层展开看,包含四个关键模块。Agent网关是唯一的流量入口,所有进出代理的消息都经过这里,做身份认证、协议转化、路由转发、限流熔断。它和微服务网关思想很像,但多了一个职责:它需要理解消息里“任务”的语义,知道这条消息该路由给哪个代理。路由规则既可以是静态配置(比如产品类问题一律进P代理),也可以由调度器动态决策。

任务引擎是调度层的神经中枢。它把用户指令拆解为可执行任务,维护任务状态机,记录每个任务的从属关系和依赖关系。我们定义的状态机是:pending、routing、running、awaiting_input、review、completed、failed、canceled。不要小看这个状态机,后面排查“两个代理互相等”的问题全靠它。

上下文总线解决的是记忆一致性问题。多代理系统最常见的翻车现场就是A代理用了B代理的私有中间结果,或者代理拿到过期上下文。上下文总线不存记忆,它只管一件事——定义消息的权限上下文:每条消息属于哪个会话、哪个任务、哪些代理可见,在消息头标好边界,代理只能看到授权的上下文段。

记忆存储分两层:短期记忆用Redis保存最近对话和任务中间态,长期知识用向量库存储沉淀下来的知识碎片。每次代理执行完任务,会把关键结论抽取出来写入长期记忆,后续新任务就能直接检索到。这里要提醒一句,不是所有AI生成结果都值得存,存之前要过一遍去重和置信度筛选。

2.3 架构选型背后的取舍逻辑

为什么非要对所有这些模块做中心化设计?我们试过一种去中心化版本:代理之间直接互发消息,不信网关。跑了两周就被打回原型——你根本不知道某条消息是谁发给谁的、在哪一步丢的、为什么代理B的工作被代理C插了一脚。技术上能跑,运维上完全不可控。因此我们在MVP阶段坚持中心化调度,等接入代理数到几十上百个,再考虑在网关内部做分区容错,或者把执行层做多副本。

同步调用vs异步消息,这个取舍也讲一下。代理执行一次任务经常要十几秒甚至几分钟,如果所有协作都走同步HTTP调用,超时、重试、线程占用都是灾难。我们全部改成了异步消息加状态回调。发起方发完消息注册一个on_complete回调,任务完成后再通知回来,这样不会因为某个代理计算慢而拖垮其他请求。

模型接入上也做了取舍。多个AI不意味着只能接同一个模型供应商。我们的执行层把模型调用封装成了统一模型网关,上游可以同时接闭源大模型、本地开源模型、甚至专门微调的小模型。低价值任务走便宜快模型,高价值决策走强模型。这套解耦的好处是成本可控,不至于因为一个代理就烧掉整个项目预算。

3. 关键技术点:让多个AI代理真正协作起来

3.1 任务编排与分配机制

多人多AI协同的系统里,用户一次自然语言请求,往往要驱动多个代理联动。最核心的问题是任务怎么拆、怎么分。我们常用的做法是三层拆解:指令意图识别、子任务生成、子任务路由。

指令意图识别阶段,网关先用意图识别模型把用户请求归类,比如“写文档”“开评审”“查排期”,每类意图对应一套编排模板。以“写跨部门周报”为例,编排模板会生成三个子任务:收集各团队进展、汇总冲突项、起草下周计划。子任务路由阶段再决定三个子任务分别给谁。我们采用“声明式路由+动态加权”混合策略:每个代理启动时声明自己的能力和适用任务类型,调度器再结合代理当前负载动态分配。这样比纯人手配置路由表更抗流量波动。

每个子任务的请求体我们严格结构化,避免把自然语言一坨丢给代理。一个标准子任务的数据结构类似这样:

{ "task_id": "task_20250621_003", "parent_request_id": "req_001", "intent": "collect_progress", "target_agent": "agent_rd", "input": { "team": "platform", "date_range": ["2025-06-16", "2025-06-20"], "format": "one_line_per_topic" }, "timeout_seconds": 120, "callback_topic": "task_result_feed" }

input字段里不给大段背景,只给必要参数,背景信息一律通过上下文总线的引用机制给。这样可以大大减少token浪费,也降低代理理解错误的概率。

3.2 共享上下文与记忆一致性

多代理协同最容易出问题的就是上下文。我们一开始天真地让所有代理读同一个会话上下文,结果一周内出现三次“代理A引用了代理B的草稿当结论”的事故。后来把上下文改成了“会话飞地+引用注入”模型。

所谓会话飞地,就是每个代理在处理某个任务时有一块独立上下文缓存,只有被明确标注为共享的信息才会放到公共区。代理之间需要通过引用方式传递信息,比如消息里写“详细资料见memory://sessions/sess_42/context_doc/market_research",而不是直接贴一大堆文本。这样做虽然增加了一条跳转,但能有效防止上下文污染。

长期记忆的一致性又是另一个问题。多个代理并行执行后,可能会对同一知识点写出冲突的长期记忆碎片。我们引入记忆版本控制和合并规则:每条记忆带来源代理、生成时间、任务ID;写入时如果检测到同主题记忆已有新版本,会触发一次合并决策,简单场景自动保留置信度更高的,复杂场景排队人工仲裁。

上下文压缩策略也要说。代理处理长任务时,有限窗口根本装不下所有历史。我们定了一个三级策略:全量上下文只保留最近两轮对话,更早的重要结论压缩为摘要,摘要再不可用时落向量库检索。执行结果和推理结论优先保真,过程细节优先压缩,这个优先级顺序在实测里效果最好。

3.3 Agent间通信协议与消息契约

代理之间通信不能靠“你用自然语言发一封邮件”这样自由散漫,必须有严格的消息契约。我们参考了微服务间的契约优先思想,定了一套基于JSON Schema的Agent-to-Agent消息协议。

消息分为两部分:envelope和payload。envelope包含消息ID、发送代理、接收代理、任务追溯ID、消息类型、时间戳、过期时间。payload按消息类型走不同schema,常见类型有request_task、submit_result、ask_clarify、confirm_action、escalate_review。每个类型字段必须明确,不允许发送方自作主张加私有字段。

举个例子,submit_result消息的payload结构如下:

{ "message_type": "submit_result", "envelope": { "msg_id": "m_8f3a", "from": "agent_product", "to": "agent_rd", "trace_id": "trace_101", "expire_at": "2025-06-21T18:00:00Z" }, "payload": { "task_id": "task_20250621_003", "status": "needs_review", "summary": "已完成行动项拆分,共7项,其中2项需RD确认", "items": [ {"id": "item_1", "content": "优化列表页加载速度", "priority": "high"} ], "attachment_refs": ["memory://sessions/sess_42/result_doc/action_items"] } }

这套契约带来两个直接好处:一是消息可审计,出了事故可以从trace_id完整还原链路;二是代理可以编程处理消息,不需要每封信都重新理解一遍自然语言。对于“协商”类通信场景,我们参考了分布式系统里的合同网协议思想:发起方广播招标request_task,候选代理投标propose_quote,发起方对比后中标award_task,未中标的收到decline。这种方式比固定任务分配更灵活,尤其适合资源分配类场景。

3.4 人类介入、权限控制与人工接管

多AI协同系统最大的风险不是AI跑得慢,而是AI在关键节点上自作主张。所以我们强调人在环。系统里每个任务都带一个autonomy_level字段,可选值从完全自动到完全人工审批。高风险操作,比如对外发送正式报价、修改变更数据库、发布线上公告,都必须经过人工审批节点;代理只能发起审批流并等待结果,不能自行继续。

权限控制这块,我们的模型是“用户-代理-工具”三级授权链。代理本身没有任何权限,它执行动作所使用的权限全部来自授权它的用户。用户创建代理时指定一个权限范围,代理调用任何工具前,网关都会校验“代理身份+用户授权+工具白名单”三者匹配才放行。这样即使某个代理被提示词攻击,攻击者能做的事也严格被限制在用户授权的工具集内。

人工接管通道也要保留。我们在网关层设计了一个interrupt接口,负责人可以把任意一个运行中的代理任务取消、挂起或修改目标。实测中这个通道平时很少用,但一旦用了基本都是在保住项目进度。记得在最初设计里把它列为P0功能。

4. 最小可行系统的落地实践

4.1 技术栈选型建议

说完了概念,讲一点能直接上手的选型。我们不推自研全部组件,MVP阶段能拼就拼。

Agent编排框架,我们对比过几个主流的:CrewAI上手快,内置角色分工和流程管理,适合快速验证协作逻辑;AutoGen偏研究型,对多代理会话的调度灵活,但生产化封装少;LangGraph胜在可编程控制的状态机,对复杂流程的把控能力最强,但学习曲线也最陡。QA、团队协作类任务用CrewAI起步比较顺,任务流程强依赖动态编排就直接上LangGraph。

运行时和消息中间件,MVP阶段用Python + FastAPI做服务层,消息用Redis Stream就够了。Redis Stream比普通List好在支持消费者组、消息确认、死信队列,这些正好是代理消息系统缺的。长期记忆用SQLite起步完全可行,检索量大再迁移到独立向量库,没必要一上来就上重型中间件。

模型接入层建议去年我们改成了统一模型网关,底层同时兼容商业API和本地部署的开源模型。本地模型用Ollama或vLLM都能快速起服务,对于成本敏感的项目,简单任务走本地小模型能省不少钱。重要一点,代理框架里不要硬编码某个模型的SDK,统一走兼容OpenAI接口风格的抽象层,后续换模型不会大动干戈。

4.2 核心流程的实现路径

第一步先定义代理角色,这是所有工作的基础。每个代理就是一组系统提示词加上一个工具集合,再加一段人格化设定。比如产品代理,我们给它的工具是创建待办、检索需求库、发送跨代理消息。这里最需要克制的是工具数量,单个代理的工具控制在5个以内,多了模型反而容易选错。

第二步搭一个最小的网关路由服务。说白了就是一个FastAPI应用,接收前端消息、解析意图、查路由表、往对应代理的消息队列投递。这个版本不需要机器学习,用关键词规则都能跑通。跑通的标志是“产品代理收到消息后,能正确回复”。先不要追求复杂。

第三步加任务状态流转。在Redis里维护每个任务的当前状态和处理历史的哈希表,处理函数在关键节点更新状态。这一步最值得花时间,因为后面排查死锁、看消息链路全靠它。参考实现只需要几十行核心逻辑:

def process_task(task): redis.hset(task.task_id, "status", "running") try: result = execute_task(task) redis.hset(task.task_id, "status", "completed") redis.hset(task.task_id, "result", result.summary()) notify_callback(task.callback_topic, result) except TimeoutError: redis.hset(task.task_id, "status", "timeout") escalate_to_human(task)

第四步把人工审批节点接进去。最简单的做法是任务状态为awaiting_input时,在IM端生成一条审批卡片,用户点击后回调接口解锁后续任务。做到这一步,一个可以演示的多人多AI协同最小系统已经成型了。

4.3 性能、成本与安全边界

性能上最容易忽略的是token成本。做过一次估算:一次跨部门周报协作,会触发5个代理、平均每个代理往返交互2次、每次携带约4000个token的上下文,总体就是5×2×4000等于40000个token,按较高价值的商业模型算一次协作光模型费用就是几个到十几个法定货币单位磕碰级别,如果每天全公司跑几百次这种协作,成本会非常可观。所以一定要引入成本控制和分级模型策略,高成本的任务要强制加人工确认。

并发控制上,建议给每个用户设置代理并发上限。我们的默认值是同时最多2个任务在跑,超出的排队。这个限制能防止用户一次提交大量需求,把队列打爆。同时也给代理配了“忙碌标志”——代理只有一个执行槽,忙的时候其他消息要么等要么转给同角色的备用代理。

安全边界主要防三件事:提示词注入、工具滥用、日志泄漏。提示词注入靠权限校验兜底,工具滥用靠白名单约束,日志泄漏靠脱敏过滤。尤其日志,代理内部处理的很多内容本质上是企业内部文档,一定不要在日志里把原文完整打出来,只保留摘要和关键词索引。

5. 常见问题与排查技巧实录

5.1 上下文污染与记忆串扰

这是多代理系统排障排行榜第一名。现象是代理A回答问题时莫名其妙地用到了代理B的私有信息。原因大概率是上下文隔离没做好。排查思路:先看消息的trace_id,确认这条消息是否经过了上下文总线;再看上下文注入逻辑,是不是把整包Redis直接灌给了代理。我们遇到的一次事故,就是代码里读上下文时把该会话红action的工具结果全量丢给了所有代理。

解决方式是把上文的“会话飞地”模型落实到位:每个代理解决某个任务时,上下文构造函数只拉取任务关联的上下文段,没有引用的内容一律不注入。记忆串扰时,清理对应的长期记忆片并按版本重写。我特别建议在预研阶段就把这层逻辑写清楚,不要在后期补丁式修补。

5.2 代理死锁与任务循环

两个代理互相等待对方先行动,谁都等不下去,这就是代理死锁。出现场景通常是两个代理的任务依赖形成了环:代理A要等B的结果,B要等A的确认。检测方法是任务状态图里如果有环一定会出现大量长时间处于running的僵尸任务。我们上线前画了一张依赖图检测工具,新任务进DAG之前先判环,有环直接拒绝并报人工处理。

同时给所有跨代理等待消息加超时,默认120秒。超时后有三种处理:重试一次、降级为“以现有上下文给出半成品”、上报人工。大量实测经验是,自动重试只适合网络抖动,逻辑死锁重试多少次都没用,必须走上报人工或是让用户修改任务目标。

任务循环也说说,典型特征是代理像复读机一样在同一个步骤来回两三次。这多半是消息契约的payload里缺了状态字段,代理拿到结果后判断不了“自己是否仍在同一轮”。解决方法是消息体一定带上回合序号和步骤类型,代理每执行一个动作检查回合变化,逻辑层也支持对重复动作的幂等丢弃。

5.3 并发冲突与权限越权

并发冲突最典型的坑是“多个用户同时给同一个代理派活”。用户A让代理整理会议纪要,用户B同时让同一代理去修改排期,结果两个任务半路串了。原因是代理本身没有互斥机制。我们在执行层给每个代理加了一个串行工作队列,同一时刻只处理一个任务,其余排队。代价是吞吐量下降,换来的是状态不乱。需要更高并发的场景,可以创建同一角色的多个代理实例,而不是让一个代理分身处理多件事。

权限越权虽然少见,但一发生就是大事。排查方法很简单,所有工具调用必须带三个ID:用户ID、代理ID、授权单ID。当发现代理调用了未授权工具时,先查用户给这个代理开的授权范围,再快照当时的提示词内容,大概率是提示词注入让代理“以为”自己有权做某件事。我们的处理是:所有代理工具调用的日志加一个特殊标记,引擎允许但审计重点盯,一旦出现未授权尝试就告警。

5.4 从观测到复盘的调试手段

多代理系统出了故障,最怕的就是“谁都不知道刚才发生了什么”。所以一开始就要做链路追踪。我们的做法是每个任务生成一个trace_id,贯穿用户请求进入网关、路由分发、多代理消息交互、到最终结果回执的每个环节,全链路日志都带上这个ID。排查问题先按trace_id拉全部日志,再建一张时序事件表复制过去查。

另外把代理的“思维过程”记录下来很重要。我们要求大模型输出时除了最终结果,还必须输出简要的决策理由,格式是“在这步我考虑了X妥协Y,因为Z条件不满足”。这个做法对调试尤其有价值,从文本看不出问题的时候,看代理的reasoning往往一针见血。当然这会导致token成本略增,但调试体验提升远大于成本增加。

最后建议定期做代理行为复盘。把过去一周所有任务的状态分布、超时率、人工介入率拉出来看。如果人工介入率持续走高,不是用户不懂系统,而是任务编排或者代理角色设定出了偏差。我们就碰到过“产品代理总是把简单任务升级给人审”的情况,原因不是代理不给力,是产品代理的系统提示词把“谨慎”权重拉得太高,调整后介入率立刻降了一半。

--

这套架构研究做下来,我个人最深刻的体会是:多人多AI协同系统最难的从来不是让单个AI变聪明,而是让多个AI在同一个系统里秩序井然地相处——谁做什么、谁能看什么、谁先等谁、谁有权决策,每一件事都得在架构层面写明规则。分布式交换机管的是数据包的进出,Agent网关管的是消息和权限的边界,原理相通的。如果还没有头绪,建议先挑一个两个月内能见到效果的小场景落地,比如跨部门周报汇总,把链条跑通再慢慢上复杂任务。后续我还会继续研究会话记忆的长期一致性与异构模型协同两个方向,有结果再来分享。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询