
AgentChat 这个名字如果你关注过 AutoGen 生态应该不会陌生。它是微软 AutoGen 团队在 0.4 版本之后主推的高层对话框架目标很简单把多个大语言模型 Agent 之间如何说话、如何协作、何时结束这件事从底层细节里抽象出来让开发者用更少的代码搭出可用的多智能体系统。我接触这个框架有大半年了从早期的实验性 API 一路用到现在的稳定版本踩过不少坑也总结出了一套比较顺手的开发方式。这篇文章就围绕 AgentChat 的核心设计、组件原理、实际部署和常见问题展开尽量把我实操中的经验讲透适合正在做多智能体应用、或者准备从单 Agent 对话切到多 Agent 协作的开发者参考。1. 项目概述与核心设计思路1.1 多智能体框架到底解决了什么问题先说一个很现实的问题单 Agent 能不能搞定复杂任务能但上限很明显。你让一个大模型 Agent 去完成撰写一份市场分析报告并校对数据准确性这种复合任务时它会面临几个坎首先是上下文窗口的消耗——一边写报告、一边还要记住前面所有推理过程很容易把 token 烧光其次是提示词冲突——你让同一个 Agent 既当创作者又当审核者它很难在两种角色之间切换得干净经常出现自己给自己放水的情况最后是流程控制——什么时候该停下来等人工确认什么时候该调工具这些逻辑全部堆在提示词里会让系统变得非常脆弱。多智能体系统的思路则是把一个大任务拆成多个小角色每个 Agent 只做一件边界清晰的事然后通过对话机制让它们协作。你可以把它理解成一个项目组有人负责写文案有人负责审校有人负责查数据大家各司其职通过会议沟通推进。AgentChat 就是把这个会议过程封装成了可编程的框架——谁来发言、按什么顺序发言、发言到什么时候结束全部由框架的调度器和终止条件控制而不是靠模型自己即兴发挥。我在实际项目中感受最深的一点是多 Agent 的价值不只是分工更是上下文隔离。每个 Agent 只需要看到和自己职责相关的历史消息不会把整个会话的上下文都塞进一个模型请求里这让长任务的稳定性提升非常明显。以前用单个 Agent 处理长文档分析经常 20 多轮对话之后就开始丢失前面的指令切成多 Agent 之后每个角色的系统提示词只需要维护自己的那一份状态模型跑起来明显更稳。1.2 AgentChat 在技术栈中的定位AgentChat 并不是一个孤立框架它和 AutoGen 的底层运行时绑定在一起。AutoGen 0.4 之后把核心拆分成了两层底层是事件驱动的autogen-core运行时负责消息传递、Agent 生命周期和异步调度上层才是autogen-agentchat也就是我们今天说的 AgentChat它面向应用开发者把对话这个最常见的人机交互模式做成了高层 API。如果你用过 LangChain 的 LangGraph会发现它们解决的是类似的问题——都是把多个节点编排成有向图并控制状态流转。但 AgentChat 的设计更聚焦于对话即协作这个模型它不要求你去定义复杂的图结构而是用参与方 调度策略 终止条件三要素来定义一个团队Team然后让团队跑一个run(task)方法。这种方式对大多数业务场景来说更直观代码量也更少。我自己选 AgentChat 的一个重要原因是它的异步支持非常彻底。底层基于asyncio所以多个团队可以并发运行这在做服务化部署的时候特别有用。比如我在一个客服工单分类系统里同时跑了十几个团队处理不同渠道的请求协程天然解决了并发问题不需要额外引入复杂的线程池。相比之下某些框架的并发只是简单的线程封装一旦 Agent 数量一多性能就拉垮。1.3 核心概念一览在进入代码之前先把 AgentChat 的四个核心概念梳理清楚后面所有实操都是围绕它们展开的。第一个是Agent也就是一个智能体实例。它绑定一个模型客户端可以配置系统提示词、工具列表和自定义行为。AgentChat 提供了几个现成类型比如AssistantAgent通用的助手型 Agent、CodingAssistantAgent偏向代码生成的 Agent、UserProxyAgent模拟人类输入、负责执行工具调用的 Agent。你大多数时候都在和这几个类打交道。第二个是Chat它代表一次对话过程的编排。在 AgentChat 里Chat并不只是一个会话记录对象它更像是一个调度器规定了参与者有哪些、发言顺序怎么定。最常用的实现是RoundRobinGroupChat轮流发言和SelectorGroupChat按选择函数决定下一个发言者它们共同构成了多 Agent 协作的骨架。第三个是Team把 Agent 和 Chat 组合起来就成为一个可执行的团队对象。团队对外暴露run()和run_stream()两个方法前者返回最终结果后者返回事件流方便你做流式输出和实时监控。第四个是Termination Condition也就是终止条件。它决定了对话什么时候结束常见的有MaxTermination达到最大轮次、TextMentionTermination某个 Agent 说出指定文本、TokenUsageTerminationtoken 用量达到阈值。没有终止条件多 Agent 对话就容易陷入死循环这是我见过最多的新手翻车现场。这四个概念的关系可以这样理解Agent 是谁在说话Chat 是按什么规则轮流说话Team 是整个会议怎么跑起来Termination 是会议什么时候散场。下面我先逐个拆解它们的原理再进入实战。2. 核心组件的原理解析2.1 Agent 的会话与行为定义Agent 的本质是一个状态机 模型调用的封装。每次它收到消息都会触发一次模型调用然后把响应作为新消息发回对话流。在 AgentChat 里AssistantAgent的定义非常轻量核心参数就三个nameAgent 标识、model_client模型客户端、system_message系统提示词。这里我要强调一个实操经验system_message是决定 Agent 行为边界的最关键配置一定要写窄不要写宽。比如你希望一个 Agent 专门做数据提取那就明确告诉它你只负责从文本中提取结构化字段不要做任何分析或总结而不是写你是一个智能助手请帮助用户解决各种问题。职责边界越窄Agent 在多轮对话里的稳定性越好因为模型不会混淆自己的角色。工具Tools是 Agent 行为定义的另一半。AssistantAgent接受一个tools参数可以传函数列表或FunctionTool对象。当你传入工具后Agent 在模型调用时会自动带上工具声明的 context模型如果觉得需要调用工具会返回一个工具调用请求框架负责执行并回填结果。这里有个容易踩的坑工具函数的 docstring 会被作为模型理解工具的说明所以 docstring 一定要写清楚参数含义和返回值含义否则模型可能生成错误的参数。2.2 对话的协调机制对话协调机制决定了多 Agent 之间以什么顺序交换消息。RoundRobinGroupChat的逻辑最简单粗暴按照参与者的列表顺序一个接一个轮流发言首轮由第一个参与者接收用户任务并开始。这种机制适合流程固定、各环节按顺序推进的场景比如先让数据 Agent 查数据、再让分析 Agent 做分析、最后让报告 Agent 输出报告。SelectorGroupChat则更灵活它通过一个选择函数来决定下一个发言者。选择函数的输入是当前对话历史输出是下一个发言者的名字。你可以在选择函数里写业务规则比如如果上一条消息包含批准就让财务 Agent 发言包含驳回就让申请 Agent 重新修改。这种机制在需要动态决策的场景更实用比如复杂的审批流、多条件分支对话。我在实际项目里用得比较多的是RoundRobinGroupChat原因是它的执行路径可预测调试成本低。每次对话的顺序都是确定的出了问题很容易定位是哪个 Agent 在第几轮产生了错误输出。SelectorGroupChat虽然灵活但选择函数一旦判断失误整个对话流的走向就会失控排查起来要翻很多轮历史。我的建议是先用轮流发言把流程跑通确认业务逻辑无误后再考虑是否换成动态选择。2.3 终止条件的机制终止条件是多 Agent 系统里最容易被忽视、却又最致命的一环。我先说结论任何团队都必须至少配置一个终止条件否则run()会一直跑下去直到模型的上下文窗口爆掉。MaxTermination是最简单的兜底方案它接受一个max_round参数当对话轮次达到上限就停止。我通常会给所有团队都配一个MaxTermination(20)作为保险哪怕业务上还有其他终止条件。第二常用的是TextMentionTermination它可以指定一个或多个文本标记当某个参与者的消息里出现了这个标记比如TERMINATE或任务完成时对话终止。终止条件之间还可以组合。AgentChat 提供了OrTermination和AndTermination操作符前者是任意一个条件满足即停止后者是全部条件满足才停止。比如一个审批流程我希望对话在审批 Agent 输出已批准或轮次超过 30 轮时结束就可以用OrTermination(TextMentionTermination(已批准), MaxTermination(30))。这里有一个容易被忽略的细节TextMentionTermination默认是检查任何参与者的消息里有没有指定文本。如果你只希望某个特定 Agent 的输出来触发终止需要给终止条件传入具体的 Agent 引用否则可能出现任务还没完成但另一个配角 Agent 无意中说了句TERMINATE导致对话提前结束的情况。我就在生产环境里被这个坑过一次后来统一改成只检查主控 Agent 的输出再没出过问题。3. 环境准备与快速上手3.1 环境安装AgentChat 的环境要求不算高Python 3.9 以上就可以。我建议在虚拟环境里安装避免污染全局环境。安装命令很简单pip install autogen-agentchat0.2这个包会自动带上autogen-core和必要的依赖包括openai客户端和pydantic。如果你后续要做流式输出的事件处理建议再装一个pip install autogen-ext[openai]autogen-ext是扩展包提供 OpenAI、Azure OpenAI、Anthropic 等模型客户端的适配器。不装这个的话AssistantAgent拿不到合适的模型客户端。我建议把包升级到比较新的稳定版再开始早期版本的一些 API 接口变动很大网上很多旧教程的代码跑不起来就是因为 API 换了一轮。安装完成后可以用pip list | grep autogen检查版本确保autogen-core和autogen-agentchat都在。3.2 模型与服务配置AgentChat 本身不直接和模型厂商的 API 交互它通过一个叫做模型客户端的抽象层来统一管理模型调用。配置 OpenAI 模型客户端的方式如下from autogen_ext.models.openai import OpenAIChatCompletionClient model_client OpenAIChatCompletionClient( modelgpt-4o, api_key你的API_KEY, )如果你用的是 Azure OpenAI对应的客户端类是AzureOpenAIChatCompletionClient需要额外指定azure_endpoint、api_version和model名称。另外如果你在本地部署了大语言模型比如通过 Ollama 或 vLLM也可以通过配置OpenAIChatCompletionClient的base_url指向本地服务地址来对接——因为本地推理服务通常也会提供 OpenAI 兼容的接口。这里有个实操要点不要把 API Key 硬编码在代码里推荐用环境变量管理。我在部署脚本里统一用API_KEY这类环境变量名然后通过os.getenv()读取这样在 Git 仓库里不会泄露密钥切换测试环境和生产环境也方便。3.3 快速构建一个单 Agent配置好模型客户端后构建一个单 Agent 并运行一次任务只需要几行代码。下面是最小可用的示例import asyncio from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.teams import RoundRobinGroupChat from autogen_agentchat.conditions import MaxTermination, TextMentionTermination from autogen_ext.models.openai import OpenAIChatCompletionClient async def main(): model_client OpenAIChatCompletionClient( modelgpt-4o, api_keyYOUR_API_KEY, ) agent AssistantAgent( nameassistant, model_clientmodel_client, system_message你是一个精通多智能体系统的助手回答时保持简洁。所有回答的结尾必须加上TERMINATE。, ) team RoundRobinGroupChat( participants[agent], termination_conditionOrTermination( TextMentionTermination(TERMINATE), MaxTermination(10), ), ) result await team.run(task请用三句话解释什么是多智能体系统) print(result.messages) if __name__ __main__: asyncio.run(main())这段代码做了三件事创建模型客户端、定义 Agent、把 Agent 放入团队并运行任务。注意我把TextMentionTermination(TERMINATE)和监督轮次的MaxTermination(10)做了组合这样就算模型忘了输出终止标记对话也不会无限跑下去。第一次跑通这个示例的时候你会发现一个单 Agent 的团队其实就是一个普通对话消息历史里包含用户任务和 Agent 的回复结构非常清晰。把单 Agent 跑通是理解后续多 Agent 协作的基础因为多 Agent 场景本质上就是在 participants 列表里多放几个 Agent。4. 多智能体对话实战4.1 双 Agent 协作问答与审校先从最经典的双 Agent 场景说起创作 Agent 生成内容审校 Agent 检查质量。这个场景在内容生产系统里非常常见比如自动生成商品文案然后让另一个 Agent 检查违禁词和事实错误。import asyncio from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.teams import RoundRobinGroupChat from autogen_agentchat.conditions import TextMentionTermination, MaxTermination from autogen_agentchat.conditions import OrTermination from autogen_ext.models.openai import OpenAIChatCompletionClient async def main(): model_client OpenAIChatCompletionClient( modelgpt-4o, api_keyYOUR_API_KEY, ) writer AssistantAgent( namewriter, model_clientmodel_client, system_message( 你是文案创作专家。根据用户需求撰写文案。 完成撰写后把内容交给 reviewer 审核。 如果 reviewer 提出修改意见按意见修改并再次提交。 ), ) reviewer AssistantAgent( namereviewer, model_clientmodel_client, system_message( 你是严格的内容审核员。检查文案是否有事实错误、敏感表达或逻辑问题。 如果内容合格回复通过如果不合格指出修改意见。 审核通过后你的回复必须以TERMINATE结尾。 ), ) team RoundRobinGroupChat( participants[writer, reviewer], termination_conditionOrTermination( TextMentionTermination(TERMINATE, reviewer), MaxTermination(12), ), ) result await team.run(task写一段关于智能家居的短视频文案30秒口播风格) for msg in result.messages: print(f[{msg.source}] {msg.content}\n) if __name__ __main__: asyncio.run(main())这里的协作逻辑是writer 先输出文案reviewer 检查。如果不合格writer 根据意见修改reviewer 再查直到 review 满意并输出TERMINATE。有人可能会问为什么不把评审规则直接写进 writer 的提示词里让一个 Agent 自问自答答案是效果差。模型在同一上下文里既是作者又是评审会在认知上产生严重偏袒更倾向于认为自己写的内容没问题。两个独立 Agent 之间反而能形成真正有效的对抗性检查。这里我把TextMentionTermination(TERMINATE, reviewer)的第二个参数指定为reviewer对象目的就是只监听 review Agent 的输出避免 writer 生成的文本里偶发的TERMINATE字样导致流程中断。这种指定触发者的写法在业务场景里非常重要。4.2 三 Agent 审批流程实战再上一个更复杂的场景采购审批。这个场景有三个 Agent 参与申请 Agent 提出采购需求、财务 Agent 审核预算、主管 Agent 做最终决策。三 Agent 的编排比双 Agent 复杂因为不再是简单的两方循环而是三方轮流发言每一轮的角色边界必须清晰。import asyncio from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.teams import RoundRobinGroupChat from autogen_agentchat.conditions import TextMentionTermination, MaxTermination, OrTermination from autogen_ext.models.openai import OpenAIChatCompletionClient async def main(): model_client OpenAIChatCompletionClient( modelgpt-4o, api_keyYOUR_API_KEY, ) requester AssistantAgent( namerequester, model_clientmodel_client, system_message你是采购申请方。准备发起采购申请说明采购物品、数量、预算范围。等待财务和主管的反馈。, ) finance AssistantAgent( namefinance, model_clientmodel_client, system_message你是财务审核员。检查预算是否充足、采购价格是否合理。只关注财务合规不讨论业务必要性。预算通过回复财务通过否则回复预算驳回并说明原因。, ) manager AssistantAgent( namemanager, model_clientmodel_client, system_message你是采购决策主管。综合申请方的理由和财务的审核意见做最终决定。如果批准回复批准采购如果拒绝回复拒绝采购最后必须加上TERMINATE。, ) team RoundRobinGroupChat( participants[requester, finance, manager], termination_conditionOrTermination( TextMentionTermination(TERMINATE, manager), MaxTermination(15), ), ) result await team.run( task申请采购需要购买3台高性能开发工作站单价预算约20000元用于新项目的AI模型训练。 ) for msg in result.messages: print(f[{msg.source}] {msg.content}\n) if __name__ __main__: asyncio.run(main())这个场景里RoundRobinGroupChat的轮流顺序是requester - finance - manager即每一轮先由申请方陈述、财务审核、主管决策。不过这里藏着一个业务逻辑问题如果财务驳回了主管其实不需要再决策但轮询机制还是会轮到主管。怎么处理办法有两种第一种是在每个 Agent 的提示词里写清楚如果上一条消息是预算驳回主管直接回复流程终止并附加 TERMINATE第二种是改用SelectorGroupChat在选择函数里判断上一条消息的内容决定下一个发言者。前者实现简单适合业务分支少的情况后者更优雅适合状态多的流程。我一般倾向先用第一种把流程跑通遇到分支实在太多再切换。4.3 流式输出与事件监听team.run()会把整个对话流程跑完后再返回最终结果这在任务耗时长比如多轮工具调用、长文档分析时会让人等得很着急。实际开发时我几乎总是用run_stream()替代run()它能实时地吐出事件流包括消息开始、消息更新、工具调用、Agent 回复等事件。from autogen_agentchat.ui import Console async def main(): # ... 同上省略 agent 定义 ... team RoundRobinGroupChat( participants[requester, finance, manager], termination_conditionOrTermination( TextMentionTermination(TERMINATE, manager), MaxTermination(15), ), ) await Console(team.run_stream(task申请采购3台高性能开发工作站...))Console是 AgentChat 提供的一个便捷工具它会把事件流渲染成可读的文本输出每个 Agent 的发言前会带上name前缀一眼就能看清当前是哪个角色在说话。这个体验对调试阶段特别友好我可以实时观察对话走向发现某个 Agent 跑偏就能立刻打断。如果你需要在事件流里做更精细的控制比如把事件推送到前端 UI 或写入日志可以自己遍历run_stream()异步迭代器。下面是一个简化示例async for event in team.run_stream(task... task ...): if event.type TaskResult: print(对话结束) elif hasattr(event, source) and event.source: print(f[{event.source}] {event.content})这里事件对象的具体字段会随版本有所不同建议你在交互环境里打印一下type(event)看看结构。事件流机制还有一个好处你可以实现人工审批节点。例如监听到财务 Agent 输出预算通过后暂停对话并将决策权限交给人类确认后再继续后续流程。这种机器跑流程、人类管关键节点的模式是目前生产环境落地最靠谱的方式。4.4 工具调用让 Agent 真正接上外部能力一个只能说话的多智能体系统价值有限真正让它发挥威力的是工具调用。AgentChat 里给 Agent 挂工具非常简单。假设我们给财务 Agent 接一个查询实时汇率的工具from autogen_agentchat.agents import AssistantAgent from autogen_agentchat.tools import FunctionTool def get_exchange_rate(currency_from: str, currency_to: str) - str: 查询两种货币之间的实时汇率。 Args: currency_from: 源货币如 USD currency_to: 目标货币如 CNY # 这里只是示例实际可以调用第三方汇率 API return 1 USD 7.1 CNY exchange_tool FunctionTool(get_exchange_rate) finance_with_tool AssistantAgent( namefinance_tool, model_clientmodel_client, tools[exchange_tool], system_message你是财务审核员需要换算外币金额时使用查询汇率工具。, )关键点有两个一是工具函数本身必须是纯函数不要在里面写大段业务逻辑二是 docstring 写得越规范模型调用时参数生成就越准确。我见过不少同学写工具函数时 docstring 特别随意比如只写查询汇率四个字模型就经常猜错参数名导致工具调用失败。后来强制团队里所有工具函数都必须写完整的 Args/Returns 格式调用准确率立刻上来了。工具调用还会影响终止条件的设计。如果某个 Agent 在调用工具过程中返回了异常对话流里会出现一条工具执行错误的消息。你可以让这个 Agent 在提示词里写当工具返回错误时向用户说明错误原因并请其检查输入不要让系统在错误状态下继续盲目往下走。5. 常见问题与排查技巧实录5.1 高频问题速查表下面把我实际开发中遇到的高频问题整理成一个速查表这些问题在 AgentChat 相关社区和我的项目群里反复出现。现象常见原因排查思路对话跑完但结果为空终止条件触发过早业务逻辑没走到最后一步检查TextMentionTermination是否被非目标 Agent 触发打印完整消息历史Agent 回复越来越短直到断掉上下文超出模型窗口部分历史被截断缩短 max_turns合并历史消息或换大上下文模型任务永远跑不完没有配置终止条件或触发文本没有被模型输出检查 termination_condition 配置看模型回复末尾是否包含指定文本工具调用参数报错工具函数 docstring 不规范检查 docstring 的 Args 描述是否和函数签名一致API 请求超时网络波动或模型响应太慢增加超时时间配置重试策略复杂任务拆小并发场景下请求被限流多个 Agent 同时调用模型 API 触发了速率限制使用信号量限制并发数或配置退避重试先说明一点不要指望模型每次都会命中你提示词里给出的回复格式。多 Agent 对话里最常出现的问题就是某个 Agent 忘了按约定格式输出终止文本导致对话回合乱掉。所以终止条件一定要有兜底MaxTermination是不可省的最后防线。5.2 令牌与上下文管理多 Agent 系统的 token 消耗比单 Agent 高一个量级因为每一次对话轮次都是一次完整的模型调用而且每个 Agent 都会接收全部或部分历史消息。如果你有 3 个 Agent 跑了 10 轮最坏情况下会产生 30 次模型调用这就是 30 次计费的 token 开销。管理上下文的第一原则是不要让每个 Agent 都看到全部对话历史。AgentChat 内部的消息处理机制会按照参与方过滤消息但具体行为取决于版本和配置。我在项目里通常会给每个 Agent 设置独立的系统提示词同时把不需要的旁支历史在提示词里明确说明忽略与你无关的消息记录。如果对话历史确实太长更彻底的做法是在中间环节做一次总结——让一个专门的 Summary Agent 把前面的对话浓缩成要点供后续 Agent 参考。虽然多了一次模型调用但能把后续每一轮的 token 消耗降下来。另一个细节是TokenUsageTermination这个终止条件。你可以设置一个总 token 预算比如 100 万 token当团队累积消耗达到预算后自动终止。这个条件特别适合控制成本敏感的批处理任务——宁可在结果不完美时终止也不能让预算失控。5.3 死循环与对话失控排查死循环是多 Agent 系统里最让人头疼的问题。现象是两个 Agent 反复说差不多的话谁也不推进流程直到 max_turns 耗尽或上下文爆掉。我总结出三个常见根因终止文本无法触发Agent 的输出格式不稳定有时输出TERMINATE有时输出终止大小写还不同。解决方案是让终止条件同时监听多个变体比如TextMentionTermination(TERMINATE, 终止, 结束)。提示词没有明确产出推进逻辑例如 writer 每轮都说文案已更新请审核reviewer 每轮都说建议修改但 writer 下一轮并没有真正按建议改因为它不知道自己应该怎么改。解决方案是在提示词里写明必须引用上一条审核意见的具体内容并逐条回应。分支逻辑和轮询机制不匹配使用RoundRobinGroupChat时某些场景下某个 Agent 其实不需要发言但轮询机制还是会让它硬发言导致流程冗长。这时应该考虑切换SelectorGroupChat或者在提示词里约束如果与你无关直接回复待定。排查死循环最快的方法是把事件流完整打出来async for event in team.run_stream(task...): if hasattr(event, source): print(f轮次 {event.generation} | {event.source} | {event.content[:100]})看最后几轮的输出模式如果同一个 Agent 连续三次说了几乎一样的话说明提示词里缺少推进指令如果两个 Agent 互相复读说明角色边界没切开它们在做同一件事。看到模式之后再回去改提示词比盲猜生效快很多。5.4 并发、网络与接口限流把 AgentChat 部署成服务后并发和限流会变成主要矛盾。模型 API 都有速率限制多 Agent 系统的并发性又很强两者天然冲突。我在一个生产项目里遇到的实际情况是同时有 20 个任务在跑每个任务内部有 3 个 Agent 互相协作瞬时请求量会打到 60 个并发很容易撞上 OpenAI 的 RMPRequests Per Minute限额。解决方案无外乎两个方向限制并发数量和做退避重试。AgentChat 底层用的是asyncio所以最简单的并发控制是给每个任务外面套一个asyncio.Semaphore把同时运行的团队数量限制在一个安全范围内semaphore asyncio.Semaphore(5) async def run_limited(task): async with semaphore: return await team.run(tasktask)另一个方向是在模型客户端级别配置重试策略。部分 OpenAI 客户端库自带 retry 和 backoff如果遇到 429 限流错误会自动等待重试。如果你用的模型服务不提供自动重试就要自己在 Agent 调用外层包一层重试逻辑捕获限流异常后做指数退避。网络超时也是经常碰到的问题。多 Agent 对话通常耗时较长单次 Agent 的模型调用可能在 30 秒以上默认的 HTTP 客户端超时时间往往不够。如果你用的是OpenAIChatCompletionClient可以在初始化时调整超时参数。我一般会把超时设置到 60 秒以上给大模型生成留足时间。6. 生产落地的一些心得6.1 从原型到生产要改的东西很多人把演示用的多 Agent 代码直接搬上线结果发现完全跑不动。区别主要在三处第一是模型路由。原型阶段可以只用一个gpt-4o打通所有 Agent但生产环境里不同类型的 Agent 适合不同模型。比如财务审核 Agent 要求逻辑严谨用推理能力强的模型文案创作 Agent 需要表达流畅用速度快的模型。AgentChat 里每个 Agent 都能绑定不同的model_client这给了你极大的调优空间。我在项目里会维护一个模型配置表按 Agent 角色分配不同的模型整体成本能降 30% 以上。第二是链路追踪。多 Agent 的调用链条比单 Agent 长得多任何一个环节出错排查问题都需要看完整的事件流。上线前一定要把日志规范化记录每个 Agent 的输入输出、工具调用、token 用量、耗时。AgentChat 的事件流机制已经很友好了你只需要把事件统一写入结构化日志系统。没有日志的多 Agent 系统就是一颗定时炸弹。第三是输入校验。多 Agent 系统会执行工具调用如果你把工具链暴露给用户输入恶意构造的 prompt 可能诱导 Agent 调用危险工具。上线前必须为工具函数加严格的参数校验和权限控制尤其是涉及数据库操作、文件读写、网络请求的这些权限敏感工具不能让 Agent 随便传参。6.2 成本控制与模型分级我在实操中摸索出一个比较有效的成本控制思路把 Agent 按思考强度分成三个等级。第一级是轻量 Agent用于做简单的文本格式化、关键词提取用便宜快速的小模型就行。第二级是标准 Agent负责大多数对话和工具调用用通用中端模型。第三级是重思考 Agent只在流程的关键决策点启用用推理增强模型。这套模型分级策略配合 AgentChat 的独立 model_client 设计实施起来非常顺手。你只需要在定义 Agent 的时候分别绑定对应的模型客户端即可。我还习惯在终止条件里叠加TokenUsageTermination给整个任务设一个 token 预算上限。这样即便某个流程出现意外也不至于产生天价账单。批处理场景还有一个省钱技巧夜间运行低成本模型。如果业务允许延迟可以把非实时任务切到批量模型或低价时段处理成本能进一步下降。AgentChat 的异步架构天然适合这种批处理跑批的模式多任务并发也不容易乱。6.3 从对话到工作流演进方向不建议一上来就让多 Agent 系统全权自主处理业务更稳妥的方式是对话 人去关键节点审批。AgentChat 的事件流机制完全可以做到跑一段对话、暂停、等人工确认、恢复。比如我们采购审批流程财务 Agent 审核通过后让事件流暂停把审核结果发给主管线下确认用户点击确认后再让主管 Agent 执行最终决策的操作。这类人在环上的设计既能体验多 Agent 的自动化优势又能规避完全自主决策带来的风险。当对话流程逐渐稳定后再考虑把高频路径固化下来某些节点不再需要 Agent 思考而是直接走预定义规则。比如财务审核如果检测到采购金额低于阈值直接放行不需要模型参与判断。这样实现Agent 负责复杂分支、规则处理简单分支的混合架构既能保证灵活性又能显著降低平均耗时和成本。我在实际项目中还会给每个 Agent 配置逃生通道卡片也就是一个特殊的系统提示词文件里面规范好 Agent 的最简行为。一旦某个版本的 Agent 在线上出现连续性错误就立刻用逃生通道替代而不是紧急改代码重新部署。这种小细节在运维阶段非常实用。写在最后的一点个人体会做了半年多 AgentChat 相关项目我最深的感觉是多智能体框架的入门门槛其实很低复杂的是你想清楚每个 Agent 的边界和它们之间的对话协议。代码反而是最简单的一层提示词设计和流程编排才是真正需要反复打磨的地方。我现在的习惯是开始写代码之前先在纸上画出各 Agent 的角色、输入输出、终止条件当这个图能清晰地回答每一步为什么由这个 Agent 来做时写代码通常一次就能跑通。另外一个建议是善用run_stream()调试。就算最终上线用的是run()开发阶段也一定要用流式模式跑看着每一步的发生过程你会更快发现问题出在哪一个 Agent、哪一轮对话。多 Agent 系统的 bug 往往不是代码写错了而是角色没说清楚或者流程没有推进。理解了这一点排查问题的思路就会完全不一样。最后分享一个小技巧给参与者命名时尽量用业务语义的英文单词比如finance_agent、reviewer_agent不要用agent1、agent2。这些名字会出现在对话历史和事件流里名字越语义化排查问题时越容易定位也能让大模型在对话时更准确地区分角色。这个小习惯是我在踩了无数次agent名字混淆的坑之后才养成的希望对你有用。