赞
踩
在LangChain框架中,"Tools"(工具)是实现与外部系统交互的一种方式,它们为语言模型(如LLMs)提供了一个接口,使得模型能够执行特定的功能或查询外部数据源。
LangChain工具的主要特点如下所示:
请看下面的代码,演示了实用LangChain中内置工具WikipediaQueryRun的过程,这个工具的作用是查询百科信息并返回结果。
- from langchain_community.tools import WikipediaQueryRun
- from langchain_community.utilities import WikipediaAPIWrapper
- # 初始化工具,这里可以按需进行配置
- api_wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=100)
- tool = WikipediaQueryRun(api_wrapper=api_wrapper)
- # 这是工具的默认名称
- print(tool.name)
- # 这是工具的默认描述
- print(tool.description)
- # 这是工具输入的默认JSON模式
- print(tool.args)
- # 我们可以看到工具是否应该直接将结果返回给用户
- print(tool.return_direct)
执行后会输出:
- 执行后会输出:
- wikipedia
- A wrapper around Wikipedia. Useful for when you need to answer general questions about people, places, companies, facts, historical events, or other subjects. Input should be a search query.
- {'query': {'title': 'Query', 'type': 'string'}}
- False
在LangChain中,创建自定义工具(Custom Tools)是创建代理(Agents)的重要环节之一,因为这些工具是执行代理任务的基础。在实现自定义工具时需要考虑如下几个关键组件。
在现实中有多种创建自定义工具的方法,例如下面的代码实现了一个虚构的搜索函数,总是返回字符串“LangChain”。
- def search(query: str) -> str:
- return "LangChain"
-
-
- print(search.name)
- print(search.description)
- print(search.args)
执行后会输出:
- search
- search(query: str) -> str - Look up things online.
- {'query': {'title': 'Query', 'type': 'string'}}
在上述代码中定义了一个名为 search 的简单函数,该函数接受一个字符串类型的参数 query,并返回字符串 "LangChain"。这个函数本身并没有与LangChain框架中的Tool组件直接关联,因此直接使用print(search.name)、print(search.description)和print(search.args)将不会按期望的方式工作,因为这些属性是在LangChain的Tool类中定义的,而不是在普通的Python函数中定义。
在LangChain中,要想使一个普通的函数变成一个Tool,需要使用LangChain提供的工具装饰器(@tool)或者继承类BaseTool等方法实现。在下面的内容中,将详细讲解将普通函数转换为LangChain工具的方法。
1. 使用 @tool 装饰器
在LangChain中,@tool装饰器是定义自定义工具最简单的方法。装饰器@tool默认使用函数名称作为工具名称,但可以通过传递一个字符串作为第一个参数来覆盖。此外,装饰器会使用函数的文档字符串作为工具的描述,因此必须提供文档字符串。请看下面的例子,演示了使用@tool装饰器创建工具的过程。
实例6-1:使用@tool装饰器创建工具(源码路径:codes\6\tool01.py)
实例文件tool01.py的具体实现代码如下所示。
- from langchain.tools import tool
-
- @tool
- def search(query: str) -> str:
- """Look up things online."""
- return "LangChain"
-
- print(search.name) # 应输出: search
- print(search.description) # 应输出: Look up things online.
- print(search.args) # 应输出: {'query': {'title': 'Query', 'type': 'string'}}
在上述代码中,@tool 装饰器会自动使用函数名作为工具的名称,并使用函数的文档字符串作为工具的描述。同时,它会推断出函数参数的JSON模式。执行后会输出:
- search
- search(query: str) -> str - Look up things online.
- {'query': {'title': 'Query', 'type': 'string'}}
2.继承类BaseTool
在LangChain框架中,通过继承类BaseTool来实现自定义工具是一种更为明确和灵活的方法。这种方法允许我们完全控制工具的行为,包括工具的名称、描述、参数模式以及执行逻辑。通过继承BaseTool类创建自定义工具的步如下:
(1)导入必要的类:首先,你需要从LangChain框架中导入BaseTool类以及其他可能需要的类,比如BaseModel用于定义参数模式。
(2)定义输入模型:使用Pydantic的BaseModel定义工具的输入参数模式,这有助于验证输入数据并提供关于预期输入的文档。
(3)创建自定义工具类:创建一个新的类,继承自BaseTool,并实现必要的方法和属性。
(4)实现_run方法:这是工具的核心执行逻辑,在这个方法中实现工具的具体功能。
(5)实现异步执行(可选):如果工具需要支持异步执行,可以额外实现一个_arun方法。
(6)设置工具的属性:包括工具的名称、描述、参数模式以及是否直接返回结果。
请看下面的例子,演示了使用@tool装饰器创建工具的过程。
实例6-2:通过继承类BaseTool实现自定义工具(源码路径:codes\6\tool02.py)
实例文件tool02.py的具体实现代码如下所示。
- from langchain.tools import BaseTool
- from langchain.pydantic_v1 import BaseModel, Field
- from typing import Optional
- from langchain.callbacks.manager import CallbackManagerForToolRun
-
- # 定义工具的输入参数模式
- class SearchInput(BaseModel):
- query: str = Field(description="The search query to be processed by the search tool")
-
- # 自定义工具类
- class CustomSearchTool(BaseTool):
- name = "Custom Search" # 工具的名称
- description = "A custom search tool that returns a fixed string." # 工具的描述
- args_schema: type = SearchInput # 工具的参数模式
-
- def _run(
- self, query: str, run_manager: Optional[CallbackManagerForToolRun] = None
- ) -> str:
- "工具的核心执行逻辑"
- return "LangChain"
-
- # 如果需要支持异步执行,可以实现_arun方法
- # def _arun(self, query: str, run_manager: Optional[AsyncCallbackManagerForToolRun] = None) -> str:
- # ""“工具的异步执行逻辑”""
- # raise NotImplementedError("CustomSearchTool does not support async")
-
- # 实例化工具
- search_tool = CustomSearchTool()
-
- # 使用工具
- print(search_tool.name) # 输出工具名称
- print(search_tool.description) # 输出工具描述
- print(search_tool.args) # 输出工具参数模式
在上述代码中,类CustomSearchTool继承自类BaseTool,并定义了一个SearchInput模型来描述输入参数。方法_run实现了工具的执行逻辑,简单地返回字符串"LangChain"。通过实例化CustomSearchTool类,你将得到一个完整的自定义工具,可以被LangChain代理使用。请注意,如果你的工具需要与LangChain的回调管理器集成,可能需要实现额外的逻辑来处理run_manager参数。此外,如果你的工具是异步的,需要实现_arun方法。在本例中没有实现异步执行,并且通过NotImplementedError明确了这一点。执行后会输出:
- Custom Search
- A custom search tool that returns a fixed string.
- {'query': {'title': 'Query', 'type': 'string'}}
3. 使用数据类StructuredTool
StructuredTool是 LangChain中的一个数据类(dataclass),允许以一种更结构化和声明式的方式来定义工具。使用 StructuredTool 可以方便地将一个普通的函数转换成一个 LangChain 工具,同时允许为工具提供名称、描述和参数模式等元数据。
使用数据类StructuredTool实现自定义工具的步骤如下:
(1)定义输入参数的 Pydantic 模型(如果需要):使用 Pydantic 的 BaseModel 来定义工具的输入参数模式。
(2)创建 StructuredTool 实例:使用 StructuredTool.from_function 静态方法来从现有函数创建一个 StructuredTool 实例。
(3)提供工具的元数据:包括工具的名称、描述、参数模式以及是否直接返回结果等。
请看下面的例子,演示了使用数据类StructuredTool创建工具的过程。
实例6-3:使用数据类StructuredTool创建工具(源码路径:codes\6\tool03.py)
实例文件tool03.py的具体实现代码如下所示。
- from langchain.tools import BaseTool, StructuredTool
- from langchain.pydantic_v1 import BaseModel, Field
-
- # 定义输入参数的 Pydantic 模型
- class SearchInput(BaseModel):
- query: str = Field(description="The search query to be processed.")
-
- # 定义一个简单的搜索函数
- def search_function(query: str) -> str:
- return "LangChain"
-
- # 使用 StructuredTool.from_function 创建 StructuredTool 实例
- search_tool = StructuredTool.from_function(
- func=search_function,
- name="Search",
- description="A tool that returns 'LangChain' for any search query.",
- args_schema=SearchInput # 提供参数模式
- )
-
- # 使用工具
- print(search_tool.name) # 输出工具名称
- print(search_tool.description) # 输出工具描述
- print(search_tool.run("test")) # 运行工具并打印结果
在上述代码中,首先定义了一个 SearchInput 模型来描述 search_function 函数的输入参数。然后,创建函数search_function,用于简单地返回字符串 "LangChain"。接着,使用 StructuredTool.from_function创建一个 StructuredTool 实例,同时提供了工具的名称、描述和参数模式。最后,通过调用 search_tool.run("test")来运行工具,这将调用原始的 search_function 函数,并返回其结果。执行后会输出:
- Search
- Search(query: str) -> str - A tool that returns 'LangChain' for any search query.
- LangChain
注意:使用 StructuredTool 是一种快速定义工具的方式,特别适用于那些不需要额外逻辑或回调处理的简单工具。
在实际应用中,通过将LangChain工具转换为OpenAI函数方式,可以在OpenAI的模型中使用这些工具,从而扩展模型的功能。将LangChain工具转换为OpenAI函数的基本步骤如下所示:
(1)导入工具和转换函数:从LangChain社区工具中导入你想要使用的特定工具类,以及用于将LangChain工具转换为OpenAI函数的convert_to_openai_function函数。
- from langchain_community.tools import YourToolClass # 替换为具体的工具类
- from langchain_core.utils.function_calling import convert_to_openai_function
(2)创建工具实例:实例化LangChain工具。
tool = YourToolClass() # 替换为具体的工具实例化
(3)将工具转换为OpenAI函数:使用convert_to_openai_function函数将LangChain工具转换为OpenAI函数。
function = convert_to_openai_function(tool)
(4)使用OpenAI模型:使用OpenAI的模型,比如ChatOpenAI,来调用这个函数。
- from langchain_openai import ChatOpenAI
- model = ChatOpenAI(model="gpt-3.5-turbo") # 选择适合的模型
(5)调用函数:通过OpenAI模型的invoke方法调用转换后的函数。
- message = model.invoke(
- [HumanMessage(content="Your input here")],
- functions=[function],
- )
请看下面的例子,演示了将LangChain工具转换为OpenAI函数并调用的过程。
实例6-4:将LangChain工具转换为OpenAI函数并调用(源码路径:codes\6\tool04.py)
实例文件tool04.py的具体实现代码如下所示。
- # 初始化OpenAI模型
- model = ChatOpenAI(model="gpt-3.5-turbo")
- # 创建工具实例
- api_wrapper = MoveFileTool()
- # 将LangChain工具转换为OpenAI函数
- tool_as_openai_function = convert_to_openai_function(api_wrapper)
- # 打印转换后的OpenAI函数信息
- print(tool_as_openai_function)
- # 构建要传递给OpenAI模型的函数列表
- functions = [tool_as_openai_function]
- # 创建一个HumanMessage实例,模拟用户的输入
- message = HumanMessage(content="move file foo to bar")
- # 使用OpenAI模型调用转换后的函数
- invoke_message = model.invoke(
- [message],
- functions=functions
- )
- print(invoke_message)#打印调用结果
- # 如果需要,可以进一步处理invoke_message以获取所需信息。例如,提取函数调用的详细信息
- function_call_info = invoke_message.additional_kwargs.get("function_call", {})
- print(function_call_info)
上述代码的实现流程如下所示:
(1)首先,导入,所有必要的依赖项,然后初始化了ChatOpenAI模型和MoveFileTool工具。
(2)接着,将MoveFileTool工具转换为一个OpenAI函数,并打印出了该函数的详细信息。
(3)然后,创建一个HumanMessage实例来模拟用户的输入,然后调用model.invoke方法来执行转换后的函数,并将结果打印出来。
(4)最后,从调用结果中提取函数调用的详细信息,并打印出来。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。