LangChain 05 - Tools 学习导航与实战

目标:这一章不是学“给模型多加几个函数”,而是学“怎么让模型具备调用外部能力的入口”。


你这一章到底要学什么


如果把 05-Tools 学完,真正应该带走的是下面 5 件事:

  1. 知道为什么大模型需要工具,而不能只靠“会聊天”
  2. 理解 @tool 本质上是在把普通函数变成“模型可调用的能力”
  3. 会区分“直接调用工具”和“把工具绑定给模型”这两种方式
  4. 理解 AIMessage -> tool_calls -> ToolMessage -> final_response 这条完整链路
  5. 知道 tool_choice 会怎样影响模型是否调用工具

一句话总结:

第 5 章学的不是“写函数”,而是“给模型接上手和脚”。


模块 1:你只需要记住这些


1. 为什么 Tools 很重要

只有文本生成能力的大模型,更像“会表达的人”。

但实际 AI 应用经常还需要这些能力:

  • 查天气
  • 做计算
  • 查数据库
  • 搜新闻
  • 调第三方接口
  • 执行动作

所以工具的价值不是让模型“更会说”,而是让模型“能做事”。

理解口诀:

模型负责判断,工具负责执行。

2. Tool Calling 本质上是什么

在 LangChain 里,工具调用本质上就是:

  • 你先定义好一个可调用函数
  • 再把这个函数的名字、描述、参数结构告诉模型
  • 模型根据上下文决定要不要调用它

所以 Tools 也经常被叫做:

  • Tool Calling
  • Function Calling

3. 两种调用方式要分清

工具常见有两种用法:

  • 方式 1:直接调用工具
  • 方式 2:绑定到模型,让模型决定何时调用

区别很重要:

  • 直接调用,适合测试函数本身是否工作正常
  • 绑定模型,适合真实 AI 应用开发

4. 工具调用的完整链路

真正要记住的是这条消息流:

  1. 用户发起问题
  2. 模型判断是否需要工具
  3. 模型返回 tool_calls
  4. 程序执行对应工具
  5. 工具返回 ToolMessage
  6. ToolMessage 再喂回模型
  7. 模型基于工具结果生成最终回答

一句话理解:

模型不会自己真的执行工具,它只是提出“我想调用哪个工具、参数是什么”,真正执行的是你的程序。

5. 为什么推荐用 @tool

虽然普通函数也能被 bind_tools() 绑定,但更推荐 @tool,因为它有几个明显好处:

  • 语义更清晰,代码一眼能看出“这是工具”
  • 可以直接 invoke()
  • 更方便生成工具描述
  • 更适合后面接 Agent

如果再配合规范的 docstring,模型更容易理解:

  • 这个工具是干什么的
  • 参数是什么意思
  • 返回值是什么

模块 2:带教式理解


1. 为什么说“不是所有问题都该调用工具”

比如用户问:

  • 2 + 3 等于几?
  • 你好啊
  • 什么是 LangChain?

这些问题模型自己就能回答。

但如果用户问:

  • 今天杭州天气如何?别瞎编
  • 苹果公司今天股价是多少?
  • 最近有什么财经新闻?

这类问题更适合通过工具获得外部信息。

所以工具不是“每次都调用”,而是“该调用时调用”。

2. tool_calls 到底是什么

很多初学者看到这里最容易误会:

response.tool_calls 不是工具执行结果,而是模型发出来的“工具调用申请单”。`

里面通常会包含:

  • 工具名 name
  • 参数 args
  • 调用 ID id

比如模型可能返回:

  • 想调用 get_weather
  • 参数是 {"city": "杭州"}

这时还不算真的查完天气,只是告诉你:

请你替我调一下这个工具。

3. ToolMessage 为什么关键

工具执行完之后,不能只 print 一下结果就结束。

因为模型还不知道工具查到了什么。

所以你需要把工具执行结果包装成 ToolMessage,再放回消息列表里,继续让模型处理。

这一步的意义是:

  • 工具负责拿数据
  • 模型负责读数据并组织成自然语言回答

4. 多工具调用怎么理解

一次提问不一定只触发一个工具。

比如:

苹果公司今天股价是多少?最近有什么新闻?

模型可能同时请求:

  • get_stock_price
  • search_news

所以不要默认 response.tool_calls 只有一个,而要按列表遍历处理。

这一点会直接影响你后面写 Agent 或工作流时的健壮性。

5. tool_choice 是干什么的

tool_choice 用来控制模型对工具的使用策略。

常见取值:

  • none:禁止调用工具
  • auto:默认值,模型自己决定
  • required:必须调用工具
  • any:和 required 等价
  • 指定工具名:强制调用某个特定工具

这几个值最值得你建立的直觉是:

  • none:哪怕你给了工具,模型也不会用
  • auto:最自然,真实开发最常见
  • required:哪怕问题本来不用工具,也可能硬调一个

这一章结束后,你应该能自己回答


1、Tools 在 LangChain 里解决的核心问题是什么?

它解决的是“模型如何连接外部能力”的问题。模型负责判断是否需要工具,工具负责执行实际任务,比如查询、检索、计算或访问 API。

2、为什么 tool_calls 不等于最终答案?

因为 tool_calls 只是模型提出的工具调用请求,真正执行工具的是应用程序。执行结果还需要通过 ToolMessage 回传给模型,模型才会生成最终答案。

3、为什么推荐用 @tool 而不是长期直接裸函数?

因为 @tool 能让函数更清楚地成为工具对象,支持更规范的描述、更方便的 invoke() 和更自然的工具回传流程,也更适合后续接 Agent。

4、为什么多工具场景一定要遍历 response.tool_calls

因为一次提问可能同时触发多个工具。如果只处理第一个,后续工具结果就会丢失,最终答案也可能不完整。

5、tool_choice="required" 有什么风险?

它会强制模型一定调用工具,即使问题本身并不需要工具,也可能出现“为了调用而调用”的情况,所以更适合实验、演示或业务上明确要求必须走工具的场景。


小测试


1. 工具调用里,真正负责执行函数的是谁?

是你的程序,不是模型本身。

2. 如果模型返回了 tool_calls,下一步最应该做什么?

读取工具名和参数,执行对应工具,并把结果作为 ToolMessage 放回消息列表。

3. 为什么“天气查询”比“解释什么是 RAG”更适合演示工具?

因为天气查询依赖外部信息,更能体现工具是模型连接外部世界的能力入口,而解释 RAG 通常模型自己就能完成。

4. tool_choice="none" 时,模型会怎样?

模型不会调用任何工具,即使已经绑定了工具。

5. 一次用户提问是否只能触发一个工具?

不是。一次提问可能触发多个工具,所以要遍历 response.tool_calls


实践任务


练习 1:先把工具当普通函数测通

目标:

  • 理解工具首先是函数
  • 确认参数和返回值是否合理

💡 建议观察:

  • @tool 后还能不能 invoke()
  • 返回的是普通内容,还是 ToolMessage

练习 2:观察模型什么时候决定调工具

目标:

  • 比较普通问题和“需要外部信息”的问题
  • 观察 response.tool_calls 是否为空

💡 建议观察:

  • 你好啊 为什么大概率不调工具
  • 今天杭州天气如何?别瞎编 为什么更容易调工具

练习 3:手动走完一次 ToolMessage 回传

目标:

  • 真正理解消息流
  • 不只会 bind_tools(),还要知道底层怎么流转

💡 建议观察:

  • 第一次模型返回的到底是不是最终答案
  • 把工具结果补回消息列表后,模型最终回答会怎样变化

练习 4:一次问题触发多个工具

目标:

  • 理解为什么 tool_calls 是列表
  • 建立“多工具并发思维”的基础

💡 建议观察:

  • 模型是否一次请求两个工具
  • 最终答案会不会自动整合多个工具结果

练习 5:切换 tool_choice

目标:

  • 建立对 none / auto / required 的直觉

💡 建议观察:

  • none 时模型如何绕开工具
  • required 时模型会不会“硬调工具”

本章一句话收尾


从第 5 章开始,你不再只是“让模型回答问题”,而是在学习“让模型学会调用能力”。