[AI/LLM/Agent/工具调用] Function Calling(函数调用):让大模型"动手干活"的【标准化工具调用机制】
0 序
Function Calling的定位:
AI Agent的四大组件(系统能力): 规划、工具调用、记忆、反思;而Function Calling作为 【工具调用】能力最底层的标准化机制。
- 作为大模型 API 提供的一种"契约"——你定义工具,模型决定何时调用并输出结构化参数,你的代码负责真正执行。它是从"聊天机器人"走向"AI Agent"的基石能力。
1 概述
1.1 概念介绍
-
Function Calling(函数调用,简称 FC,也叫 Tool Calling / Tool Use)是大型语言模型(LLM)与外部系统交互的一种标准化机制:
-
开发者把可调用的函数清单(名称、用途说明、参数结构 JSON Schema)通过 API 传给模型;
-
模型在推理时判断:当前用户请求是否需要调用某个工具?如果需要,就不直接输出自然语言答案,而是输出一个结构化请求:
{"name": "get_weather", "arguments": {"city": "北京"}}; -
真正执行函数的是你的代码(查数据库、调 HTTP 接口、发邮件等),执行结果再回传给模型;
-
模型基于工具返回的结果,生成最终的自然语言回答。
-
-
关键认知:大模型本身永远不会直接执行任何操作,它只是一个"会说话的调度器",负责决策和格式化参数,执行权始终在开发者的应用代码里。
官方定义(OpenAI):"函数调用或工具调用,指的是模型在检查提示词后,判定为了执行指令而需要调用我们所提供的某个工具时,所发出的特殊类型响应。"[1]
1.2 诞生的背景与解决的核心问题
-
背景:传统 LLM 只会"说",不会"做"——它无法访问实时数据(天气、行情、数据库)、无法操作系统(发邮件、下单、写文件)、无法执行动作(控制设备、运行代码),训练数据也有截止时间。
-
解决的核心问题:让大模型突破"纯文本生成"的边界,与外部世界(实时数据源、业务系统、API、文件系统)建立受控、结构化、可执行的连接。没有 Function Calling 之前,开发者只能用"让模型按特定文本格式输出 → 正则表达式解析"的土办法(ReAct 风格),格式不稳定、解析痛苦。
1.3 发展历程 (必读)
| 时间 | 里程碑 |
|---|---|
| 2023 年初 | Prompt 时代:工具调用靠提示词工程 + ReAct 文本协议(Thought/Action/Observation),用正则解析,格式极易出错,被戏称"每天 debug JSON 五小时"[2] |
| 2023-06-13 | 里程碑:OpenAI 在 gpt-3.5-turbo-0613 / gpt-4-0613 中【首次正式发布】 Function Calling,引入 functions 参数与 function_call 返回字段,首次把工具调用做成 API 一等公民[3] |
| 2023-11 | OpenAI DevDay 升级为 tools / tool_calls 参数,支持并行调用,旧字段保留兼容[2][4] |
| 2023-2024 | 【全行业跟进】:Anthropic(Claude)、Google(Gemini)、Meta(Llama)、国内 Qwen / DeepSeek / GLM / Kimi 等均推出对应能力,OpenAI 兼容协议成为事实标准 |
| 2024-08 | OpenAI 推出 Structured Outputs / strict 模式,用约束解码保证函数调用严格符合 JSON Schema[5] |
| 2024-11 | 里程碑:Anthropic 开源 MCP(Model Context Protocol),解决"每个应用都要重写一遍工具"的复用问题,工具生态进入协议化阶段[2] |
| 2025-至今 | MCP 规范持续演进(Streamable HTTP、OAuth 2.1 鉴权);Structured Outputs / xgrammar 等约束解码成为默认能力;各厂商推出托管 Agent 平台,Function Calling 被封装为"注册工具 + 写提示词" |
- 演进三阶段:Prompt 工程(正则解析,格式不稳)→ 模型专训(SFT 加入工具调用语料,仍有幻觉字段)→ 约束解码(解码时强制满足 JSON Schema,格式有硬保证)[2]。
1.4 核心优势 (必读)
- 稳定性:结构化 JSON 输出(尤其
strict模式),替代脆弱的文本协议 + 正则解析; - 可执行性:模型只决策、代码来执行,天然支持鉴权、权限控制、审计,安全边界清晰;
- 实时性:让模型访问训练数据之外的最新信息(天气、行情、数据库);
- 可组合:支持多轮调用、并行调用、工具链串联,是构建 Agent 的地基;
- 生态成熟:OpenAI 兼容协议被几乎所有主流模型支持,一份代码可切换多家。
1.5 主要短板与局限性 (必读)
- 幻觉与误调用:模型可能漏参、填错参数、在不该调用时触发(误触发)或该调用时跳过(漏调用);
- Token 成本:工具定义(schema)会注入到上下文并计入输入 token,工具多则成本高;
- 上下文压力:多轮
Agentic Loop会把每次的工具结果都加入对话历史,【长任务】容易撑爆上下文; - 安全风险:工具结果可能被注入恶意指令(prompt injection / 工具污染),模型可能被诱导调用危险工具;
- 各家协议不统一:OpenAI、Claude、Gemini 的字段名和消息格式有差异,跨平台切换需要适配。
1.6 适用场景 (必读)
- 实时信息查询:天气、股票行情、新闻、数据库检索;
- 业务操作:下单、订票、发邮件、创建工单;
- 代码与文件操作:运行代码沙箱、读写文件、数据转换;
- 智能助手/客服:结合企业知识库与业务系统回答并代办;
- Agent 工作流:多步骤、多工具串联的自动化任务;
- 结构化数据提取:强制输出指定 JSON 结构(配合
tool_choice: required)。
1.7 相关概念辨析(最易混淆) (必读)
| 概念 | 定义 | 与 Function Calling 的关系 |
|---|---|---|
| Function Calling | 【模型】发出结构化【调用请求】的机制 | 本体,管"工具怎么调给模型" |
| Tool / Tool Use | 实际可被调用的能力(自定义函数或厂商内置工具),Tool Use 是更广义的叫法 | Tool 是 FC 的调用对象;Anthropic 一直叫 Tool UseLLM --(Tool Use)--> 应用 --(Tool Call)--> Tool |
| MCP | 连接、发现、调用工具的一套开放协议(Anthropic 2024-11 开源) | MCP 管"工具从哪来",最终仍会转成 function call 给模型[2] |
| Skill | 把指令、脚本、资料、流程打包并按需加载的能力包 | 比工具更高层,内部常借助 FC 实现 |
| Structured Outputs | 强制模型输出符合指定 JSON Schema 的格式约束 | 同源的约束能力;无副作用场景用 SO,有副作用场景用 FC[6] |
| ReAct | 让模型"思考-行动-观察"循环的推理框架 | FC 出现前用文本协议实现;FC 是其更稳定的实现载体 |
| Agent | 能自主规划、调用工具、多轮完成任务的应用 | FC 是 Agent 的核心能力之一,没有 FC 的 Agent 是空谈 |
总结:MCP 管"工具从哪来",Function Calling 管"工具怎么调给模型",你的应用代码管"工具谁来执行"。
1.8 主流模型支持情况(2026 年现状)
- 接口协议对比(初级开发者在切换平台时最容易踩坑):
| 维度 | OpenAI / 国内兼容模型 | Anthropic Claude | Google Gemini |
|---|---|---|---|
| 工具注册字段 | tools[].function + parameters |
tools[].input_schema |
tools[].functionDeclarations + .parameters |
| 调用返回位置 | message.tool_calls[] |
content[].type="tool_use" |
candidates[].content.parts[].functionCall |
| 停止信号 | finish_reason: "tool_calls" |
stop_reason: "tool_use" |
finishReason |
| 工具结果回传 | role: "tool" |
role: "user" 包裹 tool_result |
functionResponse part |
| 并行调用 | ✅ | ✅ | ✅ |
| strict 模式 | ✅ strict: true |
✅ strict: true |
— |
-
国内生态:阿里云百炼(DashScope)确认千问(Qwen)、DeepSeek、GLM、Kimi、MiniMax 等文本生成模型均支持 Function Calling[7];字节豆包(Doubao Seed 2.0 Pro)在 τ-bench 工具调用基准上表现领先(约 90.4%)[8];DeepSeek 提供 OpenAI 兼容接口并支持 strict 模式(Beta)[6]。
-
开源可本地部署:Qwen、GLM、DeepSeek、Llama 等开源模型均支持工具调用,适合数据不出境/私有化场景。
1.9 发展趋势
- 协议即生态:MCP 正在走 LSP 当年走过的路,工具生态从"应用内绑定"走向"协议内流通"[2];
- 解码即合约:Structured Outputs + xgrammar 等硬约束会成为 API 默认能力,"让模型填对 schema"不再是提示词工程问题[2];
- Agent 即 Runtime:工具循环、状态机、观测性、权限被封装进托管 Agent 平台(OpenAI Agents Platform、Anthropic Agents、阿里 PAI、字节方舟),开发者只需"注册工具 + 写提示"[2];
- 安全左移:工具污染、间接注入、confused deputy 等安全问题被前置到开发流程[2]。
2 工作原理与架构
2.1 概念术语
| 术语 | 含义 |
|---|---|
| Schema(工具定义) | 用 JSON Schema 描述工具的名称、用途、参数结构 |
| tools 参数 | 请求中传给模型的工具清单(数组) |
| tool_choice | 控制模型调用策略:auto(自主)/ required(必须调用)/ none(禁止)/ 指定某函数 |
| tool_calls | 模型返回的调用请求(含 name + arguments) |
| tool_result | 你的代码执行后回传给模型的结果 |
| Agentic Loop | 应用驱动的 while 循环:反复"模型请求工具 → 代码执行 → 结果回传",直到模型给出最终答案 |
| strict 模式 | 约束解码保证函数调用严格符合 Schema |
| 并行调用 | 一次响应中模型调用多个独立工具 |
| 客户端工具 / 服务端工具 | 前者由你的代码执行;后者由模型厂商托管执行(如 Anthropic 的 web_search、code_execution)[6] |
2.2 核心原理:三方契约
Function Calling 的本质是三方契约[6]:
你定义工具 Schema(名称 + 描述 + 参数类型)
↓
模型决定何时调用 + 输出结构化请求(不执行!)
↓
你的代码执行并返回结果
↓
模型基于结果生成最终回答
- 模型 = 决策器:判断"该不该调用、调哪个、参数填什么";
- 代码 = 执行器:真正跑函数,掌握数据和副作用;
- Schema = 契约:让两方用统一的结构化语言对话。
2.3 工作流程(Agentic Loop)(必读)
- 完整的多轮工具调用循环如下(理解 FC 的核心):
- 规范化的循环判定(以 Claude 为例)[6]:
| stop_reason | 含义 | 你要做的 |
|---|---|---|
tool_use |
模型要调用工具 | 执行工具 → 回传结果 → 继续循环 |
end_turn |
模型给出最终答案 | 读取 content,循环结束 |
max_tokens |
输出 token 超限 | 按需截断处理 |
refusal |
模型拒绝继续 | 检查内容策略 |
总结:while stop_reason == tool_use: 执行工具、回传结果;直到模型返回最终答案。
2.4 关键技术点
- 工具定义的 Token 成本:函数定义会被注入到系统消息中,计入输入 token[1]。所以工具数量要克制、description 要精简;
- strict 模式要求:开启时要求
additionalProperties: false且所有字段标required,否则请求会被拒绝[1]; - 并行调用:一次可返回多个
tool_calls,需按index分别执行并逐个回传结果[1]; - 流式工具调用:arguments 会按
index分段到达,需自行拼接 JSON,等finish_reason后再真正发起工具调用[2]; - 服务端工具:部分厂商提供托管执行的工具(搜索、代码执行、网页抓取),无需自己维护环境[6]。
3 使用指南
3.1 环境准备
-
Python 3.8+,安装
openai库(国内模型如 DeepSeek/豆包等也大多提供 OpenAI 兼容接口,改base_url即可):pip install openai
-
注册对应模型服务商账号并获取 API Key(OpenAI / DeepSeek / 火山引擎豆包 / 阿里云百炼等)
3.2 最小可运行示例(OpenAI 兼容协议,Python)(必读)
以 DeepSeek 官方接口为例(国内直连;换其他 OpenAI 兼容服务只需改 base_url 和 model):
import json
from openai import OpenAI
client = OpenAI(api_key="你的KEY", base_url="https://api.deepseek.com/v1")
# ── 1. 定义工具(Schema)──
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "获取指定城市的当前天气。仅在用户明确询问天气时调用。",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "城市名,如'北京'"}
},
"required": ["city"],
"additionalProperties": False
},
"strict": True
}
}]
# ── 2. 真正的函数(由你的代码执行)──
def get_weather(city: str) -> str:
# 真实场景这里调用天气 API
return json.dumps({"city": city, "temp": 22, "condition": "晴"})
# ── 3. Agentic Loop ──
messages = [{"role": "user", "content": "北京今天天气怎么样?"}]
for _ in range(5): # 设置最大轮数,防止死循环
resp = client.chat.completions.create(
model="deepseek-chat",
messages=messages,
tools=tools,
tool_choice="auto"
)
msg = resp.choices[0].message
if not msg.tool_calls: # 模型直接给出最终回答
print("回答:", msg.content)
break
# ── 4. 执行模型请求的每个工具并回传结果 ──
messages.append(msg) # 先把模型的 tool_calls 加入历史
for tc in msg.tool_calls:
args = json.loads(tc.function.arguments)
result = get_weather(args["city"])
messages.append({
"role": "tool",
"tool_call_id": tc.id,
"content": result
})
- 运行逻辑:模型判断"需要调用 get_weather" → 返回 tool_calls → 你的代码执行 → 结果回传 → 模型生成最终回答"北京今天 22℃,晴"。
3.3 关键操作要点(最佳实践)(必读)
- description 写清楚"何时调用、何时不调用":这是模型判断的唯一依据,写得好坏直接影响调用成功率[6];
- 少即是多:单轮可用工具尽量 < 20 个,工具多准确率下降、token 成本上升[1];
- 把已确定的参数用代码传:不要让模型填你已经知道的参数(如 order_id),减少出错面[1];
- 默认开启 strict 模式:生产环境强烈建议
strict: true,保证格式合规[1][6]; - 工具报错要回传错误信息:把错误包装成 tool_result 回传,让模型决定重试还是换策略,而不是中断循环[6];
- 设置最大循环轮数 + 超时:防止多轮调用死循环;
- 做工具链路可观测:记录每次 tool_call 的名称、参数、耗时、状态,用于排查和账单归因[2]。
3.4 补充建议
- 先跑通上面的最小示例,理解"模型不执行、代码执行"这个核心心智;
- 上手
tool_choice的四种取值,理解调用控制; - 学习 strict 模式与 Structured Outputs 的区别;
- 练习多工具 + 并行调用场景;
- 再进阶到 ReAct/Agent 框架(如 LangChain/LlamaIndex)和 MCP 协议;
- 最后关注安全:工具白名单、结果注入防护、权限最小化。
Z FAQ for Function Calling
Q1:Function Calling 和普通 API 调用有什么区别?(必读)
- 普通 API 是"人/程序直接调用接口";FC 是"模型替你决定调哪个接口、传什么参数,再由你的代码执行"。
- 普通API:【开发者/程序】是决策者
- FC:【模型】是决策者,不是执行者。
Q2:模型会真的"执行"我的函数吗?(必读)
不会。模型只输出结构化的调用意图(函数名 + JSON 参数),真正执行一定发生在你的应用代码里。这是设计使然——保证权限、审计和安全可控。
Q3:Function Calling 和 MCP 是同一个东西吗?(必读)
不是。
- FC 是"模型 ↔ 工具"的调用机制(应用内);
- MCP 是"跨应用复用工具"的开放协议(应用间)。
- MCP 的 server 最终仍会以 function call 形式把工具暴露给模型。
Q4:工具调用会消耗多少 token?为什么账单变贵了?
工具定义(tools 数组)、tool_use 块、tool_result 块都计入输入 token。降本手段:精简 description、减少一次暴露的工具数量、复用工具定义、开启 prompt caching[6]。
Q5:为什么模型老是漏参或填错参数?(必读)
常见原因:description 写得不清楚、参数没有 enum 约束、没有开 strict 模式、工具数量太多。逐项排查即可。
Q6:工具执行出错(如数据库超时)怎么办?
不要把错误吞掉或直接中断,把错误信息作为 tool_result 回传给模型,让它重试或换策略[6]。
Q7:什么时候该用 Structured Outputs 而不是 Function Calling?(必读)
- 无副作用、只想强制输出某个 JSON 结构(如信息抽取)→ 用 Structured Outputs;
- 需要触发外部操作(API 调用、写库)→ 用 Function Calling[6]。
Q8:OpenAI、Claude、国内模型能一套代码通用吗?
大部分国内模型和 OpenAI 兼容,改 base_url + model 即可;Claude 的字段名(input_schema、tool_result、stop_reason)不同,需单独适配。
Y 推荐文献
X 参考文献
- OpenAI Function calling 官方文档
- Function Calling 完整指南(2026):原理、代码示例、主流模型对比与最佳实践 - 博客园/七牛云
- Function Calling 完整指南(2026) - SegmentFault
- 大模型基础设施工程:工具调用与 MCP - 土法炼钢兴趣小组
- Function calling and other API updates - OpenAI(2023-06-13)
- 一文搞懂 Function Calling、MCP、Tool、Skill - 掘金
- OpenAI 函数调用完全指南 - CSDN
- 大模型 Function Call - CSDN
- 来自 OpenAI 官网的 Function calling 介绍与最佳实践 - 博客园
- Function Calling(火山引擎开发者社区)
- 主流大模型 API 调用方式对比 - CSDN
- Function Calling(阿里云 Model Studio)
- Best LLMs for Function Calling (2026) - LLM Reference
- Function Calling 进化路:源起篇 - CSDN
浙公网安备 33010602011771号