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

248 lines
17 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阶段三 · 小点 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 像拉群开会一样,靠互相发自然语言消息协作完成任务,直到有人说「完成」。
- 适合研究实验与原型验证。
```mermaid
graph LR
A[AssistantAgent: 会说不会做] -->|发代码块/方案| B[UserProxyAgent: 可执行代码]
B -->|把执行结果发回| A
A -->|回复 TERMINATE| C[结束]
```
### 2. 核心类
- **ConversableAgent:** 所有 Agent 的基类,能收消息、能回消息、可配置是否执行代码、是否需人工输入。
- **AssistantAgent:** 默认「只会说不会做」的纯 LLM 角色:分析问题、写方案、生成代码,但自己不执行。
- **UserProxyAgent:** 代表「人」或「执行环境」:默认可执行 Assistant 发来的代码块,可设定人工介入模式。
| human_input_mode | 行为 | 风险 |
|-|-|-|
| `ALWAYS` | 每次发言都问真人 | 最低 |
| `TERMINATE` | 仅结束时问(默认半自动) | 中 |
| `NEVER` | 全程无人 | **最高** |
```python
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 双人组
```python
# 让 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 开会)
```python
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="设计并实现一个登录接口")
```
```mermaid
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 与熔断必须成对设置,缺一个都会出问题——光有约定会死循环,光有熔断会截断正常任务。
3. **★ 沙箱安全(最重要):** `use_docker=False` 时模型代码直接跑在你机器上!模型生成 `os.remove("C:/重要目录")` 完全可能。
```python
# 三档安全方案(从最安全到最省事):
# 方案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 需显式配置,默认不一定可用。
4. **消息默认只存内存** → 生产自建消息持久化(改 `register_reply` 钩子存库)。
> ⏳ **短期可不深究**:`register_reply` 这套"给 Agent 注入自定义回复逻辑"的钩子机制,以及消息持久化改造细节,第一遍只需知道"AutoGen 消息默认只存内存、生产要自建持久化"即可;真要接入存储时再根据你装的 0.2 / 0.4 / MAF 版本对照实现。
5. **适用边界:** 研究原型 / 内部实验最佳;对外生产系统优先 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 最小示例(伪代码)
```python
# 依赖: 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"能执行"的每一步都要先回答"它跑在哪、谁能拦它、怎么拒绝它"。
- **加分亮点 / 深度追问**:主动说"沙箱不等于绝对安全(仍需限制网络 / 文件系统权限)";追问常是"生产怎么落地"——答:代码全部送入容器 / 云沙箱执行、只暴露最小权限,并保留可审计日志。