工具/函数调用详解

B5
概念 · 核心构件

工具/函数调用详解。

语言模型只能输出文本。工具调用(又称函数调用)是把"输出文本"变成"在世界中做事"的协议:模型请求一个函数,你的代码运行它,结果再回到上下文。本文讲解确切的请求/响应形状、它隐含的循环、为何模型从不自己执行任何东西,以及让用工具的智能体保持安全的设计规则。

STEP 1

模型提议;你的代码裁决。

最重要的一个事实:模型不会调用你的函数。它输出一个结构化请求,要求你去调用它。模型内部没有代码执行。工具调用是一个有纪律的文本协议,分三步:

  • 你在请求里描述可用工具(名称、用途、参数 schema)。
  • 模型不再用散文作答,而可能输出一条工具使用消息:"用 {"city": "Paris"} 调用 get_weather。"
  • 你的应用执行真实函数,然后把结果作为一条工具结果消息发回。模型继续,此刻已能使用该结果。

模型所做的一切仍是下一令牌预测。它被后训练成在工具有帮助时输出一个特定 JSON 形状的结构;"调用"是你的代码对那个结构的反应。

STEP 2

线上格式。

# 1. You declare tools in the request
tools = [{
  "name": "get_weather",
  "description": "Current weather for a city. Use when asked about weather.",
  "input_schema": {
    "type": "object",
    "properties": {"city": {"type": "string"}},
    "required": ["city"]
  }
}]
# 2. Model replies with a tool-use request (not prose)
{ "type": "tool_use", "id": "t_01", "name": "get_weather",
  "input": { "city": "Paris" } }

# 3. YOUR code runs get_weather("Paris") and returns a tool_result
{ "type": "tool_result", "tool_use_id": "t_01",
  "content": "12C, light rain" }

# 4. Model now answers in prose, grounded in the result
"It's 12C with light rain in Paris right now."

工具描述和参数 schema 是提示词工程,不是样板。模型是否调用、如何调用某个工具,几乎完全基于那段文本来决定。含糊的描述("对用户做点事")产生不可靠的调用;精确的("按 ID 获取用户。仅当你有数字 user_id 时使用;不要瞎猜 ID")产生可靠的调用。

STEP 3

它隐含的循环。

一次工具调用很少就是终点。结果可能促使再一次调用,然后再一次,直到模型有足够信息作答。这个循环——模型 → 工具请求 → 执行 → 结果 → 模型——反复进行,直到模型输出最终答案而非工具请求,就是智能体循环(在"智能体 AI"一节详述)。工具调用是原语;循环是建于其上的模式。对初学者有两个后果:

  • 循环归你管。API 不会自动执行。是你写代码检测工具使用消息、运行函数、追加结果、再次调用模型。
  • 你需要停止条件。一个总是报错的有 bug 工具能让模型永远重试。务必给迭代次数设上限。
STEP 4

为何这个原语强大。

工具调用消除了裸 LLM 的三个结构性弱点:

  • 知识陈旧 → 实时数据。模型训练有截止日期。一个 searchget_account 工具给它当前事实,而非凭记忆的猜测。
  • 不擅精确计算 → 真实计算。模型在算术和精确逻辑上不可靠。一个 calculatorrun_sql 工具把精确性卸载给真正精确的代码。
  • 无法行动 → 能够行动。send_emailcreate_ticketdeploy——工具是 LLM 影响世界而非只描述它的方式。

这也是本节的主线:RAG 本质上是一个接入上下文的检索工具;结构化输出是同一套 JSON 塑形机制,只是对准最终答案而非函数调用。

STEP 5

不可选的安全规则。

模型产出的工具参数是不可信输入。模型可能出错,或被检索/工具内容里的提示词注入操纵。把每次工具调用都当作互联网上的陌生人向你的函数发来的请求。

  • 执行前校验。在代码里对照 schema 和你自己的业务规则重新检查参数。绝不把模型输出直接传进 shell、SQL 字符串或文件系统路径。
  • 最小权限。暴露能完成工作的最窄工具。是带服务端限额的 refund_order(order_id, amount),而非 run_arbitrary_sql
  • 为不可逆动作设闸。删除、付款、发送——要求显式确认或人工审批。即便提示词被颠覆,能力上限依然成立;一句叫模型"小心点"的话则不然。
  • 把错误作为数据返回。工具失败时,把结构化错误作为工具结果发回,让模型能据此反应("该用户不存在"),而不是让循环崩溃。
  • 尽量让工具幂等。循环可能重试;被重试的 charge_card 绝不能重复扣款。
要点

交付物

你把工具调用理解为一个文本协议:你用精确的描述和 schema 声明工具,模型输出一个结构化的工具使用请求,你的代码执行真实函数并返回工具结果,模型据此继续作答。环绕的循环及其停止条件归你管。你知道它的存在是为修复陈旧知识、薄弱计算和无法行动。而且你把每个模型产出的参数视为不可信:校验它,按最小权限限定工具,用能力上限而非指令为不可逆动作设闸,并让执行幂等。