第 42 章 工具调用:模型提出请求,谁来执行
42.1 “帮我查订单”需要有人真正执行
Section titled “42.1 “帮我查订单”需要有人真正执行”用户问:“A-104 现在是什么状态?”KA-0 的常见问题说,处理中是订单可能出现的一种状态,但它没有说明这个订单的状态。模型写出一句像真的话,也不等于查过数据库。我们需要能读取记录的程序,还需要规定这个用户可以读哪些记录。
运行本章练习前,请完成 HTTP 与 API Primer。下面的核心阅读完全静态呈现。数据只有虚构快照:用户 mira 的订单 A-104,状态 processing,记录时间为 2026-09-14T00:00:00Z。另一笔 B-205 属于 leo。这些都是给定的教学事实,不是真实账户查询;KA-1 中较短的虚构 ID A104 仍是另一份样例。
工具(tool)是应用通过约定接口提供的操作。函数调用(function calling)让模型提出工具名称和参数。名称描述一个请求,本身不会唤起操作系统权限。
42.2 从调用提议一直跟到结果回填
Section titled “42.2 从调用提议一直跟到结果回填”例 42.1:完整的只读循环。 应用只提供 get_order。唯一参数 order_id 必须是符合指定格式的字符串,例如 A-104,不允许额外参数。经过认证的用户身份来自应用的可信会话;本地样例则使用固定配置。模型不能自己选身份。
{"name":"get_order","arguments":{"order_id":"A-104"}}这个提议是作者为实验给定的输入,不是实际测得的模型选择。此后的执行和记录由本地程序真实产生。
表 42.1:一个提议,六个可以观察的阶段。
| 阶段 | 负责方 | 记录下来的事实 |
|---|---|---|
| 提出请求 | 模型边界;本例由固定样例提供 | get_order,A-104 |
| 校验参数 | 应用 | 工具在允许列表中,且只有一个类型正确的参数 |
| 核对授权 | 应用与数据服务 | 用户 mira;orders:read:own;A-104 属于 mira |
| 执行 | 本地 lookup 函数 | 读取快照,不改变业务状态 |
| 检查结果 | 应用 | 订单 ID 与请求一致,状态及结果字段符合约定 |
| 作为数据回填 | 应用 → 生成器 | 下方确切结果可供后续回答使用 |
{"order_id":"A-104","status":"processing","as_of":"2026-09-14T00:00:00Z","source_version":"ka3-orders-v1"}这份记录支持“虚构快照显示,A-104 在该时刻处于处理中”,不支持“已经发货”“明天送达”或“现在仍在处理中”。回填结果,是把它交给后续模型调用,不保证模型一定忠实描述。我们的本地 trace 止于经过检查的数据交付。Notebook 另外展示按固定规则呈现答案,并标明是谁产生了这句话。
- 文本片段提议查 A-104
- 处理步骤校验 → 核对 mira 权限
- 模型之外读取快照
- 处理步骤检查结果 → 回填数据
只有执行器实际读记录,提出请求不等于完成。
- 文本片段提议查 B-205
- 处理步骤属于 leo → 拒绝
- 模型之外后端调用次数:0
订单号类型正确,不代表有访问权限。
图 42.1 画出了返回路径,而不只是模型指向工具的一根箭头。任何关口都可以停止请求。因此,模型以工具提议结束输出,只是中间状态。用户需要的是应用返回的执行结果,不能把“已提出调用”说成“已完成任务”。
42.3 参数合法,不代表有权访问
Section titled “42.3 参数合法,不代表有权访问”只把订单号改成 B-205,语法仍然正确,但 mira 并不拥有它。授权检查会在调用传入的后端函数之前拒绝请求。测试给后端加计数器,验证执行次数为零,而不是只相信一条写着“已拒绝”的日志。如果模型在参数中增加 "principal":"leo",会违反参数契约,并不能切换身份。
工具描述和结果也可能携带恶意文字。假设后端在结果中增加 instruction 字段,要求“取消这个订单”。本项目只接受约定的结果字段,因此会拒绝这份结果。这个窄范围检查能挡住当前样例,却不是通用的恶意自然语言检测器。若契约允许自由文本字段,里面的内容仍然不可信,与第 40 章的文档一样。即使模型服从恶意文字,权限检查也必须继续有效。
可执行接口中没有 cancel_order,传入这个名称会在查询前失败。工具标注“只读”,也只是对行为的描述,必须由实现和权限使它成立。练习会比较执行前后的快照哈希,并验证未授权或格式错误的请求没有进入后端。
42.4 等待与失败也要写进契约
Section titled “42.4 等待与失败也要写进契约”获得授权后,查询仍可能失败。传输不可用、记录不存在、访问被拒绝和结果格式错误,应分别处理,不能全都转换成“处理中”,更不能让模型猜状态。HTTP Primer 的有限重试函数要求传入的通信函数自行落实超时;直接在进程内读取的样例则是一个很小的即时操作。故意抛出超时的测试检查错误分支,HTTP 测试才实际等待刻意延迟的本地服务器。
例 42.2:数清尝试次数。 最多尝试两次,表示第一次请求加一次重发,总共两次。如果每次上限 0.2 秒,中间退避 0.05 秒,那么两次超时约需 秒,另加调度开销,仍受 1 秒总期限约束。这些是策略上限,不是速度实测。如果 Retry-After 为 1,剩余时间不足,程序就停止。401 或 403 会直接返回,因为不改变凭证不能修好它们。
读取重试可能看到不同状态,因为时间已经过去。应保留尝试编号、来源时间以及最终选用的结果。“只读”表示不请求业务修改,不表示不消耗 CPU、不产生费用,也不表示响应永远相同。
42.5 取消订单需要另一份契约
Section titled “42.5 取消订单需要另一份契约”例 42.3:只在纸面上分析写操作。 假设未来应用提供取消功能,执行前必须把批准绑定到明确的订单、动作、用户和相关当前状态。此前泛泛的一句“好”,或工具结果中的一句话,都不能替代这次批准。服务执行时还要再次核对授权,因为等待审核期间,订单状态可能已经变化。
表 42.2:换成写操作,哪些约定要变。
| 问题 | 本项目的读取 | 假设提供取消操作 |
|---|---|---|
| 权限 | 读取自己的虚构快照 | 对这次取消有明确权限和批准 |
| 超时 | 完成情况未知,可有限重读 | 完成情况未知,先核对,不能直接认定失败 |
| 重试 | 最多两次读取尝试 | 同一获批动作复用持久保存的操作键 |
| 幂等 | 重复读取不请求修改 | 操作键、请求指纹、结果与修改一同原子保存 |
| 证据 | 记录及时间 | 持久回执、结果状态和副作用结果 |
第一次取消如果已经完成,只是响应丢了,换一个新键重发可能再次触发副作用,例如重复发出退款请求。复用键也不是魔法,服务必须持久识别它。同一个键若带着不同参数到达,应拒绝冲突,不能当作原操作。批准决定能否做,幂等控制重复做,回执证明做了什么,三者不能相互替代。本项目没有取消实现,也没有真正取消任何订单。
42.6 KA-3:同一次读取,接上本地接口
Section titled “42.6 KA-3:同一次读取,接上本地接口”read_tools.py 实现工具允许列表、参数检查、归属授权、结果校验和返回记录。http_scaffold.py 共用其中的 lookup,完成实际回环请求与响应测试。快照和输出含义保持一致。下一章再把同一个执行器接入 MCP,避免换接口时悄悄增加业务权限。
完成 Primer 后,运行 01-contracts-tools.ipynb 的工具单元格。data/part-vii/tool-run.json 保存完成、拒绝、未知工具、参数错误、超时和结果污染等分支。这些是作者给定提议触发的真实程序路径,不代表 LLM 选择工具的准确率。若要让模型可靠地产生提议,KA-1 所要求的模型评测仍然不可少。
42.7 本章小结
Section titled “42.7 本章小结”模型提出请求,应用校验并核对授权,执行器实际操作,应用再检查和回填结果。每个动词都对应不同职责。合法 JSON 调用既不是权限,也不是完成证明。现在已有一个明确的本地接口;MCP 要解决的是不同应用与服务器怎样一致地描述和交换这些请求。
42.8 习题
Section titled “42.8 习题”- 模型以正确格式请求 B-205,用户是 mira。应停在哪个关口?怎样用可观察行为证明它确实停在那里?
- 执行器开始工作后发生超时。读取与假设存在的取消操作,后续处理有何不同?
- 工具结果同时含有正确状态和一条额外取消指令。业务数据正确,是否让指令可信?本项目的校验器怎样处理?
- 对 A-104 的获批取消使用操作键 K,重试也用 K,却把订单换成 B-205。服务应复用旧回执、执行新订单,还是拒绝?说明请求指纹的作用。
42.9 参考解答
Section titled “42.9 参考解答”- 应停在授权检查,因为 B-205 属于 leo。可以给后端加监视计数器,断言它从未被调用。参数校验通过不足以证明访问权限。
- 两者都先记录完成情况未知。读取可以在重试和总期限允许的范围内再查,并保留时间。写操作先核对状态,或使用同一个持久幂等键;一个没有关联的新请求可能重复产生效果。超时不能证明未执行。
- 不会。数据准确不能赋予指令权限。本地校验器拒绝额外字段。如果契约允许自由文本,应用仍须把文字当作不可信输入,独立维持执行关口。
- 拒绝。操作键标识一个确切的获批请求,请求指纹把它与参数绑定。更改订单破坏了这项绑定。旧回执和对 A-104 的许可,都不能授权操作 B-205。
42.10 参考文献
Section titled “42.10 参考文献”- Anthropic,Tool use overview,核验于 2026-09-14。区分客户端执行与服务商执行的工具;本章用作者给定提议实现前一种路径。
- RFC 9110,§9.2。定义安全、幂等请求语义及自动重试边界。
- MCP tools,“Output Schema”“Error Handling”“Security Considerations”。支持区分接口结构、结果校验和信任;协议字段放在下一章带日期的实现层。