{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Teams\n", "\n", "```{include} ../warning.md\n", "```\n", "\n", "In AgentChat, teams define how groups of agents collaborate to address tasks.\n", "A team is composed of one or more agents, and interacts with your application\n", "by receiving task and returning task result.\n", "It is stateful and maintains context across multiple tasks.\n", "A team uses a stateful termination condition to determine when to stop processing the\n", "current task.\n", "\n", "The diagram below shows the relationship between team and your application.\n", "\n", "![AgentChat Teams](./agentchat-team.svg)\n", "\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", "\n", "At a high-level, a team API consists of the following methods:\n", "\n", "- {py:meth}`~autogen_agentchat.base.TaskRunner.run`: To process a task, which can be a {py:class}`str`, {py:class}`~autogen_agentchat.messages.TextMessage`, or {py:class}`~autogen_agentchat.messages.MultiModalMessage`, and returns {py:class}`~autogen_agentchat.base.TaskResult`. The task can also be `None` to resume processing the previous task if the team has not been reset.\n", "- {py:meth}`~autogen_agentchat.base.TaskRunner.run_stream`: Same as {py:meth}`~autogen_agentchat.base.TaskRunner.run`, but returns a async generator of messages and the final task result.\n", "- {py:meth}`~autogen_agentchat.base.Team.reset`: To reset the team state if the next task is not related to the previous task. Otherwise, the team can utilize the context from the previous task to process the next one.\n", "\n", "In this section, we will be using the\n", "{py:class}`~autogen_agentchat.teams.RoundRobinGroupChat` team to introduce the AgentChat team API." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Round-Robin Group Chat\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." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from autogen_agentchat.agents import AssistantAgent\n", "from autogen_agentchat.task import TextMentionTermination\n", "from autogen_agentchat.teams import RoundRobinGroupChat\n", "from autogen_ext.models import OpenAIChatCompletionClient\n", "\n", "# Create an OpenAI model client.\n", "model_client = OpenAIChatCompletionClient(\n", " model=\"gpt-4o-2024-08-06\",\n", " # api_key=\"sk-...\", # Optional if you have an OPENAI_API_KEY env variable set.\n", ")\n", "\n", "\n", "# Define a tool that gets the weather for a city.\n", "async def get_weather(city: str) -> str:\n", " \"\"\"Get the weather for a city.\"\"\"\n", " return f\"The weather in {city} is 72 degrees and Sunny.\"\n", "\n", "\n", "# Create an assistant agent.\n", "weather_agent = AssistantAgent(\n", " \"assistant\",\n", " model_client=model_client,\n", " tools=[get_weather],\n", " system_message=\"Respond 'TERMINATE' when task is complete.\",\n", ")\n", "\n", "# Define a termination condition.\n", "text_termination = TextMentionTermination(\"TERMINATE\")\n", "\n", "# Create a single-agent team.\n", "single_agent_team = RoundRobinGroupChat([weather_agent], termination_condition=text_termination)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Running Team\n", "\n", "Let's calls the {py:meth}`~autogen_agentchat.teams.BaseGroupChat.run` method\n", "to start the team with a task." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "TaskResult(messages=[TextMessage(source='user', models_usage=None, content='What is the weather in New York?'), ToolCallMessage(source='assistant', models_usage=RequestUsage(prompt_tokens=70, completion_tokens=15), content=[FunctionCall(id='call_6qWxrK1VdEVSryXKyIVpwE0h', arguments='{\"city\":\"New York\"}', name='get_weather')]), ToolCallResultMessage(source='assistant', models_usage=None, content=[FunctionExecutionResult(content='The weather in New York is 72 degrees and Sunny.', call_id='call_6qWxrK1VdEVSryXKyIVpwE0h')]), TextMessage(source='assistant', models_usage=RequestUsage(prompt_tokens=96, completion_tokens=13), content='The weather in New York is 72 degrees and sunny.'), TextMessage(source='assistant', models_usage=RequestUsage(prompt_tokens=125, completion_tokens=4), content='TERMINATE')], stop_reason=\"Text 'TERMINATE' mentioned\")\n" ] } ], "source": [ "async def run_team() -> None:\n", " result = await single_agent_team.run(task=\"What is the weather in New York?\")\n", " print(result)\n", "\n", "\n", "# Use `asyncio.run(run_team())` when running in a script.\n", "await run_team()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The team ran the same agent until the termination condition was met.\n", "In this case, the termination condition was met when the word \"TERMINATE\" is detected in the\n", "agent's response.\n", "When the team stops, it returns a {py:class}`~autogen_agentchat.base.TaskResult` object with all the messages produced by the agents in the team." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reseting Team\n", "\n", "You can reset the team by calling the {py:meth}`~autogen_agentchat.teams.BaseGroupChat.reset` method.\n", "It will clear the team's state including all of its agents'." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "await single_agent_team.reset() # Reset the team for the next run." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is usually a good idea to reset the team if the next task is not related to the previous task.\n", "However, if the next task is related to the previous task, you don't need to reset.\n", "See [Resuming Team](#resuming-team) below." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Streaming Team Messages\n", "\n", "Similar to agent's {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_messages_stream` method,\n", "you can stream the team's messages by calling the {py:meth}`~autogen_agentchat.teams.BaseGroupChat.run_stream` method.\n", "It will return a generator that yields the messages produced by the agents in the team as they are generated,\n", "and the last item will be the task result." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "source='user' models_usage=None content='What is the weather in New York?'\n", "source='assistant' models_usage=RequestUsage(prompt_tokens=70, completion_tokens=15) content=[FunctionCall(id='call_FcJlzgDmPUgGSKLjeGajFZ7V', arguments='{\"city\":\"New York\"}', name='get_weather')]\n", "source='assistant' models_usage=None content=[FunctionExecutionResult(content='The weather in New York is 72 degrees and Sunny.', call_id='call_FcJlzgDmPUgGSKLjeGajFZ7V')]\n", "source='assistant' models_usage=RequestUsage(prompt_tokens=96, completion_tokens=14) content='The weather in New York is currently 72 degrees and sunny.'\n", "source='assistant' models_usage=RequestUsage(prompt_tokens=126, completion_tokens=4) content='TERMINATE'\n", "Stop Reason: Text 'TERMINATE' mentioned\n" ] } ], "source": [ "from autogen_agentchat.base import TaskResult\n", "\n", "\n", "async def run_team_stream() -> None:\n", " async for message in single_agent_team.run_stream(task=\"What is the weather in New York?\"):\n", " if isinstance(message, TaskResult):\n", " print(\"Stop Reason:\", message.stop_reason)\n", " else:\n", " print(message)\n", "\n", "\n", "# Use `asyncio.run(run_team_stream())` when running in a script.\n", "await run_team_stream()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As the above example shows, you can obtain the reason why the team stopped by checking the {py:attr}`~autogen_agentchat.base.TaskResult.stop_reason` attribute.\n", "\n", "There is a covenient method {py:meth}`~autogen_agentchat.task.Console` that prints the messages to the console\n", "with proper formatting." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---------- user ----------\n", "What is the weather in Seattle?\n", "---------- assistant ----------\n", "[FunctionCall(id='call_QBqpeKQlczRYIlCIzKh43Kha', arguments='{\"city\":\"Seattle\"}', name='get_weather')]\n", "[Prompt tokens: 69, Completion tokens: 14]\n", "---------- assistant ----------\n", "[FunctionExecutionResult(content='The weather in Seattle is 72 degrees and Sunny.', call_id='call_QBqpeKQlczRYIlCIzKh43Kha')]\n", "---------- assistant ----------\n", "The weather in Seattle is currently 72 degrees and sunny.\n", "[Prompt tokens: 93, Completion tokens: 13]\n", "---------- assistant ----------\n", "TERMINATE\n", "[Prompt tokens: 122, Completion tokens: 4]\n", "---------- Summary ----------\n", "Number of messages: 5\n", "Finish reason: Text 'TERMINATE' mentioned\n", "Total prompt tokens: 284\n", "Total completion tokens: 31\n", "Duration: 1.82 seconds\n" ] } ], "source": [ "from autogen_agentchat.task import Console\n", "\n", "# Use `asyncio.run(single_agent_team.reset())` when running in a script.\n", "await single_agent_team.reset() # Reset the team for the next run.\n", "# Use `asyncio.run(single_agent_team.run_stream(task=\"What is the weather in Seattle?\"))` when running in a script.\n", "await Console(\n", " single_agent_team.run_stream(task=\"What is the weather in Seattle?\")\n", ") # Stream the messages to the console." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reflection Pattern\n", "\n", "Now we will create a team with two agents that implements the\n", "Reflection pattern, which is a multi-agent design pattern that uses\n", "a critic agent to evaluate the responses of a primary agent.\n", "\n", "See how the reflection pattern works using the [Core API](../../core-user-guide/design-patterns/reflection.ipynb).\n", "\n", "In this example, we will use the {py:class}`~autogen_agentchat.agents.AssistantAgent` agent class\n", "for both the primary and critic agents.\n", "We will use both the {py:class}`~autogen_agentchat.task.TextMentionTermination`\n", "and {py:class}`~autogen_agentchat.task.MaxMessageTermination` termination conditions\n", "together to stop the team." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "from autogen_agentchat.agents import AssistantAgent\n", "from autogen_agentchat.task import MaxMessageTermination, TextMentionTermination\n", "from autogen_agentchat.teams import RoundRobinGroupChat\n", "from autogen_ext.models import OpenAIChatCompletionClient\n", "\n", "# Create an OpenAI model client.\n", "model_client = OpenAIChatCompletionClient(\n", " model=\"gpt-4o-2024-08-06\",\n", " # api_key=\"sk-...\", # Optional if you have an OPENAI_API_KEY env variable set.\n", ")\n", "\n", "# Create the primary agent.\n", "primary_agent = AssistantAgent(\n", " \"primary\",\n", " model_client=model_client,\n", " system_message=\"You are a helpful AI assistant.\",\n", ")\n", "\n", "# Create the critic agent.\n", "critic_agent = AssistantAgent(\n", " \"critic\",\n", " model_client=model_client,\n", " system_message=\"Provide constructive feedback. Respond with 'APPROVE' to when your feedbacks are addressed.\",\n", ")\n", "\n", "# Define a termination condition that stops the task if the critic approves.\n", "text_termination = TextMentionTermination(\"APPROVE\")\n", "# Define a termination condition that stops the task after 5 messages.\n", "max_message_termination = MaxMessageTermination(5)\n", "# Combine the termination conditions using the `|`` operator so that the\n", "# task stops when either condition is met.\n", "termination = text_termination | max_message_termination\n", "\n", "# Create a team with the primary and critic agents.\n", "reflection_team = RoundRobinGroupChat([primary_agent, critic_agent], termination_condition=termination)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's give a poem-writing task to the team and see how the agents interact with each other." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---------- user ----------\n", "Write a short poem about fall season.\n", "---------- primary ----------\n", "Golden leaves dance on the breeze, \n", "Whispering secrets through the trees. \n", "Crisp air nips at cheeks so bright, \n", "As daylight fades to early night. \n", "\n", "Pumpkins sit on porches grand, \n", "In a painted, harvest land. \n", "Sweaters hug us, warm and snug, \n", "While cider fills each steamy mug. \n", "\n", "In this season's gentle sway, \n", "Nature tells of time's ballet. \n", "With each leaf's descent and flight, \n", "Autumn sings its soft goodnight. \n", "[Prompt tokens: 27, Completion tokens: 107]\n", "---------- critic ----------\n", "Your poem is beautiful and elegantly captures the essence of the fall season. The imagery you used creates vivid pictures of autumn landscapes and activities, making it easy for the reader to visualize the scene. The rhyming and rhythm contribute to the poem's musicality, enhancing its appeal. Each stanza highlights different aspects of fall, creating a well-rounded depiction of the season.\n", "\n", "To make the poem even more evocative, consider including a few additional sensory details or emotions tied to the season. For instance, you might evoke the sounds of rustling leaves or the feeling of warmth from a fireplace. Overall, it's a delightful and charming poem that effectively conveys the spirit of fall.\n", "\n", "If these suggestions are considered, please share the revised poem for additional feedback!\n", "[Prompt tokens: 152, Completion tokens: 148]\n", "---------- primary ----------\n", "Thank you for the thoughtful feedback! Here's a revised version of the poem, incorporating more sensory details and emotions:\n", "\n", "---\n", "\n", "Golden leaves dance on the breeze, \n", "Whispering secrets through the trees. \n", "Crisp air kisses cheeks aglow, \n", "As twilight casts a gentle show. \n", "\n", "Pumpkins guard each porch with pride, \n", "In this painted, harvest tide. \n", "Sweaters hug us, warm and snug, \n", "While cider steams in every mug. \n", "\n", "Children laugh in rustling leaves, \n", "As branches weave autumnal eaves. \n", "Fireplaces crackle, whisper warmth, \n", "Embracing hearts in homey charms. \n", "\n", "In this season's tender sway, \n", "Nature turns in grand ballet. \n", "With each leaf's descent and flight, \n", "Autumn sings its soft goodnight. \n", "\n", "---\n", "\n", "I hope this version resonates even more deeply with the spirit of fall.\n", "[Prompt tokens: 294, Completion tokens: 178]\n", "---------- critic ----------\n", "Your revised poem beautifully captures the essence of the fall season with delightful sensory details and emotions. The inclusion of words like \"twilight casts a gentle show,\" \"children laugh in rustling leaves,\" and \"fireplaces crackle\" adds depth and paints a vivid picture of autumn scenes. The addition of emotions, particularly the \"embracing hearts in homey charms,\" evokes a sense of warmth and comfort associated with this season.\n", "\n", "The poem flows smoothly with its rhythmic quality and maintains a harmonious balance in its description of autumn. Overall, it now provides an even richer and more immersive experience for the reader. Excellent work on enhancing the sensory experience—this version resonates wonderfully with the spirit of fall. \n", "\n", "APPROVE\n", "[Prompt tokens: 490, Completion tokens: 142]\n", "---------- Summary ----------\n", "Number of messages: 5\n", "Finish reason: Text 'APPROVE' mentioned, Maximum number of messages 5 reached, current message count: 5\n", "Total prompt tokens: 963\n", "Total completion tokens: 575\n", "Duration: 8.10 seconds\n" ] } ], "source": [ "# Use `asyncio.run(Console(reflection_team.run_stream(task=\"Write a short poem about fall season.\")))` when running in a script.\n", "await Console(\n", " reflection_team.run_stream(task=\"Write a short poem about fall season.\")\n", ") # Stream the messages to the console." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Resuming Team\n", "\n", "Let's run the team again with a new task while keeping the context about the previous task." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---------- user ----------\n", "将这首诗用中文唐诗风格写一遍。\n", "---------- primary ----------\n", "金叶飘舞随风起, \n", "林间低语秋声细。 \n", "凉风轻拂面颊红, \n", "夕光渐隐天色丽。 \n", "\n", "南瓜门前静自笑, \n", "丰收景色绘秋貌。 \n", "暖衣贴身享温柔, \n", "热饮氤氲杯中绕。 \n", "\n", "童声笑逐落叶中, \n", "枝叶缀出秋帷浓。 \n", "炉火轻鸣诉温情, \n", "温馨满怀思乡容。 \n", "\n", "此时佳季自徘徊, \n", "秋之舞步若梦来。 \n", "片片叶落随风去, \n", "秋声袅袅道安睡。 \n", "[Prompt tokens: 664, Completion tokens: 155]\n", "---------- critic ----------\n", "这首诗成功地以唐诗的风格捕捉了秋天的精髓,以古雅的语言和流畅的节奏展示了秋日的美丽。你运用了优美的意象,如“金叶飘舞”和“夕光渐隐”,将秋季的景色描绘得栩栩如生。词句简炼而意境深远,充满了诗意。\n", "\n", "同时,诗中融入的情感,如“温馨满怀思乡容”以及“炉火轻鸣诉温情”,有效传达了秋天的暖意与思乡之情,令人感到温暖和亲切。\n", "\n", "整体而言,这是一首极具唐诗魅力的作品,成功地展现了秋天的许多层面,并引发读者的共鸣。恭喜你完成了这次优雅的改编!\n", "\n", "APPROVE\n", "[Prompt tokens: 837, Completion tokens: 199]\n", "---------- Summary ----------\n", "Number of messages: 3\n", "Finish reason: Text 'APPROVE' mentioned\n", "Total prompt tokens: 1501\n", "Total completion tokens: 354\n", "Duration: 4.44 seconds\n" ] } ], "source": [ "# Write the poem in Chinese Tang poetry style.\n", "# Use `asyncio.run(Console(reflection_team.run_stream(task=\"将这首诗用中文唐诗风格写一遍。\")))` when running in a script.\n", "await Console(reflection_team.run_stream(task=\"将这首诗用中文唐诗风格写一遍。\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Resume with another task." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---------- user ----------\n", "Write the poem in Spanish.\n", "---------- primary ----------\n", "Certainly! Here's a translation of the poem into Spanish:\n", "\n", "---\n", "\n", "Hojas doradas bailan en la brisa, \n", "Susurran secretos en la arboleda. \n", "El aire fresco besa las mejillas, \n", "Mientras el crepúsculo se despide a su manera. \n", "\n", "Calabazas vigilan cada entrada, \n", "En esta tierra de cosecha pintada. \n", "Los suéteres nos abrazan calurosos, \n", "Mientras el vapor sube de cada taza amorosa. \n", "\n", "Risas de niños suenan en hojas caídas, \n", "Mientras ramas tejen toldos de caricias. \n", "Las chimeneas crepitan, susurran calor, \n", "Abrazando los corazones con su amor hogareño. \n", "\n", "En la danza de esta estación serena, \n", "La naturaleza gira con su escena. \n", "Con cada hoja que desciende en el viento, \n", "El otoño canta su suave cuento. \n", "\n", "---\n", "\n", "Espero que esta traducción refleje el mismo espíritu y encantamiento del poema original.\n", "[Prompt tokens: 1719, Completion tokens: 209]\n", "---------- critic ----------\n", "Your translation of the poem into Spanish beautifully captures the essence and lyrical quality of the original. The imagery and emotions are conveyed effectively, maintaining the warmth and serene atmosphere of fall that the poem embodies. Each stanza mirrors the themes presented in the English version, like the golden leaves, harvest, and cozy reflections of autumn.\n", "\n", "Overall, your translation is both poetic and faithful to the original content. If you have further adjustments or specific stylistic preferences, feel free to share. Great job on this translation!\n", "\n", "APPROVE\n", "[Prompt tokens: 1946, Completion tokens: 102]\n", "---------- Summary ----------\n", "Number of messages: 3\n", "Finish reason: Text 'APPROVE' mentioned\n", "Total prompt tokens: 3665\n", "Total completion tokens: 311\n", "Duration: 4.22 seconds\n" ] } ], "source": [ "# Write the poem in Spanish.\n", "# Use `asyncio.run(Console(reflection_team.run_stream(task=\"Write the poem in Spanish.\")))` when running in a script.\n", "await Console(reflection_team.run_stream(task=\"Write the poem in Spanish.\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Resuming A Previous Task\n", "\n", "We can call {py:meth}`~autogen_agentchat.teams.BaseGroupChat.run` or {py:meth}`~autogen_agentchat.teams.BaseGroupChat.run_stream` methods\n", "without setting the `task` again to resume the previous task. The team will continue from where it left off." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---------- primary ----------\n", "Thank you for your kind words! I'm glad the translation captures the essence and lyrical quality of the original poem. If you have any more requests or need further assistance, please feel free to let me know. I'm here to help!\n", "[Prompt tokens: 2042, Completion tokens: 46]\n", "---------- critic ----------\n", "You're very welcome! I'm glad to hear that you're satisfied with the translation. If you have any more requests, whether it's poetry, translation, or any other kind of assistance, don't hesitate to reach out. I'm here to help with whatever you need. Enjoy the rest of your creative journey!\n", "[Prompt tokens: 2106, Completion tokens: 58]\n", "---------- primary ----------\n", "Thank you for your encouraging words! I'm here to assist you with any other requests you might have, whether related to creativity, translation, or any other topic. Feel free to reach out whenever you need help or inspiration. Enjoy your journey in creativity!\n", "[Prompt tokens: 2158, Completion tokens: 50]\n", "---------- critic ----------\n", "You're welcome! It's always a pleasure to assist you. If you ever have more questions or need inspiration, don't hesitate to reach out. Happy creating, and enjoy every moment of your creative journey!\n", "[Prompt tokens: 2226, Completion tokens: 39]\n", "---------- primary ----------\n", "Thank you so much! Your encouragement is greatly appreciated. Feel free to reach out at any time for assistance or inspiration. I wish you the best on your creative journey and hope you enjoy every step of the way!\n", "[Prompt tokens: 2259, Completion tokens: 43]\n", "---------- Summary ----------\n", "Number of messages: 5\n", "Finish reason: Maximum number of messages 5 reached, current message count: 5\n", "Total prompt tokens: 10791\n", "Total completion tokens: 236\n", "Duration: 5.00 seconds\n" ] } ], "source": [ "# Use the `asyncio.run(Console(reflection_team.run_stream()))` when running in a script.\n", "await Console(reflection_team.run_stream())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Pause for User Input\n", "\n", "Often times, team needs additional input from the application (i.e., user)\n", "to continue processing the task.\n", "You can use the {py:class}`~autogen_agentchat.task.HandoffTermination` termination condition\n", "to stop the team when an agent sends a {py:class}`~autogen_agentchat.messages.HandoffMessage` message.\n", "\n", "Let's create a team with a single {py:class}`~autogen_agentchat.agents.AssistantAgent` agent\n", "with a handoff setting.\n", "\n", "```{note}\n", "The model used with {py:class}`~autogen_agentchat.agents.AssistantAgent`must support tool call\n", "to use the handoff feature.\n", "```" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "from autogen_agentchat.agents import AssistantAgent, Handoff\n", "from autogen_agentchat.task import HandoffTermination, TextMentionTermination\n", "from autogen_agentchat.teams import RoundRobinGroupChat\n", "from autogen_ext.models import OpenAIChatCompletionClient\n", "\n", "# Create an OpenAI model client.\n", "model_client = OpenAIChatCompletionClient(\n", " model=\"gpt-4o-2024-08-06\",\n", " # api_key=\"sk-...\", # Optional if you have an OPENAI_API_KEY env variable set.\n", ")\n", "\n", "# Create a lazy assistant agent that always hands off to the user.\n", "lazy_agent = AssistantAgent(\n", " \"lazy_assistant\",\n", " model_client=model_client,\n", " handoffs=[Handoff(target=\"user\", message=\"Transfer to user.\")],\n", " system_message=\"Always transfer to user when you don't know the answer. Respond 'TERMINATE' when task is complete.\",\n", ")\n", "\n", "# Define a termination condition that checks for handoff message targetting helper and text \"TERMINATE\".\n", "handoff_termination = HandoffTermination(target=\"user\")\n", "text_termination = TextMentionTermination(\"TERMINATE\")\n", "termination = handoff_termination | text_termination\n", "\n", "# Create a single-agent team.\n", "lazy_agent_team = RoundRobinGroupChat([lazy_agent], termination_condition=termination)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's run the team with a task that requires additional input from the user\n", "because the agent doesn't have relevant tools to continue processing the task." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---------- user ----------\n", "What is the weather in New York?\n", "---------- lazy_assistant ----------\n", "[FunctionCall(id='call_YHm4KPjFIWZE95YrJWlJwcv4', arguments='{}', name='transfer_to_user')]\n", "[Prompt tokens: 68, Completion tokens: 11]\n", "---------- lazy_assistant ----------\n", "[FunctionExecutionResult(content='Transfer to user.', call_id='call_YHm4KPjFIWZE95YrJWlJwcv4')]\n", "---------- lazy_assistant ----------\n", "Transfer to user.\n", "---------- Summary ----------\n", "Number of messages: 4\n", "Finish reason: Handoff to user from lazy_assistant detected.\n", "Total prompt tokens: 68\n", "Total completion tokens: 11\n", "Duration: 0.73 seconds\n" ] } ], "source": [ "from autogen_agentchat.task import Console\n", "\n", "# Use `asyncio.run(Console(lazy_agent_team.run_stream(task=\"What is the weather in New York?\")))` when running in a script.\n", "await Console(lazy_agent_team.run_stream(task=\"What is the weather in New York?\"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can see the team stopped due to the handoff message was detected.\n", "Let's continue the team by providing the information the agent needs." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "---------- user ----------\n", "It is raining in New York.\n", "---------- lazy_assistant ----------\n", "I hope you stay dry! Is there anything else you would like to know or do?\n", "[Prompt tokens: 108, Completion tokens: 19]\n", "---------- lazy_assistant ----------\n", "TERMINATE\n", "[Prompt tokens: 134, Completion tokens: 4]\n", "---------- Summary ----------\n", "Number of messages: 3\n", "Finish reason: Text 'TERMINATE' mentioned\n", "Total prompt tokens: 242\n", "Total completion tokens: 23\n", "Duration: 6.77 seconds\n" ] } ], "source": [ "# Use `asyncio.run(Console(lazy_agent_team.run_stream(task=\"It is raining in New York.\")))` when running in a script.\n", "await Console(lazy_agent_team.run_stream(task=\"It is raining in New York.\"))" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.5" } }, "nbformat": 4, "nbformat_minor": 2 }