跳转到内容

工具

拥有适当的工具抽象是构建LlamaIndex中的智能体系统的核心。定义一组工具类似于定义任何API接口,不同之处在于这些工具是为智能体而非人类使用而设计的。我们允许用户定义工具以及包含一系列底层函数的工具规范

在使用具有函数调用功能的智能体或LLM时,所选工具(以及为该工具编写的参数)在很大程度上依赖于工具的工具名称描述,包括其用途和参数。花时间调整这些参数可以显著改变LLM调用这些工具的方式。

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

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

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

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

from llama_index.core.agent.workflow import ReActAgent
from llama_index.core.tools import FunctionTool
def get_weather(location: str) -> str:
"""Usfeful for getting the weather for a given location."""
...
tool = FunctionTool.from_defaults(
get_weather,
# async_fn=aget_weather, # optional!
)
agent = ReActAgent(llm=llm, tools=tools)

为了更好的函数定义,您还可以利用 Annotated 类型来指定参数描述。

from typing import Annotated
def get_weather(
location: Annotated[
str, "A city name and state, formatted like '<name>, <state>'"
],
) -> str:
"""Useful for getting the weather for a given location."""
...
tool = FunctionTool.from_defaults(get_weather)

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

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

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

from llama_index.core.tools import QueryEngineTool
tool = QueryEngineTool.from_defaults(
query_engine, name="...", description="..."
)

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

您可以将工具规范视为需要一起使用的工具包。通常这些规范涵盖单个接口/服务中的实用工具,例如Gmail。

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

Terminal window
pip install llama-index-tools-google

然后使用它:

from llama_index.core.agent.workflow import FunctionAgent
from llama_index.tools.google import GmailToolSpec
tool_spec = GmailToolSpec()
agent = FunctionAgent(llm=llm, tools=tool_spec.to_tool_list())

查看 LlamaHub 获取社区贡献工具规范的完整列表。

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

为了解决这个问题,我们在LlamaHub工具中提供了一套初始的“实用工具”——这些工具在概念上并不与特定服务(如Gmail、Notion)绑定,而是能够增强现有工具的能力。在此特定场景中,实用工具有助于抽象化常见的缓存/索引和查询从任何API请求返回数据的模式。

让我们来了解下面的两个主要实用工具。

该工具可将任何现有的LlamaIndex数据加载器(BaseReader类)转换为智能体可使用的工具。该工具可通过调用数据加载器中触发load_data所需的所有参数及自然语言查询字符串来调用。在执行过程中,我们首先从数据加载器加载数据,对其进行索引(例如使用向量存储),然后“按需”进行查询。这三个步骤均在单次工具调用中完成。

通常这比自行研究如何加载和索引API数据更为可取。虽然这可能有助于数据复用,但用户通常只需要一个临时索引来规避任何API调用的提示窗口限制。

以下是一个使用示例:

Terminal window
pip install llama-index-readers-wikipedia
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 接受任何现有工具作为输入。作为工具规范,它实现了 to_tool_list,当调用该函数时,会返回两个工具:一个 load 工具和一个 search 工具。

load 工具执行将调用底层工具,并对输出建立索引(默认使用向量索引)。search 工具执行将接收查询字符串作为输入,并调用底层索引。

这对于任何默认会返回大量数据的API端点都很有帮助 - 例如我们的WikipediaToolSpec默认会返回完整的维基百科页面,这很容易超出大多数LLM上下文窗口的限制。

示例如下所示:

Terminal window
pip install llama-index-tools-wikipedia
from llama_index.core.agent.workflow import FunctionAgent
from llama_index.core.tools.tool_spec.load_and_search import (
LoadAndSearchToolSpec,
)
from llama_index.tools.wikipedia import WikipediaToolSpec
wiki_spec = WikipediaToolSpec()
# Get the search wikipedia tool
tool = wiki_spec.to_tool_list()[1]
# Create the Agent with load/search tools
agent = FunctionAgent(
llm=llm, tools=LoadAndSearchToolSpec.from_defaults(tool).to_tool_list()
)

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

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

tool = QueryEngineTool.from_defaults(
query_engine,
name="<name>",
description="<description>",
return_direct=True,
)
agent = FunctionAgent(llm=llm, tools=[tool])
response = await agent.run("<question that invokes tool>")

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

如果使用了 return_direct=False,那么智能体会根据聊天历史记录的内容重写回复,甚至可能发起另一个工具调用。

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

通常,调试发送给API的工具定义具体内容会很有帮助。

您可以通过使用底层函数获取当前工具模式来很好地了解这一点,该模式在OpenAI和Anthropic等API中被利用。

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