Agent 架构文档 · Markdown

AutoGen Agent 架构全景讲解

以 Agent 的生命脉络 为主线,把 Microsoft 在 microsoft/autogen 这一条线索上做的 一整套东西( autogen core actor runtime + autogen agentchat 高级团队封装 + autogen ext 扩展生态 + AutoGen Studio no code UI + Magentic On

来源文件:autogen-agent-architecture.md · 阅读时间 28 分钟

Agent 的生命脉络 为主线,把 Microsoft 在 microsoft/autogen 这一条线索上做的 一整套东西(autogen-core actor runtime + autogen-agentchat 高级团队封装 + autogen-ext 扩展生态 + AutoGen Studio no-code UI + Magentic-One 通用多 agent 编排)讲成一个统一的故事。

AutoGen 是经典的 conversational multi-agent 范式 —— "把任务拆给一群会聊天的 agent,让它们互相发消息直到达成共识"。在 2025 年初的 v0.4 重写之后,它已经从一个 "对话框抽象 + Python 脚本"长成了一个事件驱动的 actor 模型 runtime,能跨进程、跨 语言(Python / .NET)协作。

适合:想搞清楚 AutoGen v0.4 跟 v0.2 到底差在哪的迁移者 / 用 Magentic-One 做通用 agent 的研究员 / 评估开源 multi-agent 框架选型的架构师。

2026-06-08 官方复核补丁:PyPI autogen-agentchat / autogen-core 当前复核到 0.7.5,GitHub latest release 为 python-v0.7.5。本文讲的是 v0.4 重写后的 actor runtime 架构主线;当前包版本已高于文中最初口径,版本号以本条和官方发布为准。


#目录

  1. 写在前面:AutoGen 是什么 / 不是什么 0.5. 一张图看懂:AutoGen = Model + Harness(actor runtime + 对话总线)
  2. Agent 是什么 —— BaseChatAgent + 系统提示 + 工具 + 终止条件
  3. Agent 怎么活起来 —— Team.run() 一条链路到底
  4. Agent 怎么思考 —— GroupChat 五种 selector 的取舍
  5. Agent 怎么行动 —— Tool calling + Code executor + 跨 agent 委托
  6. Agent 怎么记忆 —— message thread + Memory 协议
  7. Agent 怎么开口 —— Console / Studio / 流式
  8. Agent 的外脑 —— ChatCompletionClient 抽象
  9. 关键设计权衡(架构师视角)
  10. 附录:包地图、关键概念与源码索引

#零、写在前面:AutoGen 是什么 / 不是什么

"In AutoGen, the team is the architecture." —— v0.4 把 v0.2 那种 "由 ConversableAgent 自己 reply 自己" 的隐式控制流,改成了 "Team 显式编排 + actor runtime 异步消息" 的两层。

#0.1 名称消歧:先把 "AutoGen" 这个词锁定

社区里围绕 AutoGen 这个名字其实有四个不同的项目,写文档前必须区分干净:

候选 是什么 跟 agent 有关吗
AutoGen v0.4 (microsoft/autogen,2025 年起) 重写后的 actor-model + async event-driven 框架,本文主角 本文主角
AutoGen v0.2 (legacy) 早期 ConversableAgent / GroupChat 同步 API,仍有大量用户、且仍可 pip install autogen-agentchat==0.2.x 本文配角,仅做迁移对比
Magentic-One (autogen-ext 子项目) 基于 v0.4 的 5-agent 通用编排(Orchestrator + WebSurfer + FileSurfer + Coder + ComputerTerminal) 本文配角
AG2 (ag2.ai) AutoGen v0.2 的社区 fork,独立演进 本文不展开
Microsoft Agent Framework Microsoft 2025 年底推出的"AutoGen + Semantic Kernel 合并版",AutoGen 自身已进入 maintenance 本文不展开,只在末尾提一句

本文讲的是 microsoft/autogen v0.4 这一脉

仓库现状(2026 年):v0.4 是 microsoft/autogen 仓库的"重写分水岭",此后小版本 持续迭代到 v0.7.x(2025-09 发布 python-v0.7.5),整体已进入 maintenance mode — README 明确写 "AutoGen is now in maintenance mode. It will not receive new features or enhancements and is community managed going forward.";新项目 Microsoft 推荐用 Microsoft Agent Framework(AutoGen + Semantic Kernel 合并版)。但 AutoGen 的 actor 抽象和 GroupChat 模式仍然是开源 multi-agent 领域最值得拆解的范式,所以本文 按"已稳定的最佳形态"来讲,下文凡说"v0.4"均指 v0.4 重写后的整条主线(含 v0.5/0.6/0.7)。

#0.2 核心矛盾:v0.4 在回答 v0.2 的什么痛点

矛盾 v0.2 的做法 v0.4 的回答
同步 reply 链导致单点阻塞、难扩展 ConversableAgent.send() 同步、generate_reply() 自己 reply 自己 actor 模型 + async messaging:每个 agent 是一个 actor,runtime 用消息队列驱动
GroupChat 的 speaker selection 是 prompt hack GroupChatManager 用一段 prompt 让 LLM 选下一个发言者 把 selection 抽象成 BaseGroupChatManager,可以是 RoundRobin / Selector / Swarm / Graph / Magentic
Tool 注册/执行散落在多个 agent 之间 register_function(executor=user_proxy, caller=assistant) tool 直接挂在 agent 上,AssistantAgent(tools=[...]),由 agent 自己执行
跨语言、跨进程难 只有 Python,且只能跑在一个进程里 GrpcWorkerAgentRuntime + protobuf,支持 Python / .NET 跨语言、跨进程
No observability print + logger 内置 OpenTelemetry tracing、流式事件、saving/restoring 任务进度

每个章节都会回到这五个矛盾,看具体的设计是怎么回应的。

#0.3 三层抽象:本文按这层关系展开

                    ┌─────────────────────────────────────────────────────┐
       第 6/8 章 ─→ │  AutoGen Studio   (no-code UI, drag-and-drop team)   │
                    └────────────────────────┬────────────────────────────┘
                                             │ 落到 YAML/JSON team config
                                             ▼
                    ┌─────────────────────────────────────────────────────┐
       第 1/3 章 ─→ │  autogen-agentchat (高级 API:Agent + Team)           │
                    │   AssistantAgent / UserProxyAgent /                  │
                    │   CodeExecutorAgent / SocietyOfMindAgent             │
                    │   RoundRobinGroupChat / SelectorGroupChat / Swarm /  │
                    │   GraphFlow / MagenticOneGroupChat                   │
                    └────────────────────────┬────────────────────────────┘
                                             │ 编译成 actor + 消息流
                                             ▼
                    ┌─────────────────────────────────────────────────────┐
       第 2 章   ─→ │  autogen-core (actor runtime)                        │
                    │   Agent / AgentRuntime / RoutedAgent /               │
                    │   @message_handler / TopicId / Subscription          │
                    │   SingleThreadedAgentRuntime / GrpcWorkerRuntime     │
                    └────────────────────────┬────────────────────────────┘
                                             │ 消费扩展能力
                                             ▼
                    ┌─────────────────────────────────────────────────────┐
       第 4/7 章 ─→ │  autogen-ext (扩展生态)                              │
                    │   OpenAIChatCompletionClient / Anthropic / Azure /   │
                    │   DockerCommandLineCodeExecutor / Jupyter / ACA /    │
                    │   ChromaDBVectorMemory / MultimodalWebSurfer / ...   │
                    └─────────────────────────────────────────────────────┘

记住这张图:autogen-core 是底座,agentchat 是大众工程师的入口,ext 是后台货架, Studio 是给 PM/分析师拖出来的 UI。


#零·五、一张图看懂:AutoGen = Model + Harness(actor runtime + 对话总线)

业界视角:端到端 agent 产品的差距不在底层模型,而在"模型之上的外壳(Harness)"—— 指令、能力、基础设施、可观测性四层共同决定 agent 的真实上限。

AutoGen 的特殊定位:它是 multi-agent 协作框架,不是端到端产品。 v0.4 把 harness 中"基础设施"这一层做得最重——actor runtime + 消息总线 + GroupChat 编排 几乎自成体系,跨进程跨语言都覆盖;但"指令层"主要靠开发者写 system_message,"能力层" 把 tool / code executor 拆成独立 protocol,"可观测"靠 OTel + Studio 外接。下面按"4 层 + 8 支柱" 反向索引本文档每个章节,并诚实标注"框架给了什么 / 留给开发者什么"。

#0.5.1 四层 Harness 结构

┌──────────────────────────────────────────────────────────────────────┐
│       Agent  =  Model  (LLM)  +  Harness  (AutoGen 提供 actor 底座)    │
└──────────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────────┐
│ ① 指令层  │ ⚠ 框架不管:每个 agent 的 system_message 由开发者写         │
│           │ AssistantAgent.system_message + description                → §1.1 │
│           │ SelectorGroupChat.selector_prompt(决定谁来发言)            → §3.3 │
│           │ Magentic Orchestrator 内置 ledger prompt 模板(少数"自带指令")→ §3.6 │
│           │ Swarm 的 handoff 名单写在 agent 的 handoffs= 参数            → §3.4 │
├──────────────────────────────────────────────────────────────────────┤
│ ② 能力层  │ tools=[fn]:Python callable 自动 schema 化                  → §4.1 │
│           │ FunctionTool / BaseTool:自定义 tool 协议                    → §4.1 │
│           │ CodeExecutor 接口(Local/Docker/Jupyter/ACA 四种 backend)   → §4.2 │
│           │ Handoff / SocietyOfMindAgent:跨 agent 委托原语              → §4.3 │
│           │ reflect_on_tool_use:tool 结果后再来一轮 LLM                 → §4.1 │
│           │ ext 货架:WebSurfer / FileSurfer / Coder / Terminal 现成实现 → §3.6 │
├──────────────────────────────────────────────────────────────────────┤
│ ③ 基础设施│ ★ AutoGen 最重的一层 ★                                       │       │
│           │ autogen-core actor runtime(SingleThreaded / Grpc Worker)   → §2.2 │
│           │ message_queue + TopicId + Subscription(消息总线)           → §2.2 │
│           │ GroupChat 共享 message thread(多 agent 通信底层)            → §3 / §5.1 │
│           │ ChatCompletionContext:unbounded / buffered / token-limited  → §5.1 │
│           │ Memory protocol(外挂长期记忆,ListMemory / ChromaDB / Redis)→ §5.2 │
│           │ save_state / load_state:team 级序列化                       → §5.4 │
│           │ ComponentBase:组件 dump/load(Studio 基础)                  → §6.3 │
├──────────────────────────────────────────────────────────────────────┤
│ ④ 可观测  │ run_stream:异步事件流(TextMessage / ToolCallEvent / Thought)→ §6   │
│           │ Console:彩色终端输出(调试 / demo 标配)                    → §6.1 │
│           │ AutoGen Studio:no-code UI + 实时对话气泡                    → §6.3 │
│           │ OpenTelemetry tracing:每次 agent / tool 调用打 span         → §6   │
│           │ ⚠ 没有内置 cost / 失败聚合面板(要自己接 Jaeger / 看板)      │
└──────────────────────────────────────────────────────────────────────┘

#0.5.2 八支柱对照表

# Harness 支柱 一句话定义 AutoGen 的实现(框架给 vs 开发者写) 对应章节
01 FS + Git state 必须活在 context 之外 ⚠ 给序列化不给文件系统:save_state / load_state 能把 team 全态 dump 成 dict(含 model_context / memory / speaker pointer / termination 计数),但没有"工作目录 / 产物文件"概念;要文件系统得 CodeExecutor 跑代码写或自己加 tool §5.4 / §4.2
02 Bash 通用工具 随用随装避免 token 爆炸 ✅ CodeExecutorAgent + DockerCommandLineCodeExecutor:LLM 写代码 → 容器里跑 → 返回 stdout/stderr,相当于"通用 bash";JupyterCodeExecutor 还能保持变量;⚠ 但不是"按需加载工具"模型,工具集合在 agent 创建时固定 §4.2
03 沙箱 + 子工具 行动可隔离 + 自检 ✅ 沙箱级别最高:Local / Docker / Jupyter / ACA Dynamic Sessions(云端按 session 隔离)四档可选;⚠ "自检"没有专门原语,靠 reflect_on_tool_use 让 LLM 看 tool 输出再说一遍,或者写一个 critic agent 单独评 §4.2 / §3.2
04 记忆 + 搜索 跨 turn / 跨用户拿历史 ⚠ Memory protocol 设计干净但内置实现少:ListMemory(全塞)/ ChromaDBVectorMemory(向量 top-k)/ RedisMemory;update_context 是关键钩子,每次推理前自动塞相关记忆。RAG pipeline / GraphRAG 框架不管,自己接 §5.2
05 对抗 Context Rot 长对话也别糊 ⚠ 给窗口策略不给 condenser:ChatCompletionContext 四种实现(Unbounded / Buffered / HeadAndTail / TokenLimited)按规则裁;没有"自动 summarize 历史",长任务靠 SocietyOfMindAgent 把内层折叠成一条对外 reply 间接缓解 §5.1 / §4.3
06 长程执行 多 phase 任务不跑偏 ⚠ 给协作不给 plan:GroupChat 五种 selector(RoundRobin / Selector / Swarm / GraphFlow / Magentic)覆盖编排,但只有 Magentic-One 内置 Task Ledger / Progress Ledger 的显式规划,其它范式要"plan"得自己加 agent 或 prompt §3 / §3.6
07 Hooks 强制层 失败转成永久规则 ❌ 没有内置 hook 强制层。TerminationCondition 可组合(MaxMessageTermination(20) | TextMentionTermination("APPROVE"))算是一种"硬规则",但 "agent 必须先 plan / 必须先校验"这种 phase-level 强制要靠 GraphFlow 画死边或者自定义 selector 实现 §1.4 / §3.5
08 规划 + 工具选择 别什么都试 ⚠ 推给团队拓扑:单 agent 内部就是普通 OpenAI tools 协议(看 description 让 LLM 选),跨 agent 才有"选谁"的概念(Selector / Magentic Orchestrator);没有"先 plan 后 execute"的内置范式,要么用 Magentic-One,要么用 GraphFlow 画死 §3 / §3.6

判读规则:✅ = 框架原生提供且大多场景够用;⚠ = 框架给了原语但要开发者组装;❌ = 框架不管,需要自己写或外接。

#0.5.3 当前架构的短板(按 Harness 视角看出来的)

AutoGen v0.4 的根本设计哲学是 "the team is the architecture"——它把基础设施做到极致 (actor + 消息总线 + 跨进程 + 序列化),但指令层 / 能力层 / 长程规划基本不替开发者做决策。 所以"短板"在这里更像是"它把哪些工作留给了开发者,这些工作在工程化时是真实代价":

  • Actor runtime 学习曲线陡:相比单进程 ReAct 的"调函数"心智,actor + topic + subscription + envelope 的异步消息模型要花时间消化。文档里的 §2.1 启动链路要 6 步才完成"一条用户消息发出去 → 第一个 agent 拿到"。 v0.2 那种"send / generate_reply"的直觉性彻底没了,换来的是可扩展、可观测、可恢复。
  • Context rot 没有 condenser:长会话只能靠 BufferedChatCompletionContext(N)TokenLimitedChatCompletionContext 硬截断;想做"滚动摘要 + 关键事实保留"得自己写一个 middleware agent 或者塞进 Memory.update_context 的 hook 里——没有像 Claude Code/Cursor 那样的"自动 fold + summarize"管道
  • Magentic-One 是唯一开箱即用的"通用编排器":但它本质是一个特别精致的 SelectorGroupChat
    • ledger prompt,单一编排器策略。要做"deep research + 长任务 + checkpoint 续跑"的复合场景, 对照 LangGraph 的 deep agents(todo / fs / subagent 三件套)AutoGen 没有等价模板。
  • 跨语言序列化是把双刃剑:GrpcWorkerAgentRuntime 让 Python / .NET agent 同台协作很酷, 但所有消息类型必须共享 protobuf schema——message type 演化代价大;本机 demo 跑得欢的 agent, 跨进程上线时 schema 对齐 / 版本兼容能耗掉一周。
  • 可观测主要靠 Studio(重)或自己接 OTel:框架自带 run_stream + Console 的体验很好, 但没有内置的 cost 看板 / 失败聚合 / 跨 team 的 trace 聚合。AutoGen Studio 官方明说 "not meant to be production-ready",生产可观测要 (a) 自己写 OTel exporter 到 Jaeger / Tempo, 或 (b) 接 Microsoft Agent Framework 的托管栈(AutoGen 自身已进入 maintenance)。
  • Memory 实现少而薄:ListMemory 全塞 / ChromaDBVectorMemory 向量召回 / RedisMemory, vs 同期 LangChain 几十个 vectorstore——AutoGen 的取舍是"protocol 自己接,不替你做选型", 但意味着第一次接的开发者得自己写一个 connector(好处是三十行代码搞定)。

这些"短板"换个角度看就是 AutoGen 的设计取舍——做对话 multi-agent 的 actor 底座, 把指令 / 能力 / 长程规划留给团队拓扑去回答。要做端到端 agent 产品,要么自己在 GroupChat 上面叠 plan / fs / condenser 这一层(很多生产团队的实际做法),要么迁到 Microsoft Agent Framework (AutoGen + Semantic Kernel 合并版,是 Microsoft 后续主推方向)。


#一、Agent 是什么 —— BaseChatAgent + 系统提示 + 工具 + 终止条件

"AssistantAgent 是 v0.4 的 'kitchen sink' agent:一个原型用、教学用、八九不离十 都够使的通用 agent,但生产环境里你最终多半要继承 BaseChatAgent 自己写一个。"

#1.1 在 AutoGen 里,"一个 Agent" = 一份配置 + 一个 actor

┌─────────────────────────────────────────────────────────────┐
│                    一个 AutoGen Agent                         │
├─────────────────────────────────────────────────────────────┤
│  name           : 唯一标识(runtime 内寻址用)                  │
│  description    : 自然语言描述(GroupChat selector 看这个挑人) │
│  system_message : 系统提示(决定它"是谁、能干什么")             │
│  model_client   : LLM 客户端(OpenAI / Azure / Anthropic ...)  │
│  tools          : 工具列表(Python callable 或 ToolSchema)     │
│  handoffs       : 可委托的目标 agent(Swarm 模式用)            │
│  memory         : Memory 列表(每轮调用 update_context)         │
│  model_context  : ChatCompletionContext(对话窗口管理策略)      │
│  reflect_on_tool_use : tool 返回后是否再过一遍 LLM(默认 False) │
│  model_client_stream : 是否启用 token 级流式(默认 False)        │
│                                                              │
│  ── 行为方法 ──                                              │
│  on_messages(msgs, ctx)         : 单次推理                    │
│  on_messages_stream(msgs, ctx)  : 流式推理                    │
│  on_reset(ctx)                  : 重置内部状态                │
│  produced_message_types         : 声明它会产生哪些消息类型      │
└─────────────────────────────────────────────────────────────┘

源码位置:python/packages/autogen-agentchat/src/autogen_agentchat/agents/

#1.2 v0.4 内置的几种 agent,覆盖 90% 用法

Agent 类 角色 最适合的场景
AssistantAgent 带 LLM + tools 的标配选手 你 90% 的场景,等价于 v0.2 的 AssistantAgent
UserProxyAgent 单纯收集用户输入再回传 human-in-the-loop,等价于但比 v0.2 简化非常多
CodeExecutorAgent 把 LLM 生成的代码块送进 executor 跑 code interpreter 类需求
SocietyOfMindAgent 对外暴露成单 agent,内部跑一个完整 Team 想做"团队封装成 agent"的嵌套场景
MessageFilterAgent 包另一个 agent,按规则过滤其上下游消息 多 agent 共享 thread 时屏蔽噪音(v0.4 后期补的)

这几个类共同实现 BaseChatAgent,签名约束:

class BaseChatAgent(ABC):
    @abstractmethod
    async def on_messages(
        self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken
    ) -> Response: ...

    async def on_messages_stream(
        self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken
    ) -> AsyncGenerator[BaseAgentEvent | BaseChatMessage | Response, None]: ...

    @property
    @abstractmethod
    def produced_message_types(self) -> Sequence[type[BaseChatMessage]]: ...

关键认知:v0.4 里 agent 是 stateful 的,但 on_messages 调用语义是 "传入新消息,不是完整历史"。runtime / team 负责把"完整历史"管在外层(ChatHistory 或 GroupChat 的共享上下文),而不是每次都把全量塞回 agent。这是 v0.2 那种 "send 一条消息、自己反复 reply"模式的根本反转。

#1.3 用一个最小 AssistantAgent 解剖

from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient

async def web_search(query: str) -> str:
    """Fake web search."""
    return f"AutoGen is a multi-agent framework. (q={query})"

agent = AssistantAgent(
    name="researcher",
    description="A researcher who can use the web to answer questions.",
    model_client=OpenAIChatCompletionClient(model="gpt-4o-mini"),
    tools=[web_search],
    system_message="Use tools to solve tasks.",
    reflect_on_tool_use=True,    # tool 返回后让 LLM 再总结一遍
    model_client_stream=True,    # 启用流式 token
)

result = await agent.run(task="Search 'AutoGen v0.4'")

run(task=...)BaseChatAgent 自带的便捷封装,本质是:把 task 包成 TextMessage → 调 on_messages → 收集所有产生的消息 → 包成 TaskResult 返回。 run_stream() 则是返回一个异步迭代器,吐出每一条事件 / 消息 / 工具调用,最后再吐 一个 TaskResult

#1.4 终止条件:v0.4 的"你别一直说下去"

v0.2 用 max_consecutive_auto_reply 等参数挂在每个 agent 上;v0.4 把它抽出来, 作为 TerminationCondition 显式传给 Team:

终止条件 触发时机
MaxMessageTermination(n) 全队累计消息数 ≥ n
TextMentionTermination("APPROVE") 任意 agent 发出包含该字符串的消息
TokenUsageTermination(max_tokens) 累计 token 用量到阈值
TimeoutTermination(seconds) 墙钟时间到点
HandoffTermination(target) 出现指向某个 agent 的 HandoffMessage(Swarm 必用)
SourceMatchTermination(name) 指定 agent 发完一条就停
StopMessageTermination() 某个 agent 显式产出 StopMessage
TextMessageTermination() 一旦有 TextMessage 就停(适合 nested team)
FunctionCallTermination(name) 某个具体 tool 被调用并返回
FunctionalTermination(callable) 自定义谓词
ExternalTermination() 进程外手动调 set() 停掉(UI 集成必备)

可以用 | & 组合:

termination = MaxMessageTermination(20) | TextMentionTermination("APPROVE")

"stateful but auto-reset":每个 termination 实例在一次 team.run() 里累积状态, 但 run 结束后会自动 reset,所以同一个 team 可以连续跑多轮任务。

源码位置:python/packages/autogen-agentchat/src/autogen_agentchat/conditions/


#二、Agent 怎么活起来 —— Team.run() 一条链路到底

"在 v0.4 里,'启动一个 agent' 不是 new 一个对象就完事,而是 'Team 帮你把 agent 注册到 runtime,把 termination 挂上,把消息总线接通'。"

#2.1 启动链路全景

我们以最常用的 RoundRobinGroupChat 为例,看从用户调 team.run(task="...") 到第一个 agent 拿到消息的完整链路:

用户调 await team.run(task="...")                       autogen-agentchat
         │
         ▼
 ┌─────────────────────────────────────────────────┐
 │ 1. BaseGroupChat.run()                          │
 │    - 把 task 包装成 TextMessage                  │
 │    - 调用 run_stream() 收集结果                  │
 └────────────────────┬────────────────────────────┘
                      ▼
 ┌─────────────────────────────────────────────────┐
 │ 2. BaseGroupChat._init_runtime() (lazy)         │
 │    - 创建 SingleThreadedAgentRuntime            │
 │    - 把每个参与 agent 包成一个 ChatAgentContainer│
 │    - 注册 GroupChatManager(RoundRobin/Selector)│
 │    - 建立 topic 订阅(agents <-> manager)       │
 └────────────────────┬────────────────────────────┘
                      ▼                              autogen-core
 ┌─────────────────────────────────────────────────┐
 │ 3. runtime.publish_message(GroupChatStart, …)   │
 │    - 走 SingleThreadedAgentRuntime 的消息队列    │
 │    - 派给 GroupChatManager                       │
 └────────────────────┬────────────────────────────┘
                      ▼
 ┌─────────────────────────────────────────────────┐
 │ 4. GroupChatManager.handle_start()              │
 │    - 选第一个 speaker(RoundRobin 拿第 0 个)     │
 │    - publish GroupChatRequestPublish 到该 agent  │
 └────────────────────┬────────────────────────────┘
                      ▼
 ┌─────────────────────────────────────────────────┐
 │ 5. ChatAgentContainer.handle_request_publish() │
 │    - 取出共享 message thread                    │
 │    - 调 BaseChatAgent.on_messages_stream(thread) │
 │    - 把每条产生的 message 推回 manager          │
 └────────────────────┬────────────────────────────┘
                      ▼
 ┌─────────────────────────────────────────────────┐
 │ 6. GroupChatManager.handle_message_publish()    │
 │    - append 到共享 thread                       │
 │    - 调 termination_condition(messages)         │
 │    - 没终止就选下一个 speaker,回到第 4 步       │
 │    - 终止就 publish GroupChatTermination         │
 └─────────────────────────────────────────────────┘

看清楚 actor 模型在哪: Team 不是直接调 agent 的方法,而是通过 AgentRuntime.publish_message() 推到 topic,runtime 再 dispatch 给订阅了这个 topic 的 ChatAgentContainer。所有 agent 之间的"对话"都是异步消息,没有任何 同步调用栈。

#2.2 SingleThreadedAgentRuntime:单进程 actor 调度器

┌─────────────────────────────────────────────────────────┐
│              SingleThreadedAgentRuntime                  │
├─────────────────────────────────────────────────────────┤
│   ┌──────────────────────────────────────────────────┐  │
│   │  message_queue : asyncio.Queue[Envelope]         │  │
│   └──────────────────────────────────────────────────┘  │
│   ┌──────────────────────────────────────────────────┐  │
│   │  subscriptions : List[Subscription]              │  │
│   │      TypeSubscription("default", "agent_id")     │  │
│   │      TypePrefixSubscription(...)                 │  │
│   └──────────────────────────────────────────────────┘  │
│   ┌──────────────────────────────────────────────────┐  │
│   │  agent_factories : Dict[type, factory]           │  │
│   │      lazy 创建 agent 实例                         │  │
│   └──────────────────────────────────────────────────┘  │
│                                                          │
│   主循环:                                               │
│     while not stopped:                                   │
│       envelope = await queue.get()                       │
│       targets = [s.matched(envelope.topic)              │
│                  for s in subscriptions]                 │
│       for tgt in targets:                                │
│         agent = await get_or_create(tgt)                 │
│         await agent.on_message(envelope.payload, ctx)    │
└─────────────────────────────────────────────────────────┘

源码位置: python/packages/autogen-core/src/autogen_core/_single_threaded_agent_runtime.py

#2.3 跨进程:GrpcWorkerAgentRuntime

把同一份代码改个 runtime 类,就能让 agent 跑在不同的机器/进程:

┌─────────────────────────────────────────────┐
│  Host (GrpcWorkerAgentRuntimeHost)          │
│  ─ 维护到所有 worker 的连接                  │
│  ─ 路由消息(按 subscription)               │
│  ─ 维护 RPC session(direct messaging)      │
└─────────┬───────────────┬───────────────────┘
          │ gRPC bidi      │ gRPC bidi
          │ stream         │ stream
          ▼                ▼
┌────────────────┐  ┌────────────────┐
│ Worker A       │  │ Worker B       │
│ (Python)       │  │ (.NET)         │
│ - WebSurfer    │  │ - Coder        │
│ - FileSurfer   │  │ - Terminal     │
└────────────────┘  └────────────────┘

关键约束:跨语言时所有消息类型必须共享 protobuf schema(在 autogen-coreagent_worker.proto / cloudevent.proto 基础上扩展)。

源码位置:python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/

#2.4 v0.2 的对比:为什么要这么改

v0.2:                                v0.4:
                                     
user_proxy.send(                     team = RoundRobinGroupChat([...])
    msg, recipient=assistant)        await team.run(task=...)
       │                                │
       ▼ 同步 call                       ▼ 异步 publish
assistant.generate_reply()           runtime.publish_message()
       │                                │
       ▼ 内部循环 reply                  ▼ runtime dispatch 到所有订阅者
assistant.send(reply,                manager.handle() → 选下一个
    recipient=user_proxy)            agent → publish_message → ...

差别一句话:v0.2 是"agent 之间互相调函数",v0.4 是"agent 之间互相发消息,runtime 负责送达"。前者天然单线程,后者天然事件驱动、可扩展、可观测。


#三、Agent 怎么思考 —— GroupChat 五种 selector 的取舍

"AutoGen 的 'agent 怎么思考' 问题,其实分成两层:单 agent 内部就是普通 ReAct(LLM 看 system + history,决定 reply 还是 call tool);多 agent 之间则是 'Team 怎么 决定下一个发言者',这是 GroupChat 的核心。"

单 agent 的内循环(AssistantAgent):

on_messages(new_messages):
    1. memory.update_context(model_context)        # 把 memory 塞进上下文
    2. model_context.add_messages(new_messages)
    3. model_client.create(messages, tools=...)
       ├─ 返回纯 text       → 包成 TextMessage 返回
       └─ 返回 tool_calls   → 并发执行 → ToolCallExecutionEvent
                            → reflect_on_tool_use? → 再来一轮 model_client.create
                            → 否则把 tool result 包成 ToolCallSummaryMessage 返回

这没什么特别,就是标准 OpenAI tools 协议的封装。真正有意思的是 Team 层的五种 speaker selection 策略。

#3.1 五种 Team 模式总览

Team 类 选下一个发言者的方式 适合场景
RoundRobinGroupChat 按定义顺序轮转 角色固定、流程线性(write → review → revise)
SelectorGroupChat 用一个 LLM 看历史 + 每个 agent 的 description,挑下一个 角色多、需要"看情况派人"
Swarm 当前 agent 显式发 HandoffMessage 指定下家 复杂工作流,agent 自己懂得"该把球传给谁"
GraphFlow 按预定义 DAG(DiGraph)走,支持条件、并行、循环 工程化场景,要确定性和可重放
MagenticOneGroupChat 由专门的 Orchestrator agent 负责 plan + 选人 + 重新规划 通用任务("帮我查 X 然后写报告")

#3.2 RoundRobinGroupChat:最简单也最常用

team = RoundRobinGroupChat(
    [primary_agent, critic_agent],
    termination_condition=TextMentionTermination("APPROVE"),
)
result = await team.run(task="Write a short poem about fall.")

行为:primary 写 → critic 评 → primary 改 → critic 评 → ... → critic 说 APPROVE → 停。 所有 agent 看同一份 message thread,所以 critic 能看到 primary 写的全文。

#3.3 SelectorGroupChat:让 LLM 当工头

team = SelectorGroupChat(
    participants=[planning_agent, web_search_agent, data_analyst],
    model_client=model_client,
    selector_prompt="""You are a coordinator. Read the conversation
        and pick which agent should speak next from {participants}.
        Each agent's role is described as: {roles}.
        Only pick one.""",
    allow_repeated_speaker=False,
    termination_condition=...,
)

工作机制:每收到一条消息,selector 把 history + agent description 送给 LLM,让它 返回一个 agent name;然后 publish 给那个 agent。这就是 v0.2 的 GroupChatManager prompt-based selection 的"显式版":v0.2 是在 manager 内部偷偷干这件事,v0.4 把 selector 单独抽出来,prompt、model、是否允许连发都可配置。

#3.4 Swarm:agent 自己决定下一个谁来

灵感来自 OpenAI 的 Swarm 项目。每个 agent 在 system message 里被告知 "你可以 handoff 给 [agent A, agent B]",模型生成 HandoffMessage(target="A") 后,team 直接 把控制权转给 A:

travel_agent = AssistantAgent(
    name="travel",
    handoffs=["flights", "hotels", "user"],     # 它知道可以传给谁
    system_message="...",
)

team = Swarm(
    [travel_agent, flights_agent, hotels_agent],
    termination_condition=HandoffTermination(target="user"),
)

Swarm + HandoffTermination 是 human-in-the-loop 的标配:agent 把任务做完之后 handoff 给 "user",team 结束,外层应用收集用户输入,再调一次 team.run() 续上。

#3.5 GraphFlow:工程派的最爱

把团队画成一个有向图,节点是 agent,边带条件:

from autogen_agentchat.teams import DiGraphBuilder, GraphFlow

builder = DiGraphBuilder()
builder.add_node(researcher).add_node(writer).add_node(reviewer)
builder.add_edge(researcher, writer)
builder.add_edge(writer, reviewer)
# 条件边走 add_edge(condition=...),条件可以是字符串("REVISE" in message)或 callable
builder.add_edge(reviewer, writer, condition=lambda m: "REVISE" in m.to_model_text())
# 没有显式 END 节点——流程在叶节点跑完后自动停止(由内置 DiGraphStopAgent 发 StopMessage)

team = GraphFlow(
    participants=builder.get_participants(),
    graph=builder.build(),
)

跟 LangGraph 思路高度重合 —— 这其实是 AutoGen 在"GroupChat 太自由不可控"和 "LangGraph 太强约束不灵活"之间找的折中。支持 sequential / parallel / conditional / loop 四种基本结构。

#3.6 MagenticOneGroupChat:开箱即用的"通用 agent 团队"

from autogen_agentchat.teams import MagenticOneGroupChat
from autogen_ext.agents.web_surfer import MultimodalWebSurfer
from autogen_ext.agents.file_surfer import FileSurfer
from autogen_ext.agents.magentic_one import MagenticOneCoderAgent
from autogen_agentchat.agents import CodeExecutorAgent
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor

team = MagenticOneGroupChat(
    participants=[
        MultimodalWebSurfer("WebSurfer", model_client=mc),
        FileSurfer("FileSurfer", model_client=mc),
        MagenticOneCoderAgent("Coder", model_client=mc),
        CodeExecutorAgent("Terminal", code_executor=DockerCommandLineCodeExecutor()),
    ],
    model_client=orchestrator_model_client,    # 单独给 orchestrator 一个强模型
)
result = await team.run(task="Find the latest AutoGen release notes and summarize.")

内部机制(来自论文):

                    ┌────────────────────────┐
                    │   Magentic Orchestrator │
                    │   ─ Task Ledger         │
                    │   ─ Progress Ledger     │
                    │   ─ outer / inner loop  │
                    └─┬──────────────────────┘
                      │
                      │ 选 agent + 给指令
            ┌─────────┼──────────┬─────────┬──────────┐
            ▼         ▼          ▼         ▼          ▼
      ┌─────────┐┌─────────┐┌─────────┐┌─────────┐
      │WebSurfer││FileSurfer││ Coder   ││Computer │
      │浏览器   ││ 本地文件 ││ 写代码  ││Terminal │
      └─────────┘└─────────┘└─────────┘└─────────┘
  • Task Ledger:开局 orchestrator 让 LLM 列出 facts、guesses、subtasks,写到 ledger。
  • Progress Ledger:每轮 agent 发完话,orchestrator 让 LLM 更新这个 ledger,回答四个问题:
    1. 任务完成了吗?2. 在原地打转吗?3. 下一步该谁?4. 下一步具体说啥?
  • Outer / Inner Loop:inner loop 是不停选 agent 推进任务;inner loop 卡住或重复 N 次 没进展时,跳到 outer loop 重新规划 task ledger。

MagenticOne 是 AutoGen 给 v0.4 写的 "招牌应用" —— 它本质上就是"一个 SelectorGroupChat

  • 一个特别精致的 selector prompt(含 ledger 维护)"。生产场景也可以拿这个模式自己写 orchestrator,不一定要用现成的 MagenticOneGroupChat。

源码位置:

  • python/packages/autogen-ext/src/autogen_ext/teams/magentic_one/
  • python/packages/autogen-ext/src/autogen_ext/agents/web_surfer/
  • python/packages/autogen-ext/src/autogen_ext/agents/file_surfer/

#四、Agent 怎么行动 —— Tool calling + Code executor + 跨 agent 委托

"AutoGen 把 'agent 怎么动手' 拆成三个独立机制:tool calling 走 OpenAI 协议、code execution 单独抽象成 CodeExecutor 接口、agent 之间委托走 handoff/SocietyOfMind。 三件事互不绑死,可以自由组合。"

#4.1 Tool calling:OpenAI 协议 + reflect_on_tool_use

AutoGen 的 tool 抽象兼容 OpenAI tools 格式。三种注册方式:

# (a) 直接传 Python 函数,AutoGen 自动从 type hints + docstring 生成 schema
async def web_search(query: str) -> str:
    """Search the web."""
    ...
agent = AssistantAgent(..., tools=[web_search])

# (b) 传 FunctionTool 显式声明
from autogen_core.tools import FunctionTool
tool = FunctionTool(web_search, description="Search the web", strict=True)

# (c) 自己继承 BaseTool,自定义 schema 和 run() 行为
class MyTool(BaseTool[Args, Result]): ...

核心循环(在 AssistantAgent.on_messages 里):

LLM.create(messages, tools=tool_schemas)
   │
   ├─ no tool_calls → 返回 TextMessage,结束
   └─ has tool_calls → asyncio.gather(*[tool.run(args) for ...])
        │            (注意:默认并发执行所有 tool)
        ▼
        ToolCallExecutionEvent (流式吐给上层)
        │
        ├─ reflect_on_tool_use=False (默认)
        │     → 把 tool 结果直接拼成 ToolCallSummaryMessage 返回
        │
        └─ reflect_on_tool_use=True
              → 把 tool 结果加进 model_context,再调一次 LLM.create
              → 让模型"看完结果再发话"

reflect_on_tool_use 是个性能/成本权衡:开了多花一次 LLM 调用,但模型能基于 结果做总结/纠正;不开就直接把 tool 输出塞回去,适合 tool 已经返回结构化文本的情况。

#4.2 Code executor:四种 backend,统一接口

CodeExecutor 接口在 autogen-core 里:

class CodeExecutor(ABC):
    @abstractmethod
    async def execute_code_blocks(
        self, code_blocks: list[CodeBlock], cancellation_token
    ) -> CodeResult: ...

四个实现(在 autogen-ext 里):

实现 隔离强度 stateful? 适合
LocalCommandLineCodeExecutor 无(直接跑在主机) 否(每块写到独立文件) 开发期、信任的 agent
DockerCommandLineCodeExecutor Docker 容器 默认推荐,生产环境基础隔离
JupyterCodeExecutor Jupyter kernel 是(变量保持) ML 迭代式建模
ACADynamicSessionsCodeExecutor (Azure Container Apps) 完全云端、按 session 隔离 多租户托管、企业合规

绑定方式有两种:

# 方式 1:作为独立 agent
code_agent = CodeExecutorAgent(
    name="executor",
    code_executor=DockerCommandLineCodeExecutor(work_dir="/tmp/coding"),
)
team = RoundRobinGroupChat([coder_agent, code_agent], ...)

# 方式 2:作为 AssistantAgent 的一个 tool(通过 PythonCodeExecutionTool)
agent = AssistantAgent(
    name="coder",
    tools=[PythonCodeExecutionTool(executor=DockerCommandLineCodeExecutor())],
    ...
)

历史包袱提醒:v0.2 里的 UserProxyAgent 自带 code_execution_config,它实际 就是一个 ConversableAgent + 一个 code executor 的合体。v0.4 把这两件事彻底解耦, UserProxyAgent 退化成只负责"接收用户输入",代码执行单独由 CodeExecutorAgent 干。 迁移 v0.2 项目时这是最容易踩坑的地方。

#4.3 跨 agent 委托:handoff vs SocietyOfMind

两种"agent 喊另一个 agent 来干活"的玩法:

机制 控制权转移 谁能看到中间过程
Swarm + HandoffMessage 显式转移:A handoff 给 B,B 接管对话 整个 team 共享 thread,所有 agent 看得见
SocietyOfMindAgent A 内部跑一个 inner team,最后只把"团队结论"返回给外层 外层只看到结论,inner thread 被封装

SocietyOfMind 的典型用法:把"研究 + 写作 + 审稿"的 3-agent 团队封装成一个对外的 "内容生产 agent",再放进更高层的 Team 里:

inner_team = RoundRobinGroupChat([writer, critic], termination_condition=...)
content_agent = SocietyOfMindAgent(
    name="content_producer",
    team=inner_team,
    model_client=summarizer_client,    # 用来把 inner thread 总结成对外回复
)

outer_team = SelectorGroupChat([planner, content_agent, deployer], ...)

SocietyOfMind 在最后一步会调一次 model_client,让它把 inner team 的最后几条消息 压缩成一条对外的 reply —— 这就是它名字的由来(多个 agent 的 "mind" 合成一个对外 人格)。


#五、Agent 怎么记忆 —— message thread + Memory 协议

"AutoGen 的记忆是分层的:短期靠 message thread(GroupChat 共享),中期靠 ChatCompletionContext 的窗口策略,长期靠 Memory 协议外挂。三层之间的衔接点 都在 update_context。"

#5.1 三层记忆模型

┌──────────────────────────────────────────────────────────┐
│ L3: Memory(长期,外挂)                                  │
│   - ListMemory / ChromaDBVectorMemory / RedisMemory ...   │
│   - 实现 Memory protocol:add / query / update_context     │
└────────────────────────┬─────────────────────────────────┘
                         │ update_context 时把相关记忆 push
                         ▼
┌──────────────────────────────────────────────────────────┐
│ L2: ChatCompletionContext(窗口策略)                     │
│   - UnboundedChatCompletionContext                        │
│   - BufferedChatCompletionContext(buffer_size=N)          │
│   - HeadAndTailChatCompletionContext(head=k, tail=m)      │
│   - TokenLimitedChatCompletionContext(max_tokens=...)     │
└────────────────────────┬─────────────────────────────────┘
                         │ on_messages 时拼装上下文
                         ▼
┌──────────────────────────────────────────────────────────┐
│ L1: Message thread(短期,团队共享)                       │
│   - GroupChat 维护一个 messages: List[BaseChatMessage]    │
│   - 每个 agent 看到的是 thread 的快照                      │
└──────────────────────────────────────────────────────────┘

#5.2 Memory 协议:插件式长期记忆

class Memory(ABC):
    @abstractmethod
    async def add(self, content: MemoryContent, ...) -> None: ...
    @abstractmethod
    async def query(self, query: str | MemoryContent, ...) -> MemoryQueryResult: ...
    @abstractmethod
    async def update_context(self, model_context: ChatCompletionContext) -> UpdateContextResult: ...
    @abstractmethod
    async def clear(self) -> None: ...
    @abstractmethod
    async def close(self) -> None: ...

update_context 是关键:每次 agent 推理前,它把 model_context 拿出来,根据当前 最后一条消息查相关记忆,再把命中的记忆作为一条 SystemMessage append 进去。

两个内置实现:

# (a) ListMemory:按时间顺序保留全部,update_context 时全塞进去
mem = ListMemory()
await mem.add(MemoryContent(content="User likes concise answers", mime_type="text/plain"))

# (b) ChromaDBVectorMemory:向量检索 top-k
mem = ChromaDBVectorMemory(
    config=PersistentChromaDBVectorMemoryConfig(
        collection_name="user_prefs",
        persistence_path="/tmp/chroma",
        k=3,
        score_threshold=0.4,
    )
)

agent = AssistantAgent(..., memory=[mem])

源码位置:

  • python/packages/autogen-core/src/autogen_core/memory/
  • python/packages/autogen-ext/src/autogen_ext/memory/chromadb/

#5.3 GraphRAG / RAG 不在框架里

跟 LangChain 那种"内置 RAG chain"不一样,AutoGen 把 RAG 推到外面 —— 你自己拿 向量库查文档,写到 memory 或当 tool 暴露给 agent。框架不假设你的检索栈。

#5.4 状态保存与恢复(v0.4 新功能)

v0.4 显式支持把整个 team 的状态序列化下来:

state = await team.save_state()       # 返回 dict,可 json.dump
# ... 重启进程 ...
await team.load_state(state)
result = await team.run(task="continue")

state 里包含:每个 agent 的 model_context、memory 状态、GroupChat manager 的 speaker pointer、termination condition 的累积计数。这是 v0.2 完全做不到的(v0.2 的 reply 链是同步函数调用,断了就断了)。


#六、Agent 怎么开口 —— Console / Studio / 流式

"AutoGen 的 'agent 怎么开口' 跟厂商私有平台最大的不同:它不假设你有前端。每个 agent 的输出都是一串 BaseAgentEvent / BaseChatMessage 流,要不要做 UI、做什么 UI 都是上层的事。"

#六种"输出消费方式":

┌──────────────────────────────────────────────────────────┐
│  team.run(task=...)                                       │
│      → 返回 TaskResult(messages 列表 + stop_reason)       │
│      → 适合后台批处理                                       │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│  team.run_stream(task=...)                                │
│      → AsyncGenerator,吐每条消息/事件,最后吐 TaskResult   │
│      → 适合自定义 UI(WebSocket / SSE 转发)                │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│  Console(team.run_stream(...))                            │
│      → 把 stream 转成漂亮的彩色终端输出                      │
│      → 调试和 demo 标配                                     │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│  AutoGen Studio (Web UI)                                  │
│      → 把 team 配置存成 YAML/JSON,加载后用 UI 跑           │
│      → 实时显示 agent 之间的对话气泡                         │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│  ChainLit / Streamlit / FastAPI 集成                       │
│      → 业内常见做法:把 run_stream 转 SSE / WebSocket       │
└──────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────┐
│  OpenTelemetry Trace                                      │
│      → 每个 agent 调用 / tool 调用都可以打 span             │
│      → 接到 Jaeger / Zipkin / Tempo                        │
└──────────────────────────────────────────────────────────┘

#6.1 Console:debug 必备

from autogen_agentchat.ui import Console
await Console(team.run_stream(task="..."))

它会按事件类型上色:

  • TextMessage 显示作者 + 内容
  • ToolCallRequestEvent 显示要调的 tool 名 + 参数(黄色)
  • ToolCallExecutionEvent 显示返回结果(绿色)
  • ThoughtEvent (reasoning model 的思考过程)斜体灰色

#6.2 流式 token:model_client_stream=True

默认 AssistantAgent 是 "等 LLM 全部生成完再吐 TextMessage"。打开 model_client_stream=True 后,run_stream 里会先吐一连串 ModelClientStreamingChunkEvent (每个 token 一个事件),最后才是完整的 TextMessage。前端可以照着 OpenAI SSE 协议 转出去。

#6.3 AutoGen Studio:no-code 拖拽 + 实时调试

它本身是一个 FastAPI + React 的 web app,跟 v0.4 同构:

AutoGen Studio
├── 左侧 Component Library
│      Agent / Tool / Model / Termination / Memory(可拖)
├── 中间 Team Builder
│      把组件拖进来,连线,配置参数
├── 右侧 Run Panel
│      跑 team,看实时消息流
└── 底层
      把 UI 配置序列化成 component config(YAML/JSON)
      加载时反序列化成真正的 BaseChatAgent / Team 实例

Studio 的核心抽象是 component_config —— 每个 AutoGen 组件都实现 ComponentBase,能 dump 成 dict,也能从 dict 重建。这套序列化机制是 v0.4 才有的 (v0.2 的 agent 不可序列化),是 Studio 能存在的前提。

源码位置:python/packages/autogen-studio/

生产警告:Studio 官方文档明确说"It is not meant to be a production-ready app"。 它是给 PM 和研究员快速 prototype 的工具,正经线上服务还是得自己写 backend。


#七、Agent 的外脑 —— ChatCompletionClient 抽象

"v0.4 把 LLM 抽象成 ChatCompletionClient 接口,所有 agent 只跟这个接口对话; 接哪家模型就在 autogen-ext 里挑一个 client 实现。"

#7.1 ChatCompletionClient 接口

class ChatCompletionClient(ABC):
    @abstractmethod
    async def create(
        self,
        messages: Sequence[LLMMessage],
        *,
        tools: Sequence[Tool | ToolSchema] = [],
        json_output: Optional[bool] = None,
        extra_create_args: Mapping[str, Any] = {},
        cancellation_token: Optional[CancellationToken] = None,
    ) -> CreateResult: ...

    @abstractmethod
    def create_stream(...) -> AsyncGenerator[str | CreateResult, None]: ...

    @abstractmethod
    def actual_usage(self) -> RequestUsage: ...

    @abstractmethod
    def total_usage(self) -> RequestUsage: ...

    @abstractmethod
    def model_info(self) -> ModelInfo: ...

model_info 报告"我支不支持 vision、function calling、json_output、structured_output、 是不是 reasoning model",agent 在调用时会按需 degrade。

#7.2 内置实现矩阵

Client 包路径 支持模型
OpenAIChatCompletionClient autogen_ext.models.openai GPT-4o / GPT-5 / 兼容 OpenAI 协议的模型
AzureOpenAIChatCompletionClient autogen_ext.models.openai Azure OpenAI 部署
AnthropicChatCompletionClient autogen_ext.models.anthropic Claude 3.x / 4.x
OllamaChatCompletionClient autogen_ext.models.ollama 本地 Ollama
AzureAIChatCompletionClient autogen_ext.models.azure Azure AI Foundry
SemanticKernelChatCompletionAdapter autogen_ext.models.semantic_kernel 任意 SK connector
ChatCompletionCache autogen_ext.models.cache 给任意上面的 client 加一层缓存

小细节:v0.2 里默认开 cache(use_cache=True),v0.4 默认关。要想缓存得 显式 ChatCompletionCache(inner=OpenAIChatCompletionClient(...), store=...) 包一层。这是 v0.2 → v0.4 迁移最容易忘的成本变化点。

#7.3 Tool 协议的对齐方式

每家 LLM 的 tool calling 格式各不相同(OpenAI / Anthropic / Gemini / DeepSeek 都 有差异),AutoGen 的策略是:

agent 这边只看 ToolSchema(中性表示)
       │
       ▼
client 实现负责把 ToolSchema 翻译成本家协议
       │
       ▼  调 LLM
       │
       ▼  
client 把本家返回的 tool_calls 翻译回中性的 FunctionCall 列表

所以写 agent 代码完全不用关心后端是哪家模型,client 把这事吸收了。但反过来: 如果你换 client,又用了某家独有的高级特性(比如 Anthropic 的 cache_control),就 得通过 extra_create_args 透传。

#7.4 Reasoning model 的特殊处理

OpenAI o1 / o3、DeepSeek-R1 这类 reasoning model 会输出 <think>...</think> 段或者通过额外字段返回 thinking tokens。v0.4 把这个抽象成 ThoughtEvent

  • agent 收到 thinking tokens → 包成 ThoughtEvent 流式吐出
  • 完整 thinking 内容不会默认进 model_context 的下一轮(避免污染)
  • UI 端可以选择性显示 thought(Console 默认显示,灰色斜体)

#八、关键设计权衡(架构师视角)

看完前 7 章会有一种"AutoGen 怎么什么都包了"的错觉。其实每个设计都是一次取舍。 以下挑 6 个最关键的,问题 / 回答 / 启发 三段式记下来。

#8.1 Actor model vs ReAct 单进程循环

问题:单 agent 的 ReAct 循环(思考 → 调 tool → 看结果 → 再思考)很经典也很 直觉,为什么 v0.4 一定要把它套上一层 actor model?

回答:单 agent ReAct 在工程上有三个软肋:(1) 不可拆分到多进程;(2) 不可观测, 所有思考步骤都埋在一个函数调用栈里;(3) 不可暂停 / 恢复。actor model 解决全部 三个:每个 agent 是独立 actor,消息是显式 envelope,可以 trace、可以序列化、可以 跨进程。

启发:你自己写 agent 框架的时候,不要从"我有一个 ReAct 循环"开始,而要从 "我有一个消息总线 + 若干消费者"开始。前者是 demo,后者是基础设施。


#8.2 五种 GroupChat selector 为什么要并存?

问题:RoundRobin / Selector / Swarm / Graph / Magentic,从外面看好像可以 互相模拟(比如 Selector 可以模拟 RoundRobin)。为什么不收敛成一种?

回答:因为它们对应了不同的"工程上你愿意付出的代价"

模式 你给的约束 你换来的好处
RoundRobin 你保证流程线性 零额外 LLM 调用,可重放
Selector 你写好 selector_prompt 灵活但每轮多花一次 LLM
Swarm 你训练/提示 agent 知道 handoff 完全去中心化,无需 manager
Graph 你画好 DAG 工程化 / 确定性
Magentic 你接受一个重型 orchestrator 通用任务,开箱即用

收敛成一种意味着要么强制大家用最弱约束(成本爆炸),要么强制最强约束(不灵活)。 留多种是务实的工程选择。

启发:选 selector 时先问自己一个问题 —— 这个流程的"对错"是先验已知的,还是 需要 runtime 看情况判断的?前者用 RoundRobin / Graph,后者才用 Selector / Magentic。


#8.3 v0.2 → v0.4 迁移最大的一个坑

问题:迁移 v0.2 项目到 v0.4,最容易忽视的破坏性变化是什么?

回答UserProxyAgent 的角色塌缩。在 v0.2 里 UserProxyAgent 是个"瑞士军刀": 它既负责接收用户输入,又持有 code_execution_config 来执行代码,还经常被当作 "function executor"接收别的 agent 的 tool call。三件事都干。v0.4 把它拆成三个东西:

v0.2 UserProxyAgent  =  v0.4 UserProxyAgent (只接收用户输入)
                      + v0.4 CodeExecutorAgent (跑代码)
                      + tools 直接挂在 AssistantAgent 上 (不需要"function executor")

迁移的时候如果只机械替换类名,会发现 "我的 user_proxy 不会跑代码了"、"我的 function 没人执行了"。

启发:迁移老项目时先把 v0.2 用法分类:哪些 UserProxy 是真"代理用户输入", 哪些是"假装用户的代码执行器",哪些是"function 路由器"。三类对应 v0.4 三个不同 组件。


#8.4 Memory 内置实现为什么这么少?

问题:v0.4 内置的 Memory 实现只有 ListMemory + ChromaDBVectorMemory + RedisMemory 寥寥几个,对比 LangChain 的几十个 vectorstore,是不是太弱了?

回答:AutoGen 的设计哲学是"框架不替你做选型"。Memory 是个 protocol,你接什么 向量库都行;如果接得太多反而会绑住框架版本。LangChain 那种"我帮你接好 50 家"的 风格短期看方便,长期看依赖地狱。

启发:评估 multi-agent 框架时不要只看"内置了多少 connector",要看 "我自己 要接一个新 connector 难不难"。AutoGen 的 Memory protocol 实现起来三十行代码就 能搞定,这才是关键指标。


#8.5 SocietyOfMindAgent vs 嵌套 Team:什么时候选哪个?

问题:v0.4 里"团队封装成 agent"有两条路:用 SocietyOfMindAgent 包一个 Team, 或者直接把外层 Team 的某个 agent 实现成"内部跑 sub team"的自定义 agent。两者 等价吗?

回答:不等价。区别在 "内层消息能否被外层消费者看到"

  • SocietyOfMindAgent:内层 thread 完全封装,外层只看到 model_client 总结的一条 对外消息。适合"实现细节不应暴露"的场景(比如把"内容生产团队"作为黑盒卖给 外部 orchestrator)。
  • 自定义嵌套 agent:你可以选择把内层每条消息直接转发到外层 stream(绕过 society of mind 的总结环节)。适合"调试期希望看到全过程"或"外层 selector 要根据内 层细节决策"的场景

启发:抽象层次不是越深越好。每多一层抽象就意味着 (1) 多一次 LLM 总结的成本和 信息损失,(2) 调试时多一层栈。SocietyOfMind 是"信息隐藏的工程化封装",不是"包就 对了"。


#8.6 跟 LangGraph / CrewAI 比,AutoGen 的位置

问题:选 multi-agent 框架时,AutoGen / LangGraph / CrewAI 怎么挑?

回答:一句话总结三家的核心隐喻:

框架 核心隐喻 最适合的场景
CrewAI "公司里的角色分工"(CEO / 经理 / 员工 / 任务) 角色清晰、流程线性的业务工作流,最低学习成本
LangGraph "状态机 / DAG"(节点 + 边 + 共享 state) 工程化、可重放、需要 checkpoint / human-in-the-loop
AutoGen "一群人开会聊天"(actor + message + group chat) 需要灵活协作、研究型多 agent、跨进程跨语言

成本上:AutoGen 因为 GroupChat 模式天然多轮对话,token 花费比 LangGraph 高 (社区数据 5-6 倍量级),但灵活性也是最高的。

启发:如果你的"多 agent"需求其实是"一个 agent + 几个 tool",先别上 AutoGen 这种 框架,直接 OpenAI SDK + tools 就够了。multi-agent 框架要解决的问题,是当你确信 "单 agent 不够"之后才出现的


#九、附录:包地图、关键概念与源码索引

#9.1 packages 地图(microsoft/autogen 仓库)

microsoft/autogen/
├── python/
│   └── packages/
│       ├── autogen-core/                  # ★ actor runtime 底座
│       │   src/autogen_core/
│       │     _agent.py                    # Agent 抽象
│       │     _agent_runtime.py            # AgentRuntime 接口
│       │     _routed_agent.py             # @message_handler 装饰器
│       │     _single_threaded_agent_runtime.py
│       │     _topic.py                    # TopicId / Subscription
│       │     memory/                       # Memory protocol
│       │     models/                       # ChatCompletionClient 接口
│       │     tools/                        # Tool 抽象
│       │
│       ├── autogen-agentchat/             # ★ 高级 Agent + Team
│       │   src/autogen_agentchat/
│       │     agents/                       # AssistantAgent / UserProxyAgent /
│       │                                   #   CodeExecutorAgent / SocietyOfMindAgent /
│       │                                   #   MessageFilterAgent
│       │     teams/                        # RoundRobinGroupChat / SelectorGroupChat /
│       │                                   #   Swarm / GraphFlow (含 DiGraphBuilder) /
│       │                                   #   MagenticOneGroupChat
│       │     conditions/                   # 各种 termination
│       │     messages.py                   # TextMessage / HandoffMessage / ...
│       │     ui/                           # Console
│       │
│       ├── autogen-ext/                   # ★ 扩展生态
│       │   src/autogen_ext/
│       │     models/openai/                # OpenAIChatCompletionClient
│       │     models/anthropic/             # AnthropicChatCompletionClient
│       │     models/ollama/                # 本地 Ollama
│       │     code_executors/docker/        # DockerCommandLineCodeExecutor
│       │     code_executors/jupyter/       # JupyterCodeExecutor
│       │     code_executors/azure/         # ACA Dynamic Sessions
│       │     memory/chromadb/              # ChromaDB 向量记忆
│       │     memory/redis/                 # Redis 向量记忆
│       │     agents/web_surfer/            # MultimodalWebSurfer
│       │     agents/file_surfer/           # FileSurfer
│       │     agents/magentic_one/          # MagenticOneCoderAgent
│       │     teams/magentic_one/           # MagenticOne 辅助类(编排封装)
│       │                                   # ※ MagenticOneGroupChat 本体住在
│       │                                   #    autogen_agentchat.teams
│       │     runtimes/grpc/                # 分布式 runtime
│       │     auth/                         # azure / 其它认证
│       │
│       ├── autogen-studio/                 # no-code UI(FastAPI + React)
│       │   frontend/
│       │   autogenstudio/
│       │
│       ├── autogen-magentic-one/           # 早期 Magentic 单包(已并入 autogen-ext)
│       ├── magentic-one-cli/               # `m1` 命令行
│       ├── agbench/                        # benchmarking
│       ├── autogen-test-utils/             # 测试工具
│       ├── component-schema-gen/           # component schema 生成
│       └── pyautogen/                      # legacy v0.2 兼容包
│
└── dotnet/                                  # .NET 实现(cross-language 关键)
    └── src/
        └── Microsoft.AutoGen/
            Core/                            # autogen-core 的 .NET 版
            AgentChat/                       # autogen-agentchat 的 .NET 版
            Extensions/                      # 扩展

#9.2 关键概念速查

概念 一句话定义 出现章节
Agent 实现了 on_messages 的 actor,名字 + 描述 + 行为
AgentRuntime 负责 agent 注册、消息路由、生命周期的运行时
AssistantAgent "kitchen sink" agent,LLM + tools + memory
UserProxyAgent v0.4 简化版,只负责接收用户输入 一、八
CodeExecutorAgent 把 LLM 生成的代码块送进 executor 跑的 agent
SocietyOfMindAgent 包一个 Team 对外暴露成单 agent,封装内层细节 四、八
GroupChat 共享 message thread 的多 agent 团队
GroupChatManager 决定 GroupChat 下一个 speaker 是谁的内部 actor 二、三
RoutedAgent autogen-core 里带 @message_handler 路由的 agent 基类
TopicId / Subscription 消息总线的 pub-sub 抽象
HandoffMessage Swarm 模式里 agent 显式转移控制权的消息类型
TerminationCondition 决定 team.run() 何时停的条件,可组合
CodeExecutor 代码执行抽象,Local / Docker / Jupyter / ACA 四种实现
Memory 长期记忆 protocol(add / query / update_context)
ChatCompletionContext 模型上下文窗口策略(unbounded / buffered / token-limited)
ChatCompletionClient LLM 客户端接口,所有模型对接的统一抽象
ComponentBase 让组件能 dump 成 dict / 从 dict 重建的 mixin(Studio 基础)
Magentic Orchestrator Magentic-One 的领导 agent,维护 Task / Progress Ledger

#9.3 跟其它框架的术语映射

AutoGen v0.4 LangGraph CrewAI OpenAI Swarm
AssistantAgent Node (LLM with tools) Agent Agent
Team / GroupChat Graph Crew Swarm
RoundRobinGroupChat Sequential Graph Sequential Process
SelectorGroupChat Conditional Graph Hierarchical Process
Swarm Conditional Graph + handoff Swarm (本体)
GraphFlow Graph (本体)
TerminationCondition END node + condition
Memory Checkpointer + memory store Knowledge
AutoGen Studio LangGraph Studio CrewAI UI

#9.4 跟 v0.2 的关键差异速查

主题 v0.2 v0.4
默认编程模型 同步 send/reply 异步 actor + message
配置模型 llm_config dict model_client 对象
工具注册 register_function(executor=…, caller=…) 直接 AssistantAgent(tools=[...])
GroupChat 编排 GroupChat + GroupChatManager RoundRobin/Selector/Swarm/Graph/Magentic
用户输入 UserProxyAgent (复杂) UserProxyAgent (只输入)
代码执行 UserProxyAgent.code_execution_config CodeExecutorAgent + CodeExecutor 接口
缓存 默认开(DiskCache) 默认关(ChatCompletionCache 包一层)
RAG / Teachability 内置 Teachability 用户自己实现 Memory protocol
状态保存 不支持 save_state / load_state
跨进程 / 跨语言 GrpcWorkerAgentRuntime + .NET
可观测性 print + logger OpenTelemetry tracing + 流式事件

#9.5 一句话总结

AutoGen v0.4 = "把 v0.2 的对话 multi-agent 体验,重写在一个 actor model 底座 上,再补全跨进程 / 跨语言 / 可观测 / 可序列化"。 它的最佳形态是 autogen-agentchat 这一层(90% 用户的入口),底下的 autogen-core 是给少数 需要自己实现 runtime / 跨语言协作的人准备的。Magentic-One 是它在 "通用 agent 团队" 这个 demo 命题上的招牌答案,但你自己用 SelectorGroupChat 也能写出同样 形状的东西。

#9.6 进一步阅读

2026-06-08 复核补充:当前包版本为 autogen-agentchat@0.7.5 / autogen-core@0.7.5, GitHub release 为 python-v0.7.5。旧文中"v0.4 当前主线"应理解为架构代际,不是当前包号。

返回 Agent 资料库