Skip to content

工具#

概念#

拥有适当的工具抽象是构建数据代理的核心。定义一组工具类似于定义任何 API 接口,唯一的区别在于这些工具是为代理而不是人类使用的。我们允许用户定义工具工具规范,其中包含一系列在幕后运行的函数。

在使用代理或 LLM 进行函数调用时,所选的工具(以及为该工具编写的参数)强烈依赖于工具名称和工具用途及参数的描述。花时间调整这些参数可能会导致 LLM 调用这些工具的方式发生很大变化。

工具实现了一个非常通用的接口 - 只需定义 __call__ 并返回一些基本元数据(名称、描述、函数模式)。

我们提供了几种不同类型的工具:

  • FunctionTool:函数工具允许用户轻松地将任何用户定义的函数转换为工具。它还可以自动推断函数模式。
  • QueryEngineTool:包装现有查询引擎的工具。注意:由于我们的代理抽象继承自 BaseQueryEngine,这些工具也可以包装其他代理。
  • 社区贡献的ToolSpecs,定义了围绕单个服务(如 Gmail)的一个或多个工具。
  • 用于包装其他工具以处理从工具返回大量数据的实用工具

FunctionTool#

函数工具是对任何现有函数(支持同步和异步!)的简单包装。

from llama_index.core.tools import FunctionTool


def get_weather(location: str) -> str:
    """用于获取给定位置的天气。"""
    ...


tool = FunctionTool.from_defaults(
    get_weather,
    # async_fn=aget_weather,  # 可选!
)

agent = ReActAgent.from_tools(tools, llm=llm, verbose=True)

为了更好地定义函数,您还可以利用 pydantic 来定义函数参数。

from pydantic import Field


def get_weather(
    location: str = Field(
        description="一个城市名称和州,格式为'<名称>,<州>'"
    ),
) -> str:
    """用于获取给定位置的天气。"""
    ...


tool = FunctionTool.from_defaults(get_weather)

默认情况下,工具名称将是函数名称,文档字符串将是工具描述。但您也可以覆盖这一点。

tool = FunctionTool.from_defaults(get_weather, name="...", description="...")

QueryEngineTool#

任何查询引擎都可以使用 QueryEngineTool 转换为工具:

from llama_index.core.tools import QueryEngineTool

tool = QueryEngineTool.from_defaults(
    query_engine, name="...", description="..."
)

工具规范#

我们还通过LlamaHub提供了丰富的工具和工具规范。

您可以将工具规范视为一起使用的工具包。通常,这些工具覆盖了单个接口/服务(如 Gmail)上的有用工具。

要与代理一起使用,您可以安装特定的工具规范集成:

pip install llama-index-tools-google

然后使用它:

from llama_index.agent.openai import OpenAIAgent
from llama_index.tools.google import GmailToolSpec

tool_spec = GmailToolSpec()
agent = OpenAIAgent.from_tools(tool_spec.to_tool_list(), verbose=True)

请参阅LlamaHub获取社区贡献的工具规范的完整列表,或查看我们的指南以获取有关 LlamaHub 中的工具/工具规范的完整概述!

实用工具#

通常,直接查询 API 可能会返回大量数据,这些数据本身可能会超出 LLM 的上下文窗口(或者至少会不必要地增加您使用的标记数量)。

为了解决这个问题,我们在 LlamaHub 工具中提供了一组初始的“实用工具” - 实用工具在概念上不与特定服务(例如 Gmail、Notion)绑定,而是可以增强现有工具的功能。在这种情况下,实用工具有助于抽象化来自任何 API 请求返回的数据的常见模式,需要缓存/索引和查询数据。

让我们在下面详细介绍我们的两个主要实用工具。

OnDemandLoaderTool#

这个工具将任何现有的 LlamaIndex 数据加载器(BaseReader 类)转换为代理可以使用的工具。可以使用调用工具时需要的所有参数来调用工具,以及一个自然语言查询字符串。在执行过程中,我们首先从数据加载器加载数据,对其进行索引(例如使用向量存储),然后“按需”查询它。所有这三个步骤都在单个工具调用中发生。

通常,这可能比自己找出如何加载和索引 API 数据更可取。虽然这可能允许数据的可重用性,但通常用户只需要一个临时索引来抽象化任何 API 调用的提示窗口限制。

下面给出了一个使用示例:

from llama_index.readers.wikipedia import WikipediaReader
from llama_index.core.tools.ondemand_loader_tool import OnDemandLoaderTool

tool = OnDemandLoaderTool.from_defaults(
    reader,
    name="Wikipedia Tool",
    description="A tool for loading data and querying articles from Wikipedia",
)

LoadAndSearchToolSpec#

LoadAndSearchToolSpec 接受任何现有的工具作为输入。作为工具规范,它实现了 to_tool_list 方法,当调用该方法时,会返回两个工具:一个 load 工具,然后是一个 search 工具。

load 工具的执行会调用底层工具,并对输出进行索引(默认情况下使用向量索引)。search 工具的执行会接受查询字符串作为输入,并调用底层索引。

这对于默认情况下会返回大量数据的任何 API 端点非常有用 - 例如,我们的 WikipediaToolSpec 默认情况下会返回整个维基百科页面,这将很容易超出大多数 LLM 上下文窗口的容量。

下面显示了一个示例用法:

from llama_index.tools.wikipedia import WikipediaToolSpec
from llama_index.core.tools.tool_spec.load_and_search import (
    LoadAndSearchToolSpec,
)

wiki_spec = WikipediaToolSpec()
# 获取搜索维基百科的工具
tool = wiki_spec.to_tool_list()[1]

# 使用 load/search 工具创建 Agent
agent = OpenAIAgent.from_tools(
    LoadAndSearchToolSpec.from_defaults(tool).to_tool_list(), verbose=True
)

直接返回#

您会注意到工具类构造函数中的选项 return_direct。如果将其设置为 True,则代理的响应将直接返回,而不经过代理解释和重写。这有助于减少运行时间,或设计/指定将结束代理推理循环的工具。

例如,假设您指定了一个工具:

tool = QueryEngineTool.from_defaults(
    query_engine,
    name="<name>",
    description="<description>",
    return_direct=True,
)

agent = OpenAIAgent.from_tools([tool])

response = agent.chat("<question that invokes tool>")

在上面的示例中,将调用查询引擎工具,并且该工具的响应将直接作为响应返回,执行循环将结束。

如果使用了 return_direct=False,那么代理将使用聊天历史记录的上下文重写响应,甚至进行另一个工具调用。

我们还提供了一个示例笔记本来演示如何使用 return_direct

调试工具#

通常,调试被发送到 API 的工具定义是非常有用的。

您可以通过使用获取当前工具模式的基础函数来很好地查看这一点,这在 OpenAI 和 Anthropic 等 API 中被利用。

schema = tool.metadata.get_parameters_dict()
print(schema)