工具
概览
LangChain 中的 工具抽象将一个 Python 函数与一个 模式关联起来,该模式定义了函数的 名称、描述以及 预期参数。
工具可以传递给支持工具调用的聊天模型,使模型能够请求执行具有特定输入的具体函数。
关键概念
- 工具是一种将函数及其模式封装起来的方式,以便可以将其传递给聊天模型。
- 使用 @tool 装饰器创建工具,该装饰器简化了工具创建流程,支持以下内容:
- 自动推断工具的名称、描述和预期参数,同时支持自定义。
- 定义返回工件(例如图像、数据框等)的工具。
- 使用注入式工具参数隐藏模式中的输入参数(因此对模型不可见)。
工具接口
该工具接口在 BaseTool 类中定义,该类是 可运行接口(Runnable Interface) 的子类。
该工具对应的关键属性:schema:
- 名称: 工具的中文名称。
- description: 该工具功能的描述。
- args: 返回工具参数的 JSON schema 的属性。
执行与工具关联的函数的关键方法:
- invoke: 使用给定的参数调用该工具。
- ainvoke: 使用给定参数异步调用工具。用于Langchain的异步编程。
使用 @tool 装饰器创建工具
创建工具的推荐方式是使用 @tool 装饰器。该装饰器旨在简化工具创建流程,在大多数情况下都应优先使用。定义函数后,可通过 @tool 对其进行装饰,从而创建一个实现 工具接口 的工具。
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
有关如何创建工具的更多详细信息,请参阅如何创建自定义工具指南。
LangChain 还有几种创建工具的方法;例如,通过继承 BaseTool 类或使用 StructuredTool。这些方法在 如何创建自定义工具的指南 中有所展示,但我们通常建议使用 @tool 装饰器来处理大多数情况。
直接使用工具
一旦定义了工具,您就可以通过调用该函数直接使用它。例如,要使用上面定义的 multiply 工具:
multiply.invoke({"a": 2, "b": 3})
检查
您还可以检查工具的架构和其他属性:
print(multiply.name) # multiply
print(multiply.description) # Multiply two numbers.
print(multiply.args)
# {
# 'type': 'object',
# 'properties': {'a': {'type': 'integer'}, 'b': {'type': 'integer'}},
# 'required': ['a', 'b']
# }
如果您使用的是预构建的 LangChain 或 LangGraph 组件(例如 create_react_agent),可能无需直接与工具交互。然而,了解如何使用它们对于调试和测试非常有价值。此外,在构建自定义 LangGraph 工作流时,您可能需要直接与工具进行交互。
配置模式
The @tool 装饰器提供了额外的选项来配置工具的架构(例如,修改名称、描述,或解析函数的文档字符串以推断架构)。
请查看 @tool 的 API 参考 以获取更多详细信息,并浏览 如何创建自定义工具 指南以获取示例。
工具产物
工具是可由模型调用的实用程序,其输出设计为可反馈给模型。然而,有时工具执行过程中会产生一些产物,我们希望使其对链或智能体中的下游组件可访问,但不希望暴露给模型本身。例如,如果工具返回自定义对象、数据框或图像,我们可能希望将有关该输出的某些元数据传递给模型,而不将实际输出传递给模型。同时,我们可能希望能够在其他地方访问此完整输出,例如在下游工具中。
@tool(response_format="content_and_artifact")
def some_tool(...) -> Tuple[str, Any]:
"""Tool that does something."""
...
return 'Message for chat model', some_artifact
查看 如何从工具返回工件 以获取更多详细信息。
特殊类型注解
有一系列特殊的类型注解可用于工具的函数签名中,以配置工具的运行时行为。
以下类型注解将导致工具模式中的该参数被移除。这对于不应向模型暴露且模型无法控制的参数非常有用。
- InjectedToolArg: 值应在运行时使用
.invoke或.ainvoke手动注入。 - RunnableConfig: 将 RunnableConfig 对象传递给工具。
- InjectedState: 将 LangGraph 图的整体状态传递给工具。
- InjectedStore: 将 LangGraph store 对象传递给工具。
您还可以使用 Annotated 类型配合字符串字面量,为将在工具的架构中暴露的对应参数提供一个描述,该描述将被公开。
- Annotated[..., "string literal"] -- 为参数添加描述,该描述将暴露在工具的架构中。
InjectedToolArg
在某些情况下,某些参数需要在运行时传递给工具,但不应由模型本身生成。为此,我们使用 InjectedToolArg 注解,该注解允许将某些参数从工具的架构中隐藏。
例如,如果某个工具需要在运行时动态注入user_id,它可以按如下方式构建:
from langchain_core.tools import tool, InjectedToolArg
@tool
def user_specific_tool(input_data: str, user_id: InjectedToolArg) -> str:
"""Tool that processes input data."""
return f"User {user_id} processed {input_data}"
使用 InjectedToolArg 注解 user_id 参数告诉 LangChain,该参数不应作为工具模式的一部分暴露。
有关如何使用 InjectedToolArg 的更多详细信息,请参阅 如何将运行时值传递给工具。
RunnableConfig
您可以使用 RunnableConfig 对象将自定义运行时的值传递给工具。
如果您需要从工具内部访问 RunnableConfig 对象,可以通过在工具的函数签名中使用 RunnableConfig 注解来实现。
from langchain_core.runnables import RunnableConfig
@tool
async def some_func(..., config: RunnableConfig) -> ...:
"""Tool that does something."""
# do something with config
...
await some_func.ainvoke(..., config={"configurable": {"value": "some_value"}})
config将不会成为工具架构的一部分,并将在运行时使用适当的值进行注入。
您可能需要访问 config 对象以手动将其传播到子类。如果您在 异步 环境中使用 Python 3.9 / 3.10,并且需要手动将 config 对象传播到子调用,就会发生这种情况。
请阅读 传播 RunnableConfig 以获取更多详细信息,了解如何手动将 RunnableConfig 向下传播到调用链(或升级到 Python 3.11,在该版本中此问题已不再存在)。
InjectedState
有关更多详细信息,请参阅 InjectedState 文档。
InjectedStore
有关更多详细信息,请参阅 InjectedStore 文档。
最佳实践
当设计供模型使用的工具时,请记住以下几点:
- 命名良好、文档正确且类型提示完善的工具更易于模型使用。
- 设计简单且范围狭窄的工具,因为它们更容易被模型正确使用。
- 使用支持工具调用 API 的聊天模型以利用工具功能。
工具包
LangChain 有一个工具包的概念。这是一种非常轻量的抽象,它将设计为协同完成特定任务的工具分组在一起。
接口
所有工具包都暴露了一个 get_tools 方法,该方法返回一个工具列表。因此你可以这样做:
# Initialize a toolkit
toolkit = ExampleTookit(...)
# Get list of tools
tools = toolkit.get_tools()
相关资源
查看以下资源以获取更多信息: