AutoGen:多智能体协作框架的入门与构建
ffchic Lv2

核心思想

AutoGen 的核心思想是通过对话实现协作。它将多智能体系统抽象为一个由多个“可对话”智能体组成的群聊。开发者可以定义不同角色(如 CoderProductManagerTester 等),并设定它们之间的交互规则(例如:Coder 写完代码后由 Tester 自动接管)。

任务的解决过程,就是这些智能体在群聊中通过自动化消息传递,不断对话、协作、迭代,直至最终达成目标的过程。

模型客户端配置

首先,我们先来了解一下模型客户端的配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# OpenAIChatCompletionClient 是兼容 OpenAI 接口格式的通用模型客户端,可对接 DeepSeek 等第三方服务
from autogen_ext.models.openai import OpenAIChatCompletionClient

client = OpenAIChatCompletionClient(
# 模型名称从环境变量读取,默认使用 DeepSeek 的对话模型
model=os.getenv("OPENAI_MODEL", "deepseek-chat"),
api_key=api_key,
# API 基础地址从环境变量读取,支持切换到不同的 OpenAI 兼容服务
base_url=os.getenv("OPENAI_API_BASE", "https://api.deepseek.com/v1"),
temperature=temperature, # 输出创造性程度(0.0 最保守,1.0 最随机)
max_tokens=max_tokens, # 每次生成的最大 token 数
top_p=0.9, # Nucleus 采样阈值:只从累积概率前 90% 的 token 中采样,平衡多样性与质量
model_info=ModelInfo(
family="openai", # 模型接口协议族,声明兼容 OpenAI 格式
vision=False, # 该模型不支持图像输入
function_calling=True, # 支持函数调用(Tool Call),可配合工具使用
json_output=True, # 支持结构化 JSON 输出模式
structured_output=False, # 不使用 OpenAI 的 Structured Output 严格模式
),
)

以上代码是实例化一个模型客户端的 Demo,指定了各种参数:使用的 LLM、最大 Token 数、模型信息等。

核心参数解析:Temperature

其中,temperature 是一个极其关键的参数,它控制着模型输出概率分布的“尖锐程度”。

简单来讲,在模型预测下一个词时,会把每个候选词的原始分数(Logits,)除以 (即 Temperature),公式表现为

假设现在有三个候选词及其原始分数:

  • “好”3
  • “棒”2
  • “烂”1

根据不同的 值,运算结果如下:

  • 假设一:(原始状态)
    运算后的分数不变,原始分数直接参与后续概率计算。
  • 假设二:(趋于保守)
    分数会变得苛刻,放大差距。运算后:
    “好”3/0.5=6 分)> 词 “棒”2/0.5=4 分)> 词 “烂”1/0.5=2 分),“好”的优势被进一步拉大。
  • 假设三:(趋于随机)
    分数变得宽容,缩小差距。运算后:
    “好”3/2=1.5 分)> 词 “棒”2/2=1 分)> 词 “烂”1/2=0.5 分),各个词被选中的概率变得更加相近。

总结来说,temperature 值越大,各个词之间的原始差距被缩得越小,模型选词越偏向随机发散;值越小,差距被放大,模型越偏向确定保守。

注: 实际模型中,运算后的分数最终还会通过 Softmax 函数(指数归一化)转换为 的概率!上面的 3/2/1 分只是为了方便理解 是如何放大/缩小差距的。真实模型中,转换后的概率大致呈现下方表格所示的动态变化趋势:

Temperature 效果 概率分布示例长什么样
极度确定,永远选最高概率词 好: 99%,棒: 1%,烂: 0%
保守,高概率词碾压其他 好: 80%,棒: 18%,烂: 2%
(默认) 平衡 好: 55%,棒: 35%,烂: 10%
使用模型原始分布,不做任何压缩 好: 45%,棒: 30%,烂: 25%
分布趋于均匀,各词概率接近,输出混乱 好: 36%,棒: 34%,烂: 30%

核心参数解析:top_p

top_p(Nucleus Sampling,核采样)的作用简单来说就是**“砍尾巴”**。它通常和 temperature 配合使用:先由 temperature 处理数据得出概率分布,再根据 top_p 的阈值比例来砍掉尾巴,最后才进行选词。

假设经过 temperature 处理后,候选词的概率如下:

  • “好”:45%
  • “棒”:25%
  • “绝”:15%
  • “行”:8%
  • “烂”:5%
  • …(其他低概率词):合计 2%

如果我们设置 top_p = 0.9(即 90%),模型会按概率从高到低累加,只截取累积概率刚达到 90% 时的单词集合:

  1. 第一名 “好” (45%) —— 累计:45%(没到 90%,继续)
  2. 第二名 “棒” (25%) —— 累计:70%(没到 90%,继续)
  3. 第三名 “绝” (15%) —— 累计:85%(没到 90%,继续)
  4. 第四名 “行” (8%) —— 累计:93% (超过了 90%!停!)

结果:只有 【好、棒、绝、行】 这 4 个词留下来进入最终的抽签池(并且这四个词的概率会按比例重新放大归一化到 100%)。而排在后面的“烂”以及更糟的词,将被直接拦腰斩断、彻底除名。哪怕它原本还有 5% 的机会,现在的入选概率也是 0%。

temperaturetop_p 的协同工作

在底层运行中,这两个参数可以说是“黄金搭档”。它们的协同工作流程如下:

  1. 算概率:先使用 temperature 来决定候选词分差是被放大还是缩小,计算出一个带有特定“感情色彩”的概率分布。
  2. 砍尾巴:再用 top_p 执行“截断”——看着调完之后的概率单,从上往下加,一旦累计达到阈值(如 0.9)就划线,把排在后面的“弱势词”全扔掉。
  3. 终极抽签:从活下来的“精英”圈子里,按它们的相对概率随机抽取一个词输出。

核心区别总结

比较维度 Temperature (温度) top_p (核采样 / 截断采样)
手段 像**“滤镜”**:改变所有人分数的差距。 像**“剪刀”**:直接把排在后面的选项咔嚓剪掉。
态度 温柔:即使把 调得很低,最后一名也依然有那么 0.0001% 的机会,理论上没绝杀。 冷酷:只要你没挤进去前 的圈子,直接出局,概率彻底归零。
解决的问题 防止输出过于死板(提高 ),或防止输出过于发散(降低 )。 剪除“长尾噪音”。语言模型词汇表有几万个词,往往有几千个极低概率的词(比如乱码或离谱生僻字)。top_p 的任务就是把这几千个垃圾选项永远关在门外,防止哪怕万分之一的“爆冷抽中”。

核心参数解析:json_outputstructured_output

这两个参数通常一起出现,它们主要用于指导或强制大模型以结构化的 JSON 格式返回输出。

  • json_output=True 时:
    它就像是在提示里告诉模型:“请自觉一点,把结果按照 JSON 的格式发给我。”

    • 模型表现:它会尽力返回 JSON。
    • 潜在问题:因为它只是“尽力”,有时候它可能会漏写一个逗号、多加一个引号、把字段名拼错(比如把 name 写成了 first_name),甚至在 JSON 外面还啰里啰嗦加一句“这是您要求的 JSON 代码”。
    • 可能后果:当你的程序尝试去解析(Parse)这段文本时,极易因为格式或类型的细微错误而自动报错挂掉。
  • structured_output=True 时:
    这相当于直接给大模型发了一张“固定格式的机读答题卡”。此时,这不再仅仅是一个提示语的作用,而是从大模型底层的推理生成机制层面,严格限制了模型的输出概率分布。它能确保输出百分之百符合你预先定义的 JSON Schema(数据结构)约束,连多余的一个废话字符都不会出现。

**避坑指南:**虽然当前绝大多数模型都能听懂“输出 JSON”的指令(即支持 json_output),但底层引擎直接支持严格 structured_output 模式的模型并不算多。该特性目前更广泛且成熟地应用于 OpenAI 的官方原生模型(如 GPT-4o 等)。

在上文的示例代码中,我们对接的是第三方 DeepSeek 服务,受限于 API 的原生支持情况,所以这里我们暂时将 structured_output 设置成了 False

AutoGen 的 Agent (智能体)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# AssistantAgent 是 AutoGen 中最基础的对话智能体,负责与语言模型交互并生成回复
from autogen_agentchat.agents import AssistantAgent

coding_assistant = AssistantAgent(
name="CodingMentor", # 智能体名称,用于标识和日志输出
model_client=client, # 绑定上面创建的模型客户端
system_message="""你是一位专业的 Python 编程导师。
你的职责是:
1. 清晰地解释编程概念
2. 提供带注释的代码示例
3. 建议最佳实践
4. 帮助调试问题

总是用 Markdown 格式化代码,并解释你的推理过程。""",
)

AssistantAgent

AssistantAgent 是 AutoGen 中最基础、最常用,也是最成熟的对话智能体类。它是任务的主要解决者,其核心是封装了一个大型语言模型(LLM)。

如果把 AutoGen 比作一个“虚拟外包项目组”,那么 AssistantAgent 就是这个项目组的核心脑力员工。它本身“没有手”(不具备直接在本地电脑上执行代码或操作的能力),但它拥有最强的思考与规划能力。你通过 system_message 给它分配什么角色(如:前端专家、文案策划、数据分析师),它就能胜任对应的工作。

除此之外,它还内置了以下强大的核心能力:

  • 记忆功能(维护上下文):大模型本身是无状态、没有记忆的,需要每次对话时都把之前的对话历史统一发送给大模型。AssistantAgent 内部自动实现了历史消息的管理与拼接功能。
  • 代码提取与格式化(Code Block Parsing):大模型在回答时,往往会将代码、代码注释、说明文字甚至一些废话混合在一起返回。AssistantAgent 内置了提取能力,它会自动扫描大模型回答的 Markdown 内容中的独立代码块,方便后续交给其他 Agent(如 UserProxyAgent)去执行。
  • 工具调用(Function Calling / Tool Use):可以给大模型注册一些 Python 函数(例如:get_weather(city: str)search_web(query: str))。当你问到某些模型不知道的实时/专有信息,且工具恰好可以获取时,模型会按照约定格式输出调用指令。底层机制捕获该指令后会执行对应函数,再把调用结果返回给大模型。
  • 自动化的重试与纠错(Auto-Reply & Fallback):面对复杂的任务,代码往往一次性跑不通。这时别的 Agent(通常是 UserProxyAgent 充当的执行者和测试者)在运行时如果抛出异常,会把异常信息反馈给它(例如:“你刚才写的代码抛出了 IndentationError,在第4行。”)。AssistantAgent 底层自带 auto-reply(自动回复)机制,不需要开发者写额外的 while 循环。它收到报错后会自动将报错信息塞进上下文,再次请求大模型:“根据报错,给我一个新的修复方案。” 只有当问题解决,或者达到最大重试次数(max_consecutive_auto_reply)时,交互才会停止。
  • 终止条件判断(Termination Detection):AI 群聊很容易陷入无限死循环(例如两个 AI 互相发送“谢谢你”、“不客气”)。因此,AssistantAgent 经常被配置一种“终止词”识别能力。比如,你可以约定当任务彻底完成时,在回复末尾加上 TERMINATE。框架一旦检测到该触发词,就会自动结束这轮多智能体对话任务。