多智能体进生产:从Demo到稳定运行的架构关键
发布时间:2026/11/3 13:27:38 锦皓数字建站

最近看到一份行业调研74% 的企业计划把多智能体系统纳入生产环境。这个数字给我的第一反应不是兴奋而是后背发凉。过去半年里我陆续帮几家公司把多智能体从“能演示”推到“能发版”几乎每个项目都要经历同一道坎模型选型、Prompt 调优、Demo 跑通这些环节都顺利得不像话可一旦要进生产什么并发、幂等、可观测性、优雅退出全冒出来了。很多团队把这归因于“大模型不稳定”但我在一线看到的真实瓶颈根本不在模型而是架构。多智能体本身是一套全新的分布式系统设计命题而多数人还在用单体应用或者单机脚本的思路去思考它。这篇文章就聊聊我对“多智能体进生产”这件事的理解为什么计划使用的人多、真正跑稳的人少生产级多智能体架构缺的是哪几根支柱以及我自己在实战里踩过哪些编排、部署和治理层面的坑。如果你正准备把多智能体搬上线这篇文章里的经验和教训或许能帮你少走几个月的弯路。1. 74% 计划背后多智能体从“好玩”到“有用”的分水岭1.1 调研数字里的乐观与错位调研里说的“74% 企业计划使用”和企业真正“已经在生产环境跑起来”是两个完全不同的世界。我参加过几个内部技术分享很多团队在展示多智能体时用的还是同一个剧本搭建一个“客服助手”或者“内部知识问答”几个 Agent 互相传递一下上下文现场效果非常震撼。但如果你追问一句“这个系统能支撑多少 QPSAgent 无限循环怎么办模型接口超时怎么降级任务执行一半 Pod 被杀怎么恢复”场面通常会安静下来。真正把多智能体跑进生产的项目我见到的比例远低于 74%。这和当年微服务刚火起来时很像大家听多了“模块化、独立部署、技术栈异构”的好处却没意识到微服务背后需要一整套注册中心、配置中心、链路追踪、熔断降级的基础设施。多智能体也一样——它表面上像“几个智能体的协作”本质却是多个有状态、不可预测、依赖外部大模型 API 的异质计算单元之间的复杂协作。模型能力不需要你操心API 厂商都帮你训好了但协作过程中的状态管理、故障转移、资源隔离和数据一致性每一件都得你自己扛。所以我对这份调研的解读是74% 是“意愿”真正能跨过生产门槛的可能连 7.4% 都没有。这不是诅咒而是因为大多数人还没意识到“架构能力”才是那道最窄的门。1.2 “计划使用”和“已经投产”之间隔着一套架构为什么 Demo 阶段一切顺利一上生产就问题百出我先讲一个真实案例。某制造业客户要做设备维修工单的自动派发几个 Agent 负责读工单、查库存、匹配维修工、生成任务。原型阶段我用两天就搭完了前端一调Agent 们像模像样地完成了一整套流程。可上了测试环境第一周就崩了三次一次是某个 Agent 在没有库存数据时反复尝试把 API 配额打爆一次是两个 Agent 互相调用形成循环直到超时还有一次是个别工单在流程中被重复派发导致维修组收到两条相同任务。这三个问题的根子都不是“大模型不够聪明”而是我当时没有考虑生产中必须具备的机制没有为 Agent 之间的调用设置超时和深度限制没有考虑任务状态的持久化和幂等性也没有对每个 Agent 的输入输出做审计。换句话说我只实现了智能体协作的“业务逻辑”却缺失了整个“运行环境”。我后来常给团队打一个比方单 Agent 是你雇了一个非常聪明的实习生你交代一件事他干完回来汇报中间过程你不需要全程盯着多智能体系统是你开了一个部门里面同时有三十个聪明但性格各异的实习生他们互相之间要发消息、传文件、确认进度。这时候你缺的不是“更聪明的实习生”而是一套完整的项目管理体系、沟通协议、任务看板和故障应急机制。这套“体系”就是架构。2. 生产级多智能体架构到底缺了哪三根支柱2.1 智能体之间的通信不是 RPC 而是有状态对话我见过太多多智能体 Demo 的实现方式在一个 Python 脚本里Agent A 直接调用 Agent B 的run()方法像调用一个普通函数一样。这种“硬编码 RPC”在流程固定、规模小的时候没问题但生产环境里你会很快发现Agent 之间的协作不是一次请求/响应就能结束的。Agent B 可能需要调用外部工具等外部接口返回再让工具链上的 Agent C 做二次确认这个过程中还涉及用户审批、人工兜底、超时重试。如果你用同步 RPC任何一个 Agent 卡了半步整个调用链就全卡死。正确做法是把 Agent 之间的通信从“函数调用”升级为“异步消息传递”。每个 Agent 除了拥有“执行能力”还有自己的“信箱”——它可以接收消息、处理完后再发消息。这里我建议直接借用成熟的消息模式任务消息都有一个全局唯一 ID每个消息要带 trace_id、task_id、步骤序号这样整条链路才能被追踪。实现上没有必要自己造协议Redis Stream、Kafka、RabbitMQ 都可以关键是你得把它设计成“事件驱动的流水线”而不是“你调我我调你的电话线”。为什么异步这么重要因为生产环境里外部依赖大模型 API、数据库、旧业务系统的延迟和故障是常态。异步消息允许你设置合理的重试策略、死信队列和人工介入通道。再说直白一点两个人协作用微信异步沟通比一群人挤在同一个电话会议里靠谱得多。消息队列就是这群 Agent 的微信群。2.2 任务编排从流程图到动态规划缺的失效恢复多智能体的编排逻辑通常被描述成一张流程图先做意图识别再查知识库再生成回复。Demo 里这确实够了因为流程是预定义的。但生产中你会发现很多任务不是线性流程而是‘动态规划’——Agent 会根据中间结果决定要不要分支、要不要找人审批、要不要继续追问。这种情况下基于硬编码 if-else 的编排肯定撑不住。我们需要的是一个既能承载动态分支、又能在任何一步失败时做到“可恢复”的编排引擎。目前业界比较成熟的选择有 Temporal、Camunda、贝加尔顺带提一句 LangGraph 也是不错的方向但它更适合原型生产级能力还在成熟中。这些引擎的核心价值不是帮你画图而是提供了三样东西持久化执行状态、定时重试与补偿、人工任务插入点。举个例子我们做采购审批多智能体系统时有一个分支是“当供应商报价低于市场均价 5% 时需要走人工复核”。在编排引擎里这不是一个 if 语句而是一个持久化任务Agent 提交建议后工作流暂停进入“等待人工审批”状态可以等一小时、一天甚至更长。这一状态要写到数据库里服务重启也不丢。反观硬编码的方案进程一重启工单状态就尬在“任务已提交但响应丢失”的中间地带用户投诉都找不到原因。2.3 可观测性你在调试的是“一群人的协作”不是“一段代码”我见过不少团队排查多智能体故障时的方式还是打日志在每个 Agent 打印一行“开始调用”“调用结束”。这在单 Agent 场景里勉强够用但多智能体协作的问题往往出在“上下文传递错误”和“状态不一致”上。两个 Agent 可能各自正确但它们之间的消息顺序错了最后结果就错了。这时候传统日志根本没有办法把整个链条串起来。我们需要把多智能体当作一个分布式系统来做可观测性至少包含三层链路追踪给每一次用户的原始请求生成一个 trace_id跟随这个 ID 可以查出它经过哪些 Agent、每个 Agent 消耗多少 token、每一步耗时多长、调用外部工具有没有失败。OpenTelemetry 是目前最通用的方案大模型调用LLM 的请求/响应也可以被打成 span 记录下来。状态审计每个 Agent 面对所有输入和最终输出都要有快照记录。为什么因为大模型的行为每一次都可能不同。如果线上发生了一次错误回答你需要能精确回放当时给 Agent 的 system prompt 是哪一版模型是哪个版本温度系数是多少没有这个排查大模型问题基本等于大海捞针。质量指标不能只看“任务完成率”还要看“任务正确率”。自动评估至少要有几个维度比如最终结果是否包含必须提及的条款、是否符合业务约束金额不能超限、日期不能早于今天等、语义相似度是否达标。生产环境里我甚至会建一条工作流让专门的“评审 Agent”对核心 Agent 的结果做二次校验虽然多花点 token但能拦住大量低级错误。一句话多智能体的可观测性是你给每一个 Agent 的“工作记录仪”。没有它生产环境里发生的任何诡异问题都会变成“不可复现的玄学”。3. 从 Demo 到生产的三个编排坑实测复盘3.1 坑一Agent 循环调用导致的“工程级死锁”第一次做多智能体生产部署时我遇到过最经典的坑两个 Agent 互相调用。场景是文档处理Agent A解析器负责从合同里抽取关键条款Agent B审核器负责检查条款是否有风险。审核器发现某个条款不完整就把消息发回给解析器解析器重新解析后再发回审核器而审核器如果还有疑问又能继续发回解析器……在没有设置调用深度限制的情况下这条循环会一直持续下去直到把双方上下文窗口全部耗光。事后复盘根因有两层一是代码里没有限制 Agent 之间的最大交互轮数二是设计时没考虑“死循环跳出”策略。我现在做任何多智能体编排时都会强制做三件事每个任务的 Agent 调用深度设上限比如最多 10 跳每次调用必须带超时例如 LLM API 30 秒无响应则自动熔断引入“监督 Agent”或“人工接管”开关当循环超过阈值时直接挂起任务进入人工队列。代码层面的一个常见实现是给调用入口加一个全局深度计数超出就直接抛出终止异常class AgentContext: def __init__(self, max_depth10): self.max_depth max_depth self.current_depth 0 def enter_agent_call(self): if self.current_depth self.max_depth: raise CircuitBreakerError(Agent call depth exceeded) self.current_depth 1 def exit_agent_call(self): self.current_depth - 1别小看这个简单的深度计数器加上“超时后置入人工队列”的兜底逻辑至少能避免我在线上见过的那种“两个 Agent 互相折磨到天荒地老”的场面。3.2 坑二上下文窗口在长链路里被撑爆第二个高频坑是上下文管理。很多人在 Demo 阶段习惯把“历史对话”一股脑塞给下一个 Agent觉得这样信息最全。可一旦链路变长比如一个流程里经历 5 个 Agent每个 Agent 把前面所有输出都拼到自己的 prompt 里token 数量会指数膨胀。一次业务评审会议上我亲眼看到某个 Agent 的任务还没跑完就收到了“token 上限超限”的错误而那个任务其实只是要求“归纳一下上一轮会议纪要的待办事项”。这个问题要从两个角度解决一是消息瘦身。Agent 之间传递的应该是结构化“结论摘要”而不是原始上下文。比如每轮输出统一为{结论, 证据索引, 置信度, 需要的后续输入}而不是传输完整的自然语言历史。当需要用到某段历史时再通过向量检索把相关片段取回来。二是分级记忆。短期工作记忆一次任务的上下文可以放在 Redis 里过期时间根据任务维度设置长期业务知识客户主数据、产品参数、历史工单放到向量数据库每次只做相似度检索取 top-k。这样每个 Agent 的 prompt 净输入控制在两千 token 以内推理速度和成本都稳定得多。这条经验让我后来定的规则非常简单任何 Agent 的输入只允许包含它当前这一步需要的最小信息集。如果它要写一份报价单就只给它报价模板、产品价格表和客户名称不需要把整段销售对话历史塞进去。3.3 坑三任务状态和回调错位引发的重复执行多智能体系统里异步消息意味着任务不一定是串行执行很可能同一个消息被投递两次。这不是理论而是我真实踩中的我们当时用一个第三方任务队列网络不稳定导致消费端处理完任务但在提交 ack 时超时队列把任务又投了一次。结果就是同一个“创建维修工单”动作执行了两遍客户看到两张一模一样且单号不同的工单。这个问题的专业名词叫“幂等性”。生产级系统里不管你的消息队列怎么保证“至少一次投递”你在业务侧都必须承担“去重”的责任。最简单有效的方案是设计一个基于任务唯一键的状态表每个任务进来先查状态已经是“处理中”或“完成”就只更新回调不重复执行业务动作。我用伪代码来表达这个逻辑def execute_task(task_id, payload): state redis.get(ftask:{task_id}:state) if state in (running, done): return # 已经执行过或正在执行 if not redis.setnx(ftask:{task_id}:state, running): return # 并发竞争时第二条请求直接放弃 try: agent_result run_agents(payload) redis.set(ftask:{task_id}:result, agent_result) redis.set(ftask:{task_id}:state, done) except Exception as e: redis.set(ftask:{task_id}:state, failed) raise当然这只是最小实现。更规范的做法是引入分布式锁和事务性状态机但核心思想是一样的不能把“消息到达”当成“业务必须执行”的唯一信号。你的业务动作必须通过状态机约束保证同一任务无论重试多少次效果都等同于一次成功执行。4. 架构短板如何补我们落地的参考模型与工具链4.1 分层设计Controller / Worker / Tool 三层在踩完上面那一圈坑之后我后来帮客户做多智能体系统都会先把架构收敛成一个固定的三层模型。这个模型不复杂但能让所有团队在讨论“你的 Agent 在哪里”“失败怎么处理”时用同一套语言层级职责典型组件失败策略Controller意图识别、任务拆解、编排决策、人工审批点编排引擎Temporal/Camunda、LLM 调度状态持久化重启后继续Worker单领域任务执行写报告、查库存、算报价各类 Agent包含 Prompt 模板、模型调用重试指数退避收窄输入必要时降级Tool原子能力数据库查询、API 调用、文件读写REST API、内部服务、向量数据库、规则引擎超时熔断缓存结果降级返回默认值这张表的核心在于只有 Worker 层可以用大模型Controller 层和 Tool 层要尽可能逼到逻辑确定。换句话说Controller 的拆解逻辑尽量用规则引擎或小模型做Tool 层全部是普通代码。这样你的系统里真正不可控的部分只有 Worker 层这一小块架构的可靠性评估也就清晰了。我见过太多团队把“意图识别到最终结果”整条链路都交给大模型最后业务方完全不知道系统会在哪一步出错。用上三层模型后至少你可以回答如果 Controller 错了是拆解错了如果 Worker 错了是单步执行错了如果 Tool 错了是外部依赖错了。问题边界一清楚排查时间能缩短一个数量级。4.2 消息与状态把 Redis Stream 当“智能体总线”用吞吐量要求不极端、但需要快速落地的项目我推荐用 Redis Stream 作为智能体之间的事件总线。理由很实际第一团队一般本来就在用 Redis引入新中间件成本低第二Redis Stream 支持消费者组、消息确认XACK和重新消费XPENDING正好覆盖了 Agent 消息的“至少一次投递手动重放”需求第三内存态 Redis 延迟极低特别适合 Agent 这种频繁小消息的通信模式。下面是一段消费者组消费的伪代码逻辑以 Python 为例import redis r redis.Redis(hostredis-host, port6379) stream_key agent:task_stream group_name agent_workers # 每个Worker启动时创建消费者组只在第一次创建时执行 try: r.xgroup_create(stream_key, group_name, id0, mkstreamTrue) except redis.ResponseError: pass # 组已存在 while True: # 阻塞式读取一条消息允许超时 entries r.xreadgroup(group_name, worker_id, {stream_key: }, count1, block2000) if entries: stream, messages entries[0] for msg_id, fields in messages: task_id fields[btask_id].decode() execute_task(task_id, fields) # 确认消息已处理避免重复消费 r.xack(stream_key, group_name, msg_id) # 同时把任务状态写进持久化存储这套组合的好处是线上如果出现事故你可以在消费者组里把未确认pending消息手动重新投递也就是说你拥有“让所有 Agent 从头重试一遍”的能力。这种能力在生产事故复盘时尤其珍贵——你没有能力修改已经过去的时间但你有能力把丢失的任务重新放回流水线让业务自己发现“重复使用幂等键”后收敛。4.3 观测与治理Trace、Prompt 审计和灰度发布架构做好了接下来就是治理。多智能体系统上线后最先会让你抓狂的事情就是“为什么这次回答和上次不一样”。这里我建议在技术层面和流程层面同时上三道锁第一道锁OpenTelemetry 链路追踪。在任何外部调用点大模型 SDK、数据库客户端、HTTP 工具都注入 span。尤其要记录llm.request.model、llm.request.prompt截断到固定长度、llm.response.completion、llm.usage.total_tokens。有了这些 span你才能回答“这个消费评价是哪个 Agent 在哪个 Prompt 版本下生成的”。第二道锁Prompt 版本管理。我见过太多项目用文档记录 Prompt 历史“我记得昨天改过一句话”这种情况经常发生。一个更可靠的做法是将 Prompt 作为代码配置文件入库每次修改都打一个 tag运行时从配置中心读取指定版本。审计时只要比对当时的版本号和最近的 commit就能定位精确差异。第三道锁质量评估集与灰度开关。上线一个新的 Agent 行为时别直接全量。我们通常准备一个 200 条左右的评估集包含常见场景和边缘异常情况先让新版本在小流量比如 5%上跑一天对每次调用的输出自动打分和旧版本做对比。分数达标再逐步放量到 10%、50%、100%。这里完全复用传统发布里的灰度思想只是多了一步“自动评估”。我还会在流程上加一道人工抽检每周随机抽 20 条生产任务让业务人员标注结果是否可接受。别小看这 20 条它能保证整个治理链条不是“纸面合规”而是一直有真实的人在反馈质量环路。5. 既然要进生产K8s 部署里的几个“推土机”式坑5.1 智能体实例的优雅退出与存量任务接管多智能体服务和传统无状态 HTTP 服务最大的区别在于它“跑着的任务”不是一次请求一个线程而是长时间运行的工作流。你用 K8s Deployment 管理 Agent每次发布、扩缩容或驱逐 Pod 时如果直接 kill正在执行的任务就断了。用户端看到的现象就是“我提交了工单一个小时过去了没有任何反馈”。解决思路是“优雅退出 任务接管”。K8s 里通过preStop钩子实现Kubernetes 在干掉 Pod 前执行 preStop 钩子默认会等待terminationGracePeriodSeconds指定的时间我通常设 60 秒preStop 脚本向 Agent 进程发送 SIGTERMAgent 进程收到后停止接收新任务同时把当前正在处理的任务标记为“未完成”并写回队列尾部其余消费者组 Worker 看到这条任务重新进入队列会立刻接管处理。如果用 Deployment可以给 Pod 配置这样一段生命周期钩子spec: terminationGracePeriodSeconds: 60 containers: - name: agent-worker lifecycle: preStop: exec: command: [/bin/sh, -c, curl -X POST http://localhost:8080/drain; sleep 15]这里的核心是drain接口它要完成“停止拉取新消息、标记当前任务状态、推送未完成任务回队列”这三个动作。这样做之后发布更新时你几乎感觉不到 Agent 中断过。5.2 不要所有 Agent 共用一个 PVC多租户隔离从存储开始随着任务规模增长多智能体系统往往同时服务多个业务线甚至多个客户。我做过的项目里有一家公司把设备维修、采购审批、质检报告三个业务放在一套系统里为了省事共享一个向量数据库 collection。结果上线第三周采购 Agent 在检索知识库时经常搜出设备维修的文档回答里居然出现了“维修工单”和“采购申请”混在一起的内容。多智能体系统的隔离性不光是 K8s namespace 的事更重要的是“数据感知层”的隔离。我的建议是至少做三层网络隔离不同租户或不同业务域的 Agent 使用独立 K8s ServiceAccount网络策略限制互相访问存储隔离向量数据库按租户拆分 collection或按tenant_id做强制过滤所有查询必须带过滤条件绝不允许全库检索上下文隔离Agent 的短期记忆 Redis 按照tenant:{tenant_id}:agent:{agent_id}做 key 前缀避免跨租户串数据。在代码里每条进入系统的消息都要带上租户上下文下游工具查询时自动拼上过滤条件。这一条虽然简单但我见过太多团队在原型阶段图省事省略上线后花了两周重构。5.3 突发调用洪峰下的限流与降级多智能体的每一步推理都依赖外部大模型 API而外部 API 的并发配额是有限的。一旦业务方操作失误触发某类任务的批量执行你的 Agent 会瞬间发出一百个并行 LLM 请求然后眼睁睁看着平台返回 429。更麻烦的是429 会触发 Agent 内部的自动重试重试又进一步放大请求量形成雪崩。所以生产级多智能体必须有一层“流量整形”。我的惯用组合是令牌桶限流全局限制每秒向外部模型发起的请求数具体数值根据模型服务商的配额和预算决定。超出令牌桶的任务进入排队缓冲而不是直接丢弃。优先级队列把“用户实时交互”的任务放在高优先级队列把“后台数据处理”的任务放在低优先级队列。当系统过载时优先丢弃低优先级任务保证核心业务不中断。服务降级当外部模型 API 不可用时高优任务可以降级到“最简 Prompt 的快速模型”或者直接转人工而不是永久阻塞。例如用 Redis 的 Lua 脚本实现一个简单的分布式限流器-- KEYS[1]: 限流key -- ARGV[1]: 限流窗口时间毫秒 -- ARGV[2]: 窗口内最大请求数 local current redis.call(INCR, KEYS[1]) if current 1 then redis.call(PEXPIRE, KEYS[1], ARGV[1]) end if current tonumber(ARGV[2]) then return 1 else return 0 end这只是一个最小版本。真正的生产实现还要结合 Token Bucket 与分布式锁。但原则不变多智能体的容量规划不能只看你自己的服务能扛多少并发更要看下游大模型供应商能不能扛住。不提前给流量踩刹车线上事故一定会找上门。6. 如果现在让我重新做一次我会省掉的弯路最后分享一些个人体会不一定适用所有项目但至少能让准备进生产的多智能体团队少踩几个雷。第一不要一上来就搭“豪华编排框架”。先用最笨的办法把端到端跑通明确业务指标是“解决问题的成功率”还是“响应时间”。等真正有业务量了再逐步引入持久化工作流、消息队列和链路追踪。顺序反了你会发现自己花了两周配置 Temporal业务却还没想清楚 Agent 要传哪些参数。第二人的角色千万不要删掉。多智能体系统再强也要预设“人工审批点”和“人工接管窗口”。生产环境里总会出现模型无法自主决策的场景例如合同金额超过阈值、投诉内容涉及法律条款、用户明确要求“找真人”。把这些场景提前设计成工作流中的“人工节点”比事后紧急上线一套人工介入流程要稳得多。第三评估集是你最值得投入的资产。我到现在都会在项目启动第一天建立评估集哪怕只有二十条真实历史数据。后续每次优化 Prompt、换模型、调整 Agent 行为都用它和线上抽样结果做双通道回归。没有评估集的多智能体系统就像没有刹车板的跑车——速度是有了但你真的敢开着它上生产吗第四拥抱确定性。能用规则确定的判定金额、日期、枚举值校验别交给大模型能用小模型/微调模型完成的意图分类别上大模型能用代码实现的状态转移别让 Agent 自己判断下一步。多智能体的意义在于处理真实世界里模糊、开放、动态的复杂问题而不是把原本确定的工作变成概率输出。每替换掉一个随机环节系统稳定性就上一个台阶。多智能体进生产这件事趋势已经明牌了。74% 的企业计划使用意味着未来一两年会有大量系统从原型走向生产。在这个阶段谁能把架构短板先补上谁就能把“智能协作”从技术噱头变成真正可衡量的业务价值。希望这篇经验贴能帮你提前看到那些藏在演示背后的坑也欢迎你在评论区聊聊自己踩过的多智能体生产问题。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。