创建自定义工具的3种技巧与使用场景

在使用 函数调用 或者创建 智能体 时,我们需要提供 工具列表,以便大语言模型可以使用这些工具,虽然 LangChain 内部集成了大量的工具和工具包,但并不一定适合我们的业务场景,更多场合下我们会使用自定义工具,在 LangChain 中提供了 3 种构建自定义工具的技巧:@tool 装饰器、StructuredTool.from_function()类方法、BaseTool子类,不同的方式有不同的优缺点与应用场景。

01. @tool 装饰器

@tool 装饰器是定义自定义工具的最简单方式,可以快速将当前的 函数 改造成 大语言模型工具,该装饰器默认使用函数名称作为工具名称,但可以通过传递字符串作为第一个参数来覆盖,此外,该装饰器将使用函数的 文档字符串 作为工具的描述,所以被装饰的函数必须要提供 文档字符串。

使用示例如下:

from langchain_core.tools import tool

@tool

def multiply(a: int, b: int) -> int:

    """将传递的两个数字相乘"""

    return a * b

# 打印下该工具的相关信息

print("名称: ", multiply.name)

print("描述: ", multiply.description)

print("参数: ", multiply.args)

print("直接返回: ", multiply.return_direct)

# 调用工具

print(multiply.invoke({"a": 2, "b": 8}))

输出内容:

名称:  multiply

描述:  将传递的两个数字相乘

参数:  {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}

直接返回:  False

16

除了使用默认的配置外,@tool 装饰器还可以传递多个参数来执行相应的配置,例如传递 工具名字、参数描述、是否直接返回 等

from langchain_core.pydantic_v1 import BaseModel, Field

from langchain_core.tools import tool

class CalculatorInput(BaseModel):

    a: int = Field(description="第一个数字")

    b: int = Field(description="第二个数字")

@tool("multiply_tool", args_schema=CalculatorInput, return_direct=True)

def multiply(a: int, b: int) -> int:

    """将传递的两个数字相乘"""

    return a * b

# 打印下该工具的相关信息

print("名称: ", multiply.name)

print("描述: ", multiply.description)

print("参数: ", multiply.args)

print("直接返回: ", multiply.return_direct)

# 调用工具

print(multiply.invoke({"a": 2, "b": 8}))

输出内容:

名称:  multiply_tool

描述:  将传递的两个数字相乘

参数:  {'a': {'title': 'A', 'description': '第一个数字', 'type': 'integer'}, 'b': {'title': 'B', 'description': '第二个数字', 'type': 'integer'}}

直接返回:  True

16

当使用 Google-style文档字符串 风格进行函数注释时,还可以设置 parse_docstring 为 True,这样 @tool 装饰器还可以获取到每个参数的相关解释,例如

@tool(parse_docstring=True)

def foo(bar: str, baz: int) -> str:

    """The foo.

    Args:

        bar: The bar.

        baz: The baz.

    """

    return bar

print(foo.args) 

输出内容:

{'bar': {'title': 'Bar', 'description': 'The bar.', 'type': 'string'}, 'baz': {'title': 'Baz', 'description': 'The baz.', 'type': 'integer'}}

对于一个原有的函数,并且该函数的参数相对来说比较简单,我们可以考虑使用 @tool 装饰器来转换该函数,可以极大减少重复性的工作,但是 @tool 装饰器装饰的工具并不能同时拥有 同步 和 异步 方法,只可以单独装饰,例如

from langchain_core.tools import tool

@tool

async def amultiply(a: int, b: int) -> int:

    """Multiply two numbers."""

return a * b

所以对于一些需要同时考虑 同步 和 异步 的工具来说,@tool 装饰器就没法使用了。

02. StructuredTool 类方法

第 2 种快速创建 工具 的技巧是使用 StructuredTool.from_function() 类方法,该方法提供了比 @tool 装饰器更多的配置项,例如同时支持同步和异步等,修改的示例如下

from langchain_core.pydantic_v1 import BaseModel, Field

from langchain_core.tools import StructuredTool

class CalculatorInput(BaseModel):

    a: int = Field(description="第一个数字")

    b: int = Field(description="第二个数字")

def multiply(a: int, b: int) -> int:

    """将传递的两个数字相乘"""

    return a * b

async def amultiply(a: int, b: int) -> int:

    """将传递的两个数字相乘"""

    return a * b

calculator = StructuredTool.from_function(

    func=multiply,

    coroutine=amultiply,

    name="multiply_tool",

    description="用于将传递的两个整型相乘",

    return_direct=True,

    args_schema=CalculatorInput,

)

# 打印下该工具的相关信息

print("名称: ", calculator.name)

print("描述: ", calculator.description)

print("参数: ", calculator.args)

print("直接返回: ", calculator.return_direct)

# 调用工具

print(calculator.invoke({"a": 2, "b": 8}))

输出内容:

名称:  multiply_tool

描述:  用于将传递的两个整型相乘

参数:  {'a': {'title': 'A', 'description': '第一个数字', 'type': 'integer'}, 'b': {'title': 'B', 'description': '第二个数字', 'type': 'integer'}}

直接返回:  True

16

对于已有的函数,并且想同时支持 同步 和 异步,可以考虑使用 StructuredTool.from_function() 类方法来实现,该方法的配置项很灵活,而且无需太多额外代码。

03. BaseTool 子类

在 LangChain 中,所有的工具都是 BaseTool 子类,并且使用 @tool 或者 StructuredTool.from_function() 创建的工具,底层都是包装成了 StructuredTool,本质上也是 BaseTool 的子类。

所以如果对一个自定义工具来说,如果目前并没有任何一段已经实现的代码,则可以考虑继承 BaseTool 基类,并实现 _run() 方法来实现自定义工具(和使用 StructuredTool.from_function() 代码量差异并不是特别大)。

代码示例:

from typing import Any, Type

from langchain_core.pydantic_v1 import BaseModel, Field

from langchain_core.tools import BaseTool

class CalculatorInput(BaseModel):

    a: int = Field(description="第一个数字")

    b: int = Field(description="第二个数字")

class MultiplyTool(BaseTool):

    """乘法计算工具"""

    name = "multiply_tool"

    description = "将传递的两个数字相乘"

    args_schema: Type[BaseModel] = CalculatorInput

    def _run(self, a: int, b: int) -> Any:

        return a * b

calculator = MultiplyTool()

# 打印下该工具的相关信息

print("名称: ", calculator.name)

print("描述: ", calculator.description)

print("参数: ", calculator.args)

print("直接返回: ", calculator.return_direct)

# 调用工具

print(calculator.invoke({"a": 2, "b": 8}))

输出示例:

名称:  multiply_tool

描述:  将传递的两个数字相乘

参数:  {'a': {'title': 'A', 'description': '第一个数字', 'type': 'integer'}, 'b': {'title': 'B', 'description': '第二个数字', 'type': 'integer'}}

直接返回:  False

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐