Tools
概览
LangChain 的 工具 抽象将一个 Python 函数 与一个 模式(schema) 相关联,该模式定义了函数的 名称、描述 和 预期参数。
工具 可以传递给支持 工具调用 的 聊天模型,模型可以据此请求使用特定的输入来执行特定的函数。
关键概念
- 工具是一种将函数及其模式封装起来,以便可以传递给聊天模型的方式。
- 使用
@tool装饰器创建工具。它简化了工具创 建过程,支持以下功能:- 自动推断工具的 名称、描述 和 预期参数,同时也支持自定义。
- 定义返回 产出物(artifacts)(例如:图像、数据帧等)的工具。
- 使用 注入的工具参数(injected tool arguments) 将输入参数隐藏在模式(以及模型)之外。
工具接口
工具接口定义在 BaseTool 类中,它是 Runnable Interface 的一个子类。
与工具 模式 对应的关键属性:
- name: 工具的名称。
- description: 工具功能的描述。
- args: 返回工具参数的 JSON 模式的属性。
用于执行与 工具 关联的函数:
- invoke: 使用给定的参数调用工具。
- ainvoke: 使用给定的参数异步调用工具。用于 Langchain 的 异步编程。
使用 @tool 装饰器创建工具
创建工具的推荐方式是使用 @tool 装饰器。该装饰器旨在简化工具创建过程,应在大多数情况下使用。定义函数后,您可以使用 @tool 装饰它来创建一个实现 工具接口 的工具。
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""将两个数字相乘。"""
return a * b
有关如何创建工具的更多详细信息,请参阅 如何创建自定义工具 指南。
LangChain 还有其他几种创建工具的方式;例如,通过继承 BaseTool 类或使用 StructuredTool。这些方法在 如何创建自定义工具 指南中有所展示,但我们通常建议在大多数情况下使用 @tool 装饰器。
直接使用工具
定义工具后,您可以直接通过调用函数来使用它。例如,使用上面定义的 multiply 工具:
multiply.invoke({"a": 2, "b": 3})
查看
您还可以检查工具的模式和其他属性:
print(multiply.name) # multiply
print(multiply.description) # 将两个数字相乘。
print(multiply.args)
# {
# 'type': 'object',
# 'properties': {'a': {'type': 'integer'}, 'b': {'type': 'integer'}},
# 'required': ['a', 'b']
# }
如果您使用的是预构建的 LangChain 或 LangGraph 组件,如 create_react_agent,您可能不需要直接与工具交互。但是,了解如何使用它们对于调试和测试可能很有价值。此外,在构建自定义 LangGraph 工作流时,您可能会发现直接使用工具是必要的。
配置模式
@tool 装饰器提供了其他选项来配置工具的模式(例如,修改名称、描述或解析函数的文档字符串以推断模式)。
有关更多详细信息,请参阅 @tool 的 API 参考,并查阅 如何创建自定义工具 指南中的示例。
工具产出物
工具 是模型可以调用的实用程序,其输出旨在反馈给模型。然而,有时工具执行的产出物会让我们希望将其提供给链或代理中的下游组件,但又不想将其暴露给模型本身。例如,如果一个工具返回一个自定义对象、数据帧或图像,我们可能希望将该输出的某些元数据提供给模型,而不将实际输出传递给模型。同时,我们可能希望在其他地方访问完整的输出,例如在下游工具中。
@tool(response_format="content_and_artifact")
def some_tool(...) -> Tuple[str, Any]:
"""执行某项操作的工具。"""
...
return '给聊天模型的消息', 某个产出物
有关更多详细信息,请参阅 如何从工具返回产出物。
特殊类型注解
在工具的函数签名中可以使用一些特殊 的类型注解来配置工具的运行时行为。
以下类型注解将移除该参数的工具模式。这对于不应暴露给模型且模型不应控制的参数非常有用。
- InjectedToolArg: 值应在运行时通过
.invoke或.ainvoke手动注入。 - RunnableConfig: 将
RunnableConfig对象传递给工具。 - InjectedState: 将 LangGraph 图的整体状态传递给工具。
- InjectedStore: 将 LangGraph 存储对象传递给工具。
您还可以使用 Annotated 类型配合字符串字面量来为相应的参数提供描述,该描述将被暴露在工具的模式中。
- Annotated[..., "字符串字面量"] -- 为将暴露在工具模式中的参数添加描述。
InjectedToolArg
在某些情况下,需要在运行时将某些参数传递给工具,但不能由模型本身生成。为此,我们使用 InjectedToolArg 注解,它允许某些参数从工具的模式中隐藏。
例如,如果一个工具需要在运行时动态注入 user_id,则可以这样构建:
from langchain_core.tools import tool, InjectedToolArg
@tool
def user_specific_tool(input_data: str, user_id: InjectedToolArg) -> str:
"""处理输入数据的工具。"""
return f"用户 {user_id} 已处理 {input_data}"
使用 InjectedToolArg 注解 user_id 参数,即告诉 LangChain 不应将此参数作为工具模式的一部分暴露。
有关如何使用 InjectedToolArg 的更多详细信息,请参阅 如何将运行时值传递给工具。
RunnableConfig
您可以使用 RunnableConfig 对象将自定义运行时值传递给工具。
如果您需要在工具内部访问 RunnableConfig 对象。这可以通过在工具的函数签名中使用 RunnableConfig 注解来实现。
from langchain_core.runnables import RunnableConfig
@tool
async def some_func(..., config: RunnableConfig) -> ...:
"""执行某项功能的工具。"""
# 使用 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 方法,该方法返回一个工具列表。因此,您可以这样做:
# 初始化一个工具包
toolkit = ExampleToolkit(...)
# 获取工具列表
tools = toolkit.get_tools()
相关资源
有关更多信息,请参阅以下资源: