{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 工具\n", "\n", "工具是可以由代理执行以执行操作的代码。工具可以是简单的函数,如计算器,或者是对第三方服务的 API 调用,如股票价格查询或天气预报。在 AI 代理的上下文中,工具被设计为由代理响应模型生成的函数调用来执行。\n", "\n", "AutoGen 提供了 {py:mod}`autogen_core.components.tools` 模块,其中包含一套内置工具和用于创建和运行自定义工具的实用程序。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 内置工具\n", "\n", "其中一个内置工具是 {py:class}`~autogen_core.components.tools.PythonCodeExecutionTool`,它允许代理执行 Python 代码片段。\n", "\n", "以下是如何创建和使用该工具。" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, world!\n", "\n" ] } ], "source": [ "from autogen_core.base import CancellationToken\n", "from autogen_core.components.tools import PythonCodeExecutionTool\n", "from autogen_ext.code_executors import DockerCommandLineCodeExecutor\n", "\n", "# Create the tool.\n", "code_executor = DockerCommandLineCodeExecutor()\n", "await code_executor.start()\n", "code_execution_tool = PythonCodeExecutionTool(code_executor)\n", "cancellation_token = CancellationToken()\n", "\n", "# Use the tool directly without an agent.\n", "code = \"print('Hello, world!')\"\n", "result = await code_execution_tool.run_json({\"code\": code}, cancellation_token)\n", "print(code_execution_tool.return_value_as_string(result))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "{py:class}`~autogen_core.components.code_executor.docker_executorCommandLineCodeExecutor` 类是一个内置的代码执行器,它在本地命令行环境的子进程中运行 Python 代码片段。{py:class}`~autogen_core.components.tools.PythonCodeExecutionTool` 类包装了代码执行器,并提供了一个简单的接口来执行 Python 代码片段。\n", "\n", "其他内置工具将在未来添加。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 自定义函数工具\n", "\n", "工具也可以是执行特定操作的简单 Python 函数。要创建自定义函数工具,您只需创建一个 Python 函数,并使用 {py:class}`~autogen_core.components.tools.FunctionTool` 类来包装它。\n", "\n", "{py:class}`~autogen_core.components.tools.FunctionTool` 类使用描述和类型注解来告知 LLM 何时以及如何使用给定的函数。描述提供了关于函数目的和预期用例的上下文,而类型注解则告知 LLM 预期的参数和返回类型。\n", "\n", "例如,一个获取公司股票价格的简单工具可能如下所示:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "80.44429939059668\n" ] } ], "source": [ "import random\n", "\n", "from autogen_core.base import CancellationToken\n", "from autogen_core.components.tools import FunctionTool\n", "from typing_extensions import Annotated\n", "\n", "\n", "async def get_stock_price(ticker: str, date: Annotated[str, \"Date in YYYY/MM/DD\"]) -> float:\n", " # Returns a random stock price for demonstration purposes.\n", " return random.uniform(10, 200)\n", "\n", "\n", "# Create a function tool.\n", "stock_price_tool = FunctionTool(get_stock_price, description=\"Get the stock price.\")\n", "\n", "# Run the tool.\n", "cancellation_token = CancellationToken()\n", "result = await stock_price_tool.run_json({\"ticker\": \"AAPL\", \"date\": \"2021/01/01\"}, cancellation_token)\n", "\n", "# Print the result.\n", "print(stock_price_tool.return_value_as_string(result))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tool-Equipped Agent\n", "\n", "要在代理中使用工具,您可以使用 {py:class}`~autogen_core.components.tool_agent.ToolAgent`,通过在组合模式中使用它。\n", "这里是一个使用 {py:class}`~autogen_core.components.tool_agent.ToolAgent` 作为内部代理来执行工具的工具使用代理示例。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from dataclasses import dataclass\n", "from typing import List\n", "\n", "from autogen_core.application import SingleThreadedAgentRuntime\n", "from autogen_core.base import AgentId, AgentInstantiationContext, MessageContext\n", "from autogen_core.components import RoutedAgent, message_handler\n", "from autogen_core.components.models import (\n", " ChatCompletionClient,\n", " LLMMessage,\n", " OpenAIChatCompletionClient,\n", " SystemMessage,\n", " UserMessage,\n", ")\n", "from autogen_core.components.tool_agent import ToolAgent, tool_agent_caller_loop\n", "from autogen_core.components.tools import FunctionTool, Tool, ToolSchema\n", "\n", "\n", "@dataclass\n", "class Message:\n", " content: str\n", "\n", "\n", "class ToolUseAgent(RoutedAgent):\n", " def __init__(self, model_client: ChatCompletionClient, tool_schema: List[ToolSchema], tool_agent_type: str) -> None:\n", " super().__init__(\"An agent with tools\")\n", " self._system_messages: List[LLMMessage] = [SystemMessage(\"You are a helpful AI assistant.\")]\n", " self._model_client = model_client\n", " self._tool_schema = tool_schema\n", " self._tool_agent_id = AgentId(tool_agent_type, self.id.key)\n", "\n", " @message_handler\n", " async def handle_user_message(self, message: Message, ctx: MessageContext) -> Message:\n", " # Create a session of messages.\n", " session: List[LLMMessage] = [UserMessage(content=message.content, source=\"user\")]\n", " # Run the caller loop to handle tool calls.\n", " messages = await tool_agent_caller_loop(\n", " self,\n", " tool_agent_id=self._tool_agent_id,\n", " model_client=self._model_client,\n", " input_messages=session,\n", " tool_schema=self._tool_schema,\n", " cancellation_token=ctx.cancellation_token,\n", " )\n", " # Return the final response.\n", " assert isinstance(messages[-1].content, str)\n", " return Message(content=messages[-1].content)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`ToolUseAgent` 类使用一个便利函数 {py:meth}`~autogen_core.components.tool_agent.tool_agent_caller_loop`,来处理模型和工具代理之间的交互。\n", "核心思想可以用一个简单的控制流图来描述:\n", "\n", "![ToolUseAgent 控制流图](tool-use-agent-cfg.svg)\n", "\n", "`ToolUseAgent` 的 `handle_user_message` 处理程序处理来自用户的消息,并确定模型是否生成了工具调用。如果模型生成了工具调用,那么处理程序会向 {py:class}`~autogen_core.components.tool_agent.ToolAgent` 代理发送函数调用消息来执行工具,然后使用工具调用的结果再次查询模型。这个过程会一直持续,直到模型停止生成工具调用,此时最终响应会返回给用户。\n", "\n", "通过将工具执行逻辑放在单独的代理中,我们将模型-工具交互作为消息暴露给代理运行时,因此工具执行可以在外部观察并在必要时进行拦截。\n", "\n", "要运行代理,我们需要创建一个运行时并注册代理。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "AgentType(type='tool_use_agent')" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a runtime.\n", "runtime = SingleThreadedAgentRuntime()\n", "# Create the tools.\n", "tools: List[Tool] = [FunctionTool(get_stock_price, description=\"Get the stock price.\")]\n", "# Register the agents.\n", "await ToolAgent.register(runtime, \"tool_executor_agent\", lambda: ToolAgent(\"tool executor agent\", tools))\n", "await ToolUseAgent.register(\n", " runtime,\n", " \"tool_use_agent\",\n", " lambda: ToolUseAgent(\n", " OpenAIChatCompletionClient(model=\"gpt-4o-mini\"), [tool.schema for tool in tools], \"tool_executor_agent\"\n", " ),\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "这个示例使用了 {py:class}`autogen_core.components.models.OpenAIChatCompletionClient`,对于 Azure OpenAI 和其他客户端,请参见[模型客户端](./model-clients.ipynb)。让我们用一个关于股票价格的问题来测试这个代理。" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The stock price of NVDA (NVIDIA Corporation) on June 1, 2024, was approximately $179.46.\n" ] } ], "source": [ "# Start processing messages.\n", "runtime.start()\n", "# Send a direct message to the tool agent.\n", "tool_use_agent = AgentId(\"tool_use_agent\", \"default\")\n", "response = await runtime.send_message(Message(\"What is the stock price of NVDA on 2024/06/01?\"), tool_use_agent)\n", "print(response.content)\n", "# Stop processing messages.\n", "await runtime.stop()" ] } ], "metadata": { "kernelspec": { "display_name": "autogen_core", "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.7" } }, "nbformat": 4, "nbformat_minor": 2 }