Files
2026-09-22 15:42:25 +08:00

17 KiB
Executable File
Raw Permalink Blame History

阶段三 · 小点 5:AutoGen(微软多智能体框架·进阶)

所属:阶段三 主流 Agent 开发框架 定位:AutoGen 和 CrewAI 完全不同——它不是"派活",而是让多个 Agent 像拉群开会一样互相聊,聊到有人说「完成」为止。它适合研究实验与原型,但有个必须记住的安全雷区:模型生成的代码可能真在你机器上执行。这一讲把核心类和熔断讲透,安全防线单独划重点。

精简大纲

  1. 核心理念:对话式多智能体
  2. 核心类:ConversableAgent / AssistantAgent / UserProxyAgent
  3. 双人组与 GroupChat 群聊
  4. 工程要点:熔断、TERMINATE、沙箱安全
  5. AutoGen 0.4+ 迁移对照:0.2 与 0.4 差异速查

学习内容详情

⚠️ 重要状态提示(2026 年必读):微软已把 AutoGen 与 Semantic Kernel 合并为 Microsoft Agent Framework(MAF),并于 2026 年 4 月发布 1.0;此后 AutoGen / Semantic Kernel 进入维护模式(不再新增特性),官方明确建议新项目转向 MAF。AutoGen 的 0.2 / 0.4 思路(对话式多智能体、代码执行安全、TERMINATE 约定)与 MAF 一脉相承,其底层机制仍值得学习;但做选型、上生产时请优先考虑 MAF。本文保留 AutoGen 教程,用于理解「对话式多智能体」的机理。

版本说明:本文主体对应 AutoGen 0.2.x 经典 API(pip install pyautogen);0.4+ 为全新 async API,写法不同,差异速查见第 5 节「AutoGen 0.4+ 迁移对照」。

1. 核心理念

  • 多个 Agent 像拉群开会一样,靠互相发自然语言消息协作完成任务,直到有人说「完成」。
  • 适合研究实验与原型验证。
graph LR
    A[AssistantAgent: 会说不会做] -->|发代码块/方案| B[UserProxyAgent: 可执行代码]
    B -->|把执行结果发回| A
    A -->|回复 TERMINATE| C[结束]

2. 核心类

  • ConversableAgent: 所有 Agent 的基类,能收消息、能回消息、可配置是否执行代码、是否需人工输入。
  • AssistantAgent: 默认「只会说不会做」的纯 LLM 角色:分析问题、写方案、生成代码,但自己不执行。
  • UserProxyAgent: 代表「人」或「执行环境」:默认可执行 Assistant 发来的代码块,可设定人工介入模式。
human_input_mode 行为 风险
ALWAYS 每次发言都问真人 最低
TERMINATE 仅结束时问(默认半自动) 中
NEVER 全程无人 最高
import autogen

# Assistant: "会写代码但自己不执行" 的纯LLM
assistant = autogen.AssistantAgent(
    name="coder",
    llm_config={"model": "gpt-4o", "api_key": "YOUR_KEY"},
    system_message="你是一个Python专家, 只输出代码块。",  # 角色设定
)

# UserProxy: 代表"人/执行环境", 默认可执行代码
user_proxy = autogen.UserProxyAgent(
    name="executor",
    human_input_mode="TERMINATE",   # 仅结束时才问真人 (半自动)
    code_execution_config={"work_dir": "sandbox"},  # 代码在 sandbox 目录执行
    max_consecutive_auto_reply=10,   # ★ 熔断1: 双聊最大连续自动回复
)

🔬 深度理解 · 对话式多 Agent(ConversableAgent)机制:

  1. 本质:AutoGen 的核心不是"派活 / 流水线",而是让若干 Agent 通过「互相发自然语言消息」推进任务,直到有人发终止信号。对话既是协作过程,也是共享状态本身。
  2. 机制:ConversableAgent 是所有 Agent 的基类,封装了"收消息 → 决定如何回复 → 生成回复"的循环(内部 generate_reply 会依次尝试 LLM / 执行代码 / 询问人工等回复策略)。AssistantAgent 是"只说方案 / 代码但自己不动手"的纯 LLM 角色;UserProxyAgent 代表"人 / 执行环境",可执行代码块并把结果发回——两者靠自然语言一来一回配合。
  3. 为什么重要:对话式范式让"分工"隐含在消息里,适合研究 / 原型与开放式任务;但它把控制权交给模型的叙事,可控性弱、无显式状态机——这正是它与 LangGraph(显式 State + 图编排)的最大分野。
  4. 易错点:以为多个 Agent 各自拥有完整独立状态——其实上下文就是聊天历史;也不清楚"谁自动回谁"由 initiate_chat 建立的一对一聊天关系决定,群聊则多一个管理者在指派说话人。

3. 运行模式

3.1 双人组

# 让 assistant 帮 user_proxy 完成任务
result = user_proxy.initiate_chat(
    assistant,
    message="写一个计算斐波那契数列的 Python 函数",
)
# 期望流程:
#   1. assistant 发代码块
#   2. user_proxy 提取并执行
#   3. 结果发回 → assistant 确认无误
#   4. assistant 回复 TERMINATE → 结束

3.2 GroupChat 群聊(多 Agent 开会)

pm = autogen.AssistantAgent(name="产品经理", llm_config=LLM, system_message="你负责梳理需求")
pg = autogen.AssistantAgent(name="程序员",    llm_config=LLM, system_message="你负责写代码")
qa = autogen.AssistantAgent(name="测试",      llm_config=LLM, system_message="你负责审代码")

group = autogen.GroupChat(
    agents=[pm, pg, qa],
    messages=[],                  # 群聊消息列表, 只会存在内存
    max_round=15,                 # ★ 熔断2: 群聊最大发言轮数(防无限互聊)
)
manager = autogen.GroupChatManager(groupchat=group, llm_config=LLM)
# user_proxy.initiate_chat(manager, message="设计并实现一个登录接口")
graph TD
    M[GroupChatManager 管理员: LLM判断该谁发言] --> A[产品经理]
    M --> B[程序员]
    M --> C[测试]
    A -->> M
    B -->> M
    C -->> M

4. 工程要点(重点)

  1. 两个熔断都要设: max_consecutive_auto_reply(双聊)+ max_round(群聊),否则互聊到天荒地老。
  2. TERMINATE 约定: 写进 system_message——AutoGen 靠这个关键字判断任务结束。

🔬 深度理解 · TERMINATE 与对话终止机制:

  1. 本质:TERMINATE 是一个约定好的字符串关键字,出现在某条回复末尾时 AutoGen 据此判定"任务完成、停止对话",而它本身没有任何"任务完成"的内置判定能力。
  2. 机制:你把它写进 system_message,模型觉得任务完成时以 TERMINATE 结尾回复;管理循环检测到该关键字即终止回复链。若所有参与方都不发 TERMINATE,就只能靠熔断(max_consecutive_auto_reply / max_round)硬性截断。
  3. 为什么重要:它把"何时结束"这个开放问题外包给了模型判断,正因如此不可靠——模型可能过早终止、也可能忘了终止,所以熔断是必须的兜底。
  4. 易错点:以为框架能自动识别"任务完成";或依赖模型恰好按约定回复。TERMINATE 与熔断必须成对设置,缺一个都会出问题——光有约定会死循环,光有熔断会截断正常任务。
  1. ★ 沙箱安全(最重要): use_docker=False 时模型代码直接跑在你机器上!模型生成 os.remove("C:/重要目录") 完全可能。
# 三档安全方案(从最安全到最省事):
# 方案1: 完全禁用代码执行 —— 最安全
user_safe = autogen.UserProxyAgent(
    name="safe",
    code_execution_config=False,        # 不执行任何代码, 模型只输出文本方案
)
# 方案2: Docker 沙箱隔离 —— 推荐生产
user_docker = autogen.UserProxyAgent(
    name="docker",
    code_execution_config={"docker_image": "python:3.12-slim"},  # 代码在容器里跑, 与宿主隔离
)
# 方案3: 云沙箱 E2B —— 远程隔离
# code_execution_config={"executor": "e2b", ...}

🔬 深度理解 · 代码执行安全(UserProxyAgent 三档):

  1. 本质:AutoGen 的威力与风险同源——UserProxyAgent 默认在本地工作目录里执行模型生成的代码,因此模型产出的任意命令都可能真在你的机器上跑。
  2. 机制:code_execution_config 控制执行策略——设为 False 完全禁用(只出文本方案);指定 docker_image 则把代码送进容器 / 隔离环境执行;也可接云沙箱(如 E2B)。human_input_mode 决定是否 / 何时插入人工确认。
  3. 为什么重要:模型生成恶意或意外危险代码的概率非零,且存在 prompt 注入风险——沙箱是"让 Agent 能执行"与"不让它搞坏宿主"之间最关键的安全边界。
  4. 易错点:use_docker=False 且 human_input_mode="NEVER" 时风险最高——模型代码直接、无人确认地跑在宿主机上;以为"沙箱目录"绝对安全(仍可能被系统调用逃逸);Docker 需显式配置,默认不一定可用。
  1. 消息默认只存内存 → 生产自建消息持久化(改 register_reply 钩子存库)。

⏳ 短期可不深究:register_reply 这套"给 Agent 注入自定义回复逻辑"的钩子机制,以及消息持久化改造细节,第一遍只需知道"AutoGen 消息默认只存内存、生产要自建持久化"即可;真要接入存储时再根据你装的 0.2 / 0.4 / MAF 版本对照实现。

  1. 适用边界: 研究原型 / 内部实验最佳;对外生产系统优先 LangGraph(可控性、持久化、审批流齐全)。

5. AutoGen 0.4+ 迁移对照

5.1 背景:0.4 是完全重写

  • AutoGen 0.4(2024 年底起)不是常规升级,而是完全重写:async-first(对话入口全部 async/await)、可组合的小 Agent、基于 autogen_core 的消息路由架构。
  • 社区另维护 AG2 分支(pip install ag2),延续本文所讲的 0.2.x 经典 API——老代码不想迁移,可换 AG2 继续跑。

5.2 对照表(0.2 → 0.4)

概念 0.2.x(本文) 0.4+
包名 pyautogen autogen-agentchat + autogen-ext
模型配置 llm_config=dict(config_list=[...]) 构造 model_client(如 OpenAIChatCompletionClient)传入 AssistantAgent
对话入口 同步 agent.initiate_chat() 异步 await agent.on_messages() / on_messages_stream()(后者返回 async generator,可流式取内部思考)
人工代理 UserProxyAgent(human_input_mode) 人机交互由 runtime 终端与 autogen_ext 中的 UserProxyAgent 承接
群聊 GroupChat + GroupChatManager Team 抽象(RoundRobinGroupChat / SelectorGroupChat 等)+ termination condition

5.3 0.4 最小示例(伪代码)

# 依赖: pip install autogen-agentchat autogen-ext[openai]
import asyncio

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


async def main() -> None:
    # 1) 模型先构造成 client 对象, 而不是塞进 llm_config 字典
    model_client = OpenAIChatCompletionClient(model="gpt-4o")

    agent = AssistantAgent(
        name="coder",
        model_client=model_client,
        system_message="你是一个Python专家, 只输出代码块。",
    )

    # 2) on_messages_stream 返回 async generator, 可流式取内部思考
    stream = agent.on_messages_stream(
        [TextMessage(content="写一个斐波那契函数", source="user")]
    )
    async for msg in stream:
        print(getattr(msg, "content", msg))


asyncio.run(main())   # 脚本入口统一用 asyncio.run 收束; Jupyter 中可直接 await main()

⏳ 短期可不深究:AutoGen 已进入维护模式、官方主推 MAF,0.4 / MAF 的具体异步 API 写法迭代快且社区仍在变迁——这一遍把「对话式多 Agent」的机理与 0.2 安全雷区吃透即可,真要新起项目直接从 MAF 学,不必在 0.4 迁移细节上较劲。

⚠️ 装包前先看包名:0.2.x 教程在网络上大量存在(标志:pip install pyautogen + initiate_chat),搜到的代码先判断版本再照抄。官方迁移指南(0.2 → 0.4):https://microsoft.github.io/autogen/stable/user-guide/agentchat-user-guide/migration-guide.html

⚠️ 新项目选型注意:AutoGen 已进入维护模式,官方推荐的新一代框架是 Microsoft Agent Framework,迁移文档见 https://microsoft.github.io/agent-framework/ 。若要新起项目,建议直接从 MAF 开始。

本节自检

  • 能跑通一次双人组协作并正确设置两个熔断
  • 能说清 AutoGen 代码执行的三档安全方案
  • 能说出 0.2 与 0.4 的三个核心差异

本节配套思考题(快速入门的检验)

  1. 为什么"双聊"和"群聊"各自要设不同的熔断参数?max_consecutive_auto_reply 和 max_round 分别防的是什么?
  2. AutoGen 怎么判断"任务结束了"?TERMINATE 为什么必须写进 system_message?
  3. 如果 use_docker=False 且 human_input_mode="NEVER",会发生什么最坏情况?你会怎么强制避免?
  4. AutoGen 的消息存在哪?为什么生产要自己持久化?它和 LangGraph 的 Checkpointer 对比如何?

本节常见面试题(深度解析)

针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。

面试题 1:AutoGen「对话式多 Agent」与 CrewAI「派活式」在协作模型上有何本质区别?

  • 面试官想考察:是否理解两种多智能体范式的内核差异,而不是只记住"一个是拉群一个是派活"。
  • 专业作答(含深度):
    1. AutoGen:Agent 之间用自然语言消息互相"对话",上下文就是聊天历史,分工与决策都隐含在消息流里;由 ConversableAgent 基类统一封装收发与回复策略。
    2. CrewAI:预声明角色(Agent)、任务(Task)与流程(Process),任务按序 / 分层派发,context 显式注入依赖,更像一条可预期的流水线。
    3. 关键差异:AutoGen 灵活但把控制权交给模型叙事(无显式状态机)、可控性弱;CrewAI 结构固定、可预期但表达力有限(难做精确回滚 / 复杂分支)。
    4. 选型:开放式研究与原型多用 AutoGen 思路;要可预期 / 要审批 / 要状态管理,LangGraph 是最稳的兜底。
  • 加分亮点 / 深度追问:把三者放进一张"表达能力 vs 可控性"的谱系(LangGraph 强可控、AutoGen 强表达但不控、CrewAI 中间);追问常是"为何 AutoGen 消息只存内存"——答:为了性能简单,生产需自建持久化,这与 LangGraph 内建 Checkpointer 是一处关键能力落差。

面试题 2:为什么 TERMINATE 约定不可靠?为什么它必须与熔断成对设置?

  • 面试官想考察:对"靠语言约定终止 vs 靠硬熔断兜底"这一确定性问题的理解。
  • 专业作答(含深度):
    1. TERMINATE 只是一个写进 system_message 的字符串关键字,由模型判断"何时任务完成"并回带它;框架自身没有任务完成的内置判定。
    2. 模型可能过早终止(漏做关键步骤)或忘了终止(无限续聊),所以不可靠。
    3. 熔断兜底:双聊用 max_consecutive_auto_reply,群聊用 max_round,在约定失效时从"轮数"层面强制停止,防死循环烧钱。
    4. 二者必须配合:只有约定 → 死循环;只有熔断 → 可能截断本该正常结束的任务。
  • 加分亮点 / 深度追问:类比 LangGraph 的 recursion_limit 熔断思路;追问常是"不用 TERMINATE 还能怎么终止"——答:可用函数返回值 / 轮数 / 外部条件等硬条件判定,比纯语言约定更可靠。

面试题 3:AutoGen 为什么会执行模型生成的代码?use_docker=False + human_input_mode="NEVER" 的最坏后果是什么?

  • 面试官想考察:是否真正重视"模型即代码执行者"的安全边界与梯度防护思维。
  • 专业作答(含深度):
    1. 设计使然:UserProxyAgent 代表"人 / 执行环境",默认可提取并执行 Assistant 发来的代码块,从而实现"模型写代码 → 环境跑代码 → 结果回传"的闭环。
    2. 最坏情况:use_docker=False(本地执行)+ NEVER(全程无人)时,模型生成的任意命令直接、无确认地跑在宿主机上——os.remove、删除目录、读写敏感文件都可能发生,且 prompt 注入可能诱导它这么干。
    3. 三档防护:完全禁用(False,最安全)/ Docker 容器隔离(推荐生产)/ 云沙箱 E2B(远程隔离),配合 human_input_mode 分层控制。
    4. 结论:让 Agent"能执行"的每一步都要先回答"它跑在哪、谁能拦它、怎么拒绝它"。
  • 加分亮点 / 深度追问:主动说"沙箱不等于绝对安全(仍需限制网络 / 文件系统权限)";追问常是"生产怎么落地"——答:代码全部送入容器 / 云沙箱执行、只暴露最小权限,并保留可审计日志。