
🚀 欢迎来到我的CSDN博客:Optimistic _ chen
✨ 一名热爱技术与分享的全栈开发者,在这里记录成长,专注分享编程技术与实战经验,助力你的技术成长之路,与你共同进步!
🚀我的专栏推荐:
| 专栏 | 内容特色 | 适合人群 |
|---|---|---|
| 🔥C语言从入门到精通 | 系统讲解基础语法、指针、内存管理、项目实战 | 零基础新手、考研党、复习 |
| 🔥Java基础语法 | 系统解释了基础语法、类与对象、继承 | Java初学者 |
| 🔥Java核心技术 | 面向对象、集合框架、多线程、网络编程、新特性解析 | 有一定语法基础的开发者 |
| 🔥Java EE 进阶实战 | Servlet、JSP、SpringBoot、MyBatis、项目案例拆解 | 想快速入门Java Web开发的同学 |
| 🔥Java数据结构与算法 | 图解数据结构、LeetCode刷题解析、大厂面试算法题 | 面试备战、算法爱好者、计算机专业学生 |
| 🔥Redis系列 | 从数据类型到核心特性解析 | 项目必备 |
🚀我的承诺:
✅ 文章配套代码:每篇技术文章都提供完整的可运行代码示例
✅ 持续更新:专栏内容定期更新,紧跟技术趋势
✅ 答疑交流:欢迎在文章评论区留言讨论,我会及时回复(支持互粉)
🚀 关注我,解锁更多技术干货!
⏳ 每天进步一点点,未来惊艳所有人!✍️ 持续更新中,记得⭐收藏关注⭐不迷路 ✨
📌 标签:#技术博客 #编程学习 #Java #C语言 #算法 #程序员
文章目录
聊天模型调用工具
上篇博客说了LangChain解决LLM三大痛点问题的方法之一就是⼯具调⽤——让⼤语⾔模型(LLM)具备与外部世界交互的能⼒。
调用工具后:
- 扩展边界能力,模型借助工具完成任务
- 保证消息实时性:通过调用搜索工具获得最新消息
- 处理复杂任务:将一个复杂请求分解成多个步骤,依次调用不同的工具协同完成
创建工具
我们可以使用别人封装好的工具,同时也可以使用我们自定义的工具。自定义的工具就需要@Tool装饰器创建工具。@tool 装饰器是⾃定义⼯具的最简单⽅法。
简单来说:⼯具通过@tool 加Python函数 实现
- 装饰器默认使⽤函数名称作为⼯具名称
- 装饰器将使⽤函数的⽂档字符串作为⼯具的描述
因此,函数名、类型提⽰和⽂档字符串都是传递给⼯具Schema 的⼀部分,不可缺失。定义好的描述是使模型良好运⾏的重要部分。
特别注意JSON Schema:一套专门用来约束、校验 JSON 数据格式的标准规范,用 JSON 本身写一套规则,用来规定一段合法 JSON 必须满足什么条件。
使用@tool注解(自动生成schema)
工具Schema:大模型工具调用(Function Calling)专用的结构化描述模板,基于 JSON Schema 规范,用来告诉 AI:这个工具叫什么、干什么、需要传哪些参数、参数是什么类型、哪些必填,强制 AI 生成合法参数供后端调用接口 / 函数。
from langchain_core.tools import tool
@tool
def add(a:int,b:int)->int:
"""加法运算
参数:
a:加数
b:被加数
"""
return a+b
print(add.invoke({"a":2,"b":3}))
print(add.name)
print(add.description)
print(add.args)
底层依赖 Pydantic 自动生成 JSON Schema

Pydantic Base Model(复杂结构化参数写法)
from pydantic import BaseModel, Field
class AddInput(BaseModel):
"""Add two integers."""
a: int = Field(..., description="加数")
b: int = Field(..., description="被加数")
from langchain_core.tools import tool
@tool(args_schema=AddInput)
def add(a: int, b: int) -> int:
# 未提供描述
return a + b
print(add.invoke({"a":2,"b":3}))

Annotated+@tool(轻量化带校验、描述)
from typing import Annotated
from pydantic import Field
from langchain_core.tools import tool
@tool
def add(
a: Annotated[int, Field(description="第一个加数,必须大于0", gt=0)],
b: Annotated[int, Field(description="第二个加数,必须大于0", gt=0)]
) -> int:
"""两数相加计算工具,仅支持正整数加法"""
return a + b
print(add.args)
print(add.invoke({"a": 10, "b": 20}))

使⽤StructuredTool类提供的函数创建⼯具
StructuredTool类⽤来初始化⼯具,其中from_function 类⽅法通过给定的函数来创建并返回⼀个⼯具

from langchain_core.tools import StructuredTool
def add(a:int,b:int)->int:
""" 两数相加"""
return a+b;
calculator_tool=StructuredTool.from_function(func=add)
print(calculator_tool.invoke({"a": 2, "b": 3}))

因为LLM的理解大部分来自文本描述,所以工具的输出content必须是结构良好、简洁的文本,方便LLM执行下一步指令。
在链(chain)中,⼯具调⽤之后的其他组件或函数,可能需要⼯具的原始且结构化数据(即artifact )来执⾏特定操作。这些数据可能是庞⼤的、且⾮⽂本的。这些数据不适合直接塞给模型。因此,artifact 其实是为了给链中后续的组件或函数使⽤的,不被⼤模型所直接使⽤
绑定工具
为了实际将这些工具绑定到聊天模型,可以使用聊天模型的.bind_tools()方法
它的源码如下:

工具调用
.bind_tools()方法返回了一个Runnable实例,因此我们可以使用该是咧,调用.invoke()方法,完成工具调用。
from langchain_core.tools import StructuredTool
from langchain.chat_models import init_chat_model
model=init_chat_model("deepseek-v4-pro",model_provider="deepseek")
def add(a:int,b:int)->int:
""" 两数相加"""
return a+b;
calculator_tool=StructuredTool.from_function(func=add)
#绑定工具
tools=[add]
model_with_tools=model.bind_tools(tools)
#调用工具
result=model_with_tools.invoke("2加5等于多少?")
print(result)

输出内容是AIMessage,从输出结果看AI给出的响应是进行工具的调用(这里只是调用了工具,没有答案)
记住:⼯具调⽤的⼀个关键原则是,模型根据输⼊的相关性决定何时使⽤⼯具。模型并不总是需要调⽤⼯具
将工具输出传给聊天模型
前面我们仅仅只是调用了工具,但是聊天模型并没有给我们预期中的答案。因此我们需要:
- 将工具输出传递给聊天模型,包括HumanMessage(用户输出)、AIMessage(工具调用)、ToolMessage(工具输出)
- 聊天模型根据以上信息,将最终结果AIMessage返回
因为聊天模型输入是接收聊天消息列表,所以我们需要把工具的返回构造成ToolMessage,再传给聊天模型。
from typing import Annotated
from langchain_core.tools import tool
from langchain.chat_models import init_chat_model
from pydantic import Field
from langchain_core.messages import HumanMessage
# ------------------ 1. 初始化大语言模型 ------------------
# 使用 DeepSeek 的 v4-pro 模型(需确保已配置 API Key 等环境变量)
model = init_chat_model("deepseek-v4-pro", model_provider="deepseek")
# ------------------ 2. 定义工具(函数) ------------------
# @tool 装饰器将普通 Python 函数转换为 LangChain 可识别的工具,
# 并自动根据函数签名和 Pydantic Field 生成 JSON Schema 供 LLM 理解。
@tool
def add(a: Annotated[int, Field(description="加数")],
b: Annotated[int, Field(description="被加数")]
) -> int:
"""两数相加"""
return a + b
# ------------------ 3. 将工具绑定到模型 ------------------
# 绑定后,模型在调用时会自动在请求中携带工具的定义(function calling)。
tools = [add]
model_with_tools = model.bind_tools(tools)
# ------------------ 4. 第一次调用:让模型决定是否使用工具 ------------------
# 构建初始用户消息
messages = [HumanMessage("5加3等于多少?")]
# 调用绑定了工具的模型,模型会分析意图并可能返回 tool_calls
ai_message = model_with_tools.invoke(messages)
# 将模型的响应(包含 tool_calls 决策)追加到对话历史中
messages.append(ai_message)
# ------------------ 5. 本地执行工具 ------------------
# 遍历模型返回的所有工具调用请求(可能同时请求多个)
for tool_call in ai_message.tool_calls:
# 根据工具名称选择对应的 Python 函数(这里仅演示单一 add 工具)
# 注意:实际生产环境应使用字典映射或注册表,避免硬编码
selected_tool = {"add": add}[tool_call["name"].lower()]
# 执行工具:invoke 会自动提取 tool_call 中的 args 作为参数,
# 并返回 ToolMessage 对象(包含执行结果和 tool_call_id)
tool_message = selected_tool.invoke(tool_call)
# 将工具执行结果追加到消息历史,以便模型获取计算结果
messages.append(tool_message)
# 打印此时的完整消息列表(用于调试),包含 Human、AI(带工具调用)、Tool 三条消息
print(messages)
# ------------------ 6. 第二次调用:基于工具结果生成最终回复 ------------------
# 注意:这里使用原始的 model(未绑定工具),因为我们只需让模型根据工具结果
# 生成自然语言回答,而不希望它再次尝试调用新工具。
result = model.invoke(messages)
# 打印最终回复内容
print(result)
从输出结果来看,我们调用了两次聊天模型:
- 第一次:只是将
HumanMessage发送给聊天模型进行处理,结果返回了,结果返回了包含⼯具调⽤的AIMessage,并没有返回我们想要的结果。然后我们执⾏⼯具,得到ToolMessage - 第二次:将
HumanMessage +AIMessage +ToolMessage消息记录发送给聊天模型进行处理,结果返回了包含结果的AIMessage

整个流程:
- 第一次请求发送: [HumanMessage(“5加3等于多少?”)] ,附带: tools=[add函数的JSON Schema定义]
- 第一次响应返回AIMessage(不含文本内容,有tool_calls),tool_calls = [{name: “add”, args: {a: 5, b: 3}, id: “call_xxx”}]
- 第二次请求(注意:这次用的是 model.invoke,没有绑定工具;发送: 完整消息历史 [HumanMessage, AIMessage(tool_calls), ToolMessage],注意:此时 没 有 传 递 tools 参数
- 第二次响应返回: AIMessage (content=“5加3等于8。”)
LangChain提供的⼯具
⼯具也不是全部都需要我们⾃⼰⼿搓,其实LangChain官⽅也已经给我们提供了很多现成的⼯具(Tool)和⼯具包(Toolkit)。写好的⼯具⼀般都是为了使⽤LangChain中集成的三⽅组件或⼯具⽽创造的,有搜索、数据库、⽹⻚浏览器等相关的⼯具。
官方工具

这里使用一个搜索工具类Tavily来示范:
Tavily 不仅提供了⾼度可编程的API接⼝,还具备显著优于传统搜索引擎的上下⽂相关性理解能⼒。能够以结构化、可解析的形式返回搜索结果,便于将检索到的信息直接⽤于后续的推理、⽣成或任务执⾏流程。
点击Tvaily官网获取API Key,然后配置到系统环境变量中
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage
from langchain_tavily import TavilySearch
model = init_chat_model("deepseek-v4-pro", model_provider="deepseek")
#绑定⼯具
tool =TavilySearch(max_results=4)
model_with_tools = model.bind_tools([tool])
#添加AIMessage到消息中去
messages = [
HumanMessage("中国西安今天的天⽓怎么样?")
]
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)
for tool_call in ai_msg.tool_calls:
# 执⾏⼯具调⽤,返回ToolMessage
tool_msg=tool.invoke(tool_call)
messages.append(tool_msg)
result=model_with_tools.invoke(messages)
print(result.content)

完结撒花!🎉

如果这篇博客对你有帮助,不妨点个赞支持一下吧!👍
你的鼓励是我创作的最大动力~
✨ 想获取更多干货? 欢迎关注我的专栏 → optimistic_chen
📌 收藏本文,下次需要时不迷路!
我们下期再见!💫 持续更新中……
悄悄说:点击主页有更多精彩内容哦~ 😊
845

被折叠的 条评论
为什么被折叠?



