多智能体协作编排:用“剧团”模式理解Agent系统
发布时间:2026/9/2 3:24:05 作者:尧图编辑部 阅读量:1,286

最近在带团队做 Agent 类项目时我观察到一个很有意思的现象单个 Agent 都很聪明让它写周报、做总结、搜索资料基本都能独立完成。但是一旦把两三个 Agent 放到一起让它们“协作”完成一个任务结果却常常失控——有的 Agent 反复处理同一块内容有的 Agent 把另一个 Agent 的中间结果当成最终答案还有的干脆陷入了无休止的自我讨论。这个问题不是个例。多智能体协作Multi-Agent Orchestration被很多人看作是通向复杂任务自动化的重要路径但真正落地过的工程师都知道难点从来不是“能不能调通多个模型”而是怎么设计协作流程、怎么隔离上下文、怎么控制成本以及怎么在出错时快速定位到具体某一步。因为工作流一旦串起来问题会被层层放大一个 Agent 输出里的一个小错经过后面几个 Agent 的加工可能变成一份看起来合理但完全错误的最终结果。这篇文章从一个具体的意象切入把一组 Agent 看作一个“剧团”Troupe。导演负责任务编排演员各自承担角色剧本定义流程舞台承载共享上下文。理解了这个模型你再去读 LangGraph、AutoGen、CrewAI 之类的框架会轻松很多。文中不会绑定某个具体框架而是用“概念 最小实现 排查清单”的方式讲清楚多智能体协作的底层逻辑并给出一个不依赖特定 LLM SDK 的 Python 最小示例。读完你可以直接复制代码改造自己的任务也能避开大多数新手会踩的坑。1. 为什么单个 Agent 不够用先回答一个基础问题既然单个 Agent 已经能做很多事为什么还要费劲做多智能体编排核心原因是真实项目里的任务往往不是“单一能力”能覆盖的。比如一个简单的“写一份竞品调研报告”任务里面至少包含三类动作拆解调研框架、收集并筛选信息、组织成文。你可以让一个 Agent 从头做到尾但会碰到几个实际瓶颈。第一是上下文长度。把所有调研材料、行业背景、写作要求全部塞进一个对话上下文里很快就逼近模型窗口上限。更麻烦的是当上下文里混入了大量无关信息模型很容易被“带偏”回答质量反而下降。第二是职责混杂。同一个 Agent 既要做规划又要做检索还要把关质量提示词会变得极其复杂调优一个环节经常会破坏另一个环节。第三是记忆衰减。长对话里Agent 很容易忘记最初的目标最后产出的内容可能已经偏离用户的原始需求。多智能体思路的本质是把一个完整任务拆成多个职责单一的“专业角色”每个角色只负责自己擅长的部分。规划 Agent 只拆任务检索 Agent 只查资料写作 Agent 只负责成文。这样每个 Agent 的提示词可以做到精简、明确、可复用中间产物可以单独检查和替换某个环节升级时也不用重写整条链路。但这里必须给一个清醒的判断多智能体不是银弹。它解决的是“任务复杂、职责分离、上下文受限”的问题但它同时引入了新的成本——流程设计成本、系统复杂度、调试难度、Token 消耗。如果一个任务不需要工具调用、不需要多步上下文、一个 Agent 就能高质量完成强行拆成多 Agent 只会得不偿失。判断是否值得做多智能体可以参考三个条件任务是否需要多种不同能力而不是同一个能力的多次调用。中间结果是否需要被不同角色独立检查或加工。单 Agent 是否因为上下文过长或职责过多已经出现质量下降。这三条命中得越多多智能体编排的价值就越大。2. 多智能体的核心问题不是数量而是编排很多人在刚接触多智能体时会以为只要把多个 Agent 丢到一起它们就会自动分工合作。这是最容易踩的误区。当前的主流大模型并不具备稳定、可靠的“自主涌现协作”能力尤其是在没有明确协议和流程约束的情况下多个 Agent 一起运行时更像是几个能力很强但没有共同剧本的演员各说各话。我一直觉得“Troupe剧团”这个隐喻非常贴切。一个剧团能完成一场复杂演出不是因为演员数量多而是因为有导演、有剧本、有角色分工、有舞台调度。导演负责决定演员什么时候上场、什么时候退场、拿到什么剧本演员只按自己的角色表演舞台提供了统一的场景和道具。把这些对应到多智能体系统里就是导演 - 编排器Orchestrator演员 - 各个 Agent剧本 - 工作流Workflow舞台 - 共享状态或上下文Context这个隐喻能帮你快速理解一个关键结论多智能体系统的设计重心应该放在编排层而不是模型层。模型本身的能力差距远没有编排逻辑的差距对最终效果影响大。同一个模型在“无流程、无约束”的环境下和“有清晰角色、有步骤、有校验”的环境下产出的稳定性差别巨大。我见过有的团队买了一堆最强模型结果多智能体协作效果很差因为每个 Agent 都在自由发挥输出格式千奇百怪下游 Agent 根本没法解析。反过来如果先用规则把流程定清楚每个 Agent 只做一个小而明确的动作即使模型不是最强整体效果也会稳定很多。本文标题里的Welcome to the Troupe想表达的正是这个意思多智能体不是“把多个模型堆在一起”而是“让一组角色按照统一剧本协作的系统工程”。3. 核心概念从导演到舞台继续用“剧团”模型把多智能体编排里最常出现的几个概念过一遍。这些概念在不同框架里叫法略有差异但本质相通。3.1 Agent角色不是人Agent 是承载“某项能力”的逻辑单位。它可以是一次大模型调用也可以是大模型加上工具、记忆、甚至人工审核的组合。在设计多智能体系统时建议把 Agent 理解为“输入-输出明确的函数”而不是“一个能思考的人”。每个 Agent 应该只负责一件事输入输出尽量用结构化的方式定义。3.2 Orchestrator导演编排器是系统的核心负责决定 Agent 的执行顺序、传递哪些数据、如何处理异常。现代多智能体框架里的编排器可以是简单的顺序调度也可以带条件路由、循环、并行执行。判断一个编排器设计好不好不是看它能不能安排所有步骤而是看它在出错时能不能让你快速看懂“现在演到哪一幕、谁出了问题”。3.3 Workflow剧本工作流定义了 Agent 之间的执行路径。常见的有三种形态固定流程、分支流程、动态规划流程。固定流程适合任务逻辑稳定的场景比如“先规划、再执行、后总结”分支流程适合“根据条件走不同路线”的场景比如用户输入是否需要联网搜索动态规划流程则让编排器或规划 Agent 在运行时决定下一步动作灵活但不可控建议从固定流程开始。3.4 Context舞台Context 是所有 Agent 共享的状态空间承载任务描述、中间产物、最终输出。这里的核心设计问题是“隔离”与“共享”的边界。如果所有 Agent 都能读写全部信息上下文很快就会变成大杂烩如果隔离得太狠下游 Agent 又拿不到必要信息。实践中更推荐的做法是每个 Agent 只能读取自己输入字段对应的数据只允许写入自己的输出字段。3.5 Tool道具工具是 Agent 可以调用的外部能力比如搜索、数据库查询、代码执行、API 请求。工具接入时最重要的不是功能丰富而是权限边界清晰。生产环境里Agent 的工具权限过宽是最大的安全风险之一。3.6 Memory记忆记忆分为短期记忆和长期记忆。短期记忆通常指当前任务的上下文长期记忆指跨任务的历史经验或知识库。多智能体编排里优先把记忆放在共享 Context 中管理而不是放在单个 Agent 的对话历史里。这样更可控也更方便调试。下面用一张表总结编排层常见概念概念剧团比喻技术实现设计要点Agent演员模型调用 工具 内存职责单一输入输出明确Orchestrator导演调度代码 / 框架引擎控制流程、异常、重试Workflow剧本状态机 / 图 / 伪代码显式优于隐式稳定优先Context舞台内存对象 / 数据库 / 分布式存储共享与隔离的边界Tool道具函数 / API / SDK最小权限审计留痕Memory记忆向量库 / KV 存储短期与长期分离这套概念在 LangGraph、AutoGen、CrewAI、Semantic Kernel 里都有对应实现。框架可以帮你省掉一部分样板代码但真正决定系统质量的还是你对概念边界的理解。4. 五种常见的多 Agent 编排模式不同业务场景适合不同的编排模式。理解这些模式相当于手里多了几套“演出剧本”。这里介绍五种最常见的模式并说明各自的适用场景。4.1 流水线模式Pipeline任务被拆成多个阶段按顺序执行前一个 Agent 的输出是后一个 Agent 的输入。适用场景数据清洗、内容审核、文档处理这类阶段清晰的任务。优点是逻辑简单、容易调试缺点是整体耗时是各阶段耗时的总和且某个阶段失败会影响后续所有阶段。4.2 规划-执行模式Planner-Executor一个规划 Agent 负责拆解任务多个执行 Agent 负责并行处理子任务最后再由汇总 Agent 合并结果。适用场景调研类、批量处理类、可以并行拆分的任务。这种模式效率高但需要设计好子任务的“拆解”和“合并”两个环节否则容易出现重复计算或结果遗漏。4.3 审阅/辩论模式Reviewer/ Debate一个 Agent 生成结果另一个 Agent 负责挑毛病然后让生成方根据反馈修改。可以单轮也可以多轮。适用场景代码审查、文案打磨、复杂推理。这个模式能显著提升输出质量但成本会成倍增加而且如果不能收敛很可能陷入来回扯皮。4.4 分层模式Hierarchy上级 Agent 管理下级 Agent下级 Agent 只对上级负责。每一层只暴露必要信息适合组织架构复杂、需要权限控制的场景。缺点是层级越深链路越长延迟越高。4.5 竞标/市场模式Market多个 Agent 根据任务描述出方案由裁判 Agent 选择最优方案。适合方案生成、创意任务。实现复杂且裁判 Agent 的选择标准要反复调优。下面用一张表做横向对比模式核心特点优点缺点典型场景流水线顺序执行简单、可控慢、单点失败文档处理、审核规划-执行拆解并行效率高拆解和合并难调研、批处理审阅/辩论多轮反馈质量高成本高、易发散代码审查、文案分层上下级管理权限清晰延迟高企业级复杂系统市场/竞标方案竞争创意多样实现复杂方案生成实际项目里这几种模式经常组合使用。比如“规划-执行”模式下每个执行 Agent 还可以内部跑一个小的“审阅/辩论”流程。不过建议第一次落地时只选一种模式跑通后再逐步加复杂度。5. 环境准备与前置条件本文的示例代码不依赖任何特定 LLM SDK确保在没有 API Key 时也能跑通完整编排流程。你只需要准备一个 Python 环境。Python 3.10 或更高版本本文不绑定具体小版本只要 3.10 即可。pip 和新创建的虚拟环境避免污染全局环境。示例只需要标准库如果你要接入真实大模型再自行安装对应的 SDK 或 HTTP 客户端库。如果要运行 YAML 配置示例需要安装 PyYAML本文主示例不强制依赖。创建一个项目目录并初始化虚拟环境mkdir agent-troupe-demo cd agent-troupe-demo python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate pip install --upgrade pip这里用虚拟环境的原因很简单真实项目里多智能体系统一般都会引入框架库、工具库、数据库驱动依赖冲突是迟早会遇到的问题。从一开始隔离环境能省掉很多排查依赖冲突的时间。6. 最小实现让一个“调研剧团”跑起来下面用一个最小示例演示最核心的编排思路。这个“剧团”包含四个角色规划者planner把任务拆解成步骤。调研专员researcher根据步骤收集材料。质量审阅人reviewer检查材料是否完整。报告写手writer生成最终报告。执行顺序是固定的规划 - 调研 - 审阅 - 写作。这种固定流水线是最容易理解、也最容易调试的多智能体模式。6.1 定义 Agent 与 Mock LLM先定义一个Agent数据类再用一个mock_llm函数模拟大模型返回这样不依赖任何外部服务。文件路径agent-troupe-demo/demo_troupe.pyfrom __future__ import annotations import json from dataclasses import dataclass from typing import Callable, Dict def mock_llm(prompt: str) - str: 模拟大模型调用。真实项目中把这里替换为 OpenAI / Claude / 本地模型服务即可。 if 任务规划者 in prompt: return 1. 调研 Token 计费方式\n2. 对比常见优化手段\n3. 给出成本控制建议 if 调研专员 in prompt: return 按 Token 计费是当前主流模式输入与输出分开计价缓存输入 Token 的成本更低。 if 质量审阅人 in prompt: return 结论正确但缺少量化对比建议补充对缓存策略的说明。 if 报告写手 in prompt: return 报告当前大模型 API 主要按 Token 计费控制成本的关键是减少重复输入、利用缓存并精简输出。 return dataclass class Agent: name: str role: str system_prompt: str output_key: str代码解释Agent对象保存了角色名称、提示词和输出字段名。mock_llm根据 prompt 内部的角色标记返回固定内容方便离线路演。真实项目里这个函数内部会替换成真实 LLM 调用。6.2 实现编排器 Troupe接下来实现编排器。Troupe类负责保存 Agent 列表并按固定顺序调用它们。这里特别值得注意的技术细节是每个 Agent 构造 prompt 时不会把全量上下文塞进去而是只挑选当前角色需要的字段。这是避免多 Agent 上下文污染的关键。文件路径agent-troupe-demo/demo_troupe.pydataclass class Troupe: agents: Dict[str, Agent] llm: Callable[[str], str] mock_llm def run(self, task: str) - Dict[str, str]: context: Dict[str, str] {task: task} print([troupe] task:, task) context[plan] self._call(self.agents[planner], context) print([planner] \\n, context[plan]) context[material] self._call(self.agents[researcher], context) print([researcher] \\n, context[material]) context[review] self._call(self.agents[reviewer], context) print([reviewer] \\n, context[review]) context[report] self._call(self.agents[writer], context) print([writer] \\n, context[report]) return context def _call(self, agent: Agent, context: Dict[str, str]) - str: user_prompt ( f[agent]\\n{agent.role}\\n\\n f[task]\\n{context[task]}\\n\\n ) if agent.name researcher: user_prompt f[plan]\\n{context.get(plan, )}\\n elif agent.name reviewer: user_prompt f[material]\\n{context.get(material, )}\\n elif agent.name writer: user_prompt ( f[material]\\n{context.get(material, )}\\n f[review]\\n{context.get(review, )}\\n ) user_prompt \\n请直接输出结果。 return self.llm(user_prompt)这个编排器虽然简单但已经体现了两条核心设计原则执行顺序显式写在代码里清楚可预测。每个 Agent 只拿到它需要的输入而不是整个 context。6.3 入口函数与团队配置最后写一个main函数定义“剧团”成员并执行任务。文件路径agent-troupe-demo/demo_troupe.pydef main() - None: agents: Dict[str, Agent] { planner: Agent( nameplanner, role任务规划者, system_prompt你负责把用户任务拆成具体步骤只输出步骤列表。, output_keyplan, ), researcher: Agent( nameresearcher, role调研专员, system_prompt你负责针对计划中的每一项进行调研输出简明材料。, output_keymaterial, ), reviewer: Agent( namereviewer, role质量审阅人, system_prompt你负责检查材料是否完整只输出审阅意见。, output_keyreview, ), writer: Agent( namewriter, role报告写手, system_prompt你负责根据材料和审阅意见输出最终报告。, output_keyreport, ), } troupe Troupe(agentsagents) result troupe.run(如何控制大模型 API 的推理成本) print(\\n final context ) print(json.dumps(result, ensure_asciiFalse, indent2)) if __name__ __main__: main()这段代码展示了一个很值得学习的组织方式Agent 的定义集中放在一起执行逻辑在Troupe里任务入口单独拆出来。这样当角色增加到几十个时你仍然可以通过查看配置快速知道系统里有哪些 Agent、各自负责什么。6.4 用 YAML 描述团队配置随着 Agent 数量变多直接把角色定义写在代码里会很难维护。生产项目里更推荐把团队配置抽成 YAML代码只负责加载。下面是一个配置示例供你扩展时参考。文件路径agent-troupe-demo/troupe_config.yamltroupe: name: research-team max_rounds: 5 agents: - name: planner role: 任务规划者 system_prompt: 你负责把用户任务拆成具体步骤只输出步骤列表。 output_key: plan - name: researcher role: 调研专员 system_prompt: 你负责针对计划中的每一项进行调研输出简明材料。 output_key: material - name: reviewer role: 质量审阅人 system_prompt: 你负责检查材料是否完整只输出审阅意见。 output_key: review - name: writer role: 报告写手 system_prompt: 你负责根据材料和审阅意见输出最终报告。 output_key: report代码里可以用yaml.safe_load读取这个文件。将配置和代码分离的好处是调整提示词、增减角色时不需要改动核心编排代码也方便非开发人员参与维护。7. 运行结果与效果验证运行示例python demo_troupe.py预期输出大致如下[troupe] task: 如何控制大模型 API 的推理成本 [planner] 1. 调研 Token 计费方式 2. 对比常见优化手段 3. 给出成本控制建议 [researcher] 按 Token 计费是当前主流模式输入与输出分开计价缓存输入 Token 的成本更低。 [reviewer] 结论正确但缺少量化对比建议补充对缓存策略的说明。 [writer] 报告当前大模型 API 主要按 Token 计费控制成本的关键是减少重复输入、利用缓存并精简输出。 final context { task: 如何控制大模型 API 的推理成本, plan: 1. 调研 Token 计费方式\n2. 对比常见优化手段\n3. 给出成本控制建议, material: 按 Token 计费是当前主流模式输入与输出分开计价缓存输入 Token 的成本更低。, review: 结论正确但缺少量化对比建议补充对缓存策略的说明。, report: 报告当前大模型 API 主要按 Token 计费控制成本的关键是减少重复输入、利用缓存并精简输出。 }如何判断系统运行成功从三个维度看流程完整性日志顺序是否正确最终 context 是否包含task、plan、material、review、report五个字段。内容一致性后一个 Agent 的结果是否建立在前一个 Agent 的基础上比如report是否引用了material和review的内容。可重复性同一任务连续运行多次每次输出是否稳定。如果 Mock LLM 阶段结果都不稳定问题大概率出在流程或提示词而不是模型。如果运行失败第一步不是去看模型而是确认日志顺序。日志顺序直接反映编排器是否按预期执行。顺序对但结果错问题在某个 Agent 的输出或 Prompt顺序错问题在编排逻辑。8. 多智能体常见问题与排查方法多智能体系统的调试难度远高于单 Agent因为错误会流转。下面整理一份高频问题清单。问题现象可能原因排查方式解决方案多个 Agent 输出互相覆盖共享 Context 字段名冲突打印最终 context 字段来源为每个 Agent 分配独立字段命名带角色前缀下游 Agent 拿到乱码内容上游输出格式不稳定查上游原始输出要求结构化输出并增加格式校验解析任务陷入无限循环审阅/辩论模式没有收敛条件查看运行日志观察循环轮数设置最大轮数或让第三人 Agent 做终审Token 成本迅速飙升每轮都把全量上下文传给所有 Agent统计单次调用输入长度按 Agent 过滤上下文减少无关信息某些 Agent 长期不被调用路由条件写错或编排顺序遗漏检查路由逻辑和分支条件为编排器增加单元测试覆盖全部路径一个 Agent 失败导致整条链路终止缺少失败重试或降级策略查看异常日志和调用栈为关键调用增加重试和兜底输出并行 Agent 写同一份数据共享内存或数据库同一行记录查看数据库锁和更新日志按策略字段分片或者串行化关键更新Agent 权限过大导致越权操作工具接入时未做最小权限审计工具调用记录用只读 Token、白名单接口、人工审批兜底这里重点说明两个最容易踩的坑。第一个是上下文“全量传递”。很多初学多 Agent 的人为了省事直接把整个 context 丢给每个 Agent。当时看没问题一旦任务变复杂、字段变多一个 Agent 在 prompt 里看到大量无关信息很容易被误导而且 Token 成本也会成倍增加。正确的做法是像上面示例那样在_call里按角色挑选字段。第二个是“没有可观测性”。多 Agent 系统里的 Bug 是流动的如果连每个阶段的输入输出都没记录排查会变成猜谜。从第一天起就要为每个 Agent 调用打日志记录任务 ID、Agent 名称、输入摘要、输出摘要、耗时和 Token 数。没有观测数据错误讨论只能停留在“我觉得是这里出了问题”。9. 多智能体编排的工程化最佳实践如果要把多智能体系统放到生产环境上面这些基础概念和示例还远远不够。下面总结几条工程建议。9.1 为每个 Agent 定义清晰的输入输出协议业务上Agent 可以自由发挥工程上Agent 必须遵守协议。每个 Agent 的输入、输出字段、格式、取值约束都应在代码里明确声明。Python 里可以用 Pydantic 这类库做校验也可以先用 dataclass 加断言。协议的好处是下游 Agent 不用猜测上游输出的格式也能在出错时更快定位。9.2 显式工作流优先于纯自主决策动态规划模式看起来很华丽但不可控。真实项目里建议先把流程“写死”让系统按照固定路径运行观测稳定后再考虑增加动态分支。比如从固定流水线开始稳定后再加入“是否需要多轮审阅”的条件判断。9.3 上下文隔离与共享状态分离不要把所有数据都塞进一个对象。更推荐的做法是不可变的基础输入任务描述、全局配置。可变的阶段性产物每个 Agent 的输出。只读的参考数据知识库、历史记录。在代码里可以用命名空间区分比如context.task、context.results.planner、context.ref_data。这样每个字段的来源清晰也能避免不同模块互相覆盖。9.4 引入可观测性与审计生产环境里至少要为每次 Agent 调用记录这些字段task_id、agent_name、model、input_tokens、output_tokens、duration_ms、status、error_message。如果涉及工具调用还要记录工具名称、入参、出参、调用者。出现问题时这些数据就是排查的锚点。9.5 重试、超时与兜底大模型调用本质是外部依赖必须有超时和重试。建议是网络超时设置至少 30 秒到 60 秒。失败重试 1 到 2 次重试之间加退避。对非关键 Agent可以配置“失败降级输出”保证主流程能继续。如果流程无法继续编排器应该给出明确的失败信息而不是让下游 Agent 在一个残缺的上下文里继续跑。9.6 成本控制从设计阶段开始多智能体系统最大的隐藏成本是“重复输入”。同一个调研材料被传给审阅 Agent 和写作 Agent是非常典型的重复 Token 消耗。控制方式包括只传必要字段。优先使用带缓存的模型接口。对长文本做摘要后传递。限制最终输出长度。在编排器层统计每轮成本。9.7 安全与最小权限原则Agent 能调用的工具越多风险就越大。生产环境必须遵守最小权限原则每个 Agent 只需要访问完成任务必需的资源。涉及删除、修改、转账、发消息等高危操作时应该加入人工审批环节而不是让 Agent 自动执行。9.8 用 Mock LLM 做自动化测试这是整篇文章最值得落到工程流程里的一条建议。不要直接拿真实 LLM 写完核心逻辑就跑测试因为你无法保证每次调用结果一致。先用 Mock LLM 固定输入输出把编排逻辑、异常分支、数据流全部测通再小流量接入真实模型。这样才能区分“编排逻辑 bug”和“模型输出问题”。10. 总结与后续学习方向这篇文章的核心观点可以压缩成一句话多智能体系统设计的关键不是“用了多少个 Agent”而是“编排逻辑是否清晰、上下文是否隔离、错误是否可观测”。上面用最小 Python 示例把一个固定流水线的多智能体“剧团”跑通了里面体现了字段级上下文筛选、角色化 Prompt、统一调度入口这三个最基础的设计思想。建议你把示例代码复制下来把mock_llm替换成真实模型接口再跑一遍体感会完全不同你会真正意识到模型输出不稳定给编排带来的压力。下一步可以从两个方向深入换一个人物配置把任务从“调研报告”换成你自己的真实需求练习拆解角色和定义输入输出协议。研究 LangGraph、AutoGen、CrewAI 等框架的底层实现你会发现它们解决的重点就是状态管理、并行调度和工具注册。有了这篇文章的基础概念再学那些框架会容易很多。最后给你一个实际提醒不要为了多 Agent 而多 Agent。如果单 Agent 加一个工具调用就能解决的问题引入编排层只会增加成本。多智能体编排要处理的是“一个人忙不过来”的任务而不是“把一个人能做的事拆给三个人做”。先从小团队开始跑通、观测、优化再扩容。建议把这篇文章收藏起来等你准备做多 Agent 任务编排时按里面的清单过一遍能省不少调试时间。