AutoGen 高级技巧:使用 Selector Group Chat 实现智能体动态选择

  • 👉👉👉本人承接各类AI相关应用开发项目(包括但不限于大模型微调、RAG、AI智能体、NLP、机器学习算法、运筹优化算法、数据分析EDA等) !!!
  • 👉👉👉 有意愿请私信!!!

AutoGen 的 AgentChat 模块提供了多样化的多智能体协作模式。 今天,我们将深入探索一个更高级的功能:Selector Group Chat,它允许团队根据上下文智能地选择下一个发言者,从而实现更灵活和高效的协作。

什么是 Selector Group Chat?

SelectorGroupChat 是 AutoGen 中的一种群聊模式,与 RoundRobinGroupChat 类似,它允许多个智能体参与对话。 但与轮询机制不同,SelectorGroupChat 使用一个生成式模型(例如,LLM)来动态地选择下一个发言的智能体。

SelectorGroupChat 主要特性包括:

  • 基于模型的发言者选择

  • 可配置的参与者角色和描述

  • 防止同一发言者连续发言(可选)

  • 可自定义的选择提示

  • 可自定义的选择函数来覆盖默认的基于模型的选择

这种模式的核心优势在于:

  • 上下文感知: 模型可以根据当前的对话历史和每个智能体的描述,选择最适合处理当前任务的智能体。

  • 自适应性: 团队能够根据任务进展和变化,灵活调整协作策略。

  • 智能化: 通过利用 LLM 的推理能力,实现更智能化的智能体协作。

注意: SelectorGroupChat 是一个高级 API。 如果你需要更细粒度的控制和定制,可以使用 Core API 中的群聊模式来实现自己的选择逻辑。

Selector Group Chat 的工作原理

当一个 SelectorGroupChat 团队通过 run() 或 run_stream() 收到任务时,会执行以下步骤:

  1. 选择发言者: 团队分析当前对话上下文,包括历史消息和参与者的角色描述,使用模型来选择下一个发言者。 默认情况下,除非没有其他智能体可用,否则团队不会连续选择同一智能体。你可以通过设置 allow_repeated_speaker=True 来更改此行为。 你还可以提供自定义的选择函数来覆盖默认的模型选择。

  2. 提示发言者: 团队提示被选中的智能体提供响应,然后将响应广播给所有其他参与者。

  3. 检查终止条件: 检查是否满足终止条件,如果不满足,则从步骤 1 重复该过程。

  4. 返回结果: 当对话结束时,团队返回包含此任务的对话历史记录的 TaskResult

完成任务后,对话上下文会保留在团队和所有参与者中,以便下一个任务可以从上一个对话上下文继续。你可以通过调用 reset()来重置对话上下文。

下面,我们用一个 Web 搜索和数据分析的示例来演示 SelectorGroupChat 的用法。下面我们首先导入所需要的python包:

from typing import Sequence

from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination
from autogen_agentchat.messages import AgentEvent, ChatMessage
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
智能体

此系统使用三个专门的智能体:

  • Planning Agent (规划智能体): 战略协调员,负责将复杂的任务分解为可管理的子任务。

  • Web Search Agent (网络搜索智能体): 与search_web_tool工具交互的信息检索专家。

  • Data Analyst Agent (数据分析智能体): 配备 percentage_change_tool 工具的计算智能体专家。

工具 search_web_tool 和 percentage_change_tool 是智能体可以用来执行其任务的外部工具。需要说明的是我们定义的这两个外部工具只是对实际外部工具的模拟,其目的是为了演示LLM调用外部工具的过程。

from typing import Sequence

from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_agentchat.conditions import MaxMessageTermination, TextMentionTermination
from autogen_agentchat.messages import AgentEvent, ChatMessage
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient

# 注意:此示例使用模拟工具而不是真正的 API,以进行演示
def search_web_tool(query: str) -> str:
    if "2012年伦敦奥运会" in query:
        return """以下是中国跳水队在2012年伦敦奥运会上的金牌数:
        吴敏霞/何姿:女子双人3米跳板
        陈若琳/汪皓:女子双人10米台
        陈若琳:女子单人10米台
        吴军霞:女子单人3米板
        曹缘/张雁全:男子双人10米跳台
        秦凯/罗玉通:男子双人3米板
        """
    elif "2016年里约奥运会" in query:
        return "中国跳水队在2016年里约奥运会上获得了7枚金牌。"
    elif "2020年东京奥运会" in query or "2021年" in query: # 为了兼容可能出现的年份描述
        return "中国跳水队在2020年东京奥运会上获得了7枚金牌。"
    return "未找到数据。"

def percentage_change_tool(start: float, end: float) -> float:
    return ((end - start) / start) * 100

接下来我们使用  AssistantAgent 类创建专门的智能体。 重要的是要注意,智能体的 name 和 description 属性被模型用于确定下一个发言者,因此建议定义有意义的名称和描述。


# 这里我们使用github上的免费gpt-4o模型:https://github.com/marketplace/models
model_client = OpenAIChatCompletionClient(
    model="gpt-4o",
    base_url="https://models.inference.ai.azure.com",
    api_key="XXXXXXXXX",
    model_info={"vision": True,"function_calling": True,"json_output": True,"family": "unknown"},
)

planning_agent = AssistantAgent(
    name="PlanningAgent",
    description="""一个用于规划任务的智能体,给定新任务时,该智能体应首先参与。""",
    model_client=model_client,
    system_message="""
    你是一个规划智能体。
    你的工作是将复杂的任务分解为更小、更易于管理的子任务。
    你的团队成员是:
        WebSearchAgent:搜索信息
        DataAnalystAgent:执行计算

    你只规划和委派任务 - 你自己不执行这些任务。

    分配任务时,请使用以下格式:
    1. <agent> : <task>

    完成所有任务后,总结结果并以“结束”结尾。
    """,
)

web_search_agent = AssistantAgent(
    "WebSearchAgent",
    description="一个用于在网络上搜索信息的智能体。",
    tools=[search_web_tool],
    model_client=model_client,
    system_message="""
    你是一个网络搜索智能体。
    你唯一的工具是 search_tool - 使用它来查找信息。
    你一次只进行一次搜索调用。
    获得结果后,你永远不会根据这些元素执行计算。
    """,
)

data_analyst_agent = AssistantAgent(
    "DataAnalystAgent",
    description="一个用于执行计算的数据分析智能体。",
    model_client=model_client,
    tools=[percentage_change_tool],
    system_message="""
    你是一名数据分析师。
    鉴于分配给你的任务,你应该分析数据并使用提供的工具提供结果。
    如果你没有看到数据,请索取它。
    """,
)

注意: 默认情况下,AssistantAgent 会将工具输出作为响应返回。 如果你的工具没有以自然语言格式返回格式良好的字符串,你可能希望添加一个反思步骤,以便让模型总结工具的输出,方法是在创建智能体时设置 reflect_on_tool_use=True。 

工作流程
  1. SelectorGroupChat 接收任务,并根据智能体描述选择最合适的智能体来处理初始任务(通常是规划智能体)。

  2. Planning Agent 分析任务,将其分解为子任务,并使用以下格式将每个子任务分配给最合适的智能体:
    <agent>: <task>

  3. 根据对话上下文和智能体描述,SelectorGroupChat 管理器动态选择下一个智能体来处理分配的子任务。

  4. Web Search Agent 一次执行一个搜索,并将结果存储在共享对话历史记录中。

  5. 当被选中时,Data Analyst 使用可用的计算工具处理收集到的信息。

  6. 工作流程继续进行,动态选择智能体,直到:

    • Planning Agent 确定所有子任务都已完成并发送 “结束

    • 满足了备用终止条件(例如,最大消息数)

定义智能体时,请务必包含有用的  description,因为管理器会使用它来决定接下来选择哪个智能体。

终止条件

这里我们使用两个终止条件: TextMentionTermination 在 Planning Agent 发送 “结束” 时结束对话, MaxMessageTermination 将对话限制为 25 条消息以避免无限循环。

text_mention_termination = TextMentionTermination("结束")
max_messages_termination = MaxMessageTermination(max_messages=25)
termination = text_mention_termination | max_messages_termination
选择器提示语

SelectorGroupChat 使用模型根据对话上下文选择下一个发言者。 我们将使用自定义选择器提示来与工作流程正确对齐。

selector_prompt = """选择一个智能体来执行任务。

{roles}

当前对话上下文:
{history}

阅读上面的对话,然后从 {participants} 中选择一个智能体来执行下一个任务。
确保规划智能体已分配任务,然后再让其他智能体开始工作。
请明确表示下一步该哪一个智能体进行操作
"""

提示: 尽量不要在选择器提示语中添加过多指令而导致模型超载。

什么是太多?这取决于您使用的模型的功能。对于 GPT-4o 和同等产品,您可以使用的选择器提示语,其中包含每个发言者应被选择的条件。对于较小的模型(例如 Phi-4),你应该使选择器提示尽语可能简单,如此示例中使用的提示。

一般来说,如果你发现自己为每个智能体编写了多个条件,则表明你应该考虑使用自定义选择函数,或者将任务分解为由单独的智能体或团队处理的更小的、顺序的任务。

运行团队

接下来让我们使用智能体、终止条件和自定义选择器提示语创建团队。

team = SelectorGroupChat(
    [planning_agent, web_search_agent, data_analyst_agent],
    model_client=model_client,
    termination_condition=termination,
    selector_prompt=selector_prompt,
    allow_repeated_speaker=True,
)

接下来,我们使用一个任务来运行团队,以查找有关中国跳水队在奥运会获得金牌数量的信息。

task = """
请问中国跳水队在2012年伦敦奥运会和2020年东京奥运会分别获得了多少枚金牌?
金牌总数的增长率是多少?
"""
await Console(team.run_stream(task=task))

从上面输出中,我们可以看到,在 Web Search Agent 进行了必要的搜索并且 Data Analyst Agent 完成了必要的计算之后,我们发现 中国跳水队在2012年伦敦奥运会上的金牌数量6(尽管外部工具返回的是金牌的明细结果,LLM仍然会对它进行总结,并计算出金牌数量为6),并且在2020年东京奥运会的金牌数量为7,最好得到金牌的增长率为16.67%。

自定义选择器函数

通常,我们希望更好地控制选择过程。 为此,我们可以使用自定义选择器函数置 selector_func 参数,以覆盖默认的基于模型的选择。这使我们能够实现更复杂的选择逻辑和基于状态的转换。

例如,我们希望 Planning Agent 在任何专业智能体发言后立即发言以检查进度。

注意: 从自定义选择器函数返回 None 将使用默认的基于模型的选择。

def selector_func(messages: Sequence[AgentEvent | ChatMessage]) -> str | None:
    if messages[-1].source != planning_agent.name:
        return planning_agent.name  # 始终在其他智能体发言后返回到规划智能体。
    return None


# 使用用户代理代理和选择器函数重置先前的智能体并再次运行聊天。
await team.reset()
team = SelectorGroupChat(
    [planning_agent, web_search_agent, data_analyst_agent],
    model_client=model_client,
    termination_condition=termination,
    selector_prompt=selector_prompt,
    allow_repeated_speaker=True,
    selector_func=selector_func,
)

await Console(team.run_stream(task=task))

 

从上面的智能体之间对话记录中你可以看到,规划智能体(PlanningAgent)总是在其他智能体之后立即发言。 

提示:每个智能体每次只执行一步(执行工具或者生成响应等)。如果您希望AssistantAgent重复执行,直到在运行完所有需要运行的工具后停止返回ToolCallSummaryMessage ,您可以通过检查最后一条消息并智能体(如果是 ToolCallSummaryMessage)来实现 。

用户反馈

我们可以将  UserProxyAgent 添加到团队,以便在运行期间提供用户反馈。有关  UserProxyAgent 的更多详细信息,请参阅: Human-in-the-Loop

若要在 Web 搜索示例中使用  UserProxyAgent,我们只需将其添加到团队并更新选择器函数,以便在规划智能体发言后始终检查用户反馈。
如果用户使用“APPROVE”响应,则对话将继续,否则,规划智能体将再次尝试,直到用户批准。

user_proxy_agent = UserProxyAgent("UserProxyAgent", description="一个用户批准或拒绝任务的智能体")

def selector_func_with_user_proxy(messages: Sequence[AgentEvent | ChatMessage]) -> str | None:
    if messages[-1].source != planning_agent.name and messages[-1].source != user_proxy_agent.name:
        # 规划智能体应首先在给定新任务时参与,或者检查进度。
        return planning_agent.name
    if messages[-1].source == planning_agent.name:
        if messages[-2].source == user_proxy_agent.name and "批准" in messages[-1].content.upper():  # type: ignore
            # 用户已批准该计划,继续执行下一个智能体。
            return None
        # 使用用户代理智能体来获取用户的批准以继续。
        return user_proxy_agent.name
    if messages[-1].source == user_proxy_agent.name:
        # 如果用户未批准,则返回到规划智能体。
        if "批准" not in messages[-1].content.upper():  # type: ignore
            return planning_agent.name
    return None


# 使用用户代理智能体和选择器函数重置先前的智能体并再次运行聊天。
await team.reset()
team = SelectorGroupChat(
    [planning_agent, web_search_agent, data_analyst_agent, user_proxy_agent],
    model_client=model_client,
    termination_condition=termination,
    selector_prompt=selector_prompt,
    selector_func=selector_func_with_user_proxy,
    allow_repeated_speaker=True,
)

await Console(team.run_stream(task=task))

 

从上面的输出结果我们可以看到,用户的反馈已合并到对话流中,并且用户可以批准或拒绝规划智能体的决策。这里我们注意到  UserProxyAgent 每次都是在 PlanningAgent 发言完以后介入,也就是说 这里会让 人类用户 审批 PlanningAgent 的规划结果,如果人类用户觉得  PlanningAgent 的规划结果不合理当然也可以 拒绝 ,那么PlanningAgent会重新进行规划,直到人类用户满意为止。

总结

AutoGen 的 SelectorGroupChat 提供了一种强大的方式来构建自适应的多智能体系统。 通过学习如何利用智能体描述、自定义选择器以及用户反馈,你可以构建出能够动态地选择最合适的智能体来解决复杂任务的AgentChat系统。无论是信息检索、数据分析还是用户交互,SelectorGroupChat 都能帮助你构建出更灵活、更智能的协作式应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-派神-

感谢您慷慨解囊,我会更加努力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值