{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "# Agents\n", "\n", "An agent is a software entity that communicates via messages, maintains its own state, and performs actions in response to received messages or changes in its state. \n", "\n", "```{include} ../warning.md\n", "\n", "```\n", "\n", "AgentChat provides a set of preset Agents, each with variations in how an agent might respond to received messages. \n", "\n", "Each agent inherits from a {py:class}`~autogen_agentchat.base.BaseChatAgent` class with a few generic properties:\n", "\n", "- `name`: The name of the agent. This is used by the team to uniquely identify the agent. It should be unique within the team.\n", "- `description`: The description of the agent. This is used by the team to make decisions about which agents to use. The description should detail the agent's capabilities and how to interact with it.\n", " \n", "```{tip}\n", "How do agents send and receive messages? \n", "\n", "AgentChat is built on the `autogen-core` package, which handles the details of sending and receiving messages. `autogen-core` provides a runtime environment, which facilitates communication between agents (message sending and delivery), manages their identities and lifecycles, and enforces security and privacy boundaries. \n", "AgentChat handles the details of instantiating a runtime and registering agents with the runtime.\n", "\n", "To learn more about the runtime in `autogen-core`, see the [autogen-core documentation on agents and runtime](../../core-user-guide/framework/agent-and-agent-runtime.ipynb).\n", "```\n", "\n", "Each agent also implements an {py:meth}`~autogen_agentchat.base.BaseChatAgent.on_messages` method that defines the behavior of the agent in response to a message.\n", "\n", "\n", "To begin, let us import the required classes and set up a model client that will be used by agents.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import logging\n", "\n", "from autogen_agentchat import EVENT_LOGGER_NAME\n", "from autogen_agentchat.agents import ToolUseAssistantAgent\n", "from autogen_agentchat.logging import ConsoleLogHandler\n", "from autogen_agentchat.messages import TextMessage\n", "from autogen_core.base import CancellationToken\n", "from autogen_core.components.models import OpenAIChatCompletionClient\n", "from autogen_core.components.tools import FunctionTool\n", "\n", "logger = logging.getLogger(EVENT_LOGGER_NAME)\n", "logger.addHandler(ConsoleLogHandler())\n", "logger.setLevel(logging.INFO)\n", "\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", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "## ToolUseAssistantAgent\n", "\n", "This agent responds to messages by making appropriate tool or function calls.\n", "\n", "```{tip}\n", "Understanding Tool Calling\n", "\n", "Large Language Models (LLMs) are typically limited to generating text or code responses. However, many complex tasks benefit from the ability to use external tools that perform specific actions, such as fetching data from APIs or databases.\n", "\n", "To address this limitation, modern LLMs can now accept a list of available tool schemas (descriptions of tools and their arguments) and generate a tool call message. This capability is known as **Tool Calling** or **Function Calling** and is becoming a popular pattern in building intelligent agent-based applications.\n", "\n", "For more information on tool calling, refer to the documentation from [OpenAI](https://platform.openai.com/docs/guides/function-calling) and [Anthropic](https://docs.anthropic.com/en/docs/build-with-claude/tool-use).\n", "```\n", "\n", "To set up a ToolUseAssistantAgent in AgentChat, follow these steps:\n", "\n", "1. Define the tool, typically as a Python function.\n", "2. Wrap the function in the `FunctionTool` class from the `autogen-core` package. This ensures the function schema can be correctly parsed and used for tool calling.\n", "3. Attach the tool to the agent.\n", " " ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "async def get_weather(city: str) -> str:\n", " return f\"The weather in {city} is 72 degrees and Sunny.\"\n", "\n", "\n", "get_weather_tool = FunctionTool(get_weather, description=\"Get the weather for a city\")\n", "\n", "tool_use_agent = ToolUseAssistantAgent(\n", " \"tool_use_agent\",\n", " system_message=\"You are a helpful assistant that solves tasks by only using your tools.\",\n", " model_client=model_client,\n", " registered_tools=[get_weather_tool],\n", ")" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "source='tool_use_agent' content=\"Could you please specify a city in France for which you'd like to get the current weather?\"\n" ] } ], "source": [ "tool_result = await tool_use_agent.on_messages(\n", " messages=[\n", " TextMessage(content=\"What is the weather right now in France?\", source=\"user\"),\n", " ],\n", " cancellation_token=CancellationToken(),\n", ")\n", "print(tool_result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see that the response generated by the ToolUseAssistantAgent is a tool call message which can then be executed to get the right result. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "## CodeExecutionAgent \n", "\n", "This agent preset extracts and executes code snippets found in received messages and returns the output. It is typically used within a team where a `CodingAssistantAgent` is also present - the `CodingAssistantAgent` can generate code snippets, which the `CodeExecutionAgent` receives and executes to make progress on a task. \n", "\n", "```{note}\n", "It is recommended that the `CodeExecutionAgent` uses a Docker container to execute code snippets. This ensures that the code snippets are executed in a safe and isolated environment. To use Docker, your environment must have Docker installed and running. \n", "If you do not have Docker installed, you can install it from the [Docker website](https://docs.docker.com/get-docker/) or alternatively skip the next cell.\n", "```\n", "\n", "In the code snippet below, we show how to set up a `CodeExecutionAgent` that uses the `DockerCommandLineCodeExecutor` class to execute code snippets in a Docker container. The `work_dir` parameter indicates where all executed files are first saved locally before being executed in the Docker container.\n", "\n", "\n", " " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "source='code_executor' content='No code blocks found in the thread.'\n" ] } ], "source": [ "from autogen_agentchat.agents import CodeExecutorAgent\n", "from autogen_ext.code_executors import DockerCommandLineCodeExecutor\n", "\n", "async with DockerCommandLineCodeExecutor(work_dir=\"coding\") as code_executor: # type: ignore[syntax]\n", " code_executor_agent = CodeExecutorAgent(\"code_executor\", code_executor=code_executor)\n", " code_execution_result = await code_executor_agent.on_messages(\n", " messages=[\n", " TextMessage(content=\"Here is some code \\n ```python print('Hello world') \\n``` \", source=\"user\"),\n", " ],\n", " cancellation_token=CancellationToken(),\n", " )\n", " print(code_execution_result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building Custom Agents\n", "\n", "In many cases, you may have agents with custom behaviors that do not fall into any of the preset agent categories. In such cases, you can build custom agents by subclassing the {py:class}`~autogen_agentchat.agents.BaseChatAgent` class and implementing the {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_messages` method.\n", "\n", "A common example is an agent that can be part of a team but primarily is driven by human input. Other examples include agents that respond with specific text, tool or function calls. \n", "\n", "In the example below we show hot to implement a `UserProxyAgent` - an agent that asks the user to enter some text and then returns that message as a response. " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "source='user_proxy_agent' content='Hello there'\n" ] } ], "source": [ "import asyncio\n", "from typing import Sequence\n", "\n", "from autogen_agentchat.agents import BaseChatAgent\n", "from autogen_agentchat.messages import (\n", " ChatMessage,\n", " StopMessage,\n", " TextMessage,\n", ")\n", "\n", "\n", "class UserProxyAgent(BaseChatAgent):\n", " def __init__(self, name: str) -> None:\n", " super().__init__(name, \"A human user.\")\n", "\n", " async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> ChatMessage:\n", " user_input = await asyncio.get_event_loop().run_in_executor(None, input, \"Enter your response: \")\n", " if \"TERMINATE\" in user_input:\n", " return StopMessage(content=\"User has terminated the conversation.\", source=self.name)\n", " return TextMessage(content=user_input, source=self.name)\n", "\n", "\n", "user_proxy_agent = UserProxyAgent(name=\"user_proxy_agent\")\n", "\n", "user_proxy_agent_result = await user_proxy_agent.on_messages(\n", " messages=[\n", " TextMessage(content=\"What is the weather right now in France?\", source=\"user\"),\n", " ],\n", " cancellation_token=CancellationToken(),\n", ")\n", "print(user_proxy_agent_result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "So far, we have learned a few key concepts:\n", "\n", "- How to define agents \n", "- How to send messages to agents by calling the {py:meth}`~autogen_agentchat.agents.BaseChatAgent.on_messages` method on the {py:class}`~autogen_agentchat.agents.BaseChatAgent` class and viewing the agent's response \n", "- An overview of the different types of agents available in AgentChat\n", "- How to build custom agents\n", "\n", "However, the ability to address complex tasks is often best served by groups of agents that interact as a team. Let us review how to build these teams." ] } ], "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 }