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 实际完成工具调用,欢迎持续关注。

相关推荐
BYSJMG29 分钟前
计算机大数据毕业设计推荐:基于Spark的气候疾病传播可视化分析系统【Hadoop、python、spark】
大数据·hadoop·python·信息可视化·spark·django·课程设计
yangshuo12811 小时前
AI编程工具对决:Kilo vs Augment 开发Flutter俄罗斯方块游戏实战对比
flutter·游戏·ai编程
抠头专注python环境配置2 小时前
OCR库pytesseract安装保姆级教程
python·ocr·conda
山烛2 小时前
矿物分类系统开发笔记(二):模型训练[删除空缺行]
人工智能·笔记·python·机器学习·分类·数据挖掘
大得3692 小时前
django生成迁移文件,执行生成到数据库
后端·python·django
风云信步3 小时前
微软开源 GitHub Copilot VS code plugin 源码分析 (二) copilot-instructions.md 文件的应用逻辑
aigc·ai编程·cursor
R-G-B3 小时前
【P38 6】OpenCV Python——图片的运算(算术运算、逻辑运算)加法add、subtract减法、乘法multiply、除法divide
人工智能·python·opencv·图片的运算·图片加法add·图片subtract减法·图片乘法multiply
数据智能老司机3 小时前
MCP 实战——全局视角:为什么 MCP 将成为 AI 的颠覆者
python·llm·mcp
bug菌3 小时前
还在为Java开发效率低下而苦恼?Trae能否成为你的编程救星?
aigc·ai编程·trae