langchain_core.tools.convert_runnable_to_tool
详解
langchain_core.tools.convert_runnable_to_tool
是 LangChain 框架中的一个核心函数,用于将 Runnable
对象转换为 BaseTool
对象,使其可以作为代理(Agents)或链(Chains)中的工具使用。本文详细介绍其功能、参数、使用方法、实际应用及注意事项,基于提供的源码和相关信息,确保内容条理清晰、易于理解。
1. 概述
1.1 什么是 convert_runnable_to_tool
?
convert_runnable_to_tool
是 langchain_core.tools
模块中的一个实用函数,旨在将 LangChain 的 Runnable
对象转换为 BaseTool
对象。Runnable
是 LangChain 的核心接口,支持同步和异步执行、批处理和流式输出,而 BaseTool
是工具的基类,用于定义代理或链可调用的功能单元。该函数根据 Runnable
的输入模式自动选择创建 Tool
(适合单一字符串输入)或 StructuredTool
(适合多参数输入),并配置执行方法和回调支持。
该函数在 langchain-core
0.2.14 版本中引入,增强了 LangChain 的灵活性和扩展性,允许开发者将现有的 Runnable
(如自定义函数或复杂链)集成到工具生态系统中。
1.2 与其他组件的关系
- 与
BaseTool
:BaseTool
是所有工具的基类,convert_runnable_to_tool
返回其子类(Tool
或StructuredTool
)。 - 与
StructuredTool
:当输入模式为多参数时,函数生成StructuredTool
,支持复杂输入。 - 与
@tool
装饰器:@tool
装饰器直接从函数创建工具,而convert_runnable_to_tool
将已有的Runnable
转换为工具,适合更复杂的场景。 - 与
InjectedToolArg
和InjectedToolCallId
:支持处理注入参数(如用户 ID 或工具调用 ID),确保工具模式正确。 - 与
chain
装饰器:结合langchain_core.runnables.chain
,可在工具调用链中动态处理输入或输出。
1.3 核心功能
- 工具类型选择:根据
Runnable
的输入模式(字符串或对象)选择Tool
或StructuredTool
。 - 执行方法包装:为工具定义同步和异步执行方法,支持回调传递。
- 输入模式适配:使用
args_schema
或arg_types
定义输入结构,或从Runnable
推断。 - 回调支持:通过包装函数支持回调,便于监控和日志记录。
- 版本要求:需
langchain-core>=0.2.14
,具体功能可能依赖最新版本。
2. 定义与参数
2.1 函数签名
def convert_runnable_to_tool(
runnable: Runnable,
args_schema: Optional[type[BaseModel]] = None,
*,
name: Optional[str] = None,
description: Optional[str] = None,
arg_types: Optional[dict[str, type]] = None,
) -> BaseTool:
2.2 参数详解
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
runnable | Runnable | 无默认 | 要转换的 Runnable 对象,必须提供。 |
args_schema | Optional[type[BaseModel]] | None | 可选,Pydantic 模型,定义工具的输入模式。若提供,则设置 Runnable 的输入类型。 |
name | Optional[str] | None | 可选,工具的名称。若未提供,则调用 runnable.get_name() 获取。 |
description | Optional[str] | None | 可选,工具的描述。若未提供,则调用 _get_description_from_runnable 提取。 |
arg_types | Optional[dict[str, type]] | None | 可选,参数名称到类型的字典,用于生成输入模式,适用于 Runnable 模式不明确时。 |
2.3 返回值
- 类型:
BaseTool
- 描述:返回一个
BaseTool
子类实例(Tool
或StructuredTool
),根据输入模式确定。
3. 工作原理
根据提供的源码,函数的工作流程如下:
-
设置输入类型:
- 若提供了
args_schema
,调用runnable.with_types(input_type=args_schema)
,设置Runnable
的输入类型。
- 若提供了
-
获取名称和描述:
- 若未提供
name
,调用runnable.get_name()
获取名称。 - 若未提供
description
,调用_get_description_from_runnable(runnable)
提取描述。
- 若未提供
-
确定输入模式:
-
获取
runnable.input_schema.model_json_schema()
,检查模式类型。 -
若模式为字符串(
"type": "string"
):- 创建
Tool
对象,设置:name
:工具名称。func=runnable.invoke
:同步执行方法。coroutine=runnable.ainvoke
:异步执行方法。description
:工具描述。
- 创建
-
否则(模式为对象或其他):
- 定义包装函数:
ainvoke_wrapper
:异步包装,调用await runnable.ainvoke(kwargs, config={"callbacks": callbacks})
。invoke_wrapper
:同步包装,调用runnable.invoke(kwargs, config={"callbacks": callbacks})
。
- 确定
args_schema
:- 若
arg_types
为None
且模式为对象("type": "object"
)且有属性("properties"
),使用runnable.input_schema
。 - 否则,调用
_get_schema_from_runnable_and_arg_types
生成模式。
- 若
- 使用
StructuredTool.from_function
创建工具,设置:name
:工具名称。func=invoke_wrapper
:同步执行方法。coroutine=ainvoke_wrapper
:异步执行方法。description
:工具描述。args_schema
:输入模式。
- 定义包装函数:
-
4. 使用方法
以下是 convert_runnable_to_tool
的主要使用方式,结合前文内容展示具体示例:
4.1 转换简单 Runnable
为 Tool
将单一字符串输入的 Runnable
转换为 Tool
:
from langchain_core.runnables import RunnableLambda
from langchain_core.tools import convert_runnable_to_tool
def search(query: str) -> str:
"""模拟搜索逻辑"""
return f"Search results for: {query}"
runnable = RunnableLambda(search)
tool = convert_runnable_to_tool(
runnable,
name="SearchTool",
description="Perform a search based on a query string"
)
result = tool.invoke("LangChain") # 输出 "Search results for: LangChain"
说明:由于输入模式为字符串,函数创建 Tool
对象,使用 runnable.invoke
和 runnable.ainvoke
。
4.2 转换复杂 Runnable
为 StructuredTool
将多参数输入的 Runnable
转换为 StructuredTool
:
from langchain_core.runnables import RunnableLambda
from pydantic import BaseModel, Field
from langchain_core.tools import convert_runnable_to_tool
class AddInput(BaseModel):
a: int = Field(description="第一个数字")
b: int = Field(description="第二个数字")
def add(input: AddInput) -> int:
"""添加两个数字"""
return input.a + input.b
runnable = RunnableLambda(add).with_types(input_type=AddInput)
tool = convert_runnable_to_tool(
runnable,
name="AddTool",
description="Add two numbers"
)
result = tool.invoke({"a": 2, "b": 3}) # 输出 5
说明:输入模式为对象,函数创建 StructuredTool
,使用包装函数支持回调。
4.3 使用 arg_types
当 Runnable
没有明确输入模式时,提供 arg_types
:
runnable = RunnableLambda(lambda x, y: x + y)
tool = convert_runnable_to_tool(
runnable,
name="AddTool",
description="Add two numbers",
arg_types={"x": int, "y": int}
)
result = tool.invoke({"x": 2, "y": 3}) # 输出 5
说明:arg_types
用于生成 args_schema
,确保工具支持多参数输入。
4.4 结合 chain
装饰器和 InjectedToolArg
结合前文讨论的 InjectedToolArg
和 chain
装饰器,注入运行时参数:
from langchain_core.runnables import chain, RunnableLambda
from langchain_core.tools import convert_runnable_to_tool, InjectedToolArg
from pydantic import BaseModel, Field
from typing_extensions import Annotated
class UpdateInput(BaseModel):
name: str = Field(description="用户名")
def update_user(input: UpdateInput, user_id: Annotated[str, InjectedToolArg]) -> str:
return f"Updated user {user_id} with name {input.name}"
runnable = RunnableLambda(update_user).with_types(input_type=UpdateInput)
tool = convert_runnable_to_tool(
runnable,
name="UpdateUserTool",
description="Update user profile"
)
@chain
def inject_user_id(input):
return {**input, "user_id": "123"}
chain = inject_user_id | tool
result = chain.invoke({"name": "Alice"}) # 输出 "Updated user 123 with name Alice"
说明:chain
装饰器注入 user_id
,工具通过包装函数处理输入。
5. 实际应用
convert_runnable_to_tool
在以下场景中广泛使用:
- 集成自定义逻辑:将自定义函数或链(如数据处理管道)转换为工具,集成到代理系统中。
- 模块化功能:将复杂处理链(如检索文档、生成摘要)封装为工具,简化代理或链的设计。
- 回调支持:通过包装函数支持回调,便于使用 LangSmith 进行监控和日志记录。
- 扩展工具生态:将现有的
Runnable
(如RunnableLambda
、提示模板或模型链)转换为工具,增强 LangChain 的扩展性。
示例:RAG 工具
将 RAG(检索增强生成)链转换为工具:
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.tools import create_retriever_tool
# 假设有一个检索器工具
retriever_tool = create_retriever_tool(...)
# 定义 RAG 链
prompt = ChatPromptTemplate.from_template("Answer based on: {docs}\nQuestion: {question}")
chain = (
{"docs": retriever_tool, "question": RunnablePassthrough()}
| prompt
| ChatOpenAI()
)
# 转换为工具
rag_tool = convert_runnable_to_tool(
chain,
name="RAGTool",
description="Answer questions using retrieved documents"
)
result = rag_tool.invoke("LangChain 是什么?")
说明:RAG 链被转换为工具,代理可直接调用。
6. 最佳实践
- 定义输入模式:确保
Runnable
有明确的input_schema
,或提供args_schema
或arg_types
以生成正确的模式。 - 提供名称和描述:设置有意义的
name
和description
,例如:description = "Add two numbers. Example: {'a': 2, 'b': 3} returns 5."
- 支持回调:利用包装函数的回调支持,确保监控和日志记录。
- 版本检查:通过
pip install -qU langchain
确保安装langchain-core>=0.2.14
。 - 调试工具:使用 LangSmith 跟踪工具调用,调试复杂链或代理。
7. 注意事项与限制
- 输入模式依赖:若
Runnable
没有定义input_schema
,且未提供args_schema
或arg_types
,可能导致模式生成失败。 - 回调配置:包装函数传递回调,需确保
config
中正确设置callbacks
。 - 模块路径:确保正确导入
langchain_core.tools.convert_runnable_to_tool
。 - 版本依赖:功能可能受版本限制,需确保兼容最新版本。
- 异步环境:异步调用需在支持
asyncio
的环境中运行。
8. 结论
langchain_core.tools.convert_runnable_to_tool
是一个高效的函数,通过将 Runnable
对象转换为 BaseTool
对象,扩展了 LangChain 工具生态系统的功能。它根据输入模式自动选择 Tool
或 StructuredTool
,并支持同步、异步执行和回调,适合集成自定义逻辑和复杂工作流。结合 BaseTool
、StructuredTool
、InjectedToolArg
和 chain
装饰器,开发者可以构建灵活、可维护的 LangChain 应用。遵循最佳实践并注意版本要求,将有助于充分发挥其功能。