LangChain框架入门17: 手把手教你创建LLM工具

大语言模型(LLM)是基于训练数据进行预测并生成结果的,它无法掌握训练数据之外的知识。这一点在前面的文章中已经多次提到,通过 RAG 检索的方式,可以在一定程度上缓解这一问题。

但如果我们希望大模型获取最新的时事信息呢?或者让它查找"北京最好吃的五家餐馆"的地理位置信息?又或者要求它完成一套复杂的数学计算?这些需求仅依靠大语言模型本身的能力显然无法解决。

为此,LangChain 提供了 Tools 组件,可以通过创建自定义工具的方式,让 LLM 调用外部能力:例如,获取时事信息时调用搜索工具,查询地理位置时对接高德地图等 API,执行复杂计算时也能编写专门的工具。有了工具调用,AI 应用在解决实际问题上的能力就能得到进一步提升。

在构建 LLM 对象时,可以将工具列表绑定到模型上。这样,LLM 就能够获取到这些工具的名称、描述和参数定义,并以此作为上下文信息来判断是否需要调用工具。如果需要,它会请求调用一个或多个工具,并传入相应的参数,工具调用流程图如下:

当接收到调用指令和参数后,工具会执行相应逻辑并返回结果。随后,大语言模型会结合工具的输出,对用户的提问生成最终回答。这就是LLM工具调用的基本流程。

要实现LLM工具调用,第一步就是工具的创建。本文将会详细介绍在 LangChain 中如何创建工具,在后续文章中,我们会进一步展开,讲解工具调用的完整流程。

文中所有示例代码:github.com/wzycoding/l...

一、工具是什么

LLM 和工具之间的关系好比:大语言模型像是"大脑",工具就像人的"四肢"。大脑可以对四肢发出指令,而 LLM 则会根据用户的提问来决定调用哪些工具。

所谓工具,其实就是供 LLM 调用的程序,可以是实现特定功能的类或函数,也可以是对外部 API 的封装。

一个工具通常需要包含以下几个部分:

  • 工具的名称
  • 工具的功能描述
  • 工具入参的 JSON Schema
  • 执行工具逻辑的函数

LangChain 中,支持三种方式来创建工具:

  • 函数方式
  • 通过 Runnables 创建
  • 继承 BaseTool

下面将分别介绍这三种工具创建方式。

二、通过函数创建工具

通过函数方式创建工具时,需要配合 @tool 注解,将函数转换为工具。其中,第一个参数默认为工具名称,args_schema 用于指定入参结构,return_direct 表示工具调用完成后是否直接将结果传递给大模型:当值为 True 时,结果会直接返回;当值为 False 时,结果会先经过大模型加工后再返回。示例如下:

python 复制代码
from langchain_core.tools import tool
from pydantic.v1 import Field, BaseModel
​
​
class AddNumberInput(BaseModel):
    num1: int = Field(description="第一个数")
    num2: int = Field(description="第二个数")
​
​
@tool("add-tool", args_schema=AddNumberInput, return_direct=True)
def add(num1: int, num2: int):
    """两数相加"""
    return num1 + num2
​
​
print(f"工具名称:{add.name}")
print(f"工具描述:{add.description}")
print(f"工具参数:{add.args}")
print(f"是否直接返回:{add.return_direct}")
​
print("1+1=" + str(add.invoke({"num1": 1, "num2": 1})))

执行结果如下:

python 复制代码
工具名称:add-tool
工具描述:两数相加
工具参数:{'num1': {'title': 'Num1', 'description': '第一个数', 'type': 'integer'}, 'num2': {'title': 'Num2', 'description': '第二个数', 'type': 'integer'}}
是否直接返回:True
1+1=2

除了使用注解的方式,还可以通过 StructuredTool 来创建工具。StructuredTool.from_function 类方法相比 @tool 注解提供了更多配置项,并且不需要额外编写代码。其中,func 参数用于传入同步执行的函数,coroutine 参数则用于传入异步执行的函数,其余参数的作用与前面介绍的相同。示例如下:

python 复制代码
import asyncio
​
from langchain_core.tools import StructuredTool
from pydantic.v1 import BaseModel, Field
​
​
class AddNumberInput(BaseModel):
    """加法工具入参"""
    num1: int = Field(description="第一个数")
    num2: int = Field(description="第二个数")
​
​
def add(num1: int, num2: int):
    """两数相加"""
    return num1 + num2
​
​
async def async_add(num1: int, num2: int):
    """两数相加"""
    return num1 + num2
​
​
add_tool = StructuredTool.from_function(
    func=add,
    coroutine=async_add,
    name="add_tool",
    description="两数相加",
    args_schema=AddNumberInput,
    return_direct=True,
)
​
print(f"工具名称:{add_tool.name}")
print(f"工具描述:{add_tool.description}")
print(f"工具参数:{add_tool.args}")
print(f"是否直接返回:{add_tool.return_direct}")
​
# 同步调用工具
print("1+1=" + str(add_tool.invoke({"num1": 1, "num2": 1})))
​
​
# 异步调用工具
async def async_main():
    result = await add_tool.ainvoke({"num1": 2, "num2": 5})
    print("2+5=" + str(result))
​
​
asyncio.run(async_main())

执行结果如下:

python 复制代码
工具名称:add_tool
工具描述:两数相加
工具参数:{'num1': {'title': 'Num1', 'description': '第一个数', 'type': 'integer'}, 'num2': {'title': 'Num2', 'description': '第二个数', 'type': 'integer'}}
是否直接返回:True
1+1=2
2+5=7

三、通过Runnables创建工具

通过可运行组件(Runnable)的 as_tool() 方法也可以创建工具。由于由多个可运行组件组成的链(Chain)本身也是一个 Runnable,因此可以直接调用 chain.as_tool() 方法,将整个链包装成一个工具。示例如下:

python 复制代码
import dotenv
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from pydantic.v1 import BaseModel, Field
​
# 读取env配置
dotenv.load_dotenv()
​
​
class RandomInput(BaseModel):
    """生成随机数入参"""
    count: int = Field(description="生成随机数个数")
​
​
# 1.创建提示词模板
prompt = ChatPromptTemplate.from_template("请帮我生成{count}个100以内随机数,只返回随机数本身就好")
​
# 2.构建GPT-3.5模型
llm = ChatOpenAI(model="gpt-3.5-turbo")
​
# 3.创建输出解析器
parser = StrOutputParser()
​
# 4.执行链
chain = prompt | llm | parser
​
random_tool = chain.as_tool(name="random_tool", description="生成100以内随机数", args_schema=RandomInput)
print("生成随机数:" + str(random_tool.invoke({"count": 10})))

执行结果:

python 复制代码
生成随机数:27, 63, 84, 12, 95, 41, 55, 73, 38, 9

四、通过继承BaseTool类创建工具

还可以通过继承 BaseTool 来创建自定义工具。这种方式的自由度最高,也更加灵活。示例如下:创建 AddNumberTool 类继承 BaseTool,并指定工具相关参数,同时重写 _run() 方法,在方法中实现具体的工具逻辑。

python 复制代码
from langchain_core.tools import BaseTool
from pydantic.v1 import BaseModel, Field
​
​
class AddNumberInput(BaseModel):
    """加法工具入参"""
    num1: int = Field(description="第一个数")
    num2: int = Field(description="第二个数")
​
​
class AddNumberTool(BaseTool):
    """加法工具"""
    name = "add_number_tool"
    description = "两数相加工具"
    args_schema = AddNumberInput
​
    def _run(self, num1: int, num2: int) -> int:
        return num1 + num2
​
​
add_number_tool = AddNumberTool()
​
print(f"工具名称:{add_number_tool.name}")
print(f"工具描述:{add_number_tool.description}")
print(f"工具参数:{add_number_tool.args}")
print(f"是否直接返回:{add_number_tool.return_direct}")
​
print("1+1=" + str(add_number_tool.invoke({"num1": 1, "num2": 1})))

执行结果:

python 复制代码
工具名称:add_number_tool
工具描述:两数相加工具
工具参数:{'num1': {'title': 'Num1', 'type': 'integer'}, 'num2': {'title': 'Num2', 'type': 'integer'}}
是否直接返回:False
1+1=2

五、总结

通过工具,LLM 这个"超级大脑"有了四肢,甚至可以配备各种各样的"武器"。这些"武器"就是提供给 LLM 的工具。有了工具,LLM 不再只是一个聊天助手,而是能够真正解决问题的助手。它可以根据用户的提问内容做出判断,决定需要调用哪些工具,并传递相应的参数。

LangChain 中,创建工具的方式有多种,不同方式适用于不同场景:通过函数创建工具,适合实现简单功能;将 Chain 包装成工具,方便已有逻辑的复用;如果需求比较复杂,则可以通过继承 BaseTool 类的方式,实现更灵活的工具。

通过本文的介绍,相信你已经理解了为什么需要工具,以及 LLM 如何进行工具调用。除此之外,我们还重点介绍了多种工具创建方式。在下一篇文章中,将会详细讲解如何让 LLM 实际完成工具调用,欢迎持续关注。

相关推荐
mingo_敏18 分钟前
DeepAgents : 权限(Permissions)
人工智能·深度学习·langchain
浦信仿真大讲堂24 分钟前
从重复操作到自动化闭环:如何让 CST 与 Python 真正协同起来
python·自动化·cst·仿真软件·达索软件
Gu Gu Study1 小时前
ScoutLoop开放域深度研究引擎(agent的初步设计想法)
人工智能·python
卷无止境2 小时前
写代码这件事,到底该讲究点什么?
后端·python
卷无止境2 小时前
循环复杂度到底在算什么,Python 代码怎么才能写得让人一看就懂
后端·python
lpfasd1232 小时前
MediaCrawler 项目深度分析
chrome·python·chrome devtools
Dxy12393102162 小时前
Python项目打包成EXE完整教程(PyInstaller实战避坑)
开发语言·python
bamb003 小时前
一个项目带你入门AI应用开发01
python
0566463 小时前
Python康复训练——常用标准库
开发语言·python·学习
wechatbot8883 小时前
企业微信API开发:登录-联系人查询-消息发送完整开发流程分享
汇编·微信·自动化·企业微信·ai编程·rpa