AutoGen学习笔记系列(九)Advanced - Selector Group Chat
这篇文章瞄的是AutoGen官方教学文档 Advanced
章节中的 Selector Group Chat
篇章,介绍了SelectorGroupChat
对象如何从一个Team中选择其中一个Agent与LLM进行对话,并且在得到结果后进行二次规划,同时你也可以自定义选择函数。本质上还是对Team的流程控制。
- 官网链接:https://microsoft.github.io/autogen/stable/user-guide/agentchat-user-guide/selector-group-chat.html# ;
Selector Group Chat
官方展示了一个名为 SelectorGroupChat
的对象,是一个Team对象也就是由多个Agent组成的对象,和我们之前使用的 RoundRobinGroupChat
是同一类型。它的作用在于内部的每一个Agent都会轮流向其他Agent进行广播消息,然后由LLM根据整个Team的上下文环境选择与这个Team中的哪一个Agent进行对话。
SelectorGroupChat
对象的关键特性有以下几点:
- 依靠LLM选择合适的Agent;
- 可以配置参与对象于描述;
- 防止同一个Agent持续性对话(可选);
- 可自定义的prompt;
- 可自定义选择函数
selection function
,即你也可以不让LLM进行选择而是根据你的选择函数给LLM一个Agent进行对话;
相当于之前使用的RoundRobinGroupChat
是内部Agent自发向LLM进行对话;而SelectorGroupChat
是将整个Team的上下文发给LLM,然后让LLM或者你自定义的选择函数使用其中一个Agent与LLM对话。
How Does it Work?
SelectorGroupChat
之所以能够实现上面提到的选择功能是依靠在 run()
或者 run_stream()
函数中按照下面的步骤执行:
- Team分析当前对话的上下文,包括历史记录、每一个Agent的
name
和description
,以此为依据选择下一个与LLM对话的Agent;默认情况下不会选择上一次与LLM对话的Agent,尽量避免只有一个Agent持续与LLM进行对话,除非这个Team中只有一个Agent,但也可以通过参数allow_repeated_speaker=True
的方式允许Agent持续与LLM对话;你也可以通过自定义的选择函数来筛选下一次要和LLM对话的Agent; - 被选中的Agent会将自己的prompt和LLM的response都广播给整个Team中的所有其他Agent;
- 只有当终止条件被触发时间才会终止Team,否则整个Team会持续运行下去;
- 当对话结束时会返回一个
TaskResult
类型,其中包含了所有的聊天记录;
和RoundRobinGroupChat
用法一样,一旦任务结束后Team仍然会保留完整的上下文以便你进行二次激活,并且可以使用 reset()
函数清空上下文。
Example: Web Search/Analysis
官网在这里给出了一个使用 SelectorGroupChat
进行Web内容搜索和数据分析的任务,整个Team的结构如下,设计了三个内部Agent:
- Planning Agent:将一个复杂任务拆解成简单任务并决策由哪个Agent执行,相当于上面提到的选择函数,只不过这个Agent用了LLM进行选择;
- Web Search Agent:网络内容搜索Agent使用
search_web_tool
工具进行搜索; - Data Analyst Agent:数据分析Agent使用
percentage_change_tool
工具进行计算;
上面提到的两个 search_web_tool
和 percentage_change_tool
定义如下:
# Note: This example uses mock tools instead of real APIs for demonstration purposes
def search_web_tool(query: str) -> str:if "2006-2007" in query:return """Here are the total points scored by Miami Heat players in the 2006-2007 season:Udonis Haslem: 844 pointsDwayne Wade: 1397 pointsJames Posey: 550 points..."""elif "2007-2008" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214."elif "2008-2009" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398."return "No data found."def percentage_change_tool(start: float, end: float) -> float:return ((end - start) / start) * 100
然后就是用 AssistantAgent
来定义上面三个Agent,这里官方提示在定义时最重要的是些明白Agent的 name
和 description
,因为这两个信息会变成LLM选择下一个与其对话的依据。
- 定义一个基于
gpt-4o
的模型,后面三个Agent都要用这个模型接口:
model_client = OpenAIChatCompletionClient(model="gpt-4o")
- Planning Agent 任务拆解Agent(在这里就是选择对话的Agent):
planning_agent = AssistantAgent("PlanningAgent",description="An agent for planning tasks, this agent should be the first to engage when given a new task.",model_client=model_client,system_message="""You are a planning agent.Your job is to break down complex tasks into smaller, manageable subtasks.Your team members are:WebSearchAgent: Searches for informationDataAnalystAgent: Performs calculationsYou only plan and delegate tasks - you do not execute them yourself.When assigning tasks, use this format:1. <agent> : <task>After all tasks are complete, summarize the findings and end with "TERMINATE".""",
)
- Web Search Agent 内容搜索Agent,调用
search_web_tool
工具进行搜索:
web_search_agent = AssistantAgent("WebSearchAgent",description="An agent for searching information on the web.",tools=[search_web_tool],model_client=model_client,system_message="""You are a web search agent.Your only tool is search_tool - use it to find information.You make only one search call at a time.Once you have the results, you never do calculations based on them.""",
)
- Data Analyst Agen 数据分析Agent,调用工具
percentage_change_tool
对内容进行分析:
data_analyst_agent = AssistantAgent("DataAnalystAgent",description="An agent for performing calculations.",model_client=model_client,tools=[percentage_change_tool],system_message="""You are a data analyst.Given the tasks you have been assigned, you should analyze the data and provide results using the tools provided.If you have not seen the data, ask for it.""",
)
【Note】:如果你的工具函数返回的不是自然语言格式的字符串,可以在定义Agent的时候使用 reflect_on_tool_use=True
参数让Agent帮你将字符串整理成自然语言,本质还是调用LLM。因为Team内部广播或者沟通的基本单元仍然是一个封装好自然语言的Message。
Workflow
根据官网描述,上面定义的Team运行流程如下:
SelectorGroupChat
首先接受到一个Task任务,然后根据Agent的属性name
与descriptions
信息 自主选择 最适合的一个Agent来启动整个任务,通常情况是 Planning Agent;- Planning Agent将这个Task拆分成子任务,然后按照
<Agent>:<task>
的格式分发给对应的Agent; - 根据整个Team中的上线文环境、各个Agent的
descriptions
,SelectorGroupChat
动态选择下一个与LLM进行对话的Agent; - Web Search Agent执行一次搜索动作,并将LLM返回的结果保存在共享的记录中;
- 如果Data Analyst Agent被选中,那么就使用tools来处理数据;
- 整个Team的终止条件是如果子任务中检测到
TERMINATE
或者其他终止条件;
【注意】:在自定义Agent的时候,尽量将descriptions
写成 精炼、完备、排他,因为SelectorGroupChat
会根据Team内的所有Agent的描述进行决策下一个与LLM对话的是哪个Agent;
Termination Conditions
官方在这里定义了两个终止条件TextMentionTermination
和MaxMessageTermination
,这两个终止条件我们在前面已经用了很多次了,分别是文本关键字终止和最大组内沟通信息条数终止;
text_mention_termination = TextMentionTermination("TERMINATE")
max_messages_termination = MaxMessageTermination(max_messages=25)
termination = text_mention_termination | max_messages_termination
Selector Prompt
SelectorGroupChat
基于组内的上下文环境来选择下一个与LLM对话的Agent,因此这里我们自己写一个prompt来告诉SelectorGroupChat
选择Agent的依据是什么:
selector_prompt = """Select an agent to perform task.{roles}Current conversation context:
{history}Read the above conversation, then select an agent from {participants} to perform the next task.
Make sure the planner agent has assigned tasks before other agents start working.
Only select one agent.
"""
官网在如何设置这个prompt时给了以下几个Tips:
- 这个提示词不要写的太长,防止选择器过载;
- 如何判断自己提示词是不是过长了,这个是根据LLM模型规模决定的,如果你使用的模型是GPT-4o的话就可以写稍微长一点,但模型规模较小时就不能太长,官方提供的上面demo就是对于小模型设计的;
- 如果你对每一个Agent都写了多个条件,那么其实最适合的是使用自定义选择函数,由
SelectorGroupChat
自主选择的初衷是减少你的工作量;
Running the Team
然后将上面我们提到的Agent、终止条件、自定义选择prompt结合起来形成一个Team:
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, # Allow an agent to speak multiple turns in a row.
)
然后再定义一个传给Team的任务:
task = "Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?"
那么完整代码如下:
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.conditions import TextMentionTermination, MaxMessageTermination
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.ui import Consoleimport asyncio, osos.environ["OPENAI_API_KEY"] = "你的OpenAI API Key"#-----------------------------------------------------------------------------#
# Part1. 定义两个搜索工具
def search_web_tool(query: str) -> str:if "2006-2007" in query:return """Here are the total points scored by Miami Heat players in the 2006-2007 season:Udonis Haslem: 844 pointsDwayne Wade: 1397 pointsJames Posey: 550 points..."""elif "2007-2008" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214."elif "2008-2009" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398."return "No data found."def percentage_change_tool(start: float, end: float) -> float:return ((end - start) / start) * 100#-----------------------------------------------------------------------------#
# Part2. 定义三个Agent和model
model_client = OpenAIChatCompletionClient(model="gpt-4o")planning_agent = AssistantAgent("PlanningAgent",description="An agent for planning tasks, this agent should be the first to engage when given a new task.",model_client=model_client,system_message="""You are a planning agent.Your job is to break down complex tasks into smaller, manageable subtasks.Your team members are:WebSearchAgent: Searches for informationDataAnalystAgent: Performs calculationsYou only plan and delegate tasks - you do not execute them yourself.When assigning tasks, use this format:1. <agent> : <task>After all tasks are complete, summarize the findings and end with "TERMINATE".""",
)web_search_agent = AssistantAgent("WebSearchAgent",description="An agent for searching information on the web.",tools=[search_web_tool],model_client=model_client,system_message="""You are a web search agent.Your only tool is search_tool - use it to find information.You make only one search call at a time.Once you have the results, you never do calculations based on them.""",
)data_analyst_agent = AssistantAgent("DataAnalystAgent",description="An agent for performing calculations.",model_client=model_client,tools=[percentage_change_tool],system_message="""You are a data analyst.Given the tasks you have been assigned, you should analyze the data and provide results using the tools provided.If you have not seen the data, ask for it.""",
)#-----------------------------------------------------------------------------#
# Part3. 定义Team的终止条件
text_mention_termination = TextMentionTermination("TERMINATE")
max_messages_termination = MaxMessageTermination(max_messages=25)
termination = text_mention_termination | max_messages_terminationselector_prompt = """Select an agent to perform task.{roles}Current conversation context:
{history}Read the above conversation, then select an agent from {participants} to perform the next task.
Make sure the planner agent has assigned tasks before other agents start working.
Only select one agent.
"""#-----------------------------------------------------------------------------#
# Part4. 定义任务Task
task = "Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?"#-----------------------------------------------------------------------------#
# Part5. 将Agent、model、终止条件、prompt组合成一个team
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, # Allow an agent to speak multiple turns in a row.
)#-----------------------------------------------------------------------------#
# Part6. 运行team
asyncio.run(Console(team.run_stream(task=task))
)
运行结果如下,从输出内容来看除了实际执行的部分,其他都是Team内部上下文同步的过程,感兴趣的可以自己运行看看他们的同步逻辑:
$ python demo.py
Custom Selector Function
上面提到了你也可以自定义选择函数,但如果你自定义的选择函数返回的是 None
对象那么 SelectorGroupChat
仍然会使用基于LLM模型的Agent选择。
这里官方demo中自定义选择函数非常简单,当组内最新的消息不是由PlanningAgent生成时,就直接调用PlanningAgent,否则让LLM来选择,实际上就是每执行一步都让PlanningAgent重新规划一下:
def selector_func(messages: Sequence[AgentEvent | ChatMessage]) -> str | None:if messages[-1].source != planning_agent.name:return planning_agent.namereturn None
然后需要在定义Team的时候就将选择函数设置进去:
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,
)
完成代码如下:
from autogen_agentchat.agents import AssistantAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.conditions import TextMentionTermination, MaxMessageTermination
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.ui import Console
from autogen_agentchat.messages import ChatMessage, AgentEvent
from typing import Sequenceimport asyncio, osos.environ["OPENAI_API_KEY"] = "你的OpenAI API Key"def search_web_tool(query: str) -> str:if "2006-2007" in query:return """Here are the total points scored by Miami Heat players in the 2006-2007 season:Udonis Haslem: 844 pointsDwayne Wade: 1397 pointsJames Posey: 550 points..."""elif "2007-2008" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214."elif "2008-2009" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398."return "No data found."def percentage_change_tool(start: float, end: float) -> float:return ((end - start) / start) * 100model_client = OpenAIChatCompletionClient(model="gpt-4o")planning_agent = AssistantAgent("PlanningAgent",description="An agent for planning tasks, this agent should be the first to engage when given a new task.",model_client=model_client,system_message="""You are a planning agent.Your job is to break down complex tasks into smaller, manageable subtasks.Your team members are:WebSearchAgent: Searches for informationDataAnalystAgent: Performs calculationsYou only plan and delegate tasks - you do not execute them yourself.When assigning tasks, use this format:1. <agent> : <task>After all tasks are complete, summarize the findings and end with "TERMINATE".""",
)web_search_agent = AssistantAgent("WebSearchAgent",description="An agent for searching information on the web.",tools=[search_web_tool],model_client=model_client,system_message="""You are a web search agent.Your only tool is search_tool - use it to find information.You make only one search call at a time.Once you have the results, you never do calculations based on them.""",
)data_analyst_agent = AssistantAgent("DataAnalystAgent",description="An agent for performing calculations.",model_client=model_client,tools=[percentage_change_tool],system_message="""You are a data analyst.Given the tasks you have been assigned, you should analyze the data and provide results using the tools provided.If you have not seen the data, ask for it.""",
)text_mention_termination = TextMentionTermination("TERMINATE")
max_messages_termination = MaxMessageTermination(max_messages=25)
termination = text_mention_termination | max_messages_terminationselector_prompt = """Select an agent to perform task.{roles}Current conversation context:
{history}Read the above conversation, then select an agent from {participants} to perform the next task.
Make sure the planner agent has assigned tasks before other agents start working.
Only select one agent.
"""task = "Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?"# 上面部分完全一致
#-----------------------------------------------------------------------------#
# Part1. 定义选择函数
def selector_func(messages: Sequence[AgentEvent | ChatMessage]) -> str | None:if messages[-1].source != planning_agent.name:return planning_agent.namereturn None# Part2. 设置team使用自己的选择函数
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,
)# Part3. 运行team
asyncio.run(Console(team.run_stream(task=task))
)
运行结果如下:
$ python demo.py
User Feedback
在之前的文章 AutoGen学习笔记系列(五)Tutorial -Human-in-the-Loop 中提到了 “人在回路” 策略,让人在Team走向的 关键节点 上让人来决策。在这里我们同样可以使用 UserProxyAgent
将人在回路策略引入 SelectorGroupChat
中:
首先定义 UserProxyAgent
和选择函数,在选择函数中使用 Agent 以实现人在回路,这里的逻辑如下:
- 首先第一次使用 PlanningAgent 激活整个Team的Task;
- PlanningAgent通过LLM得到下一个想要执行的Agent名;
- 由人来确认是否使用这个Agent,允许就输入
APPROVE
,否则会打回给LLM重新选择一个再来确认;
# 定义 UserProxyAgent
user_proxy_agent = UserProxyAgent("UserProxyAgent", description="A proxy for the user to approve or disapprove tasks.")# 定义使用 UserProxyAgent 的选择函数
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:# 必须让PlanningAgent作为第一个被调用的,否则任务无法启动return planning_agent.nameif messages[-1].source == planning_agent.name:if messages[-2].source == user_proxy_agent.name and "APPROVE" in messages[-1].content.upper(): # type: ignore# 如果检测到了人输入的 APPROVE 则确认下一个Agent是被被使用return Nonereturn user_proxy_agent.nameif messages[-1].source == user_proxy_agent.name:# 如果人输入的不是 APPROVE 则让 PlanningAgent重新选择if "APPROVE" not in messages[-1].content.upper(): # type: ignorereturn planning_agent.namereturn None
完整代码如下:
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.conditions import TextMentionTermination, MaxMessageTermination
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.ui import Console
from autogen_agentchat.messages import ChatMessage, AgentEvent
from typing import Sequenceimport asyncio, osos.environ["OPENAI_API_KEY"] = "你的OpenAI API Key"def search_web_tool(query: str) -> str:if "2006-2007" in query:return """Here are the total points scored by Miami Heat players in the 2006-2007 season:Udonis Haslem: 844 pointsDwayne Wade: 1397 pointsJames Posey: 550 points..."""elif "2007-2008" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214."elif "2008-2009" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398."return "No data found."def percentage_change_tool(start: float, end: float) -> float:return ((end - start) / start) * 100model_client = OpenAIChatCompletionClient(model="gpt-4o")planning_agent = AssistantAgent("PlanningAgent",description="An agent for planning tasks, this agent should be the first to engage when given a new task.",model_client=model_client,system_message="""You are a planning agent.Your job is to break down complex tasks into smaller, manageable subtasks.Your team members are:WebSearchAgent: Searches for informationDataAnalystAgent: Performs calculationsYou only plan and delegate tasks - you do not execute them yourself.When assigning tasks, use this format:1. <agent> : <task>After all tasks are complete, summarize the findings and end with "TERMINATE".""",
)web_search_agent = AssistantAgent("WebSearchAgent",description="An agent for searching information on the web.",tools=[search_web_tool],model_client=model_client,system_message="""You are a web search agent.Your only tool is search_tool - use it to find information.You make only one search call at a time.Once you have the results, you never do calculations based on them.""",
)data_analyst_agent = AssistantAgent("DataAnalystAgent",description="An agent for performing calculations.",model_client=model_client,tools=[percentage_change_tool],system_message="""You are a data analyst.Given the tasks you have been assigned, you should analyze the data and provide results using the tools provided.If you have not seen the data, ask for it.""",
)text_mention_termination = TextMentionTermination("TERMINATE")
max_messages_termination = MaxMessageTermination(max_messages=25)
termination = text_mention_termination | max_messages_terminationselector_prompt = """Select an agent to perform task.{roles}Current conversation context:
{history}Read the above conversation, then select an agent from {participants} to perform the next task.
Make sure the planner agent has assigned tasks before other agents start working.
Only select one agent.
"""task = "Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?"# 上面部分完全一致
#-----------------------------------------------------------------------------#
# Part1. 定义 UserProxyAgent
user_proxy_agent = UserProxyAgent("UserProxyAgent", description="A proxy for the user to approve or disapprove tasks.")# Part2. 定义使用 UserProxyAgent 的选择函数
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.nameif messages[-1].source == planning_agent.name:if messages[-2].source == user_proxy_agent.name and "APPROVE" in messages[-1].content.upper(): # type: ignorereturn Nonereturn user_proxy_agent.nameif messages[-1].source == user_proxy_agent.name:if "APPROVE" not in messages[-1].content.upper(): # type: ignorereturn planning_agent.namereturn None# Part2. 设置team使用自己的选择函数
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,
)# Part3. 运行team
asyncio.run(Console(team.run_stream(task=task))
)
运行结果如下,可以发现每到选择Agent的时候都会等待人进行决策:
$ python demo.py
Using Reasoning Models
上面所有的demo都是基于 gpt-4o
或 Gemini
这种满血大模型,根据上面小节 Selector Prompt
提到的几个 tips 内容,对于像 o3-mini
这种小模型而言还是要尽可能写短描述选择的prompt,而是让模型自行决策,这样可以减小模型本身的压力。官方在下面的示例中使用 o3-mini
作为模型:
from autogen_agentchat.agents import AssistantAgent, UserProxyAgent
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.conditions import TextMentionTermination, MaxMessageTermination
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.ui import Console
from autogen_agentchat.messages import ChatMessage, AgentEvent
from typing import Sequenceimport asyncio, osos.environ["OPENAI_API_KEY"] = "你的OpenAI API Key"def search_web_tool(query: str) -> str:if "2006-2007" in query:return """Here are the total points scored by Miami Heat players in the 2006-2007 season:Udonis Haslem: 844 pointsDwayne Wade: 1397 pointsJames Posey: 550 points..."""elif "2007-2008" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214."elif "2008-2009" in query:return "The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398."return "No data found."def percentage_change_tool(start: float, end: float) -> float:return ((end - start) / start) * 100text_mention_termination = TextMentionTermination("TERMINATE")
max_messages_termination = MaxMessageTermination(max_messages=25)
termination = text_mention_termination | max_messages_terminationtask = "Who was the Miami Heat player with the highest points in the 2006-2007 season, and what was the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons?"# 上面部分完全一致
#-----------------------------------------------------------------------------#
model_client = OpenAIChatCompletionClient(model="o3-mini")web_search_agent = AssistantAgent("WebSearchAgent",description="An agent for searching information on the web.",tools=[search_web_tool],model_client=model_client,system_message="""Use web search tool to find information.""",
)data_analyst_agent = AssistantAgent("DataAnalystAgent",description="An agent for performing calculations.",model_client=model_client,tools=[percentage_change_tool],system_message="""Use tool to perform calculation. If you have not seen the data, ask for it.""",
)user_proxy_agent = UserProxyAgent("UserProxyAgent",description="A user to approve or disapprove tasks.",
)selector_prompt = """Select an agent to perform task.
{roles}Current conversation context:
{history}Read the above conversation, then select an agent from {participants} to perform the next task.
When the task is complete, let the user approve or disapprove the task.
"""team = SelectorGroupChat([web_search_agent, data_analyst_agent, user_proxy_agent],model_client=model_client,termination_condition=termination, # Use the same termination condition as before.selector_prompt=selector_prompt,allow_repeated_speaker=True,
)# Part3. 运行team
asyncio.run(Console(team.run_stream(task=task))
)
运行结果如下,如果你运行的话会发现这个过程慢了不少,而且很容易出现一个Agent不停被循环调用的情况,大小模型之间的差异还是很明显的:
$ python demo.py
相关文章:

AutoGen学习笔记系列(九)Advanced - Selector Group Chat
这篇文章瞄的是AutoGen官方教学文档 Advanced 章节中的 Selector Group Chat 篇章,介绍了SelectorGroupChat对象如何从一个Team中选择其中一个Agent与LLM进行对话,并且在得到结果后进行二次规划,同时你也可以自定义选择函数。本质上还是对Tea…...

Stream特性(踩坑):惰性执行、不修改原始数据源
在日常开发中,Stream API 提供了一种高效且易于使用的工具集来处理集合数据。 本文主要讲解 Stream 的两个特性:惰性执行,不修改原始数据源。 为什么说这两个、而不讲下其他的特性呢?主要是因为在开发中如果忽略这两个特性的话&…...

springcloud sentinel教程
QPS(Queries Per Second)即每秒查询率 TPS,每秒处理的事务数目 PV(page view)即页面浏览量 UV 访问数(Unique Visitor)指独立访客访问数 一、初识Sentinel 什么是雪崩问题? 微服务之间相…...

像素的一生 Life of a Pixel - Steve Kobes 2020版
像素的一生 Life of a Pixel - Steve Kobes 2020版 《Life of a Pixel》 作者是Google大佬 Steve Kobes 2020年 介绍Chromium内核完整渲染流程的视频,介绍的非常好,想要学习了解chromium内核渲染必看! 油管视频地址为:https://w…...

系统部署【信创名录】及其查询地址
一、信创类型 (一)服务器: 1.华为云 2.腾讯云 3.阿里云 (二)中央处理器(CPU): 1.海思,鲲鹏920服务器 (三)中间件 1.人大金仓 ࿰…...

VSCode 配置优化指南:打造高效的 uni-app、Vue2/3、JS/TS 开发环境
VSCode 配置优化指南,适用于 uni-app、Vue2、Vue3、JavaScript、TypeScript 开发,包括插件推荐、设置优化、代码片段、调试配置等,确保你的开发体验更加流畅高效。 1. 安装 VSCode 如果你还未安装 VSCode,可前往 VSCode 官网 下载最新版并安装。 2. 安装推荐插件 (1) Vue…...

C++中的析构函数
目录 一、什么是析构函数: 二、析构函数的特性: 一、什么是析构函数: C中的析构函数非常简单,它的功能无非是帮助我们自动归还堆区的空间给操作系统。当我们使用内存开辟函数(如malloc()、realloc())等&a…...

同步,异步,并发,并行
同步: 任务按顺序执行,必须等待前一个任务完成后才能开始下一个任务。 任务之间是强依赖的,通过直接调用或阻塞等待实现。 示例:读取文件时,代码会阻塞直到文件读取完成。 异步: 任务无需等待前一个任务完成即可启…...

种子填充(Floodfill、泛滥填充、洪水填充) 算法c++模板
种子填充(Floodfill) 算法: 从任意 W 开始,不停地把邻接的 W 用 . 代替。1 次 DFS 后与初始 W 连接的所有 W 都被替换成 . 了。 因此,直到图中不存在 W 为止,总共进行 DFS 的次数就是答案了。 问题: 有一个大小为 N x M 的园子,雨后积水。 8 连通的积水被认为是连接在…...

MATLAB控制函数测试要点剖析
一、功能准确性检验 基础功能核验 针对常用控制函数,像用于传递函数建模的 tf 、构建状态空间模型的 ss ,以及开展阶跃响应分析的 step 等,必须确认其能精准执行基础操作。以 tf 函数为例,在输入分子与分母系数后,理…...

【新手指南】pyqt可视化远程部署deepseek7B蒸馏版模型
本地效果:(如果想做这个的本科毕设,建议美化界面。) 总结:MobaXterm远程连接autodl服务器,在MobaXterm上利用X11转发使pyqt可视化页面在自己的电脑上展现出来。 1. 官网下载MobaXterm MobaXterm free Xse…...

大语言模型在患者交互任务中的临床使用评估框架
An evaluation framework for clinical use of large language models in patient interaction tasks An evaluation framework for clinical use of large language models in patient interaction tasks | Nature Medicine 2025.1 收到时间:2023 年 8 月 8 日 …...

DeepSeek-V3 技术报告解读
DeepSeek火了有一段时间了,春节假期因为没时间,所以关于deepseek大模型一系列的技术报告一直没看,新年开工后,抽一点时间把之前的坑补起来,关于DeepSeek-V3技术报告的解读已经有很多了,但我相信不同的人去读…...

suricata安装测试
系统版本为Ubuntu 22.04.4。 # cat /etc/issue Ubuntu 22.04.4 LTS \n \l # # uname -a Linux logging 6.8.0-49-generic #49~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Nov 6 17:42:15 UTC 2 x86_64 x86_64 x86_64 GNU/Linux添加suricata的apt库。 # add-apt-repository pp…...

Java反射简单理解
Java反射是指在运行时(runtime)能够动态地获取类的内部信息,并能直接操作类的属性和方法的一种机制。通过反射,开发者可以在运行时检查类、接口、字段和方法,并且可以调用这些方法和访问这些字段,而无需在编…...

WPS Word中英文混杂空格和行间距不一致调整方案
文章目录 问题1:在两端对齐的情况下,如何删除参考文献(英文)的空格问题2:中英文混杂行间距不一致问题问题3:设置中文为固定字体,设置西文为固定字体参考 问题1:在两端对齐的情况下&a…...

探秘沃尔什-哈达玛变换(WHT)原理
沃尔什-哈达玛变换(WHT)起源 起源与命名(20世纪早期) 数学基础:该变换的理论基础由法国数学家雅克哈达玛(Jacques Hadamard)在1893年提出,其核心是哈达玛矩阵的构造。扩展与命名&…...

优雅拼接字符串:StringJoiner 的完整指南
在Java开发中,字符串拼接是高频操作。无论是日志格式化、构建CSV数据,还是生成动态SQL,开发者常需处理分隔符、前缀和后缀的组合。传统的StringBuilder虽然灵活,但代码冗余且易出错。Java 8推出的StringJoiner类,以简洁…...

AFL++安装
学习fuzzing也几天了,今天记录AFL的安装及使用 一、实验环境 虚拟机:ubuntu20.04 当然也可以uname -a去看自己的版本号 二、AFL安装 1.先更新一下工具 sudo apt update2.安装AFL必要的一些依赖,例如编译工具(如 build-essen…...

开发者社区测试报告(功能测试+性能测试)
功能测试 测试相关用例 开发者社区功能背景 在当今数字化时代,编程已经成为一项核心技能,越来越多的人开始学习编程,以适应快速变化的科技 环境。基于这一需求,我设计开发了一个类似博客的论坛系统,专注于方便程序员…...

如何优化 VS Code 远程开发环境?高效配置与性能提升策略
相关系列文章 《新手教学系列——善用 VSCode 工作区,让开发更高效》 《新手教学系列——用 VSCode 实现高效远程开发》 《Webpack 优化全攻略:彻底解决 Vue 项目 npm run dev 的内存泄露问题》 引言 随着开发环境不断进化,VS Code 作为一款轻量级的代码编辑器,已经成为…...

【二】JavaScript能力提升---this对象
目录 this的理解 this的原理 事件绑定中的this 行内绑定 动态绑定 window定时器中的this 相信小伙伴们看完这篇文章,对于this的对象可以有一个很大的提升! this的理解 对于this指针,可以先记住以下两点: this永远指向一个…...

YC 孵化项目 Pinch:实时语音翻译视频会议平台;Mistral OCR:能处理多语言多模态复杂文档丨日报
开发者朋友们大家好: 这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。 我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 技术 」、「有亮点的 产品 」、「有思考的 文章 」、「有态度的 …...

OSPF报文分析
OSPF报文分析 组播地址 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用; 224.0.1.0~238.255.255.255为用户可用的组播地址(…...

蓝桥杯刷题周计划(第二周)
目录 前言题目一题目代码题解分析 题目二题目代码题解分析 题目三题目代码题解分析 题目四题目代码题解分析 题目五题目代码题解分析 题目六题目代码题解分析 题目七题目代码题解分析 题目八题目题解分析 题目九题目代码题解分析 题目十题目代码题解分析 题目十一题目代码题解分…...

PH热榜 | 2025-03-09
1. ResumeUp 2.0 标语:聊聊,几分钟内就能帮助你打造完美的ATS简历。 介绍:告别为写完美简历而烦恼的日子吧!只需与人工智能聊天,回答几个简单的问题,就能在几分钟内生成强有力的简历,不仅能通…...

《gradio :AI demos》
《gradio :AI demos》 Folders and files Name Last commit message Last commit date parent directory .. agent_chatbot Declare exports in __all__ for type checking (#10238) 3 months ago all_demos Fix deployed Spaces (#10271) 2 months ago …...

Interop_UdsProtocolStack之数据解析器使用方法
一、背景与需求 在汽车电子领域,UDS(Unified Diagnostic Services)协议栈的响应报文解析是实现ECU诊断功能的核心环节。本文提出一种基于配置驱动的通用解析器开发方案,满足以下行业需求: 多协议兼容性:支…...

从0开始完成基于异步服务器的boost搜索引擎
文章目录 前言一、本项目涉及的技术栈和环境二、boost是什么?三、项目的相关背景四、项目的相关原理五、正排索引 vs 倒排索引 - 搜索引擎具体原理六、 编写数据去标签与数据清洗的模块 Parser6.1 下载boost的文档库6.2 去标签6.3 代码编写 七、索引模块7.1. 整体框…...

炒菜本质是 “能量(火候)与食材特性”的动态平衡
炒菜看似简单,但想要做到色香味俱全,需遵循一套清晰的逻辑链条。以下从底层逻辑到实操步骤拆解: 一、核心逻辑:控制变量,精准匹配 炒菜本质是 “能量(火候)与食材特性”的动态平衡,…...