在开发智能代理时,为了增强其功能,我们通常需要提供一组工具(Tools)供其调用。LangChain 提供了多种便捷的方法来定义和配置这些工具,包括从函数构建工具、使用结构化工具StructuredTool
以及通过继承BaseTool
类构建自定义工具。本指南将重点介绍如何通过实际代码示例,逐步掌握工具的创建和使用。
技术背景介绍
工具是智能代理与外界交互的桥梁。通过工具,代理能够执行诸如数据处理、API调用、计算等具体任务。一个工具通常包含以下几个关键组件:
- name: 工具的唯一标识。
- description: 工具的功能描述,用于帮助模型理解工具的用途。
- args_schema: 参数模式,基于Pydantic模型,用于描述输入的结构与约束条件。
- return_direct: 是否直接返回结果,而不继续调用模型。
LangChain 提供了四种常见的方式来构建工具:
- 使用装饰器
@tool
- 使用结构化工具
StructuredTool.from_function
- 从 LangChain Runnables 转换工具
- 通过继承
BaseTool
类自定义工具
核心原理解析
无论采用哪种方式构建工具,核心的设计理念是让工具具备:
- 明确的输入输出:通过 args_schema 定义输入验证规则。
- 良好的描述性:通过 name 和 description 告知模型工具的功能。
- 同步&异步支持:工具需要支持异步调用以适应现代代码需求。
以下各部分将结合代码详细讲解这些方式。
代码实现演示
1. 使用 @tool
装饰器快速创建工具
@tool
是最简单的方式,通过装饰现有函数即可将其转化成一个工具。
from langchain_core.tools import tool
# 定义一个基础工具,用于计算两个数的乘积
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
# 打印工具的相关属性
print(multiply.name) # 输出: multiply
print(multiply.description) # 输出: Multiply two numbers.
print(multiply.args) # 输出: {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}
- 异步支持
@tool
async def amultiply(a: int, b: int) -> int:
"""Multiply two numbers asynchronously."""
return a * b
注意: 使用
@tool
时,函数的注释(docstring)
会自动作为工具的描述,因此必须提供函数注释。
2. 使用 StructuredTool.from_function
定义结构化工具
相比 @tool
,StructuredTool.from_function
提供了更多的配置选项,比如工具名称、自定义参数模式以及异步协程支持。
from langchain.pydantic_v1 import BaseModel, Field
from langchain_core.tools import StructuredTool
class CalculatorInput(BaseModel):
a: int = Field(description="First number")
b: int = Field(description="Second number")
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
calculator = StructuredTool.from_function(
func=multiply,
name="Calculator",
description="A tool for multiplying two numbers",
args_schema=CalculatorInput,
return_direct=True,
)
# 调用工具
print(calculator.invoke({"a": 3, "b": 4})) # 输出: 12
- 覆盖异步实现
async def amultiply(a: int, b: int) -> int:
return a * b
calculator = StructuredTool.from_function(func=multiply, coroutine=amultiply)
3. 从 LangChain Runnables 转换为工具
LangChain Runnables 可以通过 .as_tool
方法快速转换为工具。
from langchain_core.language_models import GenericFakeChatModel
from langchain_core.prompts import ChatPromptTemplate
# 定义一个Prompt和Placeholder模型
prompt = ChatPromptTemplate.from_messages([("human", "Hello, please respond in the style of {answer_style}.")])
llm = GenericFakeChatModel(messages=iter(["hello matey"]))
chain = prompt | llm
# 转换为工具
as_tool = chain.as_tool(
name="StyleResponder",
description="Respond in a specific style."
)
# 查看工具参数
print(as_tool.args) # {'answer_style': {'title': 'Answer Style', 'type': 'string'}}
4. 继承 BaseTool
类创建自定义工具
如果您需要完全控制工具的行为,可通过继承 BaseTool
来构建自己的工具。
from langchain.pydantic_v1 import BaseModel, Field
from langchain_core.tools import BaseTool
class CalculatorInput(BaseModel):
a: int = Field(description="First number")
b: int = Field(description="Second number")
class CustomCalculatorTool(BaseTool):
name = "CustomCalculator"
description = "Perform multiplication of two numbers."
args_schema = CalculatorInput
return_direct = True
def _run(self, a: int, b: int) -> int:
return a * b
async def _arun(self, a: int, b: int) -> int:
return self._run(a, b)
# 使用工具
custom_tool = CustomCalculatorTool()
print(custom_tool.invoke({"a": 2, "b": 5})) # 输出: 10
应用场景分析
- 数据预处理:构建清洗、格式化或转换数据的工具供智能代理调用。
- API集成:定义工具以封装对外部API的访问,例如天气查询、库存获取等。
- 复杂任务管理:通过
BaseTool
定义复杂逻辑(如数据库操作、多步流程处理)。 - 异步环境支持:在协程代码中通过支持异步功能减少阻塞操作。
实践建议
- 明确工具的输入输出:为工具定义清晰的参数和返回值,避免不必要的模型推理消耗。
- 优化工具描述:将
description
写得尽量简洁而明确,以提高模型调用工具的效率。 - 优先支持异步实现:在需要高并发的场景中,设计异步工具以提高性能。
- 错误处理策略:通过
handle_tool_error
提供健壮的错误恢复机制。
如果遇到问题欢迎在评论区交流。
—END—