文章目录
- LangChain 聊天模型中工具的调用详解
-
- 聊天模型中工具的调用
-
- 创建工具
- 绑定工具
- 工具的调用
LangChain 聊天模型中工具的调用详解
聊天模型中工具的调用
调用工具的一般步骤:
定义工具(创建工具)->绑定工具->调用工具
LangChain提供的现成的工具和工具包:(工具一般都不需要自己手搓)
LangChain Python integrations – Docs by LangChain可以在这里面获取
创建工具
1.在 LangChain 中,实现了一个 @tool 装饰器来创建工具,@tool 装饰器是自定义工具的最简单方法。
# 定义工具
@tool
def add(a: int, b: int) –> int: # 函数定义
"""两数相加
Args:
a: 第一个整数
b: 第二个整数
"""
return a + b # 函数体
一共就是4个部分:
@tool 装饰器:把普通函数标记为「LangChain 工具」
函数定义:工具的名称、参数、返回值
文档字符串(Docstring):给模型看的「工具说明书」
函数体:工具的底层执行逻辑
–LangChain 用 @tool 装饰器时,会自动根据你的函数生成 Schema(工具名默认用函数名;工具描述默认用函数的文档字符串)
–若是简单定义工具,如上述示例,工具 schema 需要解析 Google 风格的文档字符串去获取参数描述
除了上面这种方式,还有其他方式可以让工具 schema,获取相关工具声明需要的内容:
1.模式1:依赖Pydantic类
# pydantic 数据验证
from pydantic import BaseModel, Field
class AddInput(BaseModel):
"""Add two integers."""
a: int = Field(..., description="First integer")
b: int = Field(..., description="Second integer")
# 除非提供默认值,不然这里所有的字段在调用工具时都是必填的
# 定义工具
from langchain_core.tools import tool
@tool(args_schema=AddInput)
def add(a: int, b: int) –> int:
return a + b
2.模式2:依赖Annotated类
from langchain_core.tools import tool
from typing_extensions import Annotated
@tool
def add(
a: Annotated[int, ..., "First integer"],
b: Annotated[int, ..., "Second integer"]
) –> int:
"""Add two integers."""
return a + b
2.使用StructuredTool类提供的函数创建工具:
这个类其中的from_function类方法通过给定的函数来创建并返回一个工具
from_function类方法的定义:
@classmethod
def from_function(
# 1. 同步函数:工具的核心执行逻辑(比如加法、查询天气)
func: Callable | None = None,
# 2. 异步协程函数:如果工具是异步执行的,传这个参数
coroutine: Callable[[...], Awaitable[Any]] | None = None,
# 3. 工具名称:AI 调用工具时用的名字,默认取函数名
name: str | None = None,
# 4. 工具描述:给 AI 看的说明书,AI 靠它判断是否调用该工具
description: str | None = None,
# 5. 是否直接返回结果:True=工具结果直接给用户,不经过AI整理;False=AI会二次加工回答
return_direct: bool = False,
# 6. 参数校验模板:Pydantic 的 BaseModel,定义工具必填/选填参数、类型
args_schema: type[BaseModel] | dict[str, Any] | None = None,
# 7. 是否自动推断参数Schema:自动从函数注解、文档字符串生成参数规则
infer_schema: bool = True,
# 强制关键字参数分隔符:后面的参数必须用 key=value 的形式传参
*,
# 8. 响应格式:content=只返回纯文本给AI;content_and_artifact=返回文本+原始数据(你刚学的)
response_format: Literal['content', 'content_and_artifact'] = 'content',
# 9. 是否自动解析文档字符串:自动从函数 """注释""" 提取描述、参数说明
parse_docstring: bool = False,
# 10. 文档字符串不合法时是否报错:开启后,注释格式错了直接抛错
error_on_invalid_docstring: bool = False,
# 11. 额外参数:接收所有未定义的关键字参数
**kwargs: Any,
# 方法返回值:一个标准的 LangChain 结构化工具(StructuredTool)对象
) –> StructuredTool:
其的官方文档介绍:from_function | langchain_core | LangChain Reference
用法介绍:
用法一:
from langchain_core.tools import StructuredTool
def multiply(a: int, b: int) –> int:
"""Multiply two numbers."""
return a * b
calculator_tool = StructuredTool.from_function(func=multiply)
print(calculator_tool.invoke({"a": 2, "b": 3})) # 输出: 6
用法二:
使用 args_schema 参数,依赖 Pydantic 类定义并提供工具输入参数的 schema 属性
使用 description 参数,替代文档字符串中对于工具描述的 schema 属性
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field
class CalculatorInput(BaseModel):
a: int = Field(description="first number")
b: int = Field(description="second number")
def multiply(a: int, b: int) –> int:
return a * b
calculator_tool = StructuredTool.from_function(
func=multiply,
name="Calculator",
description="两数相乘",
args_schema=CalculatorInput,
)
print(calculator_tool.invoke({"a": 2, "b": 3})) # 输出: 6
print(calculator_tool.name) # 输出: Calculator
用法三:
class AddInput(BaseModel):
a:int = Field(description="第一个整数")
b:int = Field(description="第二个整数")
#a:int和b:int是类型注解,被当作"类型提示"传递给工具schema
def add(a: int, b: int) –> Tuple[str, List[int]]:
nums = [a, b]
content = f"{nums}相加的结果是{a + b}"
return content, nums
add_tool = StructuredTool.from_function(
func=add,
name="ADD", # 工具名
description="两数相加", # 工具描述
args_schema=AddInput, # 工具参数
response_format="content_and_artifact"
)
# 模拟大模型调用姿势 –这样才能返回看到大模型分析的过程和结果
print(add_tool.invoke(
{
"name": "ADD",
"args": {"a": 3, "b": 4},
"type": "tool_call", # 必填
"id": "111", # 必填, 用来将工具调用请求和结果关联起来。
}
))
# 手动调用
# print(add_tool.invoke({"a": 2, "b": 5}))
绑定工具
使用聊天模型里面的.bind_tools()方法
–这里只介绍常见参数和用法,至于详细的参数介绍,可以去官方文档了解
假如已经定义好了两个工具:add和multiply
# 收集工具
tools = [add, multiply]
# 强制绑定工具
model_with_tools = model.bind_tools(tools=tools) # 会返回一个Runnable实例
工具的调用
普通调用:
result = model_with_tools.invoke("9乘6等于多少?") #返回的是AIMessage
print(result)
但是模型hi根据输入的相关性据欸的那个何时使用工具,如果给定的是一个不相关输入的话,模型都不会去调用这个工具
强制模型调用工具:
model_with_tools = model.bind_tools(tools, tool_choice="any") # 要求模型至少调用其中的一个工具
result = model_with_tools.invoke("hello world!")
print(result)
如果调用了工具的话,result将具有一个tool_calls属性,这个属性里面包括了执行这跟工具所需的一切(比如工具名称和输入参数)
result.content是给大模型看的文本结果
result.artifact是给后续组件用的原始数据
如果只像上面那样调用的话,只会看到模型要求调用工具的指令(也就是第一次AIMessage),此时并没有得到最终结果
后续应该本地代码接管这个流程然后调用工具,把结果构造成一个ToolMessage发送给模型,然后模型总结(此时模型收到了前面的完整的对话:HumanMessage[用户询问]、AIMessage(模型请求调用工具)、ToolMessage(工具返回的结果))并输出最终答案(AIMessage的形式传回本地)
完整的工具调用应该是:
# 定义消息列表,添加要传递给聊天模型的消息
message = [
HumanMessage("2乘3等于多少?6加6等于多少?")
]
ai_msg = model_with_tools.invoke(message)
message.append(ai_msg) # 把AIMessage追加到message后面
# 构造ToolMessage, 并添加到消息列表中去
for tool_call in ai_msg.tool_calls:
selected_tool = {"add": add, "multiply": multiply}[tool_call["name"].lower()]# 创建字典+从字典中选择
tool_msg = selected_tool.invoke(tool_call)
message.append(tool_msg) # 追加ToolMessage
print(model_with_tools.invoke(message).content) #这才是最终结果
网硕互联帮助中心




评论前必须登录!
注册