Tool Calling 原理
flowchart LR
A["Tool Calling 原理"]
A --> B["分类:基础概念"]
A --> C["关键词:AI"]
A --> D["关键词:Tool Calling"]
A --> E["关键词:Function Calling"]
A --> F["关键词:MCP"]
模型本身只会处理上下文里的内容。它不能自己上网、不能自己查数据库、不能自己发邮件,也不能保证复杂计算永远正确。Tool Calling 的意义,就是让模型先提出“我要用哪个工具、传什么参数”,再由应用层真正执行。这个机制,是现代 Agent 的基础。 :contentReference[oaicite:0]{index=0}
这篇文章会讲什么
前面几篇文章讲了模型如何被训练、如何利用上下文、如何通过 Prompt 被稳定控制,也讲了 Embedding、向量数据库这些“检索层”的能力。但如果你想让 AI 应用真正接入现实世界,就一定会遇到一个关键问题:
模型怎么从“会说话”,变成“能做事”?
现实里的很多任务,单靠语言模型本身是做不完的。比如:
- 查询今天的天气、汇率、股价、新闻
- 读取企业数据库、知识库、工单系统
- 发邮件、建日历、创建 Jira Ticket
- 做可靠计算、执行代码、处理文件
- 调内部 API,触发真实业务动作
这些能力都不在模型参数里,而在外部系统里。Tool Calling 就是连接这两者的桥梁。OpenAI 官方把 function calling 直接定义为让模型与外部系统交互、访问训练数据之外数据的一种方式;Anthropic 的工具使用文档也是同一思路。 :contentReference[oaicite:1]{index=1}
这篇文章想解决的,就是下面这些问题:
- 为什么 LLM 天然需要工具
- OpenAI 的 Function Calling 和 Anthropic 的 Tool Use 本质上在做什么
- MCP 为什么会成为工具生态的重要协议
- 工具 schema 应该怎么设计
- 为什么 Tool Calling 最大的风险不在“模型会不会调”,而在“应用该不该执行”
- 如何把工具调用做成一个可控、安全、可审计的系统
如果说 Prompt 工程解决的是“如何让模型表达得更好”,那么 Tool Calling 解决的就是:
如何让模型把外部能力纳入推理闭环。
延伸阅读:
- OpenAI Function Calling Guide
- Anthropic Tool Use 文档
- MCP 官方文档
先说结论:Tool Calling 不是“模型执行工具”,而是“模型生成调用意图”
很多人第一次接触 Tool Calling,容易产生一个误解:
模型会不会直接去执行函数、访问数据库、发邮件?
标准答案是:不会。
在主流设计里,模型本身只负责输出一段结构化意图,例如:
- 要调用哪个工具
- 工具参数是什么
- 是否需要多个工具串联
真正执行工具的是应用层或代理层,不是模型本体。OpenAI 官方文档明确说明,function calling 的作用是让模型生成调用外部系统的结构化请求;执行和结果处理仍由你的应用负责。 :contentReference[oaicite:2]{index=2}
所以一个更准确的理解是:
Tool Calling = 模型负责“决定做什么”,应用负责“真的去做”。
这件事非常重要,因为它直接决定了安全边界:
- 模型输出不可信
- 工具执行必须校验
- 权限控制必须在应用层
- 高风险动作不能仅靠模型一句话就直接落地
理解了这个边界,后面很多设计问题就会变得清楚。
1. 为什么 LLM 需要工具
先看定义:因为 LLM 本质上是基于上下文生成文本的模型,它既无法天然访问外部世界,也无法天然保证执行能力和结果正确性,所以必须借助工具把外部数据和动作接进来。 :contentReference[oaicite:3]{index=3}
LLM 的三类天然短板
从系统能力角度看,语言模型至少有三类先天限制。
1. 知识有边界
模型的知识来自训练数据和当前上下文。
如果数据过期、缺失,或者是你企业内部从未出现在训练语料里的信息,模型就无法凭空知道。OpenAI 官方工具文档明确把“访问训练截止时间之外的数据”列为使用工具的典型原因之一。 :contentReference[oaicite:4]{index=4}
例如:
- 实时天气
- 最新汇率
- 今天的新闻
- 你公司 CRM 里的客户数据
- 某个用户刚刚下的订单
这些都需要工具去查。
2. 不能主动操作外部系统
模型本身不会真的修改数据库、发 Slack、发邮件、创建日历事件。
这些动作都必须通过外部程序或 API 完成。OpenAI 的 function calling 和 Anthropic 的 tool use 都是在为这类“外部动作委托”提供接口。 :contentReference[oaicite:5]{index=5}
3. 计算和执行不天然可靠
语言模型可以“像会算一样”回答很多问题,但在复杂计算、代码执行、严格逻辑校验上,可靠性并不等同于专门工具。
这也是为什么计算器、代码执行环境、数据库查询工具会成为 Agent 系统里的高频工具类型。MCP 官方文档也把 search engines、calculators、databases 直接列为典型外部系统。 :contentReference[oaicite:6]{index=6}
工具到底补上了什么
你可以把工具理解成一组“外接能力模块”。
| 模型的短板 | 工具补上的能力 |
|---|---|
| 不知道最新信息 | 搜索、数据库查询、API 查询 |
| 不能做真实动作 | 邮件、工单、支付、CRM、日历、内部 API |
| 计算不稳定 | 计算器、代码执行、SQL 引擎 |
| 不能直接处理某些系统 | 文件系统、文档平台、企业 SaaS、设备控制 |
所以 Tool Calling 的真正价值,不是“让模型更聪明”,而是:
让模型在需要时能借用外部系统的确定性能力。
工具让模型从“回答问题”走向“完成任务”
这也是为什么 Tool Calling 常常被视为 Agent 的基础。
没有工具时,模型更多是在:
- 解释
- 生成
- 总结
- 改写
- 推理
有了工具以后,模型可以进入另一种工作方式:
- 判断当前问题缺什么信息或能力
- 选择合适的工具
- 生成调用参数
- 读取结果
- 基于结果继续决策或回答
这个闭环,才让“Agent”成为可能。
2. Function Calling:OpenAI 的做法
先看定义:OpenAI 的 Function Calling,本质上是让模型基于你提供的 JSON Schema,输出结构化的工具调用请求;你的应用再负责执行工具,并把结果送回模型。OpenAI 官方文档也明确把 function calling 称为 tool calling。 :contentReference[oaicite:7]{index=7}
工作流程到底是什么
一个典型的 OpenAI function calling 流程,大致是这样:
1. 应用把可用工具定义传给模型
2. 用户提问
3. 模型判断是否需要调用工具
4. 如果需要,模型输出工具名和参数
5. 应用执行真实工具
6. 应用把结果作为新的上下文送回模型
7. 模型基于工具结果继续回答
OpenAI 文档明确说明:tools 通过请求里的 tools 参数提供给模型,模型会根据用户请求自动决定是否调用。 :contentReference[oaicite:8]{index=8}
一个具体例子:天气查询
比如你定义了一个工具:
- 名称:
get_weather - 参数:
city - 含义:根据城市获取实时天气
用户问:
北京今天天气怎么样?
模型不会直接编造天气,而是更合理地输出一个结构化调用意图,例如:
{
"name": "get_weather",
"arguments": {
"city": "北京"
}
}
然后:
- 你的应用去调用真实天气 API
- 拿到结果,例如“晴,25°C”
- 再把这个结果作为工具返回消息加回上下文
- 模型再生成面向用户的自然语言答案
所以要强调一遍:
模型不查天气;模型只决定“应该查天气”。
工具定义为什么通常是 JSON Schema
OpenAI 官方文档说明 function tools 是基于 JSON Schema 定义的,这样模型才能知道:
- 工具叫什么
- 每个参数是什么类型
- 哪些参数必填
- 可选值范围是什么
- 工具的描述是什么 :contentReference[oaicite:9]{index=9}
例如一个天气工具的 schema 可能是:
{
"name": "get_weather",
"description": "获取指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,如北京、上海"
}
},
"required": ["city"]
}
}
这和前面讲结构化输出时的 schema 思路是一致的:
它不是“提示模型随便调用”,而是在定义一个可执行接口契约。
Function Calling 的本质不是“函数”,而是“结构化动作选择”
虽然名字叫 function calling,但它不一定真对应你代码里某个 Python 函数。
它本质上更像:
- 一段动作名称
- 一份参数对象
- 一个由应用层映射到真实能力的执行协议
所以你完全可以把它背后的执行目标理解为:
- HTTP API
- SQL 查询
- gRPC 服务
- 消息队列任务
- 内部工作流动作
- 外部 SaaS 操作
函数只是最直观的抽象,不是唯一实现方式。
OpenAI 近两年的一个变化:工具不只是一种
OpenAI 现在的工具体系不只是“函数工具”一种,还包括内建工具,例如 file search、web search、computer use 等。官方工具文档已经把工具能力明确分成 built-in tools 与 function tools 两大类。 :contentReference[oaicite:10]{index=10}
这意味着:
- 有些工具由平台直接提供
- 有些工具由你自己定义 schema 和执行逻辑
- 在 Agent 设计里,两者可以共存
所以今天再讲 Tool Calling,最好理解成更广义的“工具接口层”,而不仅仅是“函数调用”。
3. Tool Use:Anthropic 的做法
先看定义:Anthropic 的 Tool Use 和 OpenAI 的 Function Calling 在原理上高度一致:模型输出结构化调用请求,应用执行工具,再把结果回填给模型。区别主要在 API 组织方式和消息格式。 :contentReference[oaicite:11]{index=11}
它们本质上解决的是同一个问题
无论叫:
- Function Calling
- Tool Calling
- Tool Use
底层逻辑都是同一个闭环:
模型决定调用
→ 应用执行
→ 结果回填
→ 模型继续处理
所以在设计系统时,不必把 OpenAI 和 Anthropic 看成两个完全不同的范式。
更实用的理解是:
厂商层面的区别,更多是接口格式不同;架构层面的原则,基本相同。
Anthropic 的“工具使用”更强调内容块结构
Anthropic 的工具调用接口通常不是把调用结果藏在一大段自由文本里,而是通过结构化的内容块来表达 tool use 和 tool result。
这意味着:
- 工具调用和普通自然语言消息更容易区分
- 多轮调用更适合放在统一消息流里
- 工具请求和结果更容易被程序解析和编排
虽然具体字段和 OpenAI 不同,但工程上你要做的事几乎一样:
- 定义工具
- 描述参数
- 接收模型的调用意图
- 执行工具
- 回填结果
不用纠结术语,重点看系统边界
很多初学者会在“Function Calling”和“Tool Use”的术语上花很多时间。
但对你搭系统来说,真正重要的不是名字,而是这几个边界是否清楚:
- 模型负责什么
- 应用负责什么
- 工具 schema 由谁定义
- 执行结果如何回填
- 高风险操作谁批准
只要这几件事清楚,换一家模型 API,本质架构不会大改。
4. MCP(Model Context Protocol):为什么它重要
先看定义:MCP 是一个开放标准,用统一协议描述工具、资源和交互方式,目标是减少“每接一个系统就重写一套集成”的碎片化成本。Anthropic 在 2024 年公开发布了 MCP;2026 年该项目已进入正式社区治理阶段,并被官方描述为多公司参与的开放标准。 :contentReference[oaicite:12]{index=12}
MCP 试图解决什么问题
在 MCP 之前,一个很常见的现实是:
- OpenAI 一套工具接法
- Anthropic 一套工具接法
- IDE 一套插件体系
- 每个内部系统又一套自定义 API 封装
- 每接一个新工具,都要写适配层和胶水代码
这会导致工具生态非常碎片化。
Anthropic 在发布 MCP 时,就把这个问题讲得很清楚:
AI 系统被困在数据孤岛和定制集成里,每接一个数据源都要单独开发。MCP 的目标就是用一个开放标准替代碎片化连接方式。 :contentReference[oaicite:13]{index=13}
MCP 到底是什么
MCP 官方文档把它定义为:
一个把 AI 应用连接到外部系统的数据源、工具和工作流的开放协议。 :contentReference[oaicite:14]{index=14}
你可以把它类比成 AI 世界里的“统一接口层”:
- MCP Client:你的 AI 应用或 Agent
- MCP Server:暴露工具、资源或上下文的服务端
- 协议层:统一消息、能力发现、调用方式
MCP 官方文档甚至直接用了一个非常形象的比喻:
MCP 像 AI 应用的 USB-C。 :contentReference[oaicite:15]{index=15}
MCP 不只是工具,还包括资源和提示资产
MCP 的意义不只是“调工具”。
它想统一抽象的范围更广,至少包括:
- Tools:可调用的动作或函数
- Resources:文件、数据库、文档等可读取内容
- Prompts / Workflows:可复用的提示或工作流资产
MCP 规范里有专门的 tools 章节,明确说明 MCP server 可以向语言模型暴露可调用工具,并且每个工具都有名字和 schema 元数据。 :contentReference[oaicite:16]{index=16}
这意味着 MCP 的目标不是把某一种厂商 API 标准化,而是更进一步:
把“AI 应用如何发现和接入外部能力”这件事协议化。
MCP 为什么在 2026 变得更重要
截至 2026 年,MCP 已经不只是一个“Anthropic 提出来的新东西”,而是进入了更正式的社区治理和多公司参与阶段。官方治理与 roadmap 页面都强调了 formal governance;Anthropic 也在 2025 年宣布把 MCP 相关项目捐赠给开放基金会体系。 :contentReference[oaicite:17]{index=17}
这意味着一个趋势正在形成:
- 工具不再只是某家模型厂商的私有生态
- “写一次,多个 AI 客户端可接入”正在成为现实目标
- Agent 工具层的标准化正在加速
所以即使你今天不直接实现 MCP,也最好理解它,因为它代表了未来工具生态的方向。
5. API 集成模式:工具背后其实就是“能力封装”
先看定义:从模型角度看,工具只是名字、描述和参数 schema;但从系统角度看,工具背后可能是 REST API、数据库查询、内部服务、工作流引擎甚至代码执行环境。
工具只是接口皮,真正重要的是后面的执行器
模型看到的通常只有:
namedescriptionparameters
但真实系统里,这个工具背后可能接的是非常不同的东西:
| 工具类型 | 典型后端实现 |
|---|---|
| 查询类工具 | REST API、GraphQL、数据库、搜索服务 |
| 动作类工具 | 邮件服务、工单系统、支付 API、内部 RPC |
| 计算类工具 | 计算器、Python 执行环境、SQL 引擎 |
| 文件类工具 | 文档系统、对象存储、文件服务 |
| 多模态工具 | 图像生成、语音合成、OCR、转录服务 |
所以设计工具时,最实用的思路不是“给模型几个函数”,而是:
把你的系统能力整理成一组最小、清晰、可授权的接口。
工具设计里最常见的两类错误
1. 工具过于底层
例如直接暴露一个通用 SQL 执行器、任意 HTTP 请求器、任意 shell 命令。
这在安全和可控性上都非常危险。
2. 工具过于宽泛
例如一个叫 do_business_action 的万能工具,里面塞十几个可选参数。
模型很难判断什么时候该用、参数怎么填,也很难调试。
更稳妥的原则是:
- 工具应该语义明确
- 参数应该尽量少且清楚
- 每个工具只做一类动作
- 高风险动作最好拆开,别混在一起
一个好工具更像“业务动作单元”
举例来说,相比暴露:
execute_sqlsend_http_requestcall_internal_service
更好的做法常常是暴露:
get_user_order_statuscreate_support_ticketsend_refund_confirmation_email
原因很简单:
- 模型更容易选对
- 参数更容易校验
- 权限更容易控制
- 审计更容易做
- 失败更容易处理
这也是 Tool Calling 从“技术接口”走向“Agent 工程”的关键一步。
6. 工具描述设计:为什么 schema 和 description 决定调用质量
先看定义:模型能否正确调用工具,很大程度上不取决于模型“够不够聪明”,而取决于你有没有把工具的用途、边界和参数描述清楚。OpenAI 官方文档明确建议工具要写清函数描述和 JSON Schema,Structured Outputs 也支持更严格的 schema 约束。 :contentReference[oaicite:18]{index=18}
模型其实是在“读接口文档”
对模型来说,一个工具就是一小段文档:
- 这个工具是干什么的
- 什么时候该用
- 参数有哪些
- 参数是什么格式
- 输出大概是什么
所以工具描述写得差,模型就会像人类程序员看糟糕 API 文档一样:
- 不知道什么时候该调
- 不知道参数怎么填
- 不知道返回什么
- 不知道哪些情况不该用
好描述和坏描述的差别
坏描述
get_weather: 获取天气
问题在于:
- 不知道输入是什么
- 不知道是当前天气还是未来天气
- 不知道返回哪些字段
- 不知道城市名格式
- 不知道单位
好描述
get_weather: 获取指定城市的当前天气。输入城市名称,返回当前气温(摄氏度)、天气状况和简短体感描述。仅用于查询当前天气,不用于未来天气预报。
这段描述至少帮模型解决了:
- 什么时候该用
- 该传什么
- 会得到什么
- 不适用什么场景
参数 schema 最好足够严格
如果一个参数只允许固定选项,就用枚举。
如果一个字段必填,就明确 required。
如果日期有格式要求,就写清格式。
如果单位只能是摄氏度或华氏度,就不要让模型自由发挥。
OpenAI 的 Structured Outputs 指南明确把 JSON Schema 约束和 strict: true 当作提升可靠性的核心手段之一。 :contentReference[oaicite:19]{index=19}
所以一个很实用的原则是:
能靠 schema 约束的,就不要只靠自然语言提醒。
工具描述其实也是一种 Prompt 工程
你可以把工具 schema 看成 Prompt Engineering 的延伸。
因为你本质上还是在做同一件事:
- 减少模型猜测空间
- 明确输入和输出
- 限制错误自由度
- 提升调用稳定性
区别只在于,这次 Prompt 的对象不是“最终回答格式”,而是“工具调用格式”。
7. 安全考量:真正的风险不在模型“会不会调”,而在“调了以后要不要执行”
先看定义:模型输出的工具调用请求本质上是不可信输入。所有执行必须经过应用层校验、权限控制、参数约束、必要时人工确认。MCP 规范也专门定义了授权能力;OpenAI 和 Anthropic 的工具机制都默认由应用负责执行与安全边界。 :contentReference[oaicite:20]{index=20}
第一原则:模型输出不能直接信任
这是 Tool Calling 里最重要的一条安全原则。
因为模型可能会:
- 理解错用户意图
- 填错参数
- 选择错工具
- 生成不存在或越权的请求
- 被 prompt injection 诱导做危险动作
所以从系统角度看,模型生成的工具调用,本质上和用户输入一样,都应该被视为:
不可信请求。
主要风险有哪些
1. 越权访问
例如模型试图读取不属于当前用户的数据。
2. 参数注入
例如把恶意字符串塞进 SQL、命令、路径或模板参数里。
3. 高风险动作被误触发
例如发邮件、下单、退款、删数据、改配置。
4. 工具滥用
例如高频调用昂贵 API、无限循环调用、批量误操作。
5. 幻觉式调用
模型编出并不存在的工具名,或给出不符合 schema 的参数。
这些都不是理论风险,而是实际系统里很常见的问题。
最有效的防线都在应用层
一个稳妥的工具系统,通常至少需要这些防线:
参数校验
严格按 schema 验证字段、类型、枚举、范围、长度。
权限注入
不要让模型自己决定用户身份、租户范围、资源边界。
这些应由后端根据当前会话上下文强制注入。
最小权限
每个工具只暴露完成任务所需的最小动作面。
白名单执行
尤其是 SQL、shell、代码执行、文件操作类工具,必须限制允许的命令和资源。
预算和速率限制
防止模型被诱导连续调用昂贵工具。
高风险动作确认
发送邮件、付款、提交工单、删除数据等动作,很多场景下都应要求二次确认或人工批准。
代码执行类工具为什么特别危险
代码执行环境确实很强,因为它可以补上:
- 复杂计算
- 数据清洗
- 表格处理
- 文件转换
- 多工具编排
但它也天然高风险。
Anthropic 关于“code execution with MCP”的工程文章就特别强调,把工具交给代码环境可以降低上下文成本,但同时也意味着更需要良好的隔离和状态管理。 :contentReference[oaicite:21]{index=21}
所以代码执行工具通常必须:
- 跑在沙箱里
- 限制文件系统
- 限制网络
- 限制执行时间和资源
- 审计输入与输出
先看定义:
越通用的工具,越危险;越危险的工具,越不能完全放权给模型。
8. 实战闭环:一个天气 + 计算器 Agent 是怎么工作的
先看定义:最小可用的 Tool-Using Agent,至少包括五个部分:工具定义、模型调用、执行器、结果回填、循环控制。
一个最小系统长什么样
假设你有两个工具:
get_weather(city)calculator(expression)
用户问:
北京今天多少度?如果再加 10 度是多少?
一个典型执行流会是:
1. 把两个工具的 schema 传给模型
2. 模型先决定调用 get_weather(city="北京")
3. 应用执行天气 API,得到 25
4. 把结果作为 tool result 传回模型
5. 模型再决定调用 calculator(expression="25+10")
6. 应用执行计算器,得到 35
7. 把结果传回模型
8. 模型输出最终自然语言回答
这里最关键的不是“调用了两个工具”,而是:
模型在一个循环里,把工具结果当成新的上下文继续思考。
这正是 Agent loop 的雏形。
为什么需要循环,而不是一次调用结束
因为很多真实问题不是“一步到位”的。
模型经常需要:
- 先查一个信息
- 再根据结果决定第二个动作
- 可能再做一次转换或确认
- 最后再面向用户作答
这意味着工具调用系统通常不是:
问题 → 调一次工具 → 结束
而更像:
问题 → 判断 → 调工具 → 读结果 → 再判断 → 再调工具 → 总结
这也是为什么现代 Agent 框架通常都会有一个消息循环,而不仅仅是一次函数调用。
一个实用的系统分层方式
很多生产系统会把 Tool Calling 设计成四层:
1. Tool Registry
存放工具定义、schema、权限信息。
2. Planner / Model Layer
让模型决定该调用什么。
3. Executor
真正执行工具,处理异常、重试和权限。
4. Orchestrator
控制循环、消息拼接、结果回填、停止条件。
这样做的好处是:
- 工具和模型解耦
- 执行和决策解耦
- 安全校验集中化
- 更容易做日志和审计
9. 一个最好记住的原则:Tool Calling 让模型获得“接口感”,不是“直接控制权”
如果你只想记住一句话,那就是:
Tool Calling 的本质,不是让模型直接接管系统,而是让模型在推理中学会请求外部能力。
这句话的含义有两层:
第一层:能力扩展
模型可以借助外部系统补足知识、动作和计算能力。
第二层:边界保留
真正的执行权、权限判断和风险控制,仍然掌握在应用层。
这正是一个好 Agent 系统应有的平衡:
- 让模型负责高层决策和语言理解
- 让程序负责确定性执行和安全控制
理解这一点,你就不会把 Tool Calling 神化成“模型开始自己做事了”,而会更准确地看到:
模型是在一个被严格包裹的接口世界里,学习如何请求和组合能力。
核心概念速查
| 概念 | 一句话 |
|---|---|
| Tool Calling | 模型输出工具调用意图,应用执行工具并回填结果 :contentReference[oaicite:22]{index=22} |
| Function Calling | OpenAI 对工具调用的实现名称,基于 schema 定义函数工具 :contentReference[oaicite:23]{index=23} |
| Tool Use | Anthropic 的工具调用机制,本质与 function calling 类似 :contentReference[oaicite:24]{index=24} |
| Tool Schema | 描述工具名称、用途和参数结构的接口契约 :contentReference[oaicite:25]{index=25} |
| MCP | 连接 AI 应用与外部工具、资源、工作流的开放协议 :contentReference[oaicite:26]{index=26} |
| Tool Result Loop | 工具结果回填模型上下文,再继续决策的循环 |
| Least Privilege | 工具只暴露最小必要权限,避免越权和滥用 |
| Human-in-the-loop | 对高风险动作加入人工确认或审批的控制机制 |
下一篇
有了 Embedding、向量数据库、Tool Calling,你已经掌握了 AI 应用的三大基础能力:
能表示语义、能高效检索、能调用外部系统。
下一篇我们把这些能力真正拼成一个完整系统:
前端、后端、检索层、工具层、模型层、状态层分别负责什么,怎样才能搭出一套靠谱的 AI 应用系统架构。