群聊与发言者选择 本节摘要:共享会话编排把 N 个 Agent 放进一个会话,由选择函数(LLM、轮询或自定义)决定下一个谁说。这是「涌现式多智能体会话」的原型——Agent 不知自己在静态图里的角色,只对共享池做反应。AutoGen GroupChat 与 AG2 GroupChat 是参考实现:AutoGen v0.2 的 GroupChat 语义被社区 fork 成 AG2 保留;AutoGen v0.4 重写为事件驱动 actor 模型;微软 2026/02 把 AutoGen 转维护模式并并入 Microsoft Agent Framework(RC 2026/02,与 Semantic Kernel 合并)。
本节摘要:共享会话编排把 N 个 Agent 放进一个会话,由选择函数(LLM、轮询或自定义)决定下一个谁说。这是「涌现式多智能体会话」的原型——Agent 不知自己在静态图里的角色,只对共享池做反应。AutoGen GroupChat 与 AG2 GroupChat 是参考实现:AutoGen v0.2 的 GroupChat 语义被社区 fork 成 AG2 保留;AutoGen v0.4 重写为事件驱动 actor 模型;微软 2026/02 把 AutoGen 转维护模式并并入 Microsoft Agent Framework(RC 2026/02,与 Semantic Kernel 合并)。GroupChat 原语在 AG2 与 MAF 两条线都活着——学一次,处处用。本节用标准库从零实现 GroupChat,讲透三种选择器、终止条件、四类失败(确定性、谄媚、上下文膨胀、热点发言者),以及它与监督者的同构关系。
阅读完本节,你应当能够:
静态图(LangGraph)在工作流已知时很好。真实会话不是静态的:有时程序员问评审员,有时问研究员,有时问作者。硬编码每种可能交接会产生边爆炸。你想要的是 Agent 对共享池做反应,由某个函数决定下一个谁说话。
这正是 AutoGen GroupChat 做的。
每个 Agent 看到每条消息;每轮调一次选择函数选下一个发言者。
agent = ConversableAgent(name="coder", system_message="你写 Python 代码。", llm_config={...}) chat = GroupChat(agents=[coder, reviewer, tester], messages=[]) manager = GroupChatManager(groupchat=chat, llm_config={...})
GroupChatManager 持有选择器。一个 Agent 完成一轮后,manager 调选择器返回下一个,循环到终止条件。
三种常见模式:
2025 年初微软围绕事件驱动 actor 模型大改 AutoGen(v0.4)。社区把 v0.2 的 GroupChat 语义 fork 成 AG2,保留早期采用者集成的 API。2026/02 微软宣布 AutoGen 转维护,事件驱动 actor 模型并入 Microsoft Agent Framework(RC 2026/02,与 Semantic Kernel 合并)。GroupChat 概念两条线都活;实现细节不同。AG2 是 v0.2 兼容代码的首选上游。
⚠️ 群聊是「协调从交互中涌现」的极致形态——好处是不必预连边,坏处是失去确定性,且上下文随轮数线性膨胀。「下一个谁说」看似简单,实则是整个系统行为的控制器。
同原语,不同默认:
两者都用第 04 节的四原语。群聊默认 LLM 选择编排 + 全量池共享状态。
code/main.py 用标准库实现 GroupChat:三个 Agent(coder、reviewer、manager),轮询与 LLM 选择两种变体,TERMINATE 哨兵终止。
class GroupChat: def __init__(self, agents, selector, terminator, max_rounds=10): self.agents = agents; self.selector = selector self.terminator = terminator; self.max_rounds = max_rounds self.pool = [] def run(self, seed_message): self.pool.append({"from": "user", "content": seed_message}) current = self.agents[0] for r in range(self.max_rounds): reply = current.reply(self.pool) self.pool.append({"from": current.name, "content": reply}) if self.terminator(reply): break current = self.selector(self.agents, self.pool, current) return self.pool
def round_robin(agents, pool, last): return agents[(agents.index(last) + 1) % len(agents)] def llm_selected(agents, pool, last): # 真实里:把近 N 条消息 + 各 Agent 专长喂 LLM,返回下一位 recent = pool[-5:] return choose_best_fit(agents, recent) def custom(agents, pool, last): if last.name == "coder": # 程序员之后总给验证者 return next(a for a in agents if a.name == "reviewer") return llm_selected(agents, pool, last)
设计要点:轮询确定性但无视上下文;LLM 选择上下文敏感但每轮多一次调用且不稳定。生产里最常用的是自定义 = LLM 选择 + 回退规则,既保留上下文敏感又有可控的强制交接。
| 实现 | 选择器默认 | 共享状态 | 维护状态 |
|---|---|---|---|
| AutoGen v0.2 / AG2 GroupChat | LLM 选择 | 全量池 | AG2 社区活跃,v0.2 API 兼容 |
| AutoGen v0.4 actor 模型 | 事件驱动 | 消息事件 | 转维护,并入 MAF |
| Microsoft Agent Framework | 模式特定 | thread/context | RC 2026/02,与 Semantic Kernel 合并 |
| LangGraph | 图边条件(确定性) | StateGraph reducer | 活跃,推荐用图而非群聊做确定性场景 |
| CrewAI | manager LLM 或静态顺序 | Task 输出链式 | 活跃,角色驱动 |
💡 心法:群聊适合涌现,图适合确定性。 同一个多智能体问题,要可审计可重放就用 LangGraph 的图;要头脑风暴式的灵活就用 GroupChat。别用群聊去硬凑一个本该是 DAG 的流程。
outputs/skill-groupchat-selector.md:为给定任务配置 GroupChat 选择器——轮询 vs LLM 选择 vs 自定义,以及用什么选择器输入(近期消息、Agent 专长、话轮计数)。
code/main.py,对比轮询 vs LLM 选择下的会话。每种下哪个 Agent 主导?GroupChatManager 的默认选择器。下一节,我们聚焦 OpenAI Swarm 提出的轻量协调原语——交接与例行程序,看一种刻意无状态的编排如何用工具调用实现控制转移。