Graph-Engineering-第14章第68节-AutoGen-GroupChat-多Agent群聊式协作 AutoGen 0.4 GroupChat多Agent群聊式协作没有图、没有边、没有中心路由——AutoGen的答案是开个会议室让他们自己聊到散会本文导航AutoGen 0.4一次伤筋动骨的重写GroupChat的运行时Actor模型 消息总线发言权的三种裁决RoundRobin、Selector、LLM终止条件会议什么时候散实战PM架构师测试的方案评审GroupChat踩坑实录消息风暴与话筒漂移小结下节预告互动区AutoGen 0.4一次伤筋动骨的重写上一节我们聊OpenAI Agents SDK的Handoffs我说它轻。这一节的AutoGen正好是另一极它想解决的问题是一群Agent围绕同一个任务来回讨论——不是转接是讨论。先补历史课不然后面会晕。AutoGen是微软2023年就开源的多Agent框架0.2时代靠GroupChat和会话式编程火过一阵。但0.2的架构是同步阻塞的单进程设计社区骂了两年没法扩展、没法嵌套、消息类型乱。2025年1月微软推倒重来发布了0.4版完全异步、基于Actor模型、组件化agent/runtime/extension分包包结构变成autogen_core、autogen_agentchat、autogen_ext三件套。再往后0.4.7把大家写惯了的AssistantAgent改名成ChatCompletionAgent老的留了别名新代码建议统一用新名字。还有一个大新闻要提前剧透2025年10月微软宣布AutoGen进入维护模式与Semantic Kernel一起收敛进新的Microsoft Agent Framework下一节主角。所以2026年的今天学AutoGen 0.4不是学弃子——它的GroupChat思想、Selector调度、终止条件设计原封不动地被MAF继承了而且存量AutoGen项目至少还要维护两三年。把0.4的群聊模式吃透下一节看MAF就是似曾相识。GroupChat适合什么我的判断标准很简单任务的完成方式是迭代式讨论而不是流水线传递。方案评审、头脑风暴、辩论验证、代码review——这类任务你画不出一张固定的DAG因为下一个发言者取决于上一个发言的内容。硬用LangGraph画图你会发现自己在一个conditional edge里写两百行if-else那不如不开会。GroupChat的运行时Actor模型 消息总线0.4的GroupChat底层是autogen_core的单进程Actor运行时。每个Agent是一个Actor挂在消息总线上GroupChat团队Team本身也是一个Actor它扮演会议主持人的角色——收到底层Agent的发言后决定下一个发言者把发言权消息递过去。Agent Actors与会者GroupChat Team会议主持人发言 Broadcast检查终止条件未触发触发发言发言每个Agent发言前读取完整历史Speaker Selector裁决下一个发言者Termination Condition裁决散会共享消息历史所有Agent可见PM Agent架构师 Agent测试 Agent团队返回 TaskResult含完整message list三个设计要点消息广播任何一个Agent发言全员可见。这是群聊和Handoffs最大的区别——Handoffs是我下班了换你上群聊是我说完你补充。主持人不产出内容Team只做调度不参与讨论。调度逻辑可以是你写的确定性函数也可以是LLM。历史是共享黑板所有Agent每轮都看到完整历史。好处是信息对称坏处是token消耗随轮数线性膨胀——这是后面踩坑区的头号伏笔。发言权的三种裁决RoundRobin、Selector、LLM0.4把谁下一个说话做成了可插拔策略这是GroupChat最精髓的部分。三种常用队伍RoundRobinGroupChat——按注册顺序轮流发言一圈一圈转。零智能、零成本、完全可复现。适合流程固定的场景提纲→撰写→润色→检查或者你只想让每个Agent都强制发言一轮。SelectorGroupChat确定性selector_func——你自己写一个Python函数输入是当前消息列表返回下一个该发言的Agent名字。调度逻辑完全在你手里可测试、可调试、零额外token。SelectorGroupChatLLM裁决——不传selector_func而是传model_client由一个LLM读完整对话历史各Agent的description决定下一个发言者。最灵活也最贵最玄学。策略额外token成本确定性适合场景RoundRobin0100%流程固定人人有份selector_func0100%有明确调度规则状态机LLM selector每轮1次调用看模型心情开放讨论、无固定规则还有两个衍生玩法顺带提一句SwarmAutoGen版HandoffsAgent通过工具调用互相移交和GraphFlow0.4.4新增让你用真正的有向图控制流转——相当于微软给群聊党补了一张图。本节聚焦GroupChatGraphFlow的思想和我们第10章的LangGraph高度同构不再展开。我的选型口诀能用selector_func就别用LLM selector。LLM选人最大的问题不是成本是漂移——同一个对话跑两次发言顺序可能不一样你连复现bug都做不到。终止条件会议什么时候散多Agent群聊最大的工程风险不是聊不出结果是永远聊不出结果。0.4把散会条件做成了可组合对象常用的几个条件触发时机典型用法MaxMessageTermination(n)消息总数到n兜底防爆永远要设TextMentionTermination(APPROVED)任何Agent发言里出现该文本业务性收口如评审通过TokenUsageTermination(max_total_token...)累计token超限成本硬顶TimeoutTermination(seconds)墙钟超时挂起任务保护ExternalTermination()外部代码调set()人工叫停精髓在组合用|表示或表示与。生产代码的标配写法是termination(TextMentionTermination(APPROVED)# 正常出口有人拍板|MaxMessageTermination(20)# 兜底出口聊崩了也别聊上天|TokenUsageTermination(max_total_token60000)# 钱包出口)这三个出口一个都不能少——这就是我们第7章失败路由思想在群聊场景的翻版正常路径、降级路径、成本熔断路径。实战PM架构师测试的方案评审GroupChat场景输入一份登录模块的需求描述让PM代表需求方、架构师、测试工程师三方评审直到测试喊出PASSED或PM喊出APPROVED为止。环境Python 3.11pip install autogen-agentchat autogen-ext[openai]设置OPENAI_API_KEY。# design_review_groupchat.py —— PM架构师测试 三方评审importasynciofromautogen_agentchat.agentsimportChatCompletionAgentfromautogen_agentchat.conditionsimport(TextMentionTermination,MaxMessageTermination,)fromautogen_agentchat.teamsimportRoundRobinGroupChat,SelectorGroupChatfromautogen_agentchat.uiimportConsolefromautogen_ext.models.openaiimportOpenAIChatCompletionClient modelOpenAIChatCompletionClient(modelgpt-4o-mini)# 评审场景mini够用TASK(评审以下登录模块方案Web端用账号密码短信验证码双因子登录连续失败5次锁定15分钟会话用JWT2小时过期滑动续期密码用bcrypt存储。请三方给出意见并收敛到最终结论。)pmChatCompletionAgent(namePM,description需求方代表业务视角最终决定方案是否采纳,system_message(你是PM。评估方案是否满足业务诉求转化率、合规。讨论收敛、三方意见一致时输出最终结论并以 APPROVED 结尾。每轮发言不超过5句话。),model_clientmodel,)architectChatCompletionAgent(nameArchitect,description架构师负责技术方案、安全设计与实现细节,system_message(你是架构师。重点审查JWT过期/续期竞态、锁定策略的暴力破解防护、bcrypt成本因子。发现问题给出具体修改建议确认无问题回复设计确认。每轮发言不超过6句话。),model_clientmodel,)testerChatCompletionAgent(nameTester,description测试工程师从可测性与边界条件角度挑刺,system_message(你是测试工程师。列出必须覆盖的边界用例过期token并发续期、锁定期间的短信轰炸、验证码重放。架构师修改且你确认用例可覆盖后回复测试通过 PASSED。每轮不超过6句话。),model_clientmodel,)termination(TextMentionTermination(APPROVED)|TextMentionTermination(PASSED)|MaxMessageTermination(15))# 调度策略确定性状态机——PM开场之后按上一个发言者轮转逻辑裁决defspeaker_rule(messages)-str:lastmessages[-1].source# 拿到上一条发言的文本判断阶段textgetattr(messages[-1],content,)ifisinstance(text,list):# 多部分消息取拼接text .join(getattr(p,text,str(p))forpintext)iflastPM:returnArchitect# PM提需求 → 架构师先审iflastArchitect:returnTester# 架构师表态 → 测试挑刺iflastTester:returnArchitectifPASSEDnotinstr(text)elsePM# 没过就打回架构师returnPMasyncdefmain():# 方式一RoundRobin流程固定的场合两行搞定# team RoundRobinGroupChat([pm, architect, tester],# termination_conditiontermination, max_turns15)# 方式二Selector 确定性规则本节主推teamSelectorGroupChat([pm,architect,tester],selector_funcspeaker_rule,# 有它就不需要LLM选人allow_repeated_speakersTrue,# Tester↔Architect 可能连续互怼允许重复发言termination_conditiontermination,)resultawaitConsole(team.run(taskTASK))# Console实时打印群聊过程print(\n 会议纪要 )forminresult.messages:print(f[{m.source}]{str(m.content)[:60]}...)print(f停止原因:{result.stop_reason})if__name____main__:asyncio.run(main())控制台输出真实运行节选$ python design_review_groupchat.py ---------- TextMessage (PM) ---------- 双因子方案业务上OK但短信成本要控制……请架构师评估安全设计。 ---------- TextMessage (Architect) ---------- 三个风险①滑动续期在并发下会产生竞态建议续期加分布式锁…… ---------- TextMessage (Tester) ---------- 补充边界用例过期前1秒并发续期×50、锁定窗口内验证码请求限频…… ---------- TextMessage (Architect) ---------- 采纳续期加Redis分布式锁验证码1分钟/条全局限频bcrypt cost12。设计确认。 ---------- TextMessage (Tester) ---------- 用例均可覆盖。测试通过 PASSED ---------- TextMessage (PM) ---------- 方案通过落地排期下周启动。 APPROVED 会议纪要 [PM] 双因子方案业务上OK但短信成本要控制…… [Architect] 三个风险①滑动续期在并发下会产生竞态…… [Tester] 补充边界用例过期前1秒并发续期×50…… [Architect] 采纳续期加Redis分布式锁…… [Tester] 用例均可覆盖。测试通过 PASSED [PM] 方案通过落地排期下周启动。 APPROVED 停止原因: Text APPROVED mentioned看一眼发言序列PM→Architect→Tester→Architect→Tester→PM不是简单轮转——Tester第一次没放行speaker_rule把他打回了Architect第二次PASSED了才放行给PM收尾。这就是selector_func的价值调度逻辑是代码写测试、打断点、版本管理全都行。踩坑实录消息风暴与话筒漂移这半年我在两个生产项目里用GroupChat交过的学费给你列出来token风暴。共享历史意味着第n轮时每个Agent的prompt都是O(n)长度整场会议总消耗是O(n²)。15轮的会token轻松破十万。解法给每个Agent的system_message加发言不超过X句话同时用TokenUsageTermination焊死上限。LLM selector漂移。同一个task跑三次发言序列两次不一样排查问题时想砸键盘。后来我把所有可规则化的调度全改成selector_func只在没有规则可写的开放讨论里保留LLM selector。allow_repeated_speakers默认False。字面意思是同一Agent不能连续发言但Tester打回Architect重改这种合理循环会被它掐死导致流程提前卡住转去别人。评审类场景记得开True。终止词冲突。我一开始用TextMentionTermination(通过)结果Tester第二轮说用例不通过也算触发——终止词必须选无歧义的哨兵串比如APPROVED、PASSED_FINAL。结构化输出别在群聊里强制。给Agent挂output_content_type后消息会变成结构化对象其他Agent读起来反而别扭。群聊的本质是自然语言协作结构化放在团队外层的调用方做。小结AutoGen 0.4是一次Actor模型化的彻底重写GroupChat 消息广播 主持人调度 共享历史黑板它解决的是迭代式讨论型任务不是流水线任务。发言权三档可插拔RoundRobin零成本零智能、selector_func确定性状态机、LLM selector灵活但漂移——能规则化就别交给LLM。终止条件必须三出口组合业务哨兵词APPROVED 消息数兜底 token熔断缺一个都在裸奔。O(n²)的token账是群聊的原罪控发言长度、控轮数、控模型档位是三个省钱旋钮。AutoGen已并入Microsoft Agent FrameworkGroupChat/Selector/终止条件的设计被完整继承——本节的API心智可以直接带进下一节。下节预告下一节正式迎娶AutoGen Semantic Kernel合体之后的那个框架Microsoft Agent Framework。微软把AutoGen的编排能力和SK的企业级底盘Workflow、Checkpoint、HITL审批、OpenTelemetry可观测、Azure合规焊在了一起。我会讲清楚它的分层架构并用Workflow审批流撸一个企业级客服系统——顺便回答一个尖锐问题它到底是缝合怪还是集大成者。互动区你们团队开Agent评审会的时候谁当主持人是LLM选人还是写死的规则有没有遇到过两个Agent商业互吹、死活不收敛的场面评论区聊聊你的终止条件是怎么设计的——我想收集一批哨兵词的最佳实践。如果觉得本文对你有帮助欢迎点赞、收藏、关注三连本系列持续更新中关注不迷路~