QVeris
MCP 与工具调用

函数调用 API:供应商对比

比较函数调用API的参数结构、调用ID、结果、严格模式、并行与流式支持,并规划适配和验证。

发布日期:2026年4月2日 · QVeris团队制作
Diagram of an AI model selecting a tool, validating and correcting structured arguments, executing a call and receiving a result.
工具调用校验流程示意:先检查结构化参数,无效输入返回修正,通过校验后执行工具并收集结果。

决策摘要

摘要

循环相同,线格式不同

三家都会声明工具、返回结构化调用、等待应用执行,再消费带关联标识的结果;差异在字段名与消息编排规则。

在系统边界统一

内部只保留一份工具契约,用轻量适配器翻译三家格式,不让供应商消息结构进入业务逻辑。

严格模式不等于安全

严格 Schema 只能改善参数形状。服务端仍需校验值、鉴权、控制副作用,并把工具输出视为不可信输入。

测试完整循环

不要只测一次成功调用,还要覆盖畸形参数、多工具、流式分片、超时、重试、重复副作用、结果顺序和模型恢复。

这份对比适合谁

如果你正在选择模型供应商、迁移现有 Agent,或建设跨模型编排层,这份指南适合你。默认你已经能够调用 API、定义 JSON Schema,并在可信后端执行工具。

前置:服务端工具执行器
前置:JSON Schema 校验
前置:密钥不进入 Prompt
前置:结构化日志与链路追踪

先定义一份统一工具契约

真正稳定的单元不是某家 Payload,而是供应商无关的工具定义、标准化调用与标准化结果。供应商调用 ID 单独保存,适配器才能重建正确的回传消息。

TypeScript · 内部契约
type ToolDefinition = {
  name: string;
  description: string;
  inputSchema: JsonSchema;
  sideEffect: "read" | "write";
};

type ToolCall = {
  provider: "openai" | "anthropic" | "google";
  providerCallId: string;
  name: string;
  arguments: unknown;
  raw: unknown;
};

type ToolResult = {
  providerCallId: string;
  ok: boolean;
  content: unknown;
  evidence?: { source: string; retrievedAt: string }[];
};

OpenAI、Anthropic 与 Google 协议对比

关注点OpenAIAnthropicGoogle Gemini
工具声明type: function 加函数 Schemaname、description 与 input_schematype: function 加 Interactions 中的 parameters
调用输出function_calltool_use 内容块function_call 步骤
关联键call_idtool_use_idcall_id;必要时保留签名与状态
结果回传function_call_output下一条用户消息中的 tool_resultfunction_result
严格 Schemastrict: true;要求严格对象结构支持 strict: true支持的 Schema 子集随 API 与模型而异
并行调用支持,也可禁用支持多个 tool_use 块,也可禁用支持并行调用与组合调用
有状态续接使用响应/会话状态,或发送先前消息项在下一条用户消息中发送结果块在 Interactions 中使用 previous_interaction_id

版本边界:Google 同时存在较新的 Interactions API 术语,以及旧版 generateContent 的 functionCall/functionResponse。每个适配器只选择一个接口面,并明确记录。

OpenAI 实现:用 call_id 关联结果

请求中发送函数工具。模型输出 function_call 后,解析参数、执行已授权工具,再用相同 call_id 回传 function_call_output。应有意识地配置 tool_choice,不要默认强制调用。

OpenAI Responses API · 简化示例
const first = await client.responses.create({
  model, input: userInput,
  tools: [{ type: "function", name: "get_quote", description,
    parameters: quoteSchema, strict: true }]
});

const call = first.output.find(x => x.type === "function_call");
const result = await executeSafely(call.name, JSON.parse(call.arguments));

const final = await client.responses.create({
  model, previous_response_id: first.id,
  input: [{ type: "function_call_output", call_id: call.call_id,
    output: JSON.stringify(result) }]
});

Anthropic 实现:保持 tool_use 消息顺序

Claude 会返回一个或多个 tool_use 块,通常伴随 stop_reason: tool_use。下一条 user 消息必须包含对应的 tool_result;结果块放在其他用户文字之前,执行失败用 is_error: true 标记。

Anthropic Messages API · 简化示例
const calls = response.content.filter(x => x.type === "tool_use");
const toolResults = await Promise.all(calls.map(async call => ({
  type: "tool_result",
  tool_use_id: call.id,
  content: JSON.stringify(await executeSafely(call.name, call.input))
})));

messages.push({ role: "assistant", content: response.content });
messages.push({ role: "user", content: toolResults });

Google 实现:保留状态与签名

在 Interactions API 中,函数调用是包含 id、name、arguments 的 step;回传引用该调用 ID 的 function_result。有状态模式使用 previous_interaction_id,无状态模式则必须完整重放历史 step,包括所需的思考签名元数据。

Google Interactions API · 简化示例
const call = interaction.outputs.find(x => x.type === "function_call");
const result = await executeSafely(call.name, call.arguments);

const next = await client.interactions.create({
  model,
  previous_interaction_id: interaction.id,
  input: [{ type: "function_result", call_id: call.id,
    result }]
});

构建轻量供应商适配器

每个适配器只负责四件事:序列化工具定义、提取调用、序列化结果、保留供应商状态。校验、授权、执行、重试和证据应位于共享基础设施。

校验
授权
执行
关联结果
回答
供应商无关循环
const turn = await adapter.ask({ messages, tools: canonicalTools });
const calls = adapter.extractCalls(turn);

const results = [];
for (const call of calls) {
  const args = validate(call.name, call.arguments);
  await authorize(identity, call.name, args);
  results.push(await executeIdempotently(call, args));
}

const answer = await adapter.continue({
  state: turn.state,
  toolResults: results
});

能跨三家工作的 Schema 设计

  • 优先使用小型对象、明确属性和可预测的基础类型。
  • 枚举保持简短,并在描述里写清单位、格式、时区和默认值。
  • 统一层避免深度递归 Schema、模糊 union 与供应商私有扩展。
  • OpenAI 严格模式下,对象需要 additionalProperties: false 与 required 字段;可选值按需显式表达。
  • 解码后再次校验。符合 Schema 不代表股票代码存在、日期范围被允许,或转账已经授权。

工具选择、严格模式与并行调用

控制项适用场景生产注意
自动模型可以直接回答或调用工具。适合作为混合对话默认值。
必需或强制流程必须取得结构化数据。不要强制执行不可逆动作。
严格需要更稳定的参数形状。业务规则仍必须在服务端执行。
并行调用彼此独立且只读。依赖调用或有副作用调用要串行。

流式处理与多轮状态

绝不能从未完成的参数分片直接执行工具。先缓存 delta,等待供应商确认调用结束,再统一解码、校验,并在执行前持久化调用 ID。无状态续接时,所有供应商要求的消息项与不透明签名都要原样保留。

规则:只解析完整 JSON;只执行已持久化调用;每个已接受调用必须恰好返回一个结果。

安全、成本与延迟控制

校验与授权分开

Schema 校验回答“形状是否正确”,授权回答“这个身份能否对这个资源执行该动作”,两者缺一不可。

工具输出默认不可信

网页、文档和 API 文本可能包含间接 Prompt Injection。保留来源、限制返回字段,并把结果放在供应商指定的 tool-result 结构中。

写操作必须幂等

副作用前持久化确定性幂等键;重试应返回上次结果,而不是重复下单、发信、支付或写入。

为每一层设置预算

限制截止时间、单轮最大调用数、并发数、结果大小和 token;用户请求取消时同步终止下游工作。

常见失败模式与修复

现象常见原因修复
供应商拒绝下一轮消息结果 ID 缺失、错序或不匹配持久化原始调用,并统一由适配器生成结果消息
工具执行两次网络重试但没有幂等控制执行前去重并缓存结果
参数偶发解析失败解析未完成流片段或 Schema 含糊聚合完成后再解析,并简化、收紧 Schema
并行结果对应错误按数组位置匹配只按供应商调用 ID 匹配
模型执行了结果中的恶意文本间接 Prompt Injection最小化、标记、净化并策略检查不可信内容

供应商无关的验证基准

不要用少量 Prompt 得出一个笼统“准确率”。应对每家供应商运行同一份版本化测试集,并按失败类型分别报告。

选择:该调用时调用,不该调用时不调用
参数:Schema 与语义都有效
关联:每个调用拿到正确结果
恢复:超时、报错、空结果与重试
安全:未授权与注入请求被阻止
运维:p50/p95 延迟、成本、调用次数

跨供应商迁移清单

  1. 冻结统一工具注册表,并为每个 Schema 建立版本。
  2. 映射工具字段、选择控制、调用 ID、结果信封和会话状态。
  3. 翻译前移除目标接口不支持的 Schema 特性。
  4. 以无副作用影子模式回放生产链路。
  5. 比较工具选择、参数有效性、恢复、延迟和成本。
  6. 先灰度只读工具;幂等与授权测试通过后再开放写工具。

QVeris 实现模式

供应商原生 Function Calling 管理模型侧消息循环;MCP 可以标准化客户端发现和调用工具服务器的方式;QVeris 位于能力层,帮助 Agent 发现、检查、路由、调用并审计真实世界工具与数据,而供应商适配器继续保持 OpenAI、Anthropic 或 Google 所要求的协议。

发现

在 Prompt 暴露工具前,先找到能力并检查契约。

调用

把已校验参数路由到选定服务商或数据源。

证据

随结果返回来源、检索时间、单位和校验状态。

常见问题

函数调用和工具调用是一回事吗?

通常是。名称不同,但应用循环等价:描述工具、接收结构化调用、在模型外执行,再回传带关联标识的结果。

哪家函数调用 API 最好?

没有通用答案。应针对实际模型与负载测试 Schema、流式处理、并行行为、恢复、可观测性、成本和迁移难度。

函数调用会直接执行代码吗?

不会。模型只提出调用,应用负责校验、授权、执行和回传。

严格模式应该一直开启吗?

支持时可以开启,但服务端仍需校验。严格模式不会授予权限,也不保证业务语义正确。

并行工具调用怎么处理?

先收集全部调用,只并发彼此独立的任务,并按原始调用 ID 关联每个结果。

如何避免重复副作用?

执行前根据会话、调用 ID、工具名和标准化参数生成并持久化幂等键。

MCP 会替代供应商函数调用吗?

不会。MCP 标准化客户端与工具服务器交互,供应商 API 仍规定模型侧调用与结果消息。

QVeris 增加了什么?

QVeris 为真实世界能力补充发现、检查、路由和证据,适配器则管理供应商原生消息。

官方资料

函数调用 API:供应商对比 | QVeris Guides