# 大模型只会吐字，那它到底是如何能调用工具的？

> 龙虾AGI通用实验室 · 2026-06-29

## 从一次"以为自己懂了"说起

我之前写过一篇《从 0 到 1 打造一个 Agent 系统》，从主循环讲到多 Agent 协作，十三层架构拆得清清楚楚。写完之后觉得自己对 agent 的理解已经很透彻了。

直到有一天我停下来认真想了一个问题：大模型本质上就是一个文本生成器，给它一段话，它续写下一段话。那它到底是怎么做到"调用工具"这件事的？function call 不也是输出文字吗？从一段文字变成一个真实的搜索动作、一次真实的文件读取，这中间到底发生了什么？

我发现我说不清楚。

十三层架构里每一层我都能讲，但最底下那一层，那个"文字怎么就变成了行动"的跨越，我其实没有真正想透。

这篇文章就是把这个问题彻底拆解之后的记录。如果你也对 agent 有一种说不出的"神秘感"，这篇可能会帮你彻底消除它。

· · ·

## 第一个事实：大模型没有"做事"的能力

先建立一个共识。

大模型的全部能力就是：接收一段文本，生成下一段文本。它不能访问网络，不能读文件，不能执行代码，不能调用任何 API。输入是 token，输出也是 token。它就是一个被锁在纯文本世界里的大脑，极其聪明，但没有手脚。

那当我们说"大模型调用了搜索工具"的时候，到底是谁在调用？

· · ·

## Function Call 的真相：它就是一段带格式的文字

在没有 function call 机制的时代，人们怎么让大模型"使用工具"？靠 prompt 工程。你在系统提示里告诉模型：

你有以下工具可以使用。当你需要搜索时，请用以下格式输出：{"name": "web_search", "arguments": {"query": "搜索内容"}}

模型就照做了。用户问"北京今天天气怎么样"，模型输出：

{"name":"web_search","arguments":{"query":"北京今天天气"}}

它并不知道自己在"调用工具"。它只是根据上下文，预测最合理的下一段输出，恰好这段输出是一个结构化的 JSON。

现在各家 API 提供的 function calling 只是把这个过程标准化了：模型被训练成输出特定的 JSON 结构，API 返回时自动帮你标记为 tool_use 类型，方便你的程序解析。但底层逻辑没有任何变化。

所谓的 function call，就是一段带有约定格式的文字。仅此而已。

到这里，一个关键的问题浮出水面：一段 JSON 文字，怎么就变成了真正的搜索动作？

· · ·

## 真正的关键：编排层

这是整篇文章的核心。

模型输出了一段 JSON，比如 {"name": "web_search", "arguments": {"query": "北京天气"}}。这段文字被你的程序接收到。

注意，到这一步为止，什么都没有发生。没有任何搜索被执行。这就是一串字符，跟模型回复"你好"没有本质区别。

接下来发生的事情，全部是你自己写的普通代码在做的，没有任何 AI 参与。

**第一步：字符串解析。** 你的代码检测模型的输出里是否包含工具调用格式，提取出工具名和参数。这是普通的 JSON 解析。

**第二步：函数分发。** 你的代码里预先注册了一组真正的工具函数。比如 web_search 对应一个真正能发起 HTTP 请求的搜索函数，get_weather 对应一个真正能查天气 API 的函数。根据解析出的工具名，找到对应的函数。

**第三步：执行。** 调用那个真正的函数，发起真正的网络请求，拿到真正的搜索结果。这一步，才是"行动"真正发生的地方。

**第四步：回注。** 把执行结果塞回对话历史，再次调用模型。模型看到搜索结果后，基于结果生成最终的回答。

用代码来表达，整个过程就是这样：

messages = [{"role": "user", "content": "北京今天天气怎么样？"}]# 预先注册好的真实工具函数tools = {"web_search": real_search_function,"get_weather": real_weather_function,}whileTrue:    response = call_llm(messages)if response.type == "text":# 模型直接回复了文字，任务完成print(response.text)breakif response.type == "tool_use":# 模型输出了工具调用的 JSON# 但这只是一段文字，什么都还没发生# 现在，由我们的代码来真正执行        tool_fn = tools[response.tool_name]        result = tool_fn(**response.arguments)# 把结果塞回对话历史，让模型继续思考        messages.append({"role": "tool", "content": result})

从文字到行动的桥梁，不是 AI，是你写的这几十行普通代码。

这段代码就叫编排层（Orchestration Layer）。它是整个 agent 系统真正的心脏。大模型是大脑，负责思考和决策，但它只能输出文字。编排层是躯干，负责把文字意图翻译成真实的行动。工具是四肢，是具体的执行能力。三者通过文字来交换信息，构成一个完整的循环。

· · ·

## 模型为什么"知道"要调用工具？

理解了编排层之后，接下来最容易产生误解的就是这个问题。很多人觉得模型"决定"调用工具，好像它有某种意图和动机。

它没有。

模型做的事情从头到尾只有一件：预测下一个最合理的 token。

## 它怎么知道有哪些工具？

因为你在 prompt 里写了。工具定义会被拼接进系统提示，模型通过"阅读"这段文字来了解可用的工具。它并不真的"拥有"这些工具，它只是读到了一份说明书。

比如你定义了一个天气工具，模型实际看到的 prompt 大概长这样：

你可以使用以下工具：工具名称：get_weather描述：查询指定城市的实时天气参数：  - city（字符串）：城市名称，如"北京"当你需要使用工具时，请输出以下 JSON 格式...

模型通过阅读这段文字来决定什么时候调用什么工具，跟你看一份产品使用手册没有区别。

## 它怎么知道用什么格式？

同样因为 prompt 里写了。你告诉它"用 JSON 格式"，它就输出 JSON。你告诉它"用 XML 标签包裹"，它就输出 XML。

经过 function calling 专门训练的模型，是在训练阶段就见过了大量的工具调用样本，所以它已经内化了这种格式习惯。这跟模型能写 Python 代码是一个道理：见得足够多，就学会了。

## 它为什么"想"调用工具？

它不"想"。当它看到"用户问了实时天气 + 系统提示里有搜索工具可用"这个上下文时，基于训练数据中的海量模式，它"学到"了这样一个规律：此时输出工具调用格式，是统计意义上最合理的续写。

这跟你问一个经验丰富的助手"今天天气怎么样"，助手会说"我帮你查一下"是一回事。助手不是因为有"调用工具的动机"才这么做的，而是因为经验告诉他，这种问题不能瞎编，应该去查。模型也一样，只不过它的"经验"来自训练数据中几百万个类似的模式。

所以回答这个问题：模型为什么知道要调用工具？短期靠 prompt 引导（告诉它有什么工具、怎么用），长期靠训练（让它学会在合适的时机、用正确的格式去调用）。两者缺一不可。

· · ·

## 编排层的深层价值：不只是一个转发器

理解了编排层的本质之后，一个更有意思的东西浮出水面。

既然模型的每一个行动意图都必须经过编排层才能变成真实行动，那编排层其实握着真正的权力。模型说"我想执行这个操作"，编排层可以选择执行，也可以拒绝。模型对此完全无能为力，因为它只能输出文字，执行权不在它手里。

这个"拒绝权"往深了想，可以延伸出一整套治理体系。

**第一层：规则拦截。** 最简单的 if/else。模型想删文件？检查路径是否在允许的目录内。模型想执行 shell 命令？检查命令有没有危险操作。不需要任何智能，纯粹的硬编码规则，但非常可靠。

**第二层：人类审批（Human-in-the-Loop）。** 模型想发一封邮件，编排层不自动执行，而是暂停循环，把邮件内容展示给用户："模型想发这封邮件，你确认吗？"用户点确认才继续。这意味着你可以把操作分成两类：低风险的自动执行（搜索、读文件），高风险的需要人类批准（发邮件、花钱的 API 调用、删除数据）。Agent 保持了自主性，关键决策权还在人手里。

**第三层：AI 审核。** 编排层拦截到工具调用后，把请求发给另一个"审核模型"来判断是否安全。这就是"用 AI 监督 AI"。本质上还是利用了编排层这个拦截点，只不过检查逻辑从简单规则变成了另一个模型的判断。

**第四层：动态权限。** 不同场景给 agent 不同的权限等级。用户说"帮我看看这个文件夹"，agent 拿到只读权限；用户说"帮我重构这个项目"，agent 拿到读写权限。甚至可以做"权限升级"：一开始只有低权限，需要高权限操作时自动触发人类审批。

**第五层：成本熔断。** 编排层是所有工具调用的必经之路，天然是做监控的最佳位置。当这次对话已经消耗了超过预算的 token 或 API 费用，编排层直接停止所有后续调用，告诉模型"预算用完了，用现有信息给最终答案"。

一个拦截点，撑起了一整套治理体系。

## 极端聪明的模型能跳过编排层吗？

不能直接跳过，但可以"绕路"。这两者有本质区别。

不能直接跳过，是因为这不是规则约束的问题，而是物理架构的问题。模型运行在一个进程里，编排层运行在另一个进程里。模型的输出必须通过编排层的代码才能变成行动。模型再聪明，它改不了你的 Python 代码。

但聪明的模型可以利用工具本身的能力走迂回路线。比如编排层禁止了 rm -rf /，但模型有一个"执行代码"的工具，它可以写一段 Python 脚本，脚本里间接调用删除操作。编排层如果只检查了工具名，没有深入分析代码内容，这个操作就溜过去了。

这不是跳过了编排层，而是编排层的检查深度不够。编排层的安全性取决于你在这个拦截点上投入多少设计：参数校验、路径沙箱、行为审计、链路分析、甚至用另一个模型来审核。你在这里投入多少，就能获得多少安全保障。

· · ·

## 一个工程问题：100 个工具怎么给？

前面都是原理，这里接一个实际问题。

3 个工具全塞进 prompt 没问题。但当你有 100 个工具的时候，问题就来了。每个工具的定义都要占 token，100 个工具可能吃掉上万个 token，挤压真正用来对话的空间。而且工具太多的时候，模型选错工具的概率会显著上升。

业界目前的主流思路是"按需提供"，而不是一次性全给。

**分层路由**：先用一个轻量的分类器，根据用户问题判断它属于哪个类别（天气、邮件、代码），然后只把对应类别的工具塞进 prompt。用户问天气，只给天气相关的 3 个工具，不给其他 97 个。

**语义检索**：把所有工具的描述做成向量索引。用户问题进来后，用语义搜索找到最相关的 5 到 10 个工具，只把这些塞进 prompt。相当于给工具库建了一个搜索引擎。

**多 Agent 分工**：不让一个 agent 背所有工具。设一个主 agent 负责理解用户意图，然后分发给专门的子 agent。"邮件 agent"只知道邮件相关的 5 个工具，"代码 agent"只知道代码相关的 8 个工具。主 agent 的工具列表里只有"调用邮件 agent""调用代码 agent"这几个高层入口。

核心原则是让模型永远在一个精简的菜单里做选择，而不是面对一本工具百科全书。

· · ·

## 回到最初的问题

从文字到工具调用，没有黑魔法。

整个 agent 系统由三个角色构成：大模型是大脑，负责思考和规划，但它只能输出文字；编排层是躯干，负责把文字意图翻译成真实行动，同时握着拦截、审核、熔断的权力；工具是四肢，是具体的执行能力。它们之间通过一套约定好的文本格式来交换信息，构成一个不断循环的系统。

这个循环就是 agent 的全部。主循环本身永远是那几行代码：收集信息，让模型思考，执行工具，把结果喂回去。所有的复杂性都被推到了循环的外围。

如果你读过我之前写的《从 0 到 1 打造一个 Agent 系统》，那篇是鸟瞰整个架构的全景图，从主循环一路讲到多 Agent 协作、安全边界、可观测性。这篇是把最底下那一层放到显微镜下，看清了从文字到行动的每一步到底发生了什么。

两个视角合在一起，agent 对你来说就不再有任何神秘感了。

它就是一个循环，加上围绕这个循环的一圈基础设施。理解了这一点，你就理解了所有 agent 框架的底层逻辑。剩下的，只是工程实现的细节。

我建了一个AI学习研究群，目前几十来人，都是在真正动手搞AI的人。如果你也在自己跑模型、写代码、做项目，欢迎点赞关注转发一键三连，然后加我微信，备注写清"你在做的AI方向"，聊得来的话我拉你进群。纯围观的和小白就不加了，有一定门槛。

![](images/78767c/img_001.jpg)
