[LangChain] 学习笔记(07):大模型长出手脚——工具(Tools)定义与调用闭环

📌 核心结论(TL;DR)

  1. 本质揭秘:大模型不能直接执行本地代码。Tool Call 本质上是模型返回的一段特殊的"结构化输出"(JSON),告诉开发者需要调用什么函数、传什么参数。

  2. 执行闭环 :完整的工具调用需要三步:① 模型决策并返回 tool_calls;② 开发者在本地执行对应函数,封装为 ToolMessage;③ 将 ToolMessage 追加到历史消息中再次发给模型。

  3. 定义规范 :使用 @tool 装饰器定义工具,函数名、类型提示和文档字符串(Docstring)极其重要,它们构成了模型是否调用该工具的判断依据(Schema)。

🔍 一、 原理图解与核心概念

1. 为什么需要工具?

大模型有知识截止日期,无法获取实时数据,也无法直接操作数据库。工具(Tools)允许大模型与外部世界交互,突破自身能力的边界。

2. 底层流程:"思考-行动-观察"

  • 思考:用户提问,大模型分析意图。

  • 行动 :如果需调用工具,模型返回带有 tool_calls 的 AIMessage。注意,此时模型并未给出最终答案。

  • 执行 :开发者根据 tool_calls 中的函数名和参数,在本地执行真实函数。

  • 观察 :将执行结果包装成 ToolMessage 返还给模型,模型再据此生成最终自然语言答复。

💻 二、 精选核心代码片段

1. 定义工具(@tool 装饰器)

python 复制代码
from langchain_core.tools import tool
from typing_extensions import Annotated

@tool
def multiply(
    a: Annotated[int, ..., "第一个整数"], 
    b: Annotated[int, ..., "第二个整数"]
) -> int:
    """两数相乘。当用户询问乘法计算时使用此工具。"""
    return a * b

2. 工具绑定与调用闭环

python 复制代码
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

model = ChatOpenAI(model="deepseek-chat", ...)
# 1. 绑定工具
model_with_tools = model.bind_tools([multiply])

messages = [HumanMessage(content="9乘6等于多少?")]

# 2. 模型决策
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)

# 3. 本地执行(必须通过 tool_calls 获取参数)
for tool_call in ai_msg.tool_calls:
    tool_msg = multiply.invoke(tool_call) # 自动生成 ToolMessage
    messages.append(tool_msg)

# 4. 将执行结果交回模型生成回答
final_result = model.invoke(messages)
print(final_result.content)

3. 进阶:StructuredTool 与内容分离(content_and_artifact)

除了 @tool 装饰器,当我们需要包装第三方函数,或者需要将给大模型看的内容和给代码看的数据分离时,StructuredTool 是最佳选择。

python 复制代码
from typing import Tuple
from langchain_core.tools import StructuredTool

# 假设这是一个查询天气的复杂函数
def get_weather(city: str) -> Tuple[str, dict]:
    # 模拟调用第三方 API 返回了庞大的数据
    raw_data = {"city": city, "temp": 25, "aqi": 45, "details": "..."}
    # 但大模型只需要看一句话总结(节省 Token)
    summary = f"{city}今天晴,气温25度。"
    return summary, raw_data

weather_tool = StructuredTool.from_function(
    func=get_weather,
    name="Get_Weather",
    description="查询指定城市的天气",
    response_format="content_and_artifact"  # 核心配置!
)

# 执行后:
# content = "西安今天晴,气温25度。" (大模型看这个)
# artifact = {"city": "西安", ...}     (你的后端代码用这个)

(完整的包含多工具调用的代码已上传至 Gitee 仓库)

⚠️ 三、 踩坑排查排雷

大模型不调用工具,直接回答:

  • 排查 :检查工具的 Docstring 是否清晰描述了"什么时候该用它"。工具名不能太抽象(比如叫 calc,不如叫 multiply_numbers)。

报错 Invalid tool_call_id 或模型陷入死循环:

  • 排查 :在将本地执行结果返回给模型时,必须使用 ToolMessage 且带上 tool_call_id。如果使用 HumanMessage 传递结果,模型会不知道这是工具的执行反馈,导致逻辑混乱。

类型提示缺失导致大模型解析参数失败:

  • 排查 :一定要加上 Python 的类型提示(如 a: int),并在文档字符串中说明参数含义,LangChain 会自动生成 JSON Schema,缺少类型提示会导致模型乱传参数。
相关推荐
叼烟扛炮4 小时前
[LangChain] 学习笔记(06):突破大模型限制——结构化输出(Structured Output)
windows·笔记·学习·langchain
且从容.5 小时前
VUE3学习笔记(根据黑马教程总结)
笔记·学习
蒸蒸yyyyzwd7 小时前
关于 AI 开发相关的一些面经。
笔记·学习
2603_969694858 小时前
JDBC 基础学习笔记:API 核心原理解析与 CRUD 代码实操
数据库·笔记·mysql·学习方法·database·sql注入
迪康coolmu9 小时前
出差终端数据安全落地实战:基于迪康端点安全一体化管理系统的四道防线实践
运维·服务器·经验分享·笔记·其他·安全·php
无咎.lsy12 小时前
《机器学习》笔记
笔记·机器学习
坤坤子吖13 小时前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习
蒸蒸yyyyzwd15 小时前
后端相关学习笔记。
笔记·学习
吴凡wudianmei16 小时前
从0搭AI Agent(六):什么时候该把任务拆给多个 Agent
langchain·llm·ai编程