AI 工具 schema 怎样为函数参数保留版本兼容
来源:17golang原创
时间:2026-10-18 11:39:29 391浏览 收藏
AI 工具上线后,最容易被忽略的是函数参数 schema 其实就是一份接口契约。今天把 include_items 改成 include_lines,或者把字符串改成数组,模型、网关和旧调用方就可能同时出现不兼容。我的经验是把版本问题拆成“工具身份、输入 schema、内部规范对象”三层:能向后兼容的变化继续留在原版本,真正改变语义的变化单独发布 v2,再由服务端适配器统一处理。
实用规则是:新增字段先做可空并保留旧字段;改名、改类型、删除字段或改变含义时,不要偷偷覆盖 v1,而是保留 v1、增加 v2,并记录旧版本调用量。
本文讨论的官方函数调用资料入口是:https://developers.openai.com/api/docs/guides/function-calling。不同模型或供应商的具体字段可能不同,下面的 schema 形状应当结合目标平台的约束调整。
先把版本放在正确的边界上
我在设计工具时会先画出三层边界。第一层是模型看到的工具身份,例如 get_order_v1 和 get_order_v2;第二层是每个工具自己的 JSON Schema;第三层是业务服务内部统一使用的 OrderQuery。版本号只放在描述文本里不够可靠,因为描述可能被模型忽略,也无法帮助服务端路由。
| 边界 | 负责什么 | 兼容策略 |
|---|---|---|
| 工具身份 | 告诉模型可调用哪一代契约 | 破坏性变化新增 v2 名称 |
| 参数 schema | 限制字段、类型和必填关系 | 原版本只做加法或兼容映射 |
| 内部规范对象 | 供业务代码稳定消费 | 由 v1/v2 适配器统一转换 |

这样做的好处是模型侧和业务侧可以分别演进。工具注册表决定暴露哪一代名称,schema 决定调用参数能否被接受,适配器则把差异收敛到一个稳定的内部字段名。图中的关系是设计说明,不代表某次真实请求已经执行。
新增参数时,用可空字段保住旧调用方
非破坏性变化通常是新增筛选项、排序选项或返回偏好。不要把旧字段从 required 中拿掉后,期待所有平台都按同一种方式处理“可选”。如果启用 strict schema,官方文档要求对象属性全部列入 required,可以把业务上的可选值表示成字符串或 null 的联合类型。
{
"type": "object",
"properties": {
"schema_version": {
"type": "string",
"enum": ["v1"]
},
"order_id": {
"type": "string"
},
"include_items": {
"type": ["boolean", "null"]
}
},
"required": ["schema_version", "order_id", "include_items"],
"additionalProperties": false
}
这里的 include_items 在协议层始终出现,但值可以是 null。服务端把 null 解释为旧调用方没有提出偏好,再使用默认行为。schema_version 用枚举限制当前工具只接受 v1;当 v2 的含义发生变化时,不要仅仅把枚举扩成两个值后让一个处理器猜测差异。
新增字段还要保持旧字段的含义不变。可以新增 locale、sort 这类独立能力,但不要把旧的 include_items=true 改成“返回摘要和明细”。字段名没变而语义变了,仍然属于破坏性变化。
改名或改类型时,让 v1 和 v2 经过同一个适配器
字段改名、类型变化、枚举值删除和默认含义改变,都应该视为新的契约。以订单查询为例,v1 继续接受 include_items,v2 使用更明确的 include_lines。两边都转换成内部的 includeLines,业务层不需要知道模型调用的是哪一版。
const TOOL_VERSIONS = new Set(["v1", "v2"]);
function normalizeOrderQuery(raw) {
// 先拒绝未知版本,避免把新字段静默当成旧语义。
if (!raw || typeof raw !== "object" || !TOOL_VERSIONS.has(raw.schema_version)) {
throw new Error("unsupported tool schema version");
}
if (raw.schema_version === "v1") {
// v1 的字段名保留给旧调用方,内部统一使用新语义名称。
return {
orderId: raw.order_id,
includeLines: raw.include_items ?? false,
sourceVersion: "v1"
};
}
// v2 已经明确表达 lines,但仍把输入转换成同一个内部对象。
return {
orderId: raw.order_id,
includeLines: raw.include_lines ?? false,
sourceVersion: "v2"
};
}
适配器要做三件事:先校验版本,再做字段映射,最后保留 sourceVersion 供日志和迁移统计使用。不要在业务函数里散落 if (v1);否则下线 v1 时会漏掉隐藏分支。对于 v2 的 schema,工具身份和 schema_version 可以同时存在:前者负责选择契约,后者负责让服务端拒绝错配输入。

用迁移指标决定什么时候下线旧版本
版本发布后,不能只看新工具能否被调用。至少记录四类指标:未知版本拒绝数、schema 校验拒绝数、v1/v2 调用量,以及适配器转换后的业务失败数。若 v1 调用量仍高,说明还有调用方没有迁移;若 schema 拒绝数突然上升,优先检查工具注册版本与服务端路由是否错配。
我会把迁移分成三个阶段:先同时暴露 v1 和 v2,让新会话优先看到 v2;再在服务端保留 v1 适配器并给旧调用方发迁移提示;最后在一段可观测窗口内确认 v1 为零或低于约定阈值,再移除注册和适配代码。这个窗口不是平台保证,而是团队根据业务风险自行设定的发布策略。
- 新增能力:原字段保持原意,新字段使用可空值,旧调用方继续走默认行为。
- 改变语义:增加独立 v2 工具,不把两个版本混成一个模糊 schema。
- 服务端处理:先版本校验,再适配到统一内部对象,业务层不感知外部字段差异。
- 下线判断:结合版本调用量、拒绝数和业务失败数,而不是只看发布时间。
两个容易混淆的问题
把旧字段标成可选,是否就完成了兼容? 不一定。字段可以不再必填,但它的默认值、枚举语义和返回结果仍可能变化。兼容要同时看结构和含义。
为什么不直接在一个 schema 里接受 v1、v2 两套字段? 这样短期省去注册两个工具,长期却会让模型选择字段组合,服务端也难以判断互斥关系。只有两套字段含义高度一致、迁移周期很短时,才考虑在一个契约里做明确的联合设计。
归纳起来,schema 版本管理不是给 JSON 加一个数字,而是给工具身份、字段约束、适配入口和下线指标建立一条完整的兼容链。把破坏性变化显式化,旧调用方才有可控的迁移路径。
-
407 收藏
-
Golang · Go教程 | 2个月前 | golang · JSON · 故障排查 · Go教程 · 接口设计 · JSON Go 接口兼容性 DisallowUnknownFields 严格解码174 收藏
-
Golang · Go教程 | 2个月前 | golang · sse · Go教程 · net/http · 接口设计 · HTTP Go SSE FLUSH 流式响应 ResponseController463 收藏
-
427 收藏
-
Golang · Go教程 | 1个月前 | 标准库 · golang · 性能优化 · 接口设计 · 性能优化 Go字符串 缓冲区复用 encoding.TextAppender MarshalText245 收藏
-
191 收藏
-
296 收藏
-
317 收藏
-
375 收藏
-
216 收藏
-
174 收藏
-
144 收藏
-
199 收藏
-
133 收藏
-
144 收藏
-
349 收藏
-
318 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习