{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Termination \n", "\n", "\n", "In the previous section, we explored how to define agents, and organize them into teams that can solve tasks by communicating (a conversation). However, conversations can go on forever, and in many cases, we need to know _when_ to stop them. This is the role of the termination condition.\n", "\n", "AgentChat supports several termination condition by providing a base {py:class}`~autogen_agentchat.base.TerminationCondition` class and several implementations that inherit from it.\n", "\n", "A termination condition is a callable that takes a sequence of ChatMessage objects since the last time the condition was called, and returns a StopMessage if the conversation should be terminated, or None otherwise. Once a termination condition has been reached, it must be reset before it can be used again.\n", "\n", "Some important things to note about termination conditions: \n", "- They are stateful, and must be reset before they can be used again. \n", "- They can be combined using the AND and OR operators. \n", "- They are implemented/enforced by the team, and not by the agents. An agent may signal or request termination e.g., by sending a StopMessage, but the team is responsible for enforcing it.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To begin, let us define a simple team with only one agent and then explore how multiple termination conditions can be applied to guide the resulting behavior." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import logging\n", "\n", "from autogen_agentchat import EVENT_LOGGER_NAME\n", "from autogen_agentchat.agents import CodingAssistantAgent\n", "from autogen_agentchat.logging import ConsoleLogHandler\n", "from autogen_agentchat.task import MaxMessageTermination, TextMentionTermination\n", "from autogen_agentchat.teams import RoundRobinGroupChat\n", "from autogen_core.components.models import OpenAIChatCompletionClient\n", "\n", "logger = logging.getLogger(EVENT_LOGGER_NAME)\n", "logger.addHandler(ConsoleLogHandler())\n", "logger.setLevel(logging.INFO)\n", "\n", "\n", "model_client = OpenAIChatCompletionClient(\n", " model=\"gpt-4o-2024-08-06\",\n", " temperature=1,\n", " # api_key=\"sk-...\", # Optional if you have an OPENAI_API_KEY env variable set.\n", ")\n", "\n", "writing_assistant_agent = CodingAssistantAgent(\n", " name=\"writing_assistant_agent\",\n", " system_message=\"You are a helpful assistant that solve tasks by generating text responses and code.\",\n", " model_client=model_client,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## MaxMessageTermination \n", "\n", "The simplest termination condition is the {py:class}`~autogen_agentchat.teams.MaxMessageTermination` condition, which terminates the conversation after a fixed number of messages. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:28.807176]:\u001b[0m\n", "\n", "Write a unique, Haiku about the weather in Paris\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:29.604935], writing_assistant_agent:\u001b[0m\n", "\n", "Gentle rain whispers, \n", "Eiffel veiled in mist’s embrace, \n", "Spring’s soft sigh in France.\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:30.168531], writing_assistant_agent:\u001b[0m\n", "\n", "Gentle rain whispers, \n", "Eiffel veiled in mist’s embrace, \n", "Spring’s soft sigh in France.\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:31.213291], writing_assistant_agent:\u001b[0m\n", "\n", "Gentle rain whispers, \n", "Eiffel veiled in mist’s embrace, \n", "Spring’s soft sigh in France.\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:31.213655], Termination:\u001b[0m\n", "\n", "Maximal number of messages 3 reached, current message count: 3" ] } ], "source": [ "max_msg_termination = MaxMessageTermination(max_messages=3)\n", "round_robin_team = RoundRobinGroupChat([writing_assistant_agent], termination_condition=max_msg_termination)\n", "round_robin_team_result = await round_robin_team.run(task=\"Write a unique, Haiku about the weather in Paris\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that the conversation is terminated after the specified number of messages have been sent by the agent." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## StopMessageTermination\n", "\n", "In this scenario, the team terminates the conversation if any agent sends a `StopMessage`. So, when does an agent send a `StopMessage`? Typically, this is implemented in the `on_message` method of the agent, where the agent can check the incoming message and decide to send a `StopMessage` based on some condition. \n", "\n", "A common pattern here is prompt the agent (or some agent participating in the conversation) to emit a specific text string in it's response, which can be used to trigger the termination condition. \n", "\n", "In fact, if you review the code implementation for the default `CodingAssistantAgent` class provided by AgentChat, you will observe two things\n", "- The default `system_message` instructs the agent to end their response with the word \"terminate\" if they deem the task to be completed\n", "- in the `on_message` method, the agent checks if the incoming message contains the text \"terminate\" and returns a `StopMessage` if it does. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:31.218855]:\u001b[0m\n", "\n", "Write a unique, Haiku about the weather in Paris\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:31.752676], writing_assistant_agent:\u001b[0m\n", "\n", "Mist hugs the Eiffel, \n", "Soft rain kisses cobblestones, \n", "Autumn whispers past. \n", "\n", "TERMINATE\n", "--------------------------------------------------------------------------- \n", "\u001b[91m[2024-10-19T12:19:31.753265], Termination:\u001b[0m\n", "\n", "Stop message received" ] } ], "source": [ "writing_assistant_agent = CodingAssistantAgent(\n", " name=\"writing_assistant_agent\",\n", " system_message=\"You are a helpful assistant that solve tasks by generating text responses and code. Respond with TERMINATE when the task is done.\",\n", " model_client=model_client,\n", ")\n", "\n", "text_termination = TextMentionTermination(\"TERMINATE\")\n", "round_robin_team = RoundRobinGroupChat([writing_assistant_agent], termination_condition=text_termination)\n", "\n", "round_robin_team_result = await round_robin_team.run(task=\"Write a unique, Haiku about the weather in Paris\")" ] } ], "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.12.6" } }, "nbformat": 4, "nbformat_minor": 2 }