LangChain聊天模型---工具调用
LangChain 支持 3 种@tool这 3 种方式的核心目标都是生成 LangChain 标准的工具对象方式 1:简单直接,依赖 docstring;方式 2:灵活强大,依赖 Pydantic BaseModel;方式 3:简洁紧凑,依赖 Annotated 类型提示。
·
一、先明确:LangChain 中 “工具” 的核心作用
在 LangChain 里,“工具” 是大模型能主动调用的外部功能模块(比如计算、查询、数据处理等)。
@tool装饰器的作用是:把普通 Python 函数,转换成 LangChain 标准的 “工具对象”—— 自动生成工具的名称、描述、参数约束(Schema),让大模型能理解 “这个工具是做什么的、需要传什么参数”。
二、三种工具定义方式
LangChain 支持 3 种@tool的使用方式,对应代码里的 “方式一、方式二、方式三”,各有适用场景:
方式 1:基础用法(@tool + 普通函数 + docstring)
@tool
def add(a: int, b: int) -> int:
"""两数相加
Args:
a: 第一个整数
b: 第二个整数
"""
return a + b
核心逻辑:
@tool装饰器会自动读取函数的3 类信息(对应 “函数名、字符串文档和类型提示”都需要定义”):- 函数名
add:作为工具的名称(add.name会返回 "add"); - docstring 第一行 “两数相加”:作为工具的描述(告诉大模型 “这个工具是做什么的”);
- 参数类型提示(
a: int)+ docstring 里的Args:作为工具的参数约束(告诉大模型 “需要传什么类型的参数、参数是什么意思”)。
- 函数名
- 适用场景:简单工具,参数少、逻辑简单。
方式 2:进阶用法(@tool + Pydantic BaseModel)
class AddInput(BaseModel):
"""两数相加"""
a: int = Field(..., description="第一个整数")
b: int = Field(..., description="第二个整数")
@tool(args_schema=AddInput)
def add(a: int, b: int) -> int:
return a + b
核心逻辑:
- 用
Pydantic的BaseModel(这里是AddInput)定义工具的参数 Schema,替代方式 1 里的 docstring + 类型提示; Field(..., description="xxx")用来定义参数的 “必填性”(...表示必填)和描述;@tool(args_schema=AddInput)指定工具的参数 Schema 由这个 BaseModel 生成。- 适用场景:复杂工具(参数多、需要参数校验(比如
Field(gt=0)限制正数)、默认值等)。
方式 3:简洁用法(@tool + Annotated类型提示)
@tool
def add(
a : Annotated[int, ..., "第一个整数"],
b : Annotated[int, ..., "第二个整数"],
) -> int:
"""两数相加
Args:
a: 第一个整数
b: 第二个整数
"""
return a + b
核心逻辑:
Annotated是 Python 3.9 + 支持的类型提示(需导入from typing_extensions import Annotated),格式是Annotated[参数类型, 元数据1, 元数据2...];- 这里
Annotated[int, ..., "第一个整数"]中:int是参数类型;...表示参数必填;"第一个整数"是参数的描述;
@tool会自动读取Annotated里的 “类型 + 描述” 作为参数约束,替代方式 1 里的Args部分(更简洁)。- 适用场景:希望代码更紧凑,同时保留参数描述的场景(注意:你的写法里
...是冗余的,标准写法是Annotated[int, "第一个整数"])。
三、你当前代码的输出解释
运行代码后,4 个print的输出及意义:
add.invoke({"a": 2, "b": 3})→ 输出5:调用工具,传入参数字典,执行add函数的逻辑(两数相加)。add.name→ 输出"add":工具的名称(默认是函数名)。add.description→ 输出"两数相加\n\nArgs:\n a: 第一个整数\n b: 第二个整数":工具的描述(来自函数的 docstring),大模型会读这段文字判断是否调用这个工具。add.args→ 输出类似{"a": {"type": "integer", "description": "第一个整数"}, "b": {"type": "integer", "description": "第二个整数"}}:工具的参数 Schema(对应 “JSON Schema”),大模型会根据这个 Schema 生成正确的参数格式。
四、为什么需要 “函数名、文档、类型提示”?
原因: “这些信息都是传递给工具 schema 的”,核心是:大模型本身不会直接 “理解 Python 函数”,但它能读懂JSON Schema(一种描述数据格式的标准)。
@tool装饰器的作用,就是把 “函数名、docstring(字符串文档)、类型提示” 自动转换成大模型能理解的 JSON Schema—— 告诉大模型:
- 这个工具叫什么(name);
- 这个工具能做什么(description);
- 调用这个工具需要传什么参数、参数是什么类型(args 对应的 JSON Schema)。
总结
这 3 种方式的核心目标都是生成 LangChain 标准的工具对象,区别是参数约束的定义方式:
- 方式 1:简单直接,依赖 docstring;
- 方式 2:灵活强大,依赖 Pydantic BaseModel;
- 方式 3:简洁紧凑,依赖 Annotated 类型提示。
完整代码:
from langchain_core.tools import tool
from pydantic import BaseModel, Field
from typing_extensions import Annotated
# 定义工具
# 方式一:
# @tool
# def add(a: int, b: int) -> int:
# """两数相加
#
# Args:
# a: 第一个整数
# b: 第二个整数
# """
# return a + b
# 方式二
# class AddInput(BaseModel):
# """两数相加"""
#
# a: int = Field(..., description="第一个整数")
# b: int = Field(..., description="第二个整数")
#
#
# @tool(args_schema=AddInput)
# def add(a: int, b: int) -> int:
# return a + b
@tool
def add(
a : Annotated[int, ..., "第一个整数"],
b : Annotated[int, ..., "第二个整数"],
) -> int:
"""两数相加
Args:
a: 第一个整数
b: 第二个整数
"""
return a + b
print(add.invoke({"a": 2, "b": 3}))
print(add.name)
print(add.description)
print(add.args)
更多推荐



所有评论(0)