Blog·Studio
文章系列日历归档关于搜索
Blog·Studio

一个记录思考、笔记与作品的技术博客。

Connect

© 2026 · Blog Studio

鄂ICP备19019526号

crafted with care

stay curious ✦

  1. 文章
  2. ›LLM 函数调用协议工程 2026:四类协议统一范式

Index

  • 一、问题的提出:函数调用为什么是 LLM 应用的核心契约
  • 二、形式化:四类函数调用协议的语义对齐矩阵
  • 三、Provider 协议差异:从 JSON Schema 子集到 tooluse block 结构
  • 四、统一的工具描述语言:ToolIR 中间表示设计
  • 五、协议适配器与双向语义保真
  • 六、并行调用、依赖图与控制流:Function Calling 的拓扑编排
  • 七、流式工具调用:partial JSON 解析与渐进式 UI 渲染
  • 八、安全纵深:从 prompt injection 到 schema validation 的多层防御
  • 九、给应用开发者的工程清单:Tool Gateway + SDK + Observability 三件套
  • 参考文献

LLM 函数调用协议工程 2026:四类协议统一范式

函数调用是 LLM 应用层最关键的结构化契约,但 OpenAI/Anthropic/Google/MCP 四类协议在 JSON Schema 子集、tool_use block 结构、并行语义、流式 partial 解析上仍有显著差异;本文以应用开发者视角给出 ToolIR 中间表示 + 协议适配器 + 流式解析器 + Tool Gateway 的完整工程范式,并给出 14 条可立刻落地的工程清单。

2026年9月12日·约 40 分钟阅读·11,946 字·1 次阅读·博主
#智能体与 AI 应用开发
LLM 函数调用协议工程 2026:四类协议统一范式

Index

  • 一、问题的提出:函数调用为什么是 LLM 应用的核心契约
  • 二、形式化:四类函数调用协议的语义对齐矩阵
  • 三、Provider 协议差异:从 JSON Schema 子集到 tooluse block 结构
  • 四、统一的工具描述语言:ToolIR 中间表示设计
  • 五、协议适配器与双向语义保真
  • 六、并行调用、依赖图与控制流:Function Calling 的拓扑编排
  • 七、流式工具调用:partial JSON 解析与渐进式 UI 渲染
  • 八、安全纵深:从 prompt injection 到 schema validation 的多层防御
  • 九、给应用开发者的工程清单:Tool Gateway + SDK + Observability 三件套
  • 参考文献

AI 应用的函数调用(Function Calling)标准化与协议工程 2026:从 OpenAI Tools 到 Anthropic MCP 的统一抽象层

一句话摘要:函数调用是 LLM 应用层最关键的结构化契约,但 OpenAI/Anthropic/Google/MCP 四类协议在 JSON Schema 子集、tool_use block 结构、并行语义、流式 partial 解析上仍有显著差异;本文以"应用开发者"视角给出 ToolIR 中间表示 + 协议适配器 + 流式解析器 + Tool Gateway 的完整工程范式,并给出 14 条可立刻落地的工程清单。

一、问题的提出:函数调用为什么是 LLM 应用的核心契约

2026 年是 LLM 应用从"Prompt Engineering + RAG"走向"Agent + Tools"的转折点。如果说 2024 年 RAG 工程定义了"应用层如何从知识库召回上下文",那么 2026 年函数调用(Function Calling)协议工程定义了"应用层如何让模型结构化地调用外部世界"。一条函数调用的准确率、一次工具调用链的并行度、一组多 provider 工具描述的语义保真度,已经成为 LLM 应用能否上线、能否规模化、能否多云部署的核心瓶颈。

但应用开发者面对的现实是:没有统一的协议。OpenAI 的 Tools API 用 tools[].function.{name,description,parameters} 的扁平 JSON Schema;Anthropic 的 Tool Use 把工具描述嵌入 system 或 user 消息后通过 tool_use block 返回;Google Gemini 的 Function Calling 同时支持"函数声明"与"代码执行"两种模式;MCP(Model Context Protocol)2025 年由 Anthropic 推出后已成为事实标准,但它的 resources / tools / prompts 三元组与上面三类 API 仍然存在字段命名、错误语义、协议握手的多重差异。一个 LLM 应用如果想支持"GPT-5 + Claude 4.5 + Gemini 2.5 + 本地 MCP server"四类后端,必须维护四套工具描述、四套响应解析器、四套流式协议适配——这就是 LLM 应用层的"协议碎片化"问题。

本文以"应用开发者"视角给出系统性的工程范式:ToolIR 中间表示 + 协议适配器 + 流式解析器 + Tool Gateway 四层架构,并用 14 条工程清单给出可立刻落地的设计决策。写作目标读者是 LLM 应用架构师、AI 平台工程师、以及负责多模型策略的技术负责人——你不需要从头实现这四层,但需要理解每一层的关键设计权衡,避免在应用层做出"短期省事、长期无法多云"的决策。

二、形式化:四类函数调用协议的语义对齐矩阵

我们把"函数调用协议"形式化为一个五元组 (M,T,C,R,S)(M, T, C, R, S)(M,T,C,R,S):MMM 是消息协议(message envelope),TTT 是工具描述(tool description schema),CCC 是调用请求(call request payload),RRR 是返回结果(return result envelope),SSS 是流式语义(streaming semantic)。下表给出 2026 年 9 月的实测对齐矩阵:

协议MMM 消息载体TTT 工具描述CCC 调用请求RRR 返回结构SSS 流式语义
OpenAI Tools (2024-08+)messages[] + tools[] 顶层JSON Schema 子集(不支持 oneOf/anyOf 的复杂组合)tool_calls[].function.{name,arguments} (string-encoded JSON)role=tool + tool_call_idSSE + tool_calls.delta 增量 arguments
Anthropic Tool Use (2024-10+)messages[] 含 tool_use / tool_result blockinput_schema (JSON Schema 完整支持)tool_use.id + tool_use.input (object)tool_result.tool_use_id + contentSSE + input_json_delta 增量 JSON
Google Gemini Function Callingcontents[] + tools[] 顶层OpenAPI 3.0 子集(parameters 用 JSON Schema)functionCall.{name,args}functionResponse.{name,response}SSE + partial function call args
MCP (Model Context Protocol 2025-03+)JSON-RPC 2.0 over stdio/SSE/HTTPJSON Schema 完整 + outputSchematools/call JSON-RPC methodcontent[] typed array (text/image/resource)SSE notifications + progress

关键观察:

  1. JSON Schema 子集差异:OpenAI 在 2024-08 之前严格不支持 oneOf/anyOf,现在部分支持但行为不一致;Anthropic 完整支持;Google 走 OpenAPI 3.0 subset,限制更多。
  2. 字符串 vs 对象编码:OpenAI 的 arguments 是 JSON string(解析前必须 json.loads),Anthropic 的 input 是 object(直接 args.foo)——这是应用层最容易出错的地方。
  3. 流式 partial 协议:OpenAI 增量字符串(需自己拼 JSON),Anthropic 增量 JSON patch(结构更友好),Gemini 部分支持,MCP 通过 progress 通知。
  4. 错误语义:OpenAI 把工具错误编码为普通 role=tool content,Anthropic 用 is_error: true 块,Gemini 用 functionResponse.response.error 字段,MCP 用 JSON-RPC error 字段。

把这五元组的每个维度差异都理解清楚,是设计 ToolIR 的前置条件。

三、Provider 协议差异:从 JSON Schema 子集到 tool_use block 结构

JSON Schema 子集差异(最隐蔽的兼容性问题):

  • OpenAI:支持 type/properties/required/enum/description,对 $ref 支持有限,additionalProperties: false 必须显式声明。
  • Anthropic:完整支持 JSON Schema Draft 7 + 引用 + 组合关键字 + format 校验。
  • Google:OpenAPI 3.0 subset,description 是必填的(不填会被拒),enum 必须显式列举所有可能值。
  • MCP:完整 JSON Schema Draft 2020-12 + outputSchema(描述返回值的 schema,应用层可以做 response validation)。

协议特定的 metadata 字段:

  • OpenAI 有 strict: true(强制 JSON Schema 严格校验,2024-08 后稳定)和 parallel_tool_calls: false(强制单次只调一个工具)。
  • Anthropic 有 cache_control: {type: "ephemeral"}(在 tool description block 上可以打 cache 标记)和 disable_parallel_tool_use: true。
  • Google 有 codeExecution 配置(允许模型生成并执行 Python 代码,本质是另一种工具)。
  • MCP 有 _meta 字段(任意 provider-specific metadata)和 annotations(hint 给 UI 层做展示)。

调用请求的 wire format 差异:

// OpenAI Tools (JSON string-encoded)
{
  "tool_calls": [{
    "id": "call_abc123",
    "type": "function",
    "function": {
      "name": "get_weather",
      "arguments": "{\"city\":\"Beijing\",\"unit\":\"celsius\"}"  // 注意是 string
    }
  }]
}

// Anthropic Tool Use (native object)
{
  "type": "tool_use",
  "id": "toolu_abc123",
  "name": "get_weather",
  "input": {"city": "Beijing", "unit": "celsius"}  // 注意是 object
}

// Google Gemini
{
  "functionCall": {
    "name": "get_weather",
    "args": {"city": "Beijing", "unit": "celsius"}
  }
}

// MCP (JSON-RPC 2.0)
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {"city": "Beijing", "unit": "celsius"}
  }
}

应用层若直接用这四种 wire format 写胶水代码,每多接一个 provider 就多一份 if/else 分支。正确的做法是在 SDK 内部完成 wire ↔ ToolIR 双向转换,业务代码只看到 ToolIR。

四、统一的工具描述语言:ToolIR 中间表示设计

ToolIR(Tool Intermediate Representation)是应用层的"协议中立的工具描述语言",我们建议以下五元组结构:

interface ToolIR {
  // 元数据
  id: string;                    // 稳定 UUID,跨 provider 不变
  name: string;                  // snake_case 函数名
  description: string;           // 自然语言描述(≥ 50 字符,含动词)
  // 参数 schema(统一 JSON Schema Draft 2020-12 完整支持)
  parameters: JSONSchema;
  // 返回值 schema(MCP 风格,可选)
  outputSchema?: JSONSchema;
  // 行为约束
  behavior: {
    readonly?: boolean;          // 工具是否只读(影响 cache strategy)
    destructive?: boolean;       // 是否需要二次确认
    idempotent?: boolean;        // 是否幂等(影响 retry 策略)
    open_world?: boolean;        // 是否依赖外部世界(影响 timeout)
    requires_approval?: 'always' | 'never' | 'if_destructive';
  };
  // 运行时约束
  constraints: {
    timeout_ms: number;
    max_retries: number;
    rate_limit?: {rpm: number; tpm?: number};
    cost_estimate_usd?: number;
  };
  // Provider-specific hints(adapter 透传,不在 IR 里强类型)
  provider_hints?: Record<string, Record<string, unknown>>;
  // 协议特定元数据(cache_control, strict, codeExecution 等)
  protocol_meta?: Record<string, unknown>;
}

ToolIR 与已有 schema 库的关系:ToolIR 不是要替代 Pydantic/Zod,而是"在 Pydantic/Zod 之上加一层 provider-neutral 语义"。应用层的典型用法是:先用 Pydantic/Zod 定义参数 schema(享受 IDE 自动补全、运行时校验、序列化),再通过 pydantic_to_tool_ir(model) 或 zod_to_tool_ir(schema) 转换为 ToolIR,最后 adapter 把 ToolIR 序列化为 provider wire。ToolIR 在这两者之间起"协议中立的中介"作用——它是 OpenTelemetry GenAI semantic conventions 在工具描述层的具体化,也是 MCP 协议 server 端的标准输入格式。这一层抽象的最大价值不是减少代码量,而是让"换 provider"从 2 周重构降为 2 天配置——而 LLM 应用的 provider landscape 在 2026 年仍处于快速演化期(每季度都有新模型发布、新协议推出),可替换性就是竞争力。

ToolIR 的版本管理:ToolIR 必须带 schema_version 字段("1.0"),每次不向后兼容的改动都升级版本号。应用层在 Tool Registry 里维护 (tool_name, schema_version) → ToolDefinition 的多版本映射,避免某次 ToolIR 升级把历史 conversation log 都打挂。这是企业级 LLM 应用"灰度发布工具定义"的基础——可以先让 10% 的流量走新版本 ToolIR,观测通过后再全量。多版本共存的工程机制:(a) Tool Registry 的 get(tool_name, schema_version=default) 显式接受版本参数;(b) Conversation log 在 metadata 里记录每个 tool_call 用的是哪个 schema_version;(c) 旧版本的 ToolIR 在 Deprecation Date 之后才下线,且下线前 N 周通过 SDK 警告所有调用方。这种版本治理模式和数据库 schema migration 是同构的,工程团队可以直接复用现有 DevOps 流程。

设计决策背后的关键考量:

  1. id 独立于 name:name 是 wire format 层的 snake_case,id 是应用层的稳定句柄。当你想给工具改个名字(比如 get_weather → fetch_weather),所有引用过这个工具的 conversation log、cache key、trace span 都不需要迁移。
  2. behavior 字段独立:OpenAI 的 strict、Anthropic 的 cache_control、Google 的 codeExecution 在协议层是异构的,但在应用层它们都映射到"这个工具的运行时行为约束"——这是统一的语义。
  3. parameters 用完整 JSON Schema:OpenAI/Anthropic/Google/MCP 都承诺 JSON Schema 兼容(即使子集不同),我们用 Draft 2020-12 作为 IR 规范,adapter 负责降级到 provider-specific subset。
  4. constraints.timeout_ms 是必须的:函数调用协议本身的语义不含超时,超时是应用层约束。统一在 IR 里表达,避免每个 adapter 自己实现 timeout。
  5. provider_hints 与 protocol_meta 分离:hints 是 adapter-to-adapter 提示(如"OpenAI 这个工具描述特别长,触发 truncation 阈值"),meta 是 protocol-specific 元数据(如 cache_control)。两者在应用层都不应该被业务代码直接访问。

五、协议适配器与双向语义保真

Adapter 层负责 ToolIR ↔ provider wire format 的双向转换。核心难点是"语义保真":不是 1:1 字段映射,而是保证 provider 在自己协议下能表达 IR 的全部语义。

下行(ToolIR → provider wire):

abstract class ToolAdapter {
  abstract toWire(ir: ToolIR): ProviderToolWire;
  abstract fromWire(wire: ProviderToolCall): ToolCallIR;
  abstract toResultIR(wire: ProviderToolResult): ToolResultIR;
  abstract fromResultIR(ir: ToolResultIR): ProviderToolResultWire;
  // 流式 partial 解析(最复杂的部分)
  abstract streamParser(): ToolStreamParser;
}

class OpenAIToolsAdapter extends ToolAdapter {
  toWire(ir: ToolIR): OpenAIToolWire {
    // 1. JSON Schema 降级:移除 OpenAI 不支持的 $ref, oneOf 等
    const subSchema = downgradeToOpenAISubset(ir.parameters);
    // 2. strict 模式:如果应用层要求严格校验
    if (ir.behavior.idempotent && ir.constraints.max_retries > 0) {
      return {type: 'function', function: {name: ir.name, description: ir.description, parameters: subSchema, strict: true}};
    }
    return {type: 'function', function: {name: ir.name, description: ir.description, parameters: subSchema}};
  }
  // ...
}

上行(provider wire → ToolIR)的关键陷阱:

  1. OpenAI arguments string 解析失败:模型有时会输出 {"city": "Beijing} 这种截断的 JSON,应用层必须做 partial JSON 修复(见 §七流式解析)。
  2. Anthropic tool_use block 与 text block 同 message:一次响应可能既有 text 又 tool_use,且 tool_use 是数组,应用层必须遍历所有 blocks 不能 first()。
  3. Google Gemini 的 functionCall 嵌入 parts[]:与 text/functionResponse/inlineData 共享 parts 数组,应用层必须按 parts[i].functionCall 判别。
  4. MCP 的 content[] typed array:可能含 text / image / audio / resource / embedded_resource 五种类型,应用层必须支持多模态返回。

语义保真测试(adapter 层的 QA):每个 adapter 都要跑一个 "round-trip 测试集",把同一组 ToolIR 经过 toWire/fromWire 转换后语义不变(即 name/parameters/result 都一致),且关键约束(timeout_ms / readonly / destructive)不丢失。

六、并行调用、依赖图与控制流:Function Calling 的拓扑编排

2026 年 LLM 应用的核心效率提升来自并行函数调用:模型一次性发出多个 tool_call(如同时查天气、查股票、查日历),应用层并行执行后一次性回填——相比串行调用,端到端延迟从 N × latency 降到 max(latency)。

协议层差异:

  • OpenAI:默认并行,可通过 parallel_tool_calls: false 关闭。
  • Anthropic:默认并行,可通过 disable_parallel_tool_use: true 关闭;tool_use block 是数组,多个并行。
  • Google:默认并行,函数声明无显式 parallel 开关。
  • MCP:单次 tools/call 是一个 RPC,但应用层可以并发发多个 RPC。

应用层的"工具依赖图"(Tool Dependency Graph): 当工具之间存在依赖关系时(如"先查 user_id 再查 user_orders"),盲目并行执行会导致数据竞争。正确的做法是在 ToolIR 里声明依赖:

interface ToolIR {
  // ...
  dependencies?: {
    tools?: string[];            // 依赖的其他工具 id
    data_sources?: string[];     // 依赖的数据源
    auth_scopes?: string[];      // 需要的 auth scope
  };
}

应用层用依赖图做拓扑排序,可并行的 batch 一起发(用 Promise.all 或 asyncio.gather),有依赖的等依赖完成再发下一批。这本质上是把 DAG 调度引入 LLM 应用——和 Airflow / Prefect 的任务编排是同构的。

控制流进阶:模型可能输出"先调 A,根据 A 的结果决定调 B 还是 C"的条件分支,这种条件工具链应用层通过 tool result 反向 prompt 实现,让模型在拿到 tool result 后再做决策。这是 LLM 应用层"agent loop"的核心机制,详见 id=657(Agent 上下文工程)和 id=649(端到端延迟预算工程)。

并行执行的资源竞争与一致性:当多个并行 tool_call 访问同一资源时(如多个写操作、共享的计数器),应用层必须做"读写隔离 + 版本号"机制。具体做法:(a) 每个 tool_call 携带 idempotency_key(基于 conversation_id + tool_name + args hash),下游 API 自动去重;(b) 写操作类工具必须返回新的 version/etag,后续依赖此资源的 tool_call 必须带 expected_version,应用层在调用前校验版本一致性;(c) 并行的读操作可以不加锁,但读后写必须按依赖图顺序串行。这个设计与传统分布式系统的事务隔离级别(RC/RR/Serializable)是同构的,应用层可以复用熟悉的一致性协议设计经验。失败补偿:并行 tool_call 部分失败时(如 5 个并行里 2 个 4xx),应用层不能简单 retry 全部——成功的 3 个已经执行了副作用,必须先做"补偿事务"(compensating transaction),再 retry 失败的 2 个。这是 LLM 应用"事务一致性"的核心难题,也是 agent loop 复杂度的根源。

七、流式工具调用:partial JSON 解析与渐进式 UI 渲染

2026 年 LLM 应用 UX 的一个分水岭是流式工具调用:模型一边生成 tool_call 的 arguments JSON,应用层一边解析、渲染部分结果。这种"渐进式 UI"对延迟敏感的 LLM 应用(如 IDE 插件、客服 Copilot)是核心体验。

partial JSON 解析器设计: OpenAI 的 stream 协议每个 chunk 推送 tool_calls.delta.function.arguments(增量字符串),应用层必须累积字符串后尝试 partial parse。partial parse 算法的核心是"截断到最后一个完整的 {} 闭合边界",然后反序列化已经完整的部分:

class PartialJSONParser {
  private buffer = '';
  private lastValidPrefix = '';

  feed(chunk: string): PartialResult {
    this.buffer += chunk;
    const trimmed = this.trimToValidJSON(this.buffer);
    if (trimmed !== this.lastValidPrefix) {
      try {
        const parsed = JSON.parse(trimmed);
        this.lastValidPrefix = trimmed;
        return {state: 'complete', value: parsed, raw: trimmed};
      } catch (e) {
        return {state: 'partial', value: this.tryPartialParse(trimmed), raw: trimmed};
      }
    }
    return {state: 'pending', value: undefined, raw: this.lastValidPrefix};
  }

  private trimToValidJSON(s: string): string {
    // 找到最后一个完整闭合的 }, 然后截断
    let depth = 0;
    let inString = false;
    let escape = false;
    for (let i = 0; i < s.length; i++) {
      const c = s[i];
      if (escape) { escape = false; continue; }
      if (c === '\\') { escape = true; continue; }
      if (c === '"') { inString = !inString; continue; }
      if (inString) continue;
      if (c === '{') depth++;
      if (c === '}') {
        depth--;
        if (depth === 0) return s.slice(0, i + 1);
      }
    }
    return s.slice(0, s.lastIndexOf('{'));
  }
}

Anthropic 的 input_json_delta 优势:直接给结构化的 partial JSON,应用层不需要自己做 trim。但代价是必须监听 content_block_stop 才知道完整。

UI 层的渐进式渲染:在 IDE 插件里,应用层每拿到 partial JSON 就把已知的字段(如 path、line)高亮到编辑器;在客服 Copilot 里,已知的字段(如 order_id)先填表,未知的(如 reason)显示 loading skeleton。这种 UX 比"等所有参数到齐再渲染"快 2-4 倍感知延迟。

MCP 的流式协议:通过 SSE notifications 推送 progress 事件(带 progressToken + progress + total),应用层做进度条 UI。MCP 还支持 cancellation(通过 notifications/cancelled),应用层可以主动取消正在执行的工具。

流式协议的可观测性差异:OpenAI 的 delta 流只给字符串碎片,应用层必须自己拼装完整 JSON 才能上 span,导致 trace 里看不到"模型在生成第几个 token 时触发了哪个 tool_call";Anthropic 的 input_json_delta 流给结构化 partial JSON,应用层可以在 span 里记录"当前已解析到 input.city = Beijing";Gemini 的 partial 协议最弱,delta 粒度不可控;MCP 的 progress notification 粒度最细,应用层可以在工具执行阶段也打点("已查询 5/10 个 database row")。这个差异直接影响生产环境的调试效率——当用户报告"我的 tool_call 看起来很奇怪"时,能拿到 partial state 的团队比只能拿到最终 string 的团队 debug 快 3-5 倍。这是选择 LLM provider 时被严重低估的"工程体验"维度。

流式工具调用的 error recovery:partial JSON 解析失败的常见原因是模型输出了截断的 JSON(如 {"city": "Beijing 缺少闭合)。应用层的 fallback 策略:(a) 在最后一次 stream 结束后,对 buffer 做"自动补全"(根据 JSON Schema 推断缺失字段的默认值);(b) 如果补全后仍不合法,返回 tool_result.error = "incomplete_arguments" 给模型,让模型重新生成;(c) 不要 silent retry(直接调下游 API)——silent retry 会让对话历史里看不到错误,破坏 trace 完整性。这是 LLM 应用层最容易踩的"silent failure"陷阱之一,应用层必须把"参数不合法"显式建模为可观测的事件,而不是吞掉。

八、安全纵深:从 prompt injection 到 schema validation 的多层防御

函数调用协议的安全风险远高于普通文本生成:模型一旦有能力调用外部 API,prompt injection 就从"输出攻击"升级为"行动攻击"——攻击者可以让模型调转账 API、调删除 API、调数据外泄 API。

七层防御体系:

  1. Tool IR 层(设计期):每个工具显式声明 destructive / requires_approval / open_world 属性。destructive 工具必须经过二次确认(人类在 UI 上点"确认"按钮)才能执行。
  2. Schema 校验层(输入期):每个 tool_call 的 arguments 必须用 JSON Schema 严格校验,任何 schema 不符合的 call 立即拒绝(不传给下游)。这一步可以拦截 30-50% 的恶意构造。
  3. Argument sanity check 层(语义期):在 schema 校验之外,定义"argument 合理性检查"(如金额 ≤ 单日上限、文件路径必须在白名单内、URL 必须在公司域名内)。这种"业务级白名单"比通用 schema 校验更有效。
  4. Sandbox 执行层(运行时):工具执行必须在沙盒里(无网络/受限文件系统/受限环境变量),即使工具代码被注入也只影响沙盒。
  5. Provider-side guardrail 层(API 期):OpenAI 的 strict: true + Anthropic 的 prompt caching + Google 的 safety filters 都是 provider 提供的"原生护栏",但不能作为唯一防线——provider 护栏失效时应用层必须有 fallback。
  6. Audit log 层(全链路):每次工具调用必须记录"哪个 session、哪个 user、哪个 prompt、哪个 model、哪个 tool、什么参数、什么结果",存到不可变存储(WORM)。这是事后追溯和合规审计的基础。
  7. Rate limit + anomaly detection 层(行为期):每个用户的工具调用频率、调用模式必须监控,异常调用模式(如突然大批量数据外泄)触发自动熔断。

MCP 协议的安全增强:MCP 2025-06 引入 OAuth 2.1 资源服务器模式,应用层可以基于 OAuth scope 决定哪些用户能用哪些 MCP 工具。但应用层仍需在 SDK 内做"tool-level authz",不能依赖 MCP server 自己声明的权限。

九、给应用开发者的工程清单:Tool Gateway + SDK + Observability 三件套

第 1-5 条:Tool Gateway(应用层入口)

  1. 部署一个统一的 Tool Gateway(可以是 in-process SDK、可以是 sidecar、可以是独立服务),所有 LLM 调用必须经过 Gateway,禁止业务代码直接调 provider API。
  2. Gateway 内置 provider adapter registry(OpenAI/Anthropic/Google/MCP),用 ToolIR 描述所有工具,业务代码只 import ToolIR,不 import provider wire format。
  3. Gateway 内置工具依赖图(Tool Dependency Graph)引擎,自动并行无依赖的 tool_call,串行有依赖的。
  4. Gateway 内置 partial JSON 解析器,支持 OpenAI/Anthropic/Google/MCP 四种流式协议,向上层暴露统一的 partial_result 流。
  5. Gateway 内置七层防御体系(§八),尤其 destructive 工具的二次确认必须强制在 Gateway 实现,不能依赖 UI 层(UI 可被绕过)。

第 6-10 条:SDK(开发者接口) 6. 提供 define_tool(ToolIR) 装饰器/函数式 API,让业务开发者用 1 行代码定义一个工具,自动生成四套 provider wire。 7. 提供 execute_tool_call(call, ctx) 统一执行接口,ctx 包含 user_id、session_id、auth_scopes 等。 8. SDK 内置 Round-trip 语义保真测试套件(每个 adapter 跑 100 个测试用例,确保 ToolIR ↔ wire 双向不丢字段)。 9. SDK 内置 Pydantic/Zod schema 互转工具,让开发者用熟悉的 schema 库定义工具参数,自动生成 JSON Schema + ToolIR。 10. SDK 必须支持"懒加载 tool description"——当工具很多时(如 100+ 个 MCP server),不能把全部 description 塞进 system prompt,要按需动态选择。

第 11-14 条:Observability(可观测性) 11. 每次 tool_call 必须产生一个 trace span,包含 ToolIR.id、provider、latency、token cost、arguments schema 校验结果、错误码等。 12. 必须记录 tool_call 的 partial state stream(partial JSON 解析的中间状态),用于调试"为什么模型生成了一个不完整的 JSON"。 13. 集成 Langfuse / Helicone / Phoenix / LangSmith 之一作为 trace 后端,trace 必须包含 tool definition、tool call、tool result 三段完整链路。 14. 设置三个核心 SLO:(a) tool_call 成功率 ≥ 99.5%、(b) tool_call P95 latency ≤ 2s、(c) destructive tool 二次确认率 = 100%。任何一个 SLO 跌破触发 page。

结语:函数调用协议工程是 LLM 应用从"Prompt + RAG"走向"Agent + Tools"的必经之路,也是 2026 年最被低估的应用层基础设施。没有 ToolIR 的应用层是短命的——每一次新 provider 接入都是一次痛苦的 adapter 重写,每一次新工具添加都是一份 wire format 复制粘贴,每一次新的 prompt injection 攻击都是一次架构级风险。ToolIR + 协议适配器 + 流式解析器 + Tool Gateway 四层架构是规模化 LLM 应用的"工业地基",也是多模型策略、跨云部署、企业级合规的工程前提。

给架构师的额外 5 条决策指引:

  1. 不要从零写 SDK,先用开源:LangChain/LlamaIndex 的 tool calling 抽象虽然粗糙但已支持四类 provider,可以作为起点二次封装;Vercel AI SDK 的 provider-neutral 设计对前端友好;Cloudflare Agents SDK 把 Tool Gateway 内置到边缘运行时。选 SDK 的核心标准是"是否暴露 ToolIR 等价物让你扩展"——封闭 SDK(如某些 copilot 平台)会让你后续无法满足自定义需求。
  2. provider 锁定风险评估:每个 provider 都有"vendor lock-in"的隐藏成本——OpenAI 的 strict mode 锁定 JSON Schema 写法,Anthropic 的 prompt caching 锁定 message block 结构,Google 的 codeExecution 锁定 Python 执行环境。2026 年最务实的策略是"primary + secondary"双 provider,主用便宜且效果好的(如 GPT-5),备用 SLA 高的(如 Claude 4.5),Tool Gateway 负责 fallback 决策。这比 100% 押注单一 provider 健康得多。
  3. 不要在应用层重新实现 OAuth:很多团队试图在 Tool Gateway 里实现"用户授权某工具"的流程,结果做出来的既不安全也难维护。正确做法是直接复用 MCP 2025-06 引入的 OAuth 2.1 资源服务器模式——MCP server 端声明它需要哪些 scope,Tool Gateway 在调用时透传用户 token,scope 检查由 MCP server 自己完成。这是把"工具授权"的工程复杂度下放到协议层的范例。
  4. Tool 定义的生命周期管理:工具不是静态的——会被弃用(deprecation)、会被版本化、会有兼容性问题。应用层必须建立 Tool Registry(类似 npm registry),记录每个 tool 的 version、status(active/deprecated/removed)、migration guide。Registry 是 LLM 应用从"能跑"走向"能治理"的关键一步——没有 Registry 的应用在工具数量超过 50 个后基本无法维护。
  5. Tool IR 与 prompt 工程的协同:很多团队把 Tool Description 当作"提示词的一部分"随便写,结果模型调工具准确率只有 60-70%。正确做法是把 Tool Description 当作"prompt artifact"严格管理:(a) 每个工具的 description 必须由 prompt 工程师 + 领域专家联合评审;(b) 工具的 description 进入 prompt A/B 平台,用真实 query 数据做对比实验;(c) 工具 description 的修改要走 PR review + CI 验证(用 golden set 跑成功率回归)。这是 LLM 应用"工程化 prompt 管理"的必经之路,与 devops 中 "infrastructure as code" 是同构的工程哲学。今天就做这三件事:先把所有工具定义迁到 ToolIR;再部署一个 Tool Gateway;最后接 OpenTelemetry 把所有 tool_call trace 打通。这三件事做完,你的 LLM 应用就具备了"多模型 + 多云 + 多模态 + 多租户"的可扩展性。

参考文献

  1. OpenAI. Function Calling Guide. https://platform.openai.com/docs/guides/function-calling. 2024-08.
  2. Anthropic. Tool Use with Claude. https://docs.anthropic.com/en/docs/tool-use. 2024-10.
  3. Google. Gemini Function Calling Documentation. https://ai.google.dev/gemini-api/docs/function-calling. 2024.
  4. Anthropic. Model Context Protocol Specification. https://modelcontextprotocol.io/specification/2025-06-18. 2025.
  5. OpenAI. Structured Outputs Guide. https://platform.openai.com/docs/guides/structured-outputs. 2024-08.
  6. Anthropic. Prompt Caching for Tool Descriptions. https://docs.anthropic.com/en/docs/prompt-caching. 2024.
  7. Google. OpenAPI 3.0 Specification for Gemini Function Calling. https://ai.google.dev/gemini-api/docs/structured-output. 2024.
  8. Pydantic. JSON Schema Generation from Python Types. https://docs.pydantic.dev/latest/concepts/json_schema/. 2024.
  9. Zod. TypeScript-first Schema Validation. https://zod.dev/. 2024.
  10. JSON-RPC 2.0 Specification. https://www.jsonrpc.org/specification. 2010.
  11. W3C. JSON Schema Draft 2020-12. https://json-schema.org/draft/2020-12/schema. 2020.
  12. OpenTelemetry. GenAI Semantic Conventions for Tool Calls. https://opentelemetry.io/docs/specs/semconv/gen-ai/. 2024.
  13. Langfuse. Tool Call Tracing Documentation. https://langfuse.com/docs/observability/features/tool-calls. 2024.
  14. Phoenix (Arize). Tool Call Evaluation Framework. https://docs.arize.com/phoenix. 2024.
←返回文章列表

Related

可能也会喜欢

  • LLM 应用的多轮对话状态管理工程 2026:从会话持久化、分支回滚到跨端同步的统一架构9月16日
  • Prompt 平台工程 2026:从版本到 A/B9月15日
  • AI 应用的文档智能与 PDF/OCR 工程 20269月14日

Conversation

0 条

留下你的想法

加载评论中…

New comment