AI Agent · Function Calling

2026 Function Calling 是什么?OpenAI、Gemini、Claude 如何用 JSON 调用 API 与外部工具

2026.08.18 · 约 12 分钟阅读

Function Calling 的分水岭不是「哪家模型更聪明」,而是谁输出 JSON、谁执行副作用。下文拆协议、三家 JSON 形态与运行时边界,并给出可带走的选型矩阵与 7 步清单。

开发者工作台上的 JSON 编辑器与接线工具,象征 Function Calling 把模型接到外部 API

Function Calling(也叫 tool calling / 工具调用)在 2026 年已经从「演示技巧」变成 Agent 产品的默认协议:模型不再用散文假装调用接口,而是在约定 schema 下吐出 JSON,由你的代码去真正请求天气、查库、改文件或跑测试。真正差异不在模型谁更会聊天,而在schema 是否可校验、执行是否可审计、副作用是否可隔离

3
厂商 JSON 方言
1
共同循环:请求→执行→回填
MCP
工具发现与传输层

为什么纯文本 prompt 不够(Why)

早期做法是让模型输出「请调用 get_weather(city=北京)」,再用正则去抠。这在 demo 里能过,上线后会遇到三类硬伤:

  1. 解析不稳定——模型加礼貌用语、换参数顺序、漏引号,下游 JSON.parse 直接炸。
  2. 无法约束类型——该传枚举却传自由文本;该必填却省略;并行调用时分不清哪次对应哪次。
  3. 副作用与对话混写——模型「声称已经删除了文件」,其实你从未执行;或反过来,你执行了但模型不知道结果。

Function Calling 把「决策」留给模型、「执行」留给运行时:模型只选择工具与参数,HTTP、数据库、shell 永远不在模型进程里发生。这和 CI「一 job 一 workspace」同一思想——执行边界先于聪明程度。工具一旦能改磁盘,就要配 Agent 文件系统沙箱;一旦要跨会话记住用户偏好,就要把状态放到 独立 Memory 层,而不是塞进下一次 tool arguments。

Function Calling 三层分类(What)

不要把「接了 OpenAI tools」当成架构。至少拆三层:

层级职责典型载体谁拥有
L1 Schema工具名、JSON Schema、描述、必填字段OpenAI tools[].function、Gemini functionDeclarations、Claude input_schema产品 / 平台团队
L2 Runtime校验参数、注入密钥、超时、重试、审计自研 Agent loop、LangGraph、Claude Code你的后端或本机 Agent
L3 Transport如何发现与连接工具进程直连 HTTP、MCP stdio/SSE、内部 RPC基础设施

非对称结论:厂商 API 只标准化了 L1 的「JSON 信封」;L2 的权限与 L3 的进程隔离,三家都不替你做完。MCP 解决的是 L3 发现与会话,不是「自动安全」。

完整循环如下。注意箭头方向:模型从不持有你的 API Key,密钥只存在 Runtime。

┌──────────────┐     JSON tool request      ┌──────────────────┐
│  LLM API     │  ────────────────────────► │  Your runtime    │
│  (OpenAI /   │     name + arguments       │  (Agent loop)    │
│   Gemini /   │                            │                  │
│   Claude)    │  ◄──────────────────────── │  execute tool    │
└──────────────┘     tool result JSON       │  • HTTP APIs     │
                                            │  • DB / search   │
                                            │  • shell / MCP   │
                                            └────────┬─────────┘
                                                     │
                                                     ▼
                                            ┌──────────────────┐
                                            │ Policy + secrets │
                                            │ allowlist, audit │
                                            │ Cloud Mac / VPC  │
                                            └──────────────────┘

核心对比:OpenAI vs Gemini vs Claude

工具入口执行能力上下文适合人群
OpenAI toolsChat Completions / Responses API由你执行;arguments 常为 JSON 字符串并行 tool_calls[];可选 strict schema已有 OpenAI SDK、网关统一成 OpenAI 形态
Gemini functionDeclarationsGemini API / Vertex由你执行;可 toolConfig.mode 强制/禁止调用Schema 类型名常用大写 OBJECT/STRINGGCP 栈、需要 mode 开关的产品
Claude tool_useMessages API / Claude Code由你执行;input 已是对象而非字符串content 块:tool_use / tool_resultAnthropic 栈、IDE Agent、MCP 生态
MCP 工具客户端连 MCP ServerServer 进程内执行;模型仍只出 JSON工具列表运行时发现本地/远程工具目录要热插拔

真正分水岭不是「谁支持 Function Calling」(2026 年三家都支持),而是参数是字符串还是对象、并行调用怎么对齐、以及失败结果如何写回。网关层(OpenRouter / 自建)通常把三家归一成内部 ToolCall{name, id, args},再分发到同一 L2 Runtime。

三家 JSON 怎么写(How)

下面用同一个 get_weather 工具对照。生产环境请把 description 写清边界(「只查公开气象,不查个人位置」),避免模型把不该暴露的字段塞进参数。

OpenAI:tools + tool_calls

请求侧把工具挂在 tools。模型若决定调用,助手消息带 tool_callsarguments字符串化的 JSON,你必须先 parse 再校验。

{
  "model": "gpt-4.1",
  "messages": [{"role": "user", "content": "What's the weather in Beijing?"}],
  "tools": [{
    "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Current weather for a city",
      "parameters": {
        "type": "object",
        "properties": {
          "city": {"type": "string", "description": "City name"},
          "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
        },
        "required": ["city"]
      }
    }
  }]
}

模型返回形态(简化):

{
  "role": "assistant",
  "tool_calls": [{
    "id": "call_abc123",
    "type": "function",
    "function": {
      "name": "get_weather",
      "arguments": "{\"city\":\"Beijing\",\"unit\":\"celsius\"}"
    }
  }]
}

执行后,你再发一条 role: tool(或 Responses API 等价字段),tool_call_id 对齐,content 放结果字符串。然后模型用自然语言或再一次 tool_call 继续。

Gemini:functionDeclarations + toolConfig

Gemini 把声明放在 tools[].functionDeclarations。类型字段习惯用大写。用 toolConfig.functionCallingConfig.mode 可设 AUTOANY(必须调工具)或 NONE(禁止调工具)——这是产品开关,不是安全沙箱。

{
  "contents": [{"role": "user", "parts": [{"text": "What's the weather in Beijing?"}]}],
  "tools": [{
    "functionDeclarations": [{
      "name": "get_weather",
      "description": "Current weather for a city",
      "parameters": {
        "type": "OBJECT",
        "properties": {
          "city": {"type": "STRING"},
          "unit": {"type": "STRING", "enum": ["celsius", "fahrenheit"]}
        },
        "required": ["city"]
      }
    }]
  }],
  "toolConfig": {"functionCallingConfig": {"mode": "AUTO"}}
}

模型侧常见 functionCall part(name + args 对象)。你执行后回 functionResponse part。不要假设字段名与 OpenAI 完全一致,SDK 版本之间也有 Chat vs Gemini 原生差异。

Claude:tools + tool_use / tool_result

Claude Messages API 的工具用 input_schema(JSON Schema)。助手回复是 content 块数组:可能先有一段 text,再跟 tool_useinput 已经是对象,少一次 parse,但仍要做 schema 校验——模型仍可能漏字段。

{
  "model": "claude-sonnet-4-6",
  "max_tokens": 1024,
  "tools": [{
    "name": "get_weather",
    "description": "Current weather for a city",
    "input_schema": {
      "type": "object",
      "properties": {
        "city": {"type": "string"},
        "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
      },
      "required": ["city"]
    }
  }],
  "messages": [{"role": "user", "content": "What's the weather in Beijing?"}]
}
{
  "role": "assistant",
  "content": [{
    "type": "tool_use",
    "id": "toolu_01XYZ",
    "name": "get_weather",
    "input": {"city": "Beijing", "unit": "celsius"}
  }]
}

把结果写回时,用 role: usertool_resulttool_use_id 必须一致:

{
  "role": "user",
  "content": [{
    "type": "tool_result",
    "tool_use_id": "toolu_01XYZ",
    "content": "{\"temp_c\": 28, \"condition\": \"clear\"}"
  }]
}

Claude Code / Cursor 等 IDE Agent 在此之上又加了 MCP:模型看到的仍是「一组带 JSON Schema 的工具」,只是进程通过 MCP 会话热插拔。协议变了,循环没变

场景怎么选(决策矩阵)

如果你是…就选原因
已有 OpenAI 兼容网关统一成 OpenAI tools 方言生态最大;下游 adapter 一次写成
主栈在 GCP / VertexGemini functionDeclarations + mode少一层翻译;mode 适合「这一轮必须调检索」
主力是 Claude Code / AnthropicClaude tools + MCPcontent 块与 IDE 工具目录一致
要同时接三家模型内部规范化 ToolCall + 每家 adapter不要让业务代码写三套 if-else
工具会改文件 / 跑命令远程 Mac 工作区 + 路径白名单JSON 再漂亮也挡不住错误 rm
只要只读 SaaS API无服务器函数 + 密钥托管无需整机;仍要做参数 allowlist

组合 A — 个人最快(半天)

  • 单模型:OpenAI 或 Claude,注册 1–3 个只读工具(搜索、天气、文档检索)。
  • 参数校验:用 JSON Schema 库拒绝额外字段;密钥放环境变量,永不进 prompt。
  • 日志:记录 tool, args_hash, latency, ok,不要把完整密钥或 PII 打进日志。

组合 B — 小团队生产(推荐)

  • 网关归一:对内 ToolCall;对外 adapter 到 OpenAI / Gemini / Claude。
  • L2 Policy:按工具分超时、并发、日限额;危险工具二次确认或仅在隔离节点运行。
  • 执行面:只读 API 用函数计算;写仓库 / 跑测试放到 Cloud Mac 会话,对齐 远程 Mac 自动化 的销毁纪律。
  • 记忆与工具参数分离:用户偏好走 Memory,不塞进每次 arguments

组合 C — 企业合规

  • 工具目录走审批;schema 变更打 PR。
  • MCP / 自定义 server 跑在无出网或受控 VPC;审计 JSONL 出工作区。
  • 禁止把 bash 做成万能工具而不带路径策略。

常见误区

  1. 以为模型会替你鉴权——Key 在 Runtime;模型只看到 schema 与历史结果。
  2. 把 OpenAI 的字符串 arguments 直接当对象用——先 parse,失败当模型错误重试或降级。
  3. description 写成「万能助手」——描述越泛,模型越爱乱调工具;写清何时不该调用。
  4. 忽略并行 tool_calls——两个调用共享可变状态会竞态;只读可并行,写入要串行或加锁。
  5. 把失败当无结果——应回传结构化 error,让模型改参数或换工具,而不是沉默。
  6. MCP = 安全——MCP 是传输与发现;root 设成家目录照样裸奔。

落地步骤(7 步 Action Plan)

  1. 列出工具清单——名称、副作用级别(只读 / 写入 / 不可逆)、超时、数据驻留。
  2. 写 JSON Schema——必填、enum、禁止 additionalProperties;description 写边界。
  3. 实现最小 loop——一次用户消息 → 可能的 tool_calls → 执行 → 回填 → 最终回答;先单工具。
  4. 加校验与密钥隔离——parse 失败、schema 失败、未知工具名一律拒绝并审计。
  5. 接第二家模型 adapter——证明内部 ToolCall 可映射 Claude content 块与 Gemini parts。
  6. 给写入类工具加沙箱——路径白名单或远程工作区;对照文件系统指南做 deny 测试。
  7. 观测 7 天——统计误调用率、平均 round-trip、并行冲突;把高频误调用改成更窄的 schema。

FAQ

Function Calling 和普通 JSON mode 有什么区别?

JSON mode / structured output 约束的是最终回复形状(例如抽出订单字段)。Function Calling 约束的是中间的工具请求,并且默认会进入多轮:执行后再生成。两者可组合,但解决的问题不同。

模型会不会直接访问我的数据库?

不会。除非你的 Runtime 把「任意 SQL」做成工具且未做权限。默认循环里模型只能提出符合 schema 的参数。

三家能不能共用一份 schema?

核心 JSON Schema 可以共用,再写成各家信封(OpenAI parameters、Gemini 大写 type、Claude input_schema)。枚举与必填要回归测试,因为各家对 strict 的实现不完全一样。

Claude Code 里的工具是 Function Calling 吗?

是同一类循环:模型产出结构化调用,宿主执行(含 MCP)。差别在工具目录由 IDE/MCP 动态提供,而不是你每次在 HTTP 请求里手写 tools 数组。

工具结果要不要进长期记忆?

原始 API 响通常太大且含瞬时数据。应摘要后写入 Memory,而不是把整段 tool_result 当永久状态。详见 帮助中心 与 Memory 选型文。

总结

2026 年谈 Function Calling,请把它当成带 schema 的 RPC:OpenAI、Gemini、Claude 只是三种 JSON 方言,共同语法是「模型提议、运行时执行、结果回填」。选型看你的模型网关与工具副作用;安全看 L2 校验与执行面隔离,而不是看哪家的营销名。

上线前自问:如果模型此刻发出 write_file,实际落盘的是哪台机器、哪个目录? 若答不上来,先别接写入类工具。只读 API 可以今天就接;改代码、跑测试,请放到可销毁的 Cloud Mac 节点,并先看清 套餐定价

延伸阅读

把工具执行放到隔离的 Cloud Mac 节点

天气查询可以在无服务器函数里跑;改仓库、跑测试、调内网 API 则需要可销毁的执行环境。远程 Mac 节点按会话隔离工作区,适合 Claude Code / Cursor / 自研 tool loop。

立即订购 · 查看定价

Function Calling

把工具执行放到隔离的 Cloud Mac 节点

M4 · Cloud Mac · isolated tool runtime

立即订购