From ad123641daf956a4700cd0a67c05296ff1146d7c Mon Sep 17 00:00:00 2001 From: Mohammad Mazraeh Date: Wed, 8 Jan 2025 06:23:31 -0800 Subject: [PATCH] Update agent and agent runtime doc with routed agent (#4935) * add back removed note Signed-off-by: Mohammad Mazraeh * fix formatting issues Signed-off-by: Mohammad Mazraeh --------- Signed-off-by: Mohammad Mazraeh --- .../framework/agent-and-agent-runtime.ipynb | 565 +++++++++--------- 1 file changed, 282 insertions(+), 283 deletions(-) diff --git a/python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/agent-and-agent-runtime.ipynb b/python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/agent-and-agent-runtime.ipynb index bfff326b56d0..f1de10bf494d 100644 --- a/python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/agent-and-agent-runtime.ipynb +++ b/python/packages/autogen-core/docs/src/user-guide/core-user-guide/framework/agent-and-agent-runtime.ipynb @@ -1,285 +1,284 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Agent and Agent Runtime\n", - "\n", - "In this and the following section, we focus on the core concepts of AutoGen:\n", - "agents, agent runtime, messages, and communication.\n", - "You will not find any AI models or tools here, just the foundational\n", - "building blocks for building multi-agent applications.\n", - "\n", - "```{note}\n", - "The Core API is designed to be unopinionated and flexible. So at times, you\n", - "may find it challenging. Continue if you are building\n", - "an interactive, scalable and distributed multi-agent system and want full control\n", - "of all workflows.\n", - "If you just want to get something running\n", - "quickly, you may take a look at the [AgentChat API](../../agentchat-user-guide/index.md).\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "An agent in AutoGen is an entity defined by the base class {py:class}`autogen_core.Agent`.\n", - "It has a unique identifier of the type {py:class}`autogen_core.AgentId`,\n", - "a metadata dictionary of the type {py:class}`autogen_core.AgentMetadata`,\n", - "and method for handling messages {py:meth}`autogen_core.BaseAgent.on_message_impl`.\n", - "\n", - "An agent runtime is the execution environment for agents in AutoGen.\n", - "Similar to the runtime environment of a programming language,\n", - "an agent runtime provides the necessary infrastructure to facilitate communication\n", - "between agents, manage agent lifecycles, enforce security boundaries, and support monitoring and\n", - "debugging.\n", - "For local development, developers can use {py:class}`~autogen_core.SingleThreadedAgentRuntime`,\n", - "which can be embedded in a Python application.\n", - "\n", - "```{note}\n", - "Agents are not directly instantiated and managed by application code.\n", - "Instead, they are created by the runtime when needed and managed by the runtime.\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Implementing an Agent\n", - "\n", - "To implement an agent, the developer must subclass the {py:class}`~autogen_core.BaseAgent` class\n", - "and implement the {py:meth}`~autogen_core.BaseAgent.on_message_impl` method.\n", - "This method is invoked when the agent receives a message. For example,\n", - "the following agent handles a simple message type and prints the message it receives:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from dataclasses import dataclass\n", - "\n", - "from autogen_core import AgentId, BaseAgent, MessageContext\n", - "\n", - "\n", - "@dataclass\n", - "class MyMessageType:\n", - " content: str\n", - "\n", - "\n", - "class MyAgent(BaseAgent):\n", - " def __init__(self) -> None:\n", - " super().__init__(\"MyAgent\")\n", - "\n", - " async def on_message_impl(self, message: MyMessageType, ctx: MessageContext) -> None:\n", - " print(f\"Received message: {message.content}\") # type: ignore" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This agent only handles `MyMessageType` messages. \n", - "To handle multiple message types, developers can subclass the {py:class}`~autogen_core.RoutedAgent` class\n", - "which provides an easy-to use API to implement different message handlers for different message types.\n", - "See the next section on [message and communication](./message-and-communication.ipynb)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Registering Agent Type\n", - "\n", - "To make agents available to the runtime, developers can use the\n", - "{py:meth}`~autogen_core.BaseAgent.register` class method of the\n", - "{py:class}`~autogen_core.BaseAgent` class.\n", - "The process of registration associates an agent type, which is uniquely identified by a string, \n", - "and a factory function\n", - "that creates an instance of the agent type of the given class.\n", - "The factory function is used to allow automatic creation of agent instances \n", - "when they are needed.\n", - "\n", - "Agent type ({py:class}`~autogen_core.AgentType`) is not the same as the agent class. In this example,\n", - "the agent type is `AgentType(\"my_agent\")` and the agent class is the Python class `MyAgent`.\n", - "The factory function is expected to return an instance of the agent class \n", - "on which the {py:meth}`~autogen_core.BaseAgent.register` class method is invoked.\n", - "Read [Agent Identity and Lifecycles](../core-concepts/agent-identity-and-lifecycle.md)\n", - "to learn more about agent type and identity.\n", - "\n", - "```{note}\n", - "Different agent types can be registered with factory functions that return \n", - "the same agent class. For example, in the factory functions, \n", - "variations of the constructor parameters\n", - "can be used to create different instances of the same agent class.\n", - "```\n", - "\n", - "To register an agent type with the \n", - "{py:class}`~autogen_core.SingleThreadedAgentRuntime`,\n", - "the following code can be used:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "AgentType(type='my_agent')" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from autogen_core import SingleThreadedAgentRuntime\n", - "\n", - "runtime = SingleThreadedAgentRuntime()\n", - "await MyAgent.register(runtime, \"my_agent\", lambda: MyAgent())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Once an agent type is registered, we can send a direct message to an agent instance\n", - "using an {py:class}`~autogen_core.AgentId`.\n", - "The runtime will create the instance the first time it delivers a\n", - "message to this instance." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Received message: Hello, World!\n" - ] - } - ], - "source": [ - "agent_id = AgentId(\"my_agent\", \"default\")\n", - "runtime.start() # Start processing messages in the background.\n", - "await runtime.send_message(MyMessageType(\"Hello, World!\"), agent_id)\n", - "await runtime.stop() # Stop processing messages in the background." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```{note}\n", - "Because the runtime manages the lifecycle of agents, an {py:class}`~autogen_core.AgentId`\n", - "is only used to communicate with the agent or retrieve its metadata (e.g., description).\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Running the Single-Threaded Agent Runtime\n", - "\n", - "The above code snippet uses `runtime.start()` to start a background task\n", - "to process and deliver messages to recepients' message handlers.\n", - "This is a feature of the\n", - "local embedded runtime {py:class}`~autogen_core.SingleThreadedAgentRuntime`.\n", - "\n", - "To stop the background task immediately, use the `stop()` method:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "runtime.start()\n", - "# ... Send messages, publish messages, etc.\n", - "await runtime.stop() # This will return immediately but will not cancel\n", - "# any in-progress message handling." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can resume the background task by calling `start()` again.\n", - "\n", - "For batch scenarios such as running benchmarks for evaluating agents,\n", - "you may want to wait for the background task to stop automatically when\n", - "there are no unprocessed messages and no agent is handling messages --\n", - "the batch may considered complete.\n", - "You can achieve this by using the `stop_when_idle()` method:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "runtime.start()\n", - "# ... Send messages, publish messages, etc.\n", - "await runtime.stop_when_idle() # This will block until the runtime is idle." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can also directly process messages one-by-one without a background task using:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "await runtime.process_next()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Other runtime implementations will have their own ways of running the runtime." - ] - } - ], - "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 + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Agent and Agent Runtime\n", + "\n", + "In this and the following section, we focus on the core concepts of AutoGen:\n", + "agents, agent runtime, messages, and communication.\n", + "You will not find any AI models or tools here, just the foundational\n", + "building blocks for building multi-agent applications.\n", + "\n", + "```{note}\n", + "The Core API is designed to be unopinionated and flexible. So at times, you\n", + "may find it challenging. Continue if you are building\n", + "an interactive, scalable and distributed multi-agent system and want full control\n", + "of all workflows.\n", + "If you just want to get something running\n", + "quickly, you may take a look at the [AgentChat API](../../agentchat-user-guide/index.md).\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "An agent in AutoGen is an entity defined by the base class {py:class}`autogen_core.Agent`.\n", + "It has a unique identifier of the type {py:class}`autogen_core.AgentId`,\n", + "a metadata dictionary of the type {py:class}`autogen_core.AgentMetadata`,\n", + "\n", + "and method for handling messages {py:meth}`autogen_core.BaseAgent.on_message_impl`. In most cases, you can subclass your agents from higher level class {py:class}`autogen_core.RoutedAgent` which enables you to route messages to corresponding message handler specified with {py:meth}`autogen_core.message_handler` decorator and proper type hint for the `message` variable.\n", + "An agent runtime is the execution environment for agents in AutoGen.\n", + "Similar to the runtime environment of a programming language,\n", + "an agent runtime provides the necessary infrastructure to facilitate communication\n", + "between agents, manage agent lifecycles, enforce security boundaries, and support monitoring and\n", + "debugging.\n", + "For local development, developers can use {py:class}`~autogen_core.SingleThreadedAgentRuntime`,\n", + "which can be embedded in a Python application.\n", + "\n", + "```{note}\n", + "Agents are not directly instantiated and managed by application code.\n", + "Instead, they are created by the runtime when needed and managed by the runtime.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implementing an Agent\n", + "\n", + "To implement an agent, the developer must subclass the {py:class}`~autogen_core.RoutedAgent` class\n", + "and implement the {py:meth}`~autogen_core.RoutedAgent.on_message_impl` method.\n", + "This method is invoked when the agent receives a message. For example,\n", + "the following agent handles a simple message type `MyMessageType` and prints the message it receives:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from dataclasses import dataclass\n", + "\n", + "from autogen_core import AgentId, MessageContext, RoutedAgent, message_handler\n", + "\n", + "\n", + "@dataclass\n", + "class MyMessageType:\n", + " content: str\n", + "\n", + "\n", + "class MyAgent(RoutedAgent):\n", + " def __init__(self) -> None:\n", + " super().__init__(\"MyAgent\")\n", + "\n", + " @message_handler\n", + " async def handle_my_message_type(self, message: MyMessageType, ctx: MessageContext) -> None:\n", + " print(f\"Received message: {message.content}\") # type: ignore" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This agent only handles `MyMessageType` and messages will be delivered to `handle_my_message_type` method. Developers can have multiple message handlers for different message types by using `@message_handler` decorator and setting the type hint for the `message` variable in the handler function. You can also leverage [python typing union](https://docs.python.org/3/library/typing.html#typing.Union) for the `message` variable in one message handler function if it better suits agent's logic.\n", + "See the next section on [message and communication](./message-and-communication.ipynb)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Registering Agent Type\n", + "\n", + "To make agents available to the runtime, developers can use the\n", + "{py:meth}`~autogen_core.BaseAgent.register` class method of the\n", + "{py:class}`~autogen_core.BaseAgent` class.\n", + "The process of registration associates an agent type, which is uniquely identified by a string, \n", + "and a factory function\n", + "that creates an instance of the agent type of the given class.\n", + "The factory function is used to allow automatic creation of agent instances \n", + "when they are needed.\n", + "\n", + "Agent type ({py:class}`~autogen_core.AgentType`) is not the same as the agent class. In this example,\n", + "the agent type is `AgentType(\"my_agent\")` and the agent class is the Python class `MyAgent`.\n", + "The factory function is expected to return an instance of the agent class \n", + "on which the {py:meth}`~autogen_core.BaseAgent.register` class method is invoked.\n", + "Read [Agent Identity and Lifecycles](../core-concepts/agent-identity-and-lifecycle.md)\n", + "to learn more about agent type and identity.\n", + "\n", + "```{note}\n", + "Different agent types can be registered with factory functions that return \n", + "the same agent class. For example, in the factory functions, \n", + "variations of the constructor parameters\n", + "can be used to create different instances of the same agent class.\n", + "```\n", + "\n", + "To register an agent type with the \n", + "{py:class}`~autogen_core.SingleThreadedAgentRuntime`,\n", + "the following code can be used:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "AgentType(type='my_agent')" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from autogen_core import SingleThreadedAgentRuntime\n", + "\n", + "runtime = SingleThreadedAgentRuntime()\n", + "await MyAgent.register(runtime, \"my_agent\", lambda: MyAgent())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once an agent type is registered, we can send a direct message to an agent instance\n", + "using an {py:class}`~autogen_core.AgentId`.\n", + "The runtime will create the instance the first time it delivers a\n", + "message to this instance." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Received message: Hello, World!\n" + ] + } + ], + "source": [ + "agent_id = AgentId(\"my_agent\", \"default\")\n", + "runtime.start() # Start processing messages in the background.\n", + "await runtime.send_message(MyMessageType(\"Hello, World!\"), agent_id)\n", + "await runtime.stop() # Stop processing messages in the background." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```{note}\n", + "Because the runtime manages the lifecycle of agents, an {py:class}`~autogen_core.AgentId`\n", + "is only used to communicate with the agent or retrieve its metadata (e.g., description).\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running the Single-Threaded Agent Runtime\n", + "\n", + "The above code snippet uses `runtime.start()` to start a background task\n", + "to process and deliver messages to recepients' message handlers.\n", + "This is a feature of the\n", + "local embedded runtime {py:class}`~autogen_core.SingleThreadedAgentRuntime`.\n", + "\n", + "To stop the background task immediately, use the `stop()` method:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "runtime.start()\n", + "# ... Send messages, publish messages, etc.\n", + "await runtime.stop() # This will return immediately but will not cancel\n", + "# any in-progress message handling." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can resume the background task by calling `start()` again.\n", + "\n", + "For batch scenarios such as running benchmarks for evaluating agents,\n", + "you may want to wait for the background task to stop automatically when\n", + "there are no unprocessed messages and no agent is handling messages --\n", + "the batch may considered complete.\n", + "You can achieve this by using the `stop_when_idle()` method:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "runtime.start()\n", + "# ... Send messages, publish messages, etc.\n", + "await runtime.stop_when_idle() # This will block until the runtime is idle." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also directly process messages one-by-one without a background task using:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "await runtime.process_next()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Other runtime implementations will have their own ways of running the runtime." + ] + } + ], + "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.11" + } + }, + "nbformat": 4, + "nbformat_minor": 2 }