工具
拥有适当的工具抽象是构建LlamaIndex中的智能体系统的核心。定义一组工具类似于定义任何API接口,不同之处在于这些工具是为智能体而非人类使用而设计的。我们允许用户定义工具以及包含一系列底层函数的工具规范。
在使用具有函数调用功能的智能体或LLM时,所选工具(以及为该工具编写的参数)在很大程度上依赖于工具的工具名称和描述,包括其用途和参数。花时间调整这些参数可以显著改变LLM调用这些工具的方式。
一个工具实现了一个非常通用的接口 - 只需定义 __call__ 并返回一些基本元数据(名称、描述、函数模式)。
我们提供几种不同类型的工具:
FunctionTool: 函数工具允许用户轻松将任何自定义函数转换为工具。它可以自动推断函数模式,或让您自定义各个方面。QueryEngineTool: 一个封装现有查询引擎的工具。注意:由于我们的智能体抽象继承自BaseQueryEngine,这些工具也可以封装其他智能体。- 社区贡献的
ToolSpecs定义了围绕单个服务(如 Gmail)的一个或多个工具 - 用于封装其他工具的工具集,以处理从工具返回大量数据的情况
FunctionTool
Section titled “FunctionTool”函数工具是对任何现有函数(支持同步和异步!)的简单封装。
from llama_index.core.agent.workflow import ReActAgentfrom 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
Section titled “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.core.agent.workflow import FunctionAgentfrom 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请求返回数据的模式。
让我们来了解下面的两个主要实用工具。
OnDemandLoaderTool
Section titled “OnDemandLoaderTool”该工具可将任何现有的LlamaIndex数据加载器(BaseReader类)转换为智能体可使用的工具。该工具可通过调用数据加载器中触发load_data所需的所有参数及自然语言查询字符串来调用。在执行过程中,我们首先从数据加载器加载数据,对其进行索引(例如使用向量存储),然后“按需”进行查询。这三个步骤均在单次工具调用中完成。
通常这比自行研究如何加载和索引API数据更为可取。虽然这可能有助于数据复用,但用户通常只需要一个临时索引来规避任何API调用的提示窗口限制。
以下是一个使用示例:
pip install llama-index-readers-wikipediafrom llama_index.readers.wikipedia import WikipediaReaderfrom 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
Section titled “LoadAndSearchToolSpec”LoadAndSearchToolSpec 接受任何现有工具作为输入。作为工具规范,它实现了 to_tool_list,当调用该函数时,会返回两个工具:一个 load 工具和一个 search 工具。
load 工具执行将调用底层工具,并对输出建立索引(默认使用向量索引)。search 工具执行将接收查询字符串作为输入,并调用底层索引。
这对于任何默认会返回大量数据的API端点都很有帮助 - 例如我们的WikipediaToolSpec默认会返回完整的维基百科页面,这很容易超出大多数LLM上下文窗口的限制。
示例如下所示:
pip install llama-index-tools-wikipediafrom llama_index.core.agent.workflow import FunctionAgentfrom 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 tooltool = wiki_spec.to_tool_list()[1]
# Create the Agent with load/search toolsagent = 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)