From 02ef110e10e464535c873f911171deafe280c9b4 Mon Sep 17 00:00:00 2001 From: Gerardo Moreno Date: Sat, 23 Nov 2024 21:36:32 -0800 Subject: [PATCH] Selector Group Chat Tutorial (#4112) (#4326) * Selector Group Chat Tutorial (#4112) * update doc * update * Add custom selector function * Update doc --------- Co-authored-by: Eric Zhu --- .../docs/drawio/selector-group-chat.drawio | 52 ++ .../tutorial/selector-group-chat.ipynb | 503 ++++++++++++------ .../tutorial/selector-group-chat.svg | 3 + .../agentchat-user-guide/tutorial/swarm.ipynb | 12 +- .../agentchat-user-guide/tutorial/teams.ipynb | 9 +- 5 files changed, 407 insertions(+), 172 deletions(-) create mode 100644 python/packages/autogen-core/docs/drawio/selector-group-chat.drawio create mode 100644 python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.svg diff --git a/python/packages/autogen-core/docs/drawio/selector-group-chat.drawio b/python/packages/autogen-core/docs/drawio/selector-group-chat.drawio new file mode 100644 index 00000000000..ad363bfd7fa --- /dev/null +++ b/python/packages/autogen-core/docs/drawio/selector-group-chat.drawio @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.ipynb b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.ipynb index 0a3bb0fe313..3377d3d47c3 100644 --- a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.ipynb +++ b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.ipynb @@ -11,46 +11,61 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `SelectorGroupChat` implements a team coordination pattern where participants take turns publishing messages, with the next speaker selected by a generative model (LLM) based on the conversation context. This enables dynamic and context-aware multi-agent conversations.\n", + "{py:class}`~autogen_agentchat.teams.SelectorGroupChat` implements a team where participants take turns broadcasting messages to all other participants,\n", + "with the next speaker selected by a generative model (e.g., an LLM) based on the shared context. \n", + "This enables dynamic and context-aware multi-agent collaboration.\n", "\n", - "\n", - "`SelectorGroupChat` provides several key features:\n", - "- Dynamic speaker selection using an LLM to analyze conversation context\n", + "{py:class}`~autogen_agentchat.teams.SelectorGroupChat` provides several key features:\n", + "- Model-based speaker selection\n", "- Configurable participant roles and descriptions\n", "- Optional prevention of consecutive turns by the same speaker\n", "- Customizable selection prompting\n", + "- Customizable selection function to override the default model-based selection\n", + "\n", + "```{note}\n", + "{py:class}`~autogen_agentchat.teams.SelectorGroupChat` is a high-level API.\n", + "If you need more control and customization that is not supported by this API,\n", + "you can take a look at the [Group Chat Pattern](../../core-user-guide/design-patterns/group-chat.ipynb)\n", + "in the Core API documentation and implement your own group chat logic.\n", + "```\n", + "\n", + "## How does it work?\n", "\n", + "{py:class}`~autogen_agentchat.teams.SelectorGroupChat` is a group chat similar to {py:class}`~autogen_agentchat.teams.RoundRobinGroupChat`,\n", + "but with a model-based next speaker selection mechanism.\n", + "When the team receives a task through {py:meth}`~autogen_agentchat.teams.BaseGroupChat.run` or {py:meth}`~autogen_agentchat.teams.BaseGroupChat.run_stream`,\n", + "the following steps are executed:\n", "\n", - "### Speaker Selection Process\n", + "1. The team analyzes the current conversation context, including the conversation history and participants' {py:attr}`~autogen_agentchat.base.ChatAgent.name` and {py:attr}`~autogen_agentchat.base.ChatAgent.description` attributes, to determine the next speaker using a model. You can override the model by providing a custom selection function.\n", + "2. The team prompts the selected speaker agent to provide a response, which is then **broadcasted** to all other participants.\n", + "3. The termination condition is checked to determine if the conversation should end, if not, the process repeats from step 1.\n", + "4. When the conversation ends, the team returns the {py:class}`~autogen_agentchat.base.TaskResult` containing the conversation history from this task.\n", "\n", - "The chat uses an LLM to select the next speaker by:\n", - "1. Analyzing the conversation history\n", - "2. Evaluating participant roles and descriptions\n", - "3. Using a configurable prompt template to make the selection\n", - "4. Validating that exactly one participant is selected\n", - "\n" + "Once the team finishes the task, the conversation context is kept within the team and all participants, so the next task can continue from the previous conversation context.\n", + "You can reset the conversation context by calling {py:meth}`~autogen_agentchat.teams.BaseGroupChat.reset`.\n", + "\n", + "In this section, we will demonstrate how to use {py:class}`~autogen_agentchat.teams.SelectorGroupChat` with a simple example for a web search and data analysis task." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Web Search and Analysis Example" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ - "import asyncio\n", - "from typing import List, Sequence\n", + "from typing import Sequence\n", "\n", - "from autogen_agentchat.agents import (\n", - " BaseChatAgent,\n", - " CodingAssistantAgent,\n", - " ToolUseAssistantAgent,\n", - ")\n", - "from autogen_agentchat.base import Response\n", - "from autogen_agentchat.messages import ChatMessage, StopMessage, TextMessage\n", - "from autogen_agentchat.task import TextMentionTermination\n", + "from autogen_agentchat.agents import AssistantAgent\n", + "from autogen_agentchat.messages import AgentMessage\n", + "from autogen_agentchat.task import Console, MaxMessageTermination, TextMentionTermination\n", "from autogen_agentchat.teams import SelectorGroupChat\n", - "from autogen_core.base import CancellationToken\n", - "from autogen_core.components.tools import FunctionTool\n", "from autogen_ext.models import OpenAIChatCompletionClient" ] }, @@ -58,61 +73,167 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Defining Agents\n", - "The `UserProxyAgent` allows the user to input messages directly. This agent waits for user input and returns a text message or a stop message if the user decides to terminate the conversation." + "### Agents\n", + "\n", + "![Selector Group Chat](selector-group-chat.svg)\n", + "\n", + "This system uses three specialized agents:\n", + "\n", + "- **Planning Agent**: The strategic coordinator that breaks down complex tasks into manageable subtasks. \n", + "- **Web Search Agent**: An information retrieval specialist that interfaces with the `search_web_tool`.\n", + "- **Data Analyst Agent**: An agent specialist in performing calculations equipped with `percentage_change_tool`. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tools `search_web_tool` and `percentage_change_tool` are external tools that the agents can use to perform their tasks." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ - "class UserProxyAgent(BaseChatAgent):\n", - " def __init__(self, name: str) -> None:\n", - " super().__init__(name, \"A human user.\")\n", - "\n", - " @property\n", - " def produced_message_types(self) -> List[type[ChatMessage]]:\n", - " return [TextMessage, StopMessage]\n", - "\n", - " async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> Response:\n", - " user_input = await asyncio.get_event_loop().run_in_executor(None, input, \"Enter your response: \")\n", - " if \"TERMINATE\" in user_input:\n", - " return Response(chat_message=StopMessage(content=\"User has terminated the conversation.\", source=self.name))\n", - " return Response(chat_message=TextMessage(content=user_input, source=self.name))\n", - "\n", - " async def on_reset(self, cancellation_token: CancellationToken) -> None:\n", - " pass" + "# Note: This example uses mock tools instead of real APIs for demonstration purposes\n", + "def search_web_tool(query: str) -> str:\n", + " if \"2006-2007\" in query:\n", + " return \"\"\"Here are the total points scored by Miami Heat players in the 2006-2007 season:\n", + " Udonis Haslem: 844 points\n", + " Dwayne Wade: 1397 points\n", + " James Posey: 550 points\n", + " ...\n", + " \"\"\"\n", + " elif \"2007-2008\" in query:\n", + " return \"The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.\"\n", + " elif \"2008-2009\" in query:\n", + " return \"The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.\"\n", + " return \"No data found.\"\n", + "\n", + "\n", + "def percentage_change_tool(start: float, end: float) -> float:\n", + " return ((end - start) / start) * 100" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's create the specialized agents using the {py:class}`~autogen_agentchat.agents.AssistantAgent` class.\n", + "It is important to note that the agents' {py:attr}`~autogen_agentchat.base.ChatAgent.name` and {py:attr}`~autogen_agentchat.base.ChatAgent.description` attributes are used by the model to determine the next speaker,\n", + "so it is recommended to provide meaningful names and descriptions." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ - "async def flight_search(start: str, destination: str, date: str) -> str:\n", - " return \"\\n\".join(\n", - " [\n", - " f\"AC24 from {start} to {destination} on {date} is $500\",\n", - " f\"UA23 from {start} to {destination} on {date} is $450\",\n", - " f\"AL21 from {start} to {destination} on {date} is $400\",\n", - " ]\n", - " )\n", - "\n", - "\n", - "async def flight_booking(flight: str, date: str) -> str:\n", - " return f\"Booked flight {flight} on {date}\"" + "model_client = OpenAIChatCompletionClient(model=\"gpt-4o\")\n", + "\n", + "planning_agent = AssistantAgent(\n", + " \"PlanningAgent\",\n", + " description=\"An agent for planning tasks, this agent should be the first to engage when given a new task.\",\n", + " model_client=model_client,\n", + " system_message=\"\"\"\n", + " You are a planning agent.\n", + " Your job is to break down complex tasks into smaller, manageable subtasks.\n", + " Your team members are:\n", + " Web search agent: Searches for information\n", + " Data analyst: Performs calculations\n", + "\n", + " You only plan and delegate tasks - you do not execute them yourself.\n", + "\n", + " When assigning tasks, use this format:\n", + " 1. : \n", + "\n", + " After all tasks are complete, summarize the findings and end with \"TERMINATE\".\n", + " \"\"\",\n", + ")\n", + "\n", + "web_search_agent = AssistantAgent(\n", + " \"WebSearchAgent\",\n", + " description=\"A web search agent.\",\n", + " tools=[search_web_tool],\n", + " model_client=model_client,\n", + " system_message=\"\"\"\n", + " You are a web search agent.\n", + " Your only tool is search_tool - use it to find information.\n", + " You make only one search call at a time.\n", + " Once you have the results, you never do calculations based on them.\n", + " \"\"\",\n", + ")\n", + "\n", + "data_analyst_agent = AssistantAgent(\n", + " \"DataAnalystAgent\",\n", + " description=\"A data analyst agent. Useful for performing calculations.\",\n", + " model_client=model_client,\n", + " tools=[percentage_change_tool],\n", + " system_message=\"\"\"\n", + " You are a data analyst.\n", + " Given the tasks you have been assigned, you should analyze the data and provide results using the tools provided.\n", + " \"\"\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Workflow\n", + "\n", + "1. The task is received by the {py:class}`~autogen_agentchat.teams.SelectorGroupChat` which, based on agent descriptions, selects the most appropriate agent to handle the initial task (typically the Planning Agent).\n", + "\n", + "2. The **Planning Agent** analyzes the task and breaks it down into subtasks, assigning each to the most appropriate agent using the format:\n", + " ` : `\n", + "\n", + "3. Based on the conversation context and agent descriptions, the {py:class}`~autogen_agent.teams.SelectorGroupChat` manager dynamically selects the next agent to handle their assigned subtask.\n", + "\n", + "4. The **Web Search Agent** performs searches one at a time, storing results in the shared conversation history.\n", + "\n", + "5. The **Data Analyst** processes the gathered information using available calculation tools when selected.\n", + "\n", + "6. The workflow continues with agents being dynamically selected until either:\n", + " - The Planning Agent determines all subtasks are complete and sends \"TERMINATE\"\n", + " - An alternative termination condition is met (e.g., a maximum number of messages)\n", + "\n", + "When defining your agents, make sure to include a helpful {py:attr}`~autogen_agentchat.base.ChatAgent.description` since this is used to decide which agent to select next." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The `ToolUseAssistantAgent` is responsible for calling external tools. In this example, two tools are defined: `flight_search` and `flight_booking`.\n", + "Let's create the team with two termination conditions:\n", + "{py:class}`~autogen_agentchat.task.TextMentionTermination` to end the conversation when the Planning Agent sends \"TERMINATE\",\n", + "and {py:class}`~autogen_agentchat.task.MaxMessageTermination` to limit the conversation to 25 messages to avoid infinite loop." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "text_mention_termination = TextMentionTermination(\"TERMINATE\")\n", + "max_messages_termination = MaxMessageTermination(max_messages=25)\n", + "termination = text_mention_termination | max_messages_termination\n", "\n", - "Additionally, the `CodingAssistantAgent` serves as a general travel assistant with predefined behavior specified in the `system_message`." + "team = SelectorGroupChat(\n", + " [planning_agent, web_search_agent, data_analyst_agent],\n", + " model_client=OpenAIChatCompletionClient(model=\"gpt-4o-mini\"),\n", + " termination_condition=termination,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we run the team with a task to find information about an NBA player." ] }, { @@ -124,144 +245,200 @@ "name": "stdout", "output_type": "stream", "text": [ + "---------- user ----------\n", + "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?\n", + "---------- PlanningAgent ----------\n", + "To answer your question, we need to separate this task into several subtasks:\n", "\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:35:30.283450]:\u001b[0m\n", + "1. Web search agent: Find out who was the Miami Heat player with the highest points in the 2006-2007 NBA season.\n", + "2. Web search agent: Find the total rebounds for that player in the 2007-2008 NBA season.\n", + "3. Web search agent: Find the total rebounds for that player in the 2008-2009 NBA season.\n", + "4. Data analyst: Calculate the percentage change in the player's total rebounds between the 2007-2008 and 2008-2009 seasons.\n", "\n", - "Help user plan a trip and book a flight." + "Let's start with these tasks.\n", + "[Prompt tokens: 159, Completion tokens: 130]\n", + "---------- WebSearchAgent ----------\n", + "[FunctionCall(id='call_js7ogBp0UDmHfvLo6BmWFpM1', arguments='{\"query\":\"Miami Heat player highest points 2006-2007 season\"}', name='search_web_tool')]\n", + "[Prompt tokens: 279, Completion tokens: 26]\n", + "---------- WebSearchAgent ----------\n", + "[FunctionExecutionResult(content='Here are the total points scored by Miami Heat players in the 2006-2007 season:\\n Udonis Haslem: 844 points\\n Dwayne Wade: 1397 points\\n James Posey: 550 points\\n ...\\n ', call_id='call_js7ogBp0UDmHfvLo6BmWFpM1')]\n", + "---------- WebSearchAgent ----------\n", + "[FunctionCall(id='call_G7ATvIq0rSjc8fqLdKQ5uWI4', arguments='{\"query\": \"Dwyane Wade total rebounds 2007-2008 season\"}', name='search_web_tool'), FunctionCall(id='call_Xzw9bAvgfo40EjILophG5pnl', arguments='{\"query\": \"Dwyane Wade total rebounds 2008-2009 season\"}', name='search_web_tool')]\n", + "[Prompt tokens: 371, Completion tokens: 70]\n", + "---------- WebSearchAgent ----------\n", + "[FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.', call_id='call_G7ATvIq0rSjc8fqLdKQ5uWI4'), FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.', call_id='call_Xzw9bAvgfo40EjILophG5pnl')]\n", + "---------- WebSearchAgent ----------\n", + "The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, with 1,397 points.\n", + "\n", + "Between the 2007-2008 and 2008-2009 seasons, Dwyane Wade's total rebounds increased from 214 to 398. To calculate the percentage change:\n", + "\n", + "Percentage Change = \\(\\frac{(398 - 214)}{214} \\times 100\\)\n", + "\n", + "Now, a data analyst would calculate the actual percentage change based on these numbers.\n", + "[Prompt tokens: 506, Completion tokens: 107]\n", + "---------- DataAnalystAgent ----------\n", + "[FunctionCall(id='call_76VkQ2nnKrwtuI1dmjLQ7G5P', arguments='{\"start\":214,\"end\":398}', name='percentage_change_tool')]\n", + "[Prompt tokens: 383, Completion tokens: 20]\n", + "---------- DataAnalystAgent ----------\n", + "[FunctionExecutionResult(content='85.98130841121495', call_id='call_76VkQ2nnKrwtuI1dmjLQ7G5P')]\n", + "---------- DataAnalystAgent ----------\n", + "The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade. His total rebounds increased by approximately 85.98% between the 2007-2008 and 2008-2009 seasons.\n", + "[Prompt tokens: 424, Completion tokens: 52]\n", + "---------- PlanningAgent ----------\n", + "The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, scoring 1,397 points. Between the 2007-2008 and 2008-2009 seasons, Dwyane Wade's total rebounds increased by approximately 85.98%. \n", + "\n", + "TERMINATE\n", + "[Prompt tokens: 470, Completion tokens: 66]\n", + "---------- Summary ----------\n", + "Number of messages: 11\n", + "Finish reason: Text 'TERMINATE' mentioned\n", + "Total prompt tokens: 2592\n", + "Total completion tokens: 471\n", + "Duration: 11.95 seconds\n" ] }, + { + "data": { + "text/plain": [ + "TaskResult(messages=[TextMessage(source='user', models_usage=None, content='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?'), TextMessage(source='PlanningAgent', models_usage=RequestUsage(prompt_tokens=159, completion_tokens=130), content=\"To answer your question, we need to separate this task into several subtasks:\\n\\n1. Web search agent: Find out who was the Miami Heat player with the highest points in the 2006-2007 NBA season.\\n2. Web search agent: Find the total rebounds for that player in the 2007-2008 NBA season.\\n3. Web search agent: Find the total rebounds for that player in the 2008-2009 NBA season.\\n4. Data analyst: Calculate the percentage change in the player's total rebounds between the 2007-2008 and 2008-2009 seasons.\\n\\nLet's start with these tasks.\"), ToolCallMessage(source='WebSearchAgent', models_usage=RequestUsage(prompt_tokens=279, completion_tokens=26), content=[FunctionCall(id='call_js7ogBp0UDmHfvLo6BmWFpM1', arguments='{\"query\":\"Miami Heat player highest points 2006-2007 season\"}', name='search_web_tool')]), ToolCallResultMessage(source='WebSearchAgent', models_usage=None, content=[FunctionExecutionResult(content='Here are the total points scored by Miami Heat players in the 2006-2007 season:\\n Udonis Haslem: 844 points\\n Dwayne Wade: 1397 points\\n James Posey: 550 points\\n ...\\n ', call_id='call_js7ogBp0UDmHfvLo6BmWFpM1')]), ToolCallMessage(source='WebSearchAgent', models_usage=RequestUsage(prompt_tokens=371, completion_tokens=70), content=[FunctionCall(id='call_G7ATvIq0rSjc8fqLdKQ5uWI4', arguments='{\"query\": \"Dwyane Wade total rebounds 2007-2008 season\"}', name='search_web_tool'), FunctionCall(id='call_Xzw9bAvgfo40EjILophG5pnl', arguments='{\"query\": \"Dwyane Wade total rebounds 2008-2009 season\"}', name='search_web_tool')]), ToolCallResultMessage(source='WebSearchAgent', models_usage=None, content=[FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2007-2008 is 214.', call_id='call_G7ATvIq0rSjc8fqLdKQ5uWI4'), FunctionExecutionResult(content='The number of total rebounds for Dwayne Wade in the Miami Heat season 2008-2009 is 398.', call_id='call_Xzw9bAvgfo40EjILophG5pnl')]), TextMessage(source='WebSearchAgent', models_usage=RequestUsage(prompt_tokens=506, completion_tokens=107), content=\"The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, with 1,397 points.\\n\\nBetween the 2007-2008 and 2008-2009 seasons, Dwyane Wade's total rebounds increased from 214 to 398. To calculate the percentage change:\\n\\nPercentage Change = \\\\(\\\\frac{(398 - 214)}{214} \\\\times 100\\\\)\\n\\nNow, a data analyst would calculate the actual percentage change based on these numbers.\"), ToolCallMessage(source='DataAnalystAgent', models_usage=RequestUsage(prompt_tokens=383, completion_tokens=20), content=[FunctionCall(id='call_76VkQ2nnKrwtuI1dmjLQ7G5P', arguments='{\"start\":214,\"end\":398}', name='percentage_change_tool')]), ToolCallResultMessage(source='DataAnalystAgent', models_usage=None, content=[FunctionExecutionResult(content='85.98130841121495', call_id='call_76VkQ2nnKrwtuI1dmjLQ7G5P')]), TextMessage(source='DataAnalystAgent', models_usage=RequestUsage(prompt_tokens=424, completion_tokens=52), content='The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade. His total rebounds increased by approximately 85.98% between the 2007-2008 and 2008-2009 seasons.'), TextMessage(source='PlanningAgent', models_usage=RequestUsage(prompt_tokens=470, completion_tokens=66), content=\"The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, scoring 1,397 points. Between the 2007-2008 and 2008-2009 seasons, Dwyane Wade's total rebounds increased by approximately 85.98%. \\n\\nTERMINATE\")], stop_reason=\"Text 'TERMINATE' mentioned\")" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "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?\"\n", + "\n", + "# Use asyncio.run(...) if you are running this in a script.\n", + "await Console(team.run_stream(task=task))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As we can see, after the Web Search Agent conducts the necessary searches and the Data Analyst Agent completes the necessary calculations, we find that Dwayne Wade was the Miami Heat player with the highest points in the 2006-2007 season, and the percentage change in his total rebounds between the 2007-2008 and 2008-2009 seasons is 85.98%!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Custom Selector Function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Often times we want better control over the selection process. \n", + "To this end, we can set the `selector_func` argument with a custom selector function to override the default model-based selection.\n", + "For instance, we want the Planning Agent to speak immediately after any specialized agent to check the progress.\n", + "\n", + "```{note}\n", + "Returning `None` from the custom selector function will use the default model-based selection.\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "---------- user ----------\n", + "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?\n", + "---------- PlanningAgent ----------\n", + "To solve this inquiry, let's break it down into smaller tasks again:\n", "\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:35:48.275743], User:\u001b[0m\n", - "\n", - "\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:35:50.795496], TravelAssistant:\u001b[0m\n", - "\n", - "I'd be happy to help you plan your trip! To get started, could you please provide me with the following details:\n", - "\n", - "1. Your departure city and the destination city.\n", - "2. Your travel dates (departure and return).\n", - "3. The number of travelers and their ages (if any children are involved).\n", - "4. Your budget for flights and accommodations, if you have one in mind.\n", - "5. Any specific activities or attractions you're interested in at the destination.\n", - "\n", - "Once I have this information, I can help you find the best options!\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:35:59.701486], User:\u001b[0m\n", - "\n", - "Traveling to toronto from new york\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:36:02.325330], TravelAssistant:\u001b[0m\n", - "\n", - "Great choice! Toronto is a vibrant city with a lot to offer. Now, could you please provide the following additional details to help me assist you better?\n", - "\n", - "1. What are your travel dates (departure and return)?\n", - "2. How many travelers will be going, and what are their ages?\n", - "3. Do you have a budget for the flight and accommodations?\n", - "4. Are there any specific activities or attractions you’re interested in while in Toronto?\n", - "\n", - "Once I have this information, I can help you find the best flights and suggestions for your trip!\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:36:20.633004], User:\u001b[0m\n", - "\n", - "leaving on december 7 and returning on 12\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:36:23.202871], TravelAssistant:\u001b[0m\n", - "\n", - "Thank you for the details! Here's what I have so far:\n", - "\n", - "- **Departure City:** New York\n", - "- **Destination City:** Toronto\n", - "- **Departure Date:** December 7\n", - "- **Return Date:** December 12\n", + "1. Find out who was the Miami Heat player with the highest points in the 2006-2007 NBA season.\n", + "2. Find that player's total rebounds for the 2007-2008 NBA season.\n", + "3. Find that player's total rebounds for the 2008-2009 NBA season.\n", + "4. Calculate the percentage change in the player's total rebounds from the 2007-2008 to the 2008-2009 season.\n", "\n", - "Now, could you please provide:\n", + "Let's proceed with these tasks and find the necessary information.\n", + "[Prompt tokens: 595, Completion tokens: 115]\n", + "---------- WebSearchAgent ----------\n", + "The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, who scored a total of 1,397 points.\n", "\n", - "1. The number of travelers and their ages.\n", - "2. Your budget for flights and accommodations (if applicable).\n", - "3. Any specific activities or attractions you're interested in while in Toronto.\n", + "In terms of his rebound statistics:\n", + "- In the 2007-2008 season, Dwyane Wade recorded 214 total rebounds.\n", + "- In the 2008-2009 season, he recorded 398 total rebounds.\n", "\n", - "This will help me provide more tailored options for your trip!\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:36:38.096554], User:\u001b[0m\n", + "To find the percentage change in his total rebounds, a data analyst would perform the following calculation:\n", "\n", - "just myself one adult\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:36:40.307824], FlightBroker:\u001b[0m\n", + "\\[\n", + "\\text{Percentage Change} = \\left( \\frac{398 - 214}{214} \\right) \\times 100\n", + "\\]\n", "\n", - "Thanks for the information! Here's what I have:\n", + "A data analyst would use the above numbers to determine the percentage change in his total rebounds between these two seasons.\n", + "[Prompt tokens: 794, Completion tokens: 154]\n", + "---------- PlanningAgent ----------\n", + "The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, with a total of 1,397 points. His total rebounds increased from 214 in the 2007-2008 season to 398 in the 2008-2009 season.\n", "\n", - "- **Departure City:** New York\n", - "- **Destination City:** Toronto\n", - "- **Departure Date:** December 7\n", - "- **Return Date:** December 12\n", - "- **Number of Travelers:** 1 Adult\n", + "Let's have a data analyst calculate the percentage change: \n", "\n", - "Could you let me know if you have a budget for flights and accommodations? Additionally, are there any specific activities or attractions you're interested in while in Toronto? This will help me provide the best options for your trip!\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:36:45.875280], User:\u001b[0m\n", + "1. Data analyst: Calculate the percentage change in Dwyane Wade's total rebounds between the 2007-2008 and 2008-2009 seasons using the formula provided by the Web search agent.\n", + "[Prompt tokens: 878, Completion tokens: 116]\n", + "---------- DataAnalystAgent ----------\n", + "[FunctionCall(id='call_Fh84DXp5MxFzutmKVvclw5Cz', arguments='{\"start\":214,\"end\":398}', name='percentage_change_tool')]\n", + "[Prompt tokens: 942, Completion tokens: 20]\n", + "---------- DataAnalystAgent ----------\n", + "[FunctionExecutionResult(content='85.98130841121495', call_id='call_Fh84DXp5MxFzutmKVvclw5Cz')]\n", + "---------- DataAnalystAgent ----------\n", + "The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade. The percentage change in his total rebounds between the 2007-2008 season and the 2008-2009 season was approximately 85.98%.\n", + "[Prompt tokens: 983, Completion tokens: 56]\n", + "---------- PlanningAgent ----------\n", + "The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, with a total of 1,397 points. Between the 2007-2008 and 2008-2009 seasons, his total rebounds increased by approximately 85.98%. \n", "\n", - "that's it\n", - "--------------------------------------------------------------------------- \n", - "\u001b[91m[2024-10-08T20:36:50.925624], FlightBroker:\u001b[0m\n", - "\n", - "Your flights have been successfully booked! Here are the details:\n", - "\n", - "- **Departure:** New York to Toronto\n", - " - **Flight:** AL21\n", - " - **Date:** December 7, 2023\n", - "\n", - "- **Return:** Toronto to New York\n", - " - **Flight:** AL21\n", - " - **Date:** December 12, 2023\n", - "\n", - "If you need help with accommodations, activities, or anything else for your trip, feel free to let me know! \n", - "\n", - "TERMINATE" + "TERMINATE\n", + "[Prompt tokens: 1065, Completion tokens: 65]\n", + "---------- Summary ----------\n", + "Number of messages: 8\n", + "Finish reason: Text 'TERMINATE' mentioned\n", + "Total prompt tokens: 5257\n", + "Total completion tokens: 526\n", + "Duration: 11.98 seconds\n" ] }, { "data": { "text/plain": [ - "TeamRunResult(messages=[TextMessage(source='user', content='Help user plan a trip and book a flight.'), TextMessage(source='User', content=''), TextMessage(source='TravelAssistant', content=\"I'd be happy to help you plan your trip! To get started, could you please provide me with the following details:\\n\\n1. Your departure city and the destination city.\\n2. Your travel dates (departure and return).\\n3. The number of travelers and their ages (if any children are involved).\\n4. Your budget for flights and accommodations, if you have one in mind.\\n5. Any specific activities or attractions you're interested in at the destination.\\n\\nOnce I have this information, I can help you find the best options!\"), TextMessage(source='User', content='Traveling to toronto from new york'), TextMessage(source='TravelAssistant', content='Great choice! Toronto is a vibrant city with a lot to offer. Now, could you please provide the following additional details to help me assist you better?\\n\\n1. What are your travel dates (departure and return)?\\n2. How many travelers will be going, and what are their ages?\\n3. Do you have a budget for the flight and accommodations?\\n4. Are there any specific activities or attractions you’re interested in while in Toronto?\\n\\nOnce I have this information, I can help you find the best flights and suggestions for your trip!'), TextMessage(source='User', content='leaving on december 7 and returning on 12'), TextMessage(source='TravelAssistant', content=\"Thank you for the details! Here's what I have so far:\\n\\n- **Departure City:** New York\\n- **Destination City:** Toronto\\n- **Departure Date:** December 7\\n- **Return Date:** December 12\\n\\nNow, could you please provide:\\n\\n1. The number of travelers and their ages.\\n2. Your budget for flights and accommodations (if applicable).\\n3. Any specific activities or attractions you're interested in while in Toronto.\\n\\nThis will help me provide more tailored options for your trip!\"), TextMessage(source='User', content='just myself one adult'), TextMessage(source='FlightBroker', content=\"Thanks for the information! Here's what I have:\\n\\n- **Departure City:** New York\\n- **Destination City:** Toronto\\n- **Departure Date:** December 7\\n- **Return Date:** December 12\\n- **Number of Travelers:** 1 Adult\\n\\nCould you let me know if you have a budget for flights and accommodations? Additionally, are there any specific activities or attractions you're interested in while in Toronto? This will help me provide the best options for your trip!\"), TextMessage(source='User', content=\"that's it\"), StopMessage(source='FlightBroker', content='Your flights have been successfully booked! Here are the details:\\n\\n- **Departure:** New York to Toronto\\n - **Flight:** AL21\\n - **Date:** December 7, 2023\\n\\n- **Return:** Toronto to New York\\n - **Flight:** AL21\\n - **Date:** December 12, 2023\\n\\nIf you need help with accommodations, activities, or anything else for your trip, feel free to let me know! \\n\\nTERMINATE'), StopMessage(source='StopMessageTermination', content='Stop message received')])" + "TaskResult(messages=[TextMessage(source='user', models_usage=None, content='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?'), TextMessage(source='PlanningAgent', models_usage=RequestUsage(prompt_tokens=595, completion_tokens=115), content=\"To solve this inquiry, let's break it down into smaller tasks again:\\n\\n1. Find out who was the Miami Heat player with the highest points in the 2006-2007 NBA season.\\n2. Find that player's total rebounds for the 2007-2008 NBA season.\\n3. Find that player's total rebounds for the 2008-2009 NBA season.\\n4. Calculate the percentage change in the player's total rebounds from the 2007-2008 to the 2008-2009 season.\\n\\nLet's proceed with these tasks and find the necessary information.\"), TextMessage(source='WebSearchAgent', models_usage=RequestUsage(prompt_tokens=794, completion_tokens=154), content='The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, who scored a total of 1,397 points.\\n\\nIn terms of his rebound statistics:\\n- In the 2007-2008 season, Dwyane Wade recorded 214 total rebounds.\\n- In the 2008-2009 season, he recorded 398 total rebounds.\\n\\nTo find the percentage change in his total rebounds, a data analyst would perform the following calculation:\\n\\n\\\\[\\n\\\\text{Percentage Change} = \\\\left( \\\\frac{398 - 214}{214} \\\\right) \\\\times 100\\n\\\\]\\n\\nA data analyst would use the above numbers to determine the percentage change in his total rebounds between these two seasons.'), TextMessage(source='PlanningAgent', models_usage=RequestUsage(prompt_tokens=878, completion_tokens=116), content=\"The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, with a total of 1,397 points. His total rebounds increased from 214 in the 2007-2008 season to 398 in the 2008-2009 season.\\n\\nLet's have a data analyst calculate the percentage change: \\n\\n1. Data analyst: Calculate the percentage change in Dwyane Wade's total rebounds between the 2007-2008 and 2008-2009 seasons using the formula provided by the Web search agent.\"), ToolCallMessage(source='DataAnalystAgent', models_usage=RequestUsage(prompt_tokens=942, completion_tokens=20), content=[FunctionCall(id='call_Fh84DXp5MxFzutmKVvclw5Cz', arguments='{\"start\":214,\"end\":398}', name='percentage_change_tool')]), ToolCallResultMessage(source='DataAnalystAgent', models_usage=None, content=[FunctionExecutionResult(content='85.98130841121495', call_id='call_Fh84DXp5MxFzutmKVvclw5Cz')]), TextMessage(source='DataAnalystAgent', models_usage=RequestUsage(prompt_tokens=983, completion_tokens=56), content='The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade. The percentage change in his total rebounds between the 2007-2008 season and the 2008-2009 season was approximately 85.98%.'), TextMessage(source='PlanningAgent', models_usage=RequestUsage(prompt_tokens=1065, completion_tokens=65), content='The Miami Heat player with the highest points in the 2006-2007 season was Dwyane Wade, with a total of 1,397 points. Between the 2007-2008 and 2008-2009 seasons, his total rebounds increased by approximately 85.98%. \\n\\nTERMINATE')], stop_reason=\"Text 'TERMINATE' mentioned\")" ] }, - "execution_count": 4, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "user_proxy = UserProxyAgent(\"User\")\n", - "flight_broker = ToolUseAssistantAgent(\n", - " \"FlightBroker\",\n", - " description=\"An assistant for booking flights\",\n", - " model_client=OpenAIChatCompletionClient(model=\"gpt-4o-mini\"),\n", - " registered_tools=[\n", - " FunctionTool(flight_search, description=\"Search for flights\"),\n", - " FunctionTool(flight_booking, description=\"Book a flight\"),\n", - " ],\n", - ")\n", - "travel_assistant = CodingAssistantAgent(\n", - " \"TravelAssistant\",\n", - " description=\"A travel assistant\",\n", - " model_client=OpenAIChatCompletionClient(model=\"gpt-4o-mini\"),\n", - " system_message=\"You are a travel assistant.\",\n", - ")\n", + "def selector_func(messages: Sequence[AgentMessage]) -> str | None:\n", + " if messages[-1].source != planning_agent.name:\n", + " return planning_agent.name\n", + " return None\n", + "\n", "\n", - "termination = TextMentionTermination(\"TERMINATE\")\n", "team = SelectorGroupChat(\n", - " [user_proxy, flight_broker, travel_assistant],\n", + " [planning_agent, web_search_agent, data_analyst_agent],\n", " model_client=OpenAIChatCompletionClient(model=\"gpt-4o-mini\"),\n", " termination_condition=termination,\n", + " selector_func=selector_func,\n", ")\n", - "await team.run(task=\"Help user plan a trip and book a flight.\")" + "\n", + "await Console(team.run_stream(task=task))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can see from the conversation log that the Planning Agent always speaks immediately after the specialized agents." ] } ], @@ -281,7 +458,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.6" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.svg b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.svg new file mode 100644 index 00000000000..4a4009992c4 --- /dev/null +++ b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/selector-group-chat.svg @@ -0,0 +1,3 @@ + + +
Selector
Selector
Web Search Agent
Web Search Agent
Planning Agent
Planning Agent
Data Analyst
Agent
Data Analyst...
SelectorGroupChat
SelectorGroupChat
Application/User
Application/User
Task
Task
TaskResult
TaskResult
\ No newline at end of file diff --git a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb index 6ff950b10ef..68e77690d45 100644 --- a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb +++ b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/swarm.ipynb @@ -26,11 +26,11 @@ "\n", "At its core, the {py:class}`~autogen_agentchat.teams.Swarm` team is a group chat\n", "where agents take turn to generate a response. \n", - "Similar to the {py:class}`~autogen_agentchat.teams.SelectorGroupChat`\n", - "and {py:class}`~autogen_agentchat.teams.RoundRobinGroupChat`: participant agents\n", - "all share the same mesasge context.\n", + "Similar to {py:class}`~autogen_agentchat.teams.SelectorGroupChat`\n", + "and {py:class}`~autogen_agentchat.teams.RoundRobinGroupChat`, participant agents\n", + "broadcast their responses so all agents share the same mesasge context.\n", "\n", - "But different from the other two group chat teams, at each turn,\n", + "Different from the other two group chat teams, at each turn,\n", "**the speaker agent is selected based on the most recent\n", "{py:class}`~autogen_agentchat.messages.HandoffMessage` message in the context.**\n", "This naturally requires each agent in the team to be able to generate\n", @@ -76,7 +76,7 @@ "\n", "Additionally, we let the user interact with the agents, when agents handoff to `\"user\"`.\n", "\n", - "#### Workflow:\n", + "#### Workflow\n", "1. The **Travel Agent** initiates the conversation and evaluates the user's request.\n", "2. Based on the request:\n", " - For refund-related tasks, the Travel Agent hands off to the **Flights Refunder**.\n", @@ -282,7 +282,7 @@ "- **News Analyst**: An agent focused on gathering and summarizing recent news articles relevant to the stock, using tools such as `get_news`.\n", "- **Writer**: An agent tasked with compiling the findings from the stock and news analysis into a cohesive final report.\n", "\n", - "#### Workflow:\n", + "#### Workflow\n", "1. The **Planner** initiates the research process by delegating tasks to the appropriate agents in a step-by-step manner.\n", "2. Each agent performs its task independently and appends their work to the shared **message thread/history**. Rather than directly returning results to the planner, all agents contribute to and read from this shared message history. When agents generate their work using the LLM, they have access to this shared message history, which provides context and helps track the overall progress of the task.\n", "3. Once an agent completes its task, it hands off control back to the planner.\n", diff --git a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/teams.ipynb b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/teams.ipynb index 5c0b257dfec..51976a5370d 100644 --- a/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/teams.ipynb +++ b/python/packages/autogen-core/docs/src/user-guide/agentchat-user-guide/tutorial/teams.ipynb @@ -22,9 +22,9 @@ "\n", "AgentChat provides several preset teams that implements one or more [multi-agent design patterns](../../core-user-guide/design-patterns/index.md) to simplify development. Here is a list of the preset teams:\n", "\n", - "- {py:class}`~autogen_agentchat.teams.RoundRobinGroupChat`: All participants share context and takes turn to respond in a round-robin fashion.\n", - "- {py:class}`~autogen_agentchat.teams.SelectorGroupChat`: All participants share context and use a model-based selector (with custom override) to select the next agent to respond.\n", - "- {py:class}`~autogen_agentchat.teams.Swarm`: All participants share context and use {py:class}`~autogen_agentchat.messages.HandoffMessage`to pass control to the next agent.\n", + "- {py:class}`~autogen_agentchat.teams.RoundRobinGroupChat`: All participants share context and takes turn to respond in a round-robin fashion. We will cover this team in this section.\n", + "- {py:class}`~autogen_agentchat.teams.SelectorGroupChat`: All participants share context and use a model-based selector (with custom override) to select the next agent to respond. See [Selector Group Chat](./selector-group-chat.ipynb) for more details.\n", + "- {py:class}`~autogen_agentchat.teams.Swarm`: All participants share context and use {py:class}`~autogen_agentchat.messages.HandoffMessage`to pass control to the next agent. See [Swarm](./swarm.ipynb) for more details.\n", "\n", "At a high-level, a team API consists of the following methods:\n", "\n", @@ -42,6 +42,9 @@ "source": [ "## Round-Robin Group Chat\n", "\n", + "{py:class}`~autogen_agentchat.teams.RoundRobinGroupChat` is a simple team that allows all agents to share context and take turns to respond in a round-robin fashion.\n", + "On its turn, each agent broadcasts its response to all other agents in the team, so all agents have the same context.\n", + "\n", "We will start by creating a team with a single {py:class}`~autogen_agentchat.agents.AssistantAgent` agent\n", "and {py:class}`~autogen_agentchat.task.TextMentionTermination`\n", "termination condition that stops the team when a word is detected."