工具调用是怎么运作的?
模型从不执行任何东西。它发出一个结构化请求,你的代码去执行,结果再以文本形式传回去。剩下的一切都由此推出。
你对外暴露一个工具:get_weather(city, unit)。模型只能看到它的名字、描述和参数 schema。
最重要的一点:模型永远只发出一个请求。除非你的代码决定执行,否则什么都不会运行。
关于工具调用,最重要的一点是那件没有发生的事:模型从不执行任何东西。
它发出的只是一个结构化请求。要不要跑、怎么跑,由你的代码决定,跑完再把结果交回去。模型唯一的能力就是读文本、写文本——工具调用是叠在这之上的一个协议,不是什么新本事。
想通这一点,安全模型和失效模式就都能直接推出来。
一次完整交互
你在请求里描述有哪些工具可用。模型可能不直接作答,而是发来一个工具调用。
1 · 你声明工具,每个工具带一个名字、一段描述和一份参数 schema:
{
"name": "get_weather",
"description": "Get current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"unit": {"enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}2 · 模型请求调用,而不是产出文本:
{"tool": "get_weather", "arguments": {"city": "Tokyo", "unit": "celsius"}}**3 · 你的代码执行它。**这完全发生在你这一侧——模型在等着。
4 · 你把结果返回,作为对话里的一条消息。
5 · 模型继续,此时结果已在上下文中。它可能给出回答,也可能再调一个工具。
为什么它可靠
工具参数格式正确的比例,远高于让模型自由输出 JSON,原因有两个。
模型是专门针对这种格式训练过的,这个模式被强化得很深。而且各家服务商还会施加 schema 约束生成——采样那一步被掩码限制,只有在你 schema 下合法的 token 才可能被选中。于是畸形参数从「不太可能」变成了「结构上难以出现」。
这就是为什么,纯粹为了拿到结构化数据而定义一个「工具」,即使背后没有任何函数,也是一种正当做法。
工具描述就是 prompt
这是最值得花力气做对的一件事。
模型选哪个工具,只看描述,别的都不看。描述含糊就会选错工具,而这是 agent 行为出问题最常见的原因——比推理出错还常见。
描述必须说清:这个工具做什么、什么时候用、什么时候不要用、返回什么。两个描述重叠的工具,模型会分不清。见把工具定义写好。
并发与串行
当多个调用彼此独立时,模型可以一次请求好几个工具——一轮里查三个城市的天气,并发执行。值得支持,因为能大幅降低延迟。
有依赖的调用必须串行:先搜索,读到结果,再去取它指名的那份文档。模型在看到第一个结果之前,没法构造第二个调用——循环存在的根本原因就在这里。
安全
因为执行的是你的代码,**每一个安全决策都归你。**模型只是一个不可信的函数参数来源。
**独立校验参数。**符合 schema 不等于获得授权。一个格式规范的删记录请求,仍然是一个删记录请求。
**在执行处强制执行权限。**检查的是用户能做什么,而不是模型要了什么。模型根本不知道是谁在提问。
**假设提示注入一定会发生。**工具返回结果是以文本形式进入上下文的。检索到的文档或抓取的网页里,可能藏着形似指令的文本。只要某个工具会读取不可信内容,就把下游一切视为可能已被影响——这是 agent 安全领域最核心的未解难题,没有彻底的缓解办法。部分防御手段:让破坏性工具碰不到不可信输入,对后果重大的操作要求人工确认。
**给不可逆操作设闸。**发送、删除、付款、部署。只读工具可以放开跑;其他任何操作都该有一个人在链路里把关。
实操要点
**把错误当正常结果返回。**失败的工具应当返回 {"error": "City not found"},而不是抛异常。这样模型还能自己纠偏——换个拼写,或者问问用户。抛异常会直接终结循环,白白浪费掉你花钱买来的恢复能力。
**保持结果精简。**工具的返回会进入之后每一轮的上下文窗口。一个倒出 10,000 token JSON 的工具,会毒化这次运行的剩余部分。只返回真正要紧的字段。
**工具越少越好。**相似工具超过十几个以后,选择准确率就开始下降。合并它们,或者按任务路由到某个子集。
**尽可能让工具幂等。**重试总会发生。
要点回顾
- 模型发出的是请求,执行的是你的代码。它自己不跑任何东西。
- schema 约束生成让工具参数远比自由文本 JSON 可靠。
- 描述就是 prompt——含糊或重叠的描述会导致工具选错,这是 agent 最常见的失效。
- 安全全靠你:独立校验、按用户权限执行、给不可逆操作设闸。
- 工具返回结果是不可信文本,可能夹带提示注入。
- 把错误当结果返回,模型才有机会恢复;保持输出精简。
下一篇: Agent 循环