AutoGen:把多 Agent 应用表达成可编程对话
原始来源
Qingyun Wu 等,2023:AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation,本页按 arXiv v2 阅读。
本页是原创学习导读,不含原文复刻;论文版权与完整内容以原始来源为准。
学完后你应该能做到什么
读完本篇,你应该能够:
- 用角色、内部上下文、能力和回复规则定义一个 Conversable Agent,而不是只给模型起一个角色名。
- 区分 Conversation Programming 中的 computation 与 control flow。
- 追踪一条消息怎样触发 LLM、工具、代码执行或人类输入,并最终产生下一条消息。
- 为双 Agent 与多 Agent 流程明确发言者选择、终止、最大轮次、异常处理和人工接管。
- 判断一个任务真的需要多 Agent,还是单 Agent 加工具就足够。
问题背景:复杂应用为什么不能只靠一段提示词
一个“帮我分析股票数据并画图”的任务,表面上只有一句话,实际却包含多种工作:理解要求、写代码、安装或调用依赖、执行程序、读错误、修改代码、检查图表,再决定是否结束。把这些能力都塞进一次模型调用,会遇到几个困难:
- 模型可以生成代码,却不能天然证明代码真实执行过。
- 工具执行结果和人类反馈需要回到模型,但谁负责转发并不明确。
- 不同任务需要不同的人类参与程度和不同的停止条件。
- 当角色增加时,谁下一位发言、消息发给谁、怎样避免无限对话会成为新的控制问题。
AutoGen 的回答是:把 LLM、人类和工具能力封装成能够收发消息的 Agent,再把整个应用写成这些 Agent 的对话计算与控制流。这里的“对话”不是闲聊,而是一种应用编排接口。
先记住几个术语:
- Conversable Agent:拥有特定角色、内部上下文和一组能力,并能接收、处理和回复消息的实体。
- Capability:Agent 处理消息时可以调用的能力,例如 LLM 推理、人类输入、代码执行或函数调用。
- Conversation:Agent 间的消息序列;消息既传递内容,也推动状态机前进。
- Auto-reply:收到消息后自动执行
generate_reply并把结果发回,直到满足终止条件。 - Conversation Programming:定义 Agent 及其能力,再定义它们的对话计算和控制流。
Agent 不等于一个模型实例
一个 Agent 可以由 LLM、工具、人类或它们的组合支撑;多个 Agent 也可能共享同一种模型。真正的差异来自上下文、能力、权限、回复函数和控制规则,而不是名字。
机制契约:消息驱动的应用状态机
| 部分 | AutoGen 论文中的含义 | 设计时需要明确的问题 |
|---|---|---|
| 输入 | 一条来自用户或其他 Agent 的消息 | 消息格式是什么,发送者是谁,是否可信 |
| Agent 状态 | 角色、收发消息形成的内部上下文、能力配置 | 哪些历史可见,哪些工具可用,是否允许人工输入 |
| Computation | Agent 为生成回复所执行的动作 | 调 LLM、执行函数、运行代码还是请求人类 |
| Control flow | 计算以什么顺序和条件发生 | 下一位发言者是谁,发给谁,何时转入子对话 |
| 输出 | 新消息、工具结果、代码结果或人类反馈 | 怎样被下一位 Agent 消费,是否需要结构化 |
| 停止条件 | 终止消息、程序化谓词、最大自动回复数、人工终止 | 谁有权结束,结束是否等于任务验收通过 |
flowchart TD M["收到一条消息"] --> R["Agent 更新自己的会话上下文"] R --> D{"选择回复能力"} D -->|"LLM"| L["推理或生成内容"] D -->|"Tool / Code"| T["执行函数或代码"] D -->|"Human"| H["请求或接收人类输入"] L --> G["generate_reply 形成新消息"] T --> G H --> G G --> E{"满足终止条件?"} E -->|"是"| X["结束会话并交付结果"] E -->|"否"| C["控制流选择接收者或下一位发言者"] C --> M
这套机制把一个隐含的工作流拆成两部分:每个节点“会算什么”,以及消息“下一步流向哪里”。
核心机制一:Conversable Agent 怎样工作
论文中的 Conversable Agent 具备四个关键属性。
1. 角色定义处理责任
角色说明这名 Agent 在会话中负责什么,例如“提出代码方案”“执行代码”“审查结果”。角色影响模型提示和回复行为,但角色名本身没有隔离效果。
2. 内部上下文由消息历史形成
Agent 根据自己发送和接收的消息维护上下文。不同 Agent 可以看到不同历史,因此能形成信息隔离。例如执行器只需要收到代码和运行参数,不必读取规划者的全部推理;评审者可以只收到候选产物、要求和独立证据。
3. 能力可以组合
论文把常见后端能力概括为三类:
- LLM:理解消息、生成回复、写代码、吸收反馈。
- Human:在配置的轮次或条件下请求人类输入,人也可以选择跳过。
- Tools:执行代码或函数调用,把真实结果重新放入对话。
一个 Agent 可以只拥有其中一种,也可以混合使用。论文中的预配置 AssistantAgent 主要由 LLM 支撑;UserProxyAgent 可以代理人类输入,并执行模型建议的代码或函数。这是论文版本的历史抽象,不代表当前 AutoGen 库 API 永远保持相同。
4. 统一消息接口触发回复
Agent 通过 send、receive 和 generate_reply 一类统一接口协作。默认自动回复机制是:收到消息后调用回复逻辑,生成新消息并发回,除非终止条件已经满足。回复函数可以来自 LLM、代码/函数执行、人类输入,也可以由开发者注册自定义逻辑。
因此,一条消息不是静态文本,而像事件循环中的事件:它更新状态、触发计算、产生下一事件。
核心机制二:Conversation Programming 分开“计算”与“控制”
论文把 Conversation Programming 拆成两个概念:
- Computation:Agent 为回复当前消息做的动作。它可能调用 LLM、执行代码、调用工具、让人审阅,最后都表现为一条新消息。
- Control flow:这些计算发生的次序与条件。它决定消息发给谁、哪位 Agent 下一步行动、何时进入子会话,以及什么时候终止。
控制可以通过三种方式表达:
- 自然语言控制:例如要求 Agent 完成所有任务后回复
TERMINATE,或规定先提出方案再执行。 - 编程语言控制:用 Python 谓词判断终止、设置人类输入模式、限制自动回复次数、注册自定义回复函数。
- 两者之间切换:代码调用带控制指令的 LLM,或由 LLM 提议函数调用,让自然语言决策进入程序化路径。
这种融合提供灵活性,也带来可靠性差异。max_auto_reply 一类代码限制是确定的;要求模型“合适时结束”则可能漏判。安全关键条件应尽可能落到可执行控制上。
双 Agent 案例:写代码和执行代码怎样闭环
考虑任务:“读取本地销售 CSV,计算月度增长率并保存图表。”下面是一条简化但机制完整的对话轨迹。
| 步骤 | 发送者 → 接收者 | 消息或动作 | 系统状态 |
|---|---|---|---|
| 1 | UserProxy → Assistant | 发送任务、允许读取的文件路径和验收要求 | 建立目标与权限边界 |
| 2 | Assistant → UserProxy | 生成 Python 代码,请求执行 | 候选代码进入消息,但尚无执行证据 |
| 3 | UserProxy | 在隔离环境运行代码 | 真实执行发生 |
| 4 | UserProxy → Assistant | 返回 KeyError: revenue 和实际列名 | 环境反馈进入会话上下文 |
| 5 | Assistant → UserProxy | 修改列名映射并再次请求执行 | 生成第二版候选代码 |
| 6 | UserProxy | 执行成功,检查输出文件存在 | 获得运行结果和最小断言 |
| 7 | UserProxy → Assistant | 返回统计摘要、图表路径和断言结果 | 模型可以基于事实总结,而非假装执行 |
| 8 | Assistant → UserProxy | 给出最终说明并发送终止标记 | 对话满足终止规则 |
| 9 | UserProxy / 人类 | 核对业务口径后接受或要求修改 | “会话终止”才映射成“任务验收” |
这个模式的价值不在于一定要有两个模型。UserProxy 可以没有 LLM,只负责人工交互和受控执行。分开两者,是为了让“提出代码”和“拥有执行权限”处在不同信任边界。
多 Agent 案例:发言者选择本身就是算法
任务复杂后,可以加入 Engineer、Critic、Executor 与 User Proxy,并由 Manager 管理群聊。论文中的动态群聊管理器执行三个步骤:选择一位发言者、请求其回复、再把回复广播给其他成员。
sequenceDiagram participant U as User Proxy participant M as Manager participant E as Engineer participant C as Critic participant X as Executor U->>M: 任务、限制与验收标准 M->>E: 选择 Engineer 提出方案 E-->>M: 代码与假设 M->>C: 选择 Critic 独立审查 C-->>M: 风险与修改意见 M->>E: 回传审查意见 E-->>M: 修订代码 M->>X: 请求隔离执行 X-->>M: 日志、测试和产物 M->>U: 汇总证据,请求最终验收
Manager 不是装饰。若总是轮流发言,Executor 可能在代码尚未准备好时运行;若模型随意选择发言者,又可能让 Engineer 与 Critic 互相重复。发言策略必须结合当前任务状态,例如 DRAFTED → REVIEWED → EXECUTED → ACCEPTED,而不只看最后一段自然语言。
多 Agent 真正有价值的情况包括:
- 角色拥有不同工具或权限,例如只有 Executor 可以运行代码。
- 角色拥有不同信息,例如 Critic 不看生成者的自我辩护,只看需求与产物。
- 工作可以并行,例如多个检索者查不同数据源。
- 需要独立的规则检查器,例如棋盘 Agent 验证合法走法。
如果所有角色看到相同上下文、调用相同模型、没有独立工具和验收标准,那么增加角色常常只会复制 token 和错误。
用伪代码表示对话控制
agents = {
"assistant": AssistantAgent(llm=True, tools=[]),
"executor": UserProxyAgent(
human_input="on_demand",
code_execution="sandbox",
),
}
message = user_task
sender, receiver = "executor", "assistant"
for turn in range(MAX_TURNS):
receiver_state = update_context(receiver, sender, message)
reply = agents[receiver].generate_reply(receiver_state)
if violates_policy(reply):
request_human_review(reply)
break
if accepted_result(reply):
finish(reply)
break
sender, receiver = receiver, choose_next_agent(reply)
message = reply
else:
stop_as_incomplete("maximum conversation length reached")真实实现还要把异常、超时、重试、幂等性和权限放进控制层。重点是:模型生成回复只是 computation;choose_next_agent、策略门禁和终止判断才是 control flow。
证据该怎么看
论文用数学、编程、问答、运筹、在线决策、娱乐等应用展示框架,并报告部分基准和试点结果。它主要证明 AutoGen 能以统一抽象表达多种会话模式,并在若干应用中取得有用结果;它不是“多 Agent 普遍优于单 Agent”的大规模受控实验。
一个很能说明边界的例子是动态群聊试点:作者在 12 个手工构造的复杂任务上比较双 Agent、使用角色扮演发言选择的四 Agent 群聊,以及使用任务式发言选择的同成员群聊。GPT-4 对应成功数分别为 9、11、8。也就是说,四个 Agent 加上不合适的选择策略,反而低于两个 Agent。样本很小,不能外推为稳定排名,但足以说明编排策略和终止设计比角色数量本身重要。
论文的会话棋盘示例还移除了负责规则验证的 Board Agent;只提示两个玩家“保证走法合法”会产生非法走法并打断游戏。这个消融支持一个工程判断:当规则可执行时,独立验证组件通常比让生成模型自我保证更可靠。
失败模式与调试顺序
| 失败现象 | 常见根因 | 修复方向 |
|---|---|---|
| Agent 互相重复、对话不结束 | 终止条件模糊,状态只存在自然语言里 | 增加结构化阶段、最大轮次和程序化终止 |
| Reviewer 总同意生成者 | 上下文、模型和标准没有独立性 | 提供独立证据、不同工具或确定性规则检查 |
| 工具结果被误当成模型文本 | 消息没有类型和来源元数据 | 区分 tool_result、human_input、assistant_message |
| 多 Agent 比单 Agent 更差 | 通信开销、上下文复制、发言顺序错误 | 先建立单 Agent 基线,再验证每个新增角色的增益 |
| 代码执行造成越权或污染 | 执行 Agent 权限过大、缺少隔离 | 最小权限、沙箱、资源限额和危险操作审批 |
| 对话结束但任务未完成 | TERMINATE 被当成业务验收 | 将终止与外部测试、产物检查、人工验收分开 |
历史贡献与今天的工程解释
论文的历史贡献是提出并实现 Conversable Agent 与 Conversation Programming:用统一消息接口组合 LLM、人类和工具能力,并用自然语言与代码共同描述静态或动态的多 Agent 对话流程。
今天更稳妥的工程解释是:多 Agent 是一种模块化工作流表达方式,而不是自动提高智能的按钮。应先证明不同角色确实需要不同的上下文、工具、权限、并行分工或独立验证,再承担额外的延迟、成本和失败面。
论文描述的是 2023 年 AutoGen 及其当时的内置 Agent 和示例。后续库的包结构与 API 可能改变;本篇用于掌握机制,不应作为当前版本的复制粘贴手册。
与 MCP 的区别
AutoGen 重点是应用内部的参与者、消息和控制流;MCP 重点是Host 与外部 Server 之间怎样用共同协议暴露资源、提示和工具。AutoGen 回答“谁与谁协作以及下一步轮到谁”,MCP 回答“外部能力如何被发现和调用”。一个 AutoGen Agent 可以使用 MCP Client,但两者不处在同一抽象层。
自测:确认你真的掌握了机制
- 用四个字段定义一个 Conversable Agent:角色、上下文、能力和回复规则。为什么只有角色名不够?
- 在“写代码—运行—修复”的双 Agent 案例中,哪些步骤属于 computation,哪些属于 control flow?
- 为什么
TERMINATE只能结束会话,不一定证明任务成功? - 四 Agent 群聊在什么条件下可能比双 Agent 更差?
- 设计一个必须人工确认的工具调用:确认点应放在哪一条消息与哪一个权限边界之间?
参考答案与判断要点
- 角色给出责任,但上下文决定可见信息,能力决定能做什么,回复规则决定如何响应;后三者不变时,换名字不会产生真正分工。
- LLM 生成、代码执行和人类审查是 computation;选择接收者、安排执行时机、失败回路与停止判断是 control flow。
- 模型可能过早输出终止词;任务成功必须由测试、状态断言、产物检查或人工验收确认。
- 角色没有独立价值、消息复制上下文、发言策略不匹配任务状态、终止不稳或通信成本超过分工收益时都会更差。
- 模型提出结构化调用后,具备执行权限的 Agent 在真正调用工具前向人类显示参数和副作用;人类批准才跨过执行边界。