在构建代理时,你需要提供一组工具(Tools)供其使用。工具不仅仅是一个函数,它包括多个组件,如下所述:
| Attribute | Type | Description |
|---|---|---|
| name | str | 必须在提供给一个LLM或代理的一组工具中唯一。 |
| description | str | 描述工具的功能。用于LLM或代理的上下文。 |
| args_schema | Pydantic BaseModel | 可选但推荐,可以用来提供更多信息(如少样例)或验证预期参数。 |
| return_direct | boolean | 仅对代理相关。如果为True,调用给定的工具后,代理将停止并直接将结果返回给用户。 |
LangChain 支持从以下几种方式创建工具:
- Functions;
- LangChainRunnables;
- 通过继承
BaseTool– 这种方法最灵活,提供最大的控制权,但需要更多的努力和代码。
对于大多数使用场景,使用函数创建工具就足够了,可以通过简单的 @tool 装饰器实现。如果需要更多配置,例如同步和异步实现,可以使用 StructuredTool.from_function 方法。
创建工具的不同方法
从函数创建工具
@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)
print(multiply.description)
print(multiply.args)
异步实现:
from langchain_core.tools import tool
@tool
async def amultiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
使用结构化工具 (StructuredTool)
StructuredTool.from_function 方法提供了比 @tool 装饰器稍微多一点的可配置性,而无需额外的代码。
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field
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}))
print(calculator.name)
print(calculator.description)
print(calculator.args)
创建异步工具
LangChain 工具实现了 Runnable 接口。所有的 Runnable 都暴露了 invoke 和 ainvoke 方法(以及其他方法如 batch, abatch, astream 等)。
如果你只提供了同步实现的工具,仍然可以使用 ainvoke 接口,但需要注意以下几点:
- LangChain 默认提供一个假定函数计算开销较大的异步实现,因此会将执行委托给另一个线程。
- 如果你在异步代码库中工作,应创建异步工具,以避免因线程带来的小开销。
- 同时需要同步和异步实现时,使用
StructuredTool.from_function或继承BaseTool。
from langchain_core.tools import StructuredTool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
async def amultiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
calculator = StructuredTool.from_function(func=multiply, coroutine=amultiply)
print(calculator.invoke({"a": 2, "b": 3}))
print(await calculator.ainvoke({"a": 2, "b": 5}))
错误处理
如果你要使用工具与代理交互,可能需要一个错误处理策略,以便代理能够从错误中恢复并继续执行。一个简单的策略是从工具内部抛出 ToolException 并使用 handle_tool_error 指定错误处理程序。
from langchain_core.tools import ToolException, StructuredTool
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,
)
get_weather_tool.invoke({"city": "foobar"})
实践建议
- 命名和描述:选择适当的名称和描述,提高模型的性能。
- 文档字符串:提供详细的文档字符串,用于自动生成的工具描述。
- 错误处理:确保对工具中的潜在错误进行处理,以使代理能够继续正常运行。
通过这些方法,你可以创建功能齐全且健壮的定制工具,并在你的应用程序中高效地利用LangChain工具的力量。
如果遇到问题欢迎在评论区交流。
3205

被折叠的 条评论
为什么被折叠?



