文章目录 一 LangChain 自定义工具概述 二创建自定义工具的三种方法 2.1 方法一:@tool 装饰器 2.1.1 同步方法案例 2.1.2 工具描述方式1:传参 2.1.3 工具描述方式2:文档字符串 2.2 方法二:StructuredTool类 2.2.1 StructuredTool创建自定义工具 2.2.2 StructuredTool配置信息 2.3 方法三:BaseTool类 三 异步工具的实现 四 工具错误处理策略
一 LangChain 自定义工具概述
LangChain提供了一套工具、组件和接口,可简化创建由大型语言模型(LLM)和聊天模型提供支持的应用程序的过程。 在构建智能代理时,为其提供合适的工具是确保其强大功能的关键,LangChain作为一个支持创建和管理工具的框架,能让开发者以模块化方式扩展代理的能力。
当构建代理时,需要为其提供一组工具列表,代理可以使用这些工具。除了调用的实际函数之外,工具由几个组件组成: name(str)是必需的,并且在提供给代理的工具集中必须是唯一的; description(str)是可选的但建议的,因为代理使用它来确定工具的使用方式; return_direct(bool)默认为False; args_schema(PydanticBaseModel)是可选的但建议的,可以用于提供更多信息或用于验证预期参数。
二创建自定义工具的三种方法
LangChain为开发人员提供了不同的方式来创建工具,这些工具可以被智能代理或语言模型调用。 第一种方法是使用@tool装饰器(定义自定义工具的最简单方法); 第二种方法是使用StructuredTool类,允许更细粒度的配置而无需过多的代码; 第三种方法是基于BaseTool类构造子类显式自定义工具,工具定义提供最大限度的把控,但需要做更多的工作。
2.1 方法一:@tool 装饰器
使用@tool修饰符是自定义工具最简单的方法。默认情况下修饰符用函数的名字作为工具名称,但传字符串作为第一个参数可以重命名工具名称。例如,可以创建一个总是返回字符串"LangChain"的虚构搜索函数,或者将两个数字相乘的乘法函数。这些函数最大的区别是第一个函数只有一个输入,第二个函数需要多个输入。
2.1.1 同步方法案例
from langchain_core. tools import tool
@tool
def multiply ( a: int , b: int ) - > int : """Multiply two numbers""" return a* bprint ( multiply. name)
print ( multiply. description)
print ( multiply. args)
2.1.2 工具描述方式1:传参
通过将工具名称和 JSON 参数传递给工具装饰器进行自定义
from langchain_core. tools import tool
from pydantic import BaseModel, Fieldclass CalculatorInput ( BaseModel) : a: int = Field( description= "The first number" ) b: int = Field( description= "The second number" ) @tool ( "multiplication-tool" , args_schema= CalculatorInput, return_direct= True )
def multiply ( a: int , b: int ) - > int : """Multiply two numbers""" return a * bprint ( multiply. name)
print ( multiply. description)
print ( multiply. args)
print ( multiply. return_direct)
2.1.3 工具描述方式2:文档字符串
@tool 可以选择性地解析 Google 风格文档字符串,并将文档字符串组件(如参数描述)与工具模式的相关部分关联起来。
@tool ( parse_docstring= True )
def foo ( bar: str , baz: int ) - > str : """The foo.Args:bar: The bar.baz: The baz.""" return bar
foo. args_schema. schema( )
{ 'description' : 'The foo.' , 'properties' : { 'bar' : { 'description' : 'The bar.' , 'title' : 'Bar' , 'type' : 'string' } , 'baz' : { 'description' : 'The baz.' , 'title' : 'Baz' , 'type' : 'integer' } } , 'required' : [ 'bar' , 'baz' ] , 'title' : 'fooSchema' , 'type' : 'object' }
2.2 方法二:StructuredTool类
使用StructuredTool类,允许更细粒度的配置而无需过多的代码
2.2.1 StructuredTool创建自定义工具
使用StructuredTool
的from_function
可以创建自定义工具,包含两个参数func,coroutine
,分别指定同步方法和异步方法。
import asyncio
from langchain_core. tools import StructuredTooldef multiply ( a: int , b: int ) - > int : """Multiply two numbers""" return a* b
async def a_multiply ( a: int , b: int ) - > int : """Multiply two numbers""" return a* basync def main ( ) : calculator= StructuredTool. from_function( func= multiply, coroutine= a_multiply) print ( calculator. run( { "a" : 2 , "b" : 3 } ) ) print ( calculator. invoke( { "a" : 2 , "b" : 3 } ) ) print ( await calculator. ainvoke( { "a" : 2 , "b" : 5 } ) ) asyncio. run( main( ) )
2.2.2 StructuredTool配置信息
import asyncio
from langchain_core. tools import StructuredTool
from pydantic import Field, BaseModelclass CalculatorInput ( BaseModel) : a: int = Field( description= "The first number" ) b: int = Field( description= "The second number" )
def multiply ( a: int , b: int ) - > int : """Multiply two numbers""" return a* b
async def async_multiply ( a: int , b: int ) - > int : """Multiply two numbers""" return a* basync def main ( ) : calculator= StructuredTool. from_function( func= multiply, name= "calculator" , description= "Multiply two numbers" , args_schema= CalculatorInput, coroutine= async_multiply, return_direct= True ) print ( calculator. name) print ( calculator. description) print ( calculator. args) asyncio. run( main( ) )
2.3 方法三:BaseTool类
接受字符串或 dict 输入的 LangChain Runnables 可以使用 as_tool 方法转换为工具,该方法允许为参数指定名称、描述和其他模式信息。
from langchain_core. language_models import GenericFakeChatModel
from langchain_core. output_parsers import StrOutputParser
from langchain_core. prompts import ChatPromptTemplate
prompt = ChatPromptTemplate. from_messages( [ ( "human" , "Hello. Please respond in the style of {answer_style}." ) ]
)
llm = GenericFakeChatModel( messages= iter ( [ "hello matey" ] ) )
chain = prompt | llm | StrOutputParser( )
as_tool = chain. as_tool( name= "Style responder" , description= "Description of when to use tool."
)
print ( as_tool. args)
三 异步工具的实现
LangChain的工具可以实现异步版本,以节省计算资源和提高效率。在定义异步工具时,需要使用async/await语法,并确保函数和工具名准确反映功能,提供详细的文档字符串。对于涉及外部API调用的工具,建议使用API代理服务来提高访问的稳定性,并确保异步工具充分利用并发优势,避免阻塞操作。
from langchain_core. tools import tool@tool
async def multiply ( a: int , b: int ) - > int : """Multiply two numbers""" return a* bprint ( multiply. name)
print ( multiply. description)
print ( multiply. args)
四 工具错误处理策略
为了让代理能从错误中恢复并继续执行,需要特定的错误处理策略。可以抛出ToolException
并定义错误处理函数,设置handle_tool_error
属性来定义工具错误的应对策略,可以是字符串、布尔值或函数。需要注意的是仅引发ToolException
是无效的,需要先设置该工具的handle_tool_error
,因为它的默认值为False
。
from langchain_core. tools import StructuredTool
from langchain_core. tools import ToolExceptiondef get_weather ( city: str ) - > str : """获取给定城市的天气。""" raise ToolException( f"错误:没有名为 { city} 的城市。" ) get_weather_tool = StructuredTool. from_function( func= get_weather, handle_tool_error= True ,
) response = get_weather_tool. invoke( { "city" : "天京" } )
print ( response)
from langchain_core. tools import StructuredTool
from langchain_core. tools import ToolExceptiondef get_weather ( city: str ) - > str : """获取给定城市的天气。""" raise ToolException( f"错误:没有名为 { city} 的城市。" ) get_weather_tool = StructuredTool. from_function( func= get_weather, handle_tool_error= "没有找到这个城市" ,
) response = get_weather_tool. invoke( { "city" : "天京" } )
print ( response)
from langchain_core. tools import StructuredTool
from langchain_core. tools import ToolExceptiondef get_weather ( city: str ) - > str : """获取给定城市的天气。""" raise ToolException( f"错误:没有名为 { city} 的城市。" ) def _handle_tool_error ( error: ToolException) - > str : """处理工具错误。""" return f"工具执行期间发生以下错误:` { error. args[ 0 ] } `" get_weather_tool = StructuredTool. from_function( func= get_weather, handle_tool_error= _handle_tool_error
) response = get_weather_tool. invoke( { "city" : "天京" } )
print ( response)