工具 — 怎么找到它、怎么调它、怎么把结果送回模型
这一章讲三件事: 一个工具送到客户端手里时长什么样;模型怎么表示「我要用它」; 以及跑完之后结果怎么送回模型才算完整。
它在全书链条里的位置: 这是全书的主干。 第 06 章的两类东西、第 07 章的反向能力、第 09 章的规模问题, 全部是这一章那个四步循环的变体或它的后果。
1. 三类东西,同一个套路
这一节先给一张地图,省得你把后面两章当成三套新东西来学。
服务器能提供的东西一共三类,书里管它们叫原语—— 协议规定好的那几种基本零件,不能再往下拆:
| 这一类 | 干什么用 | 这本书在哪一章讲 |
|---|---|---|
| 工具 | 让模型动手改变外面的东西 | 本章 |
| 只读数据 | 让模型看到它本来看不到的东西 | 第 06 章 |
| 写好的话术 | 让用户挑一段现成的话发给模型 | 第 06 章 |
三类的调法完全一样,而且只有两步:先要一张清单,再挑一个用1。
① 要清单 tools/list resources/list prompts/list
② 挑一个用 tools/call resources/read prompts/get
↑ ↑ ↑
本章讲 第 06 章 第 06 章
图说:三列的形状一模一样,只是方法名不同。
学会第一列,另外两列只需要记住动词换成了什么。
所以本章其实是在教一套通用动作。 后面遇到新的一类东西,你要问的第一个问题永远是: 「它的清单方法叫什么、它的使用方法叫什么。」
2. 列清单:一个工具在客户端手里长什么样
这一节是主走查的第 1 步。
本章主走查的输入:用户在聊天框里打了一句「12 乘以 30 是多少」。 连着的是第 04 章那台计算器服务器。下面出现的具体字串和数值, 除了四个工具名来自书里,其余是我们按规范写的示例。
客户端向服务器要一张清单,拿回来四条,每条长这样:
| 里面有什么 | 这条的值 | 干什么用 |
|---|---|---|
| 名字 | multiply_two_numbers | 之后调用时靠它指认 |
| 说明 | 「把两个数相乘」 | 模型就是靠这句话决定要不要用它 |
| 参数表 | a(数字,必填)、b(数字,必填) | 告诉模型该填什么 |
| 其他附注 | (这台没填) | 比如「这个工具会改东西,别乱试」 |
书里列的属性名是 name、description、inputSchema、annotations2。
中间那个 inputSchema 就是表里那一行「参数表」——
一份写清「这个工具收什么参数」的表:每个参数叫什么、是什么类型、哪些必填。
这份写法本身也不是 MCP 发明的,它有自己的名字叫 JSON Schema(JSON 数据的格式说明书)。
参数表里那个「类型」只有几种可填,最常见的是三种:数字、真假、
以及字符串——一串连在一起的文字,比如一个文件路径、一个人名。
这台计算器的 a 和 b 都是数字,所以模型填 12 和 30,不会填 "十二"。
为什么它必须存在? 因为模型不会读你的源码。 它能看到的只有这张表和上面那句说明——说明写得含糊,它就挑错;参数表写得不全,它就填错。 (这一点会在第 09 章变成一个真正的麻烦。)
书里对工具本身的定义很朴素:一个大语言模型可以在需要时决定去调用的、确定性的函数; 函数里想干什么都行,从算数到查天气3。它并不神秘,神秘的只是「谁来决定调它」。
3. 模型怎么表示「我要用这个工具」
这一节是主走查的第 2 步,也是最容易被误解的一步。
宿主应用把那四条工具描述,连同用户那句「12 乘以 30 是多少」,一起发给模型。 这是第一次调用模型。
模型回过来的东西不是答案,是一个停顿信号:
模型的回复:
stop_reason = "tool_use" ← 这个字段就是停顿信号
内容里带着一块:
name = "multiply_two_numbers"
input = { "a": 12, "b": 30 }
id = "toolu_01ABC…" ← 这次请求的编号,等下要原样带回来
图说:模型没有执行任何东西。它只是写下了「我要用哪个、参数是什么」,
然后把球踢回给宿主应用。
书里对这一格的说法是:如果回复的 stop_reason 是 tool_use,
那就说明模型正在等你把它请求的那个工具的结果回给它4。
两个细节值得记住:
第一,模型可能一次要求调好几个工具。 所以宿主那一侧要把回复里所有工具请求 挑出来做成一个列表,挨个跑5。我们这个例子只有一个。
第二,那个 id 必须原样带回去。 因为一次要好几个的时候,
结果得靠它认领是哪一个的。
拿到这块之后,宿主应用去调服务器:方法名 tools/call,
参数是 multiply_two_numbers 和 {a: 12, b: 30}。这是全程唯一一次调服务器。