尧图精选

AI SDK 内嵌 zod3ToJsonSchema 深度解析:为 Zod v3 Schema 生成 JSON Schema 的完整指南

🕒 发布时间:2026/9/12 17:07:56 📁 来源:尧图网络
AI SDK 内嵌 zod3ToJsonSchema 深度解析为 Zod v3 Schema 生成 JSON Schema 的完整指南【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai导读本篇文章聚焦 AI SDKTypeScript仓库内ai-sdk/provider-utils中内置的zod3-to-json-schema模块它是 AI SDK 将用户定义的 Zod v3 Schema 转换为 JSON Schemadraft-07的核心实现是工具调用tool calling、结构化输出等能力向模型提供商传递 schema 的关键一环。读完本文你将理解该模块为何要脱离上游zod-to-json-schema独立维护、它的入口 API 与全部配置选项、30 余种 Zod 类型的转换映射关系以及它在 AI SDK 中如何被schema.ts集成并与 Zod v4 并存。模块由来为什么 AI SDK 要内置一份 zod-to-json-schema模块的 README 明确说明了它的来历这段代码最初拷贝自 Stefan Terdell 的开源项目zod-to-json-schema原因在于该上游库的peerDependency是zod: ^3.24.1而 AI SDK 需要同时支持用户已经在使用的zod4。如果直接依赖上游库就会导致用户的依赖树中同时出现zod3和zod4两个大版本带来类型不一致、体积膨胀等隐患。因此 AI SDK 选择将这份针对 Zod v3 的转换器以源码形式 vendoring 进仓库即zod3-to-json-schema目录并在 packages/provider-utils/package.json 中把 Zod 声明为更宽松的peerDependencies: zod: ^3.25.76 || ^4.1.8同时将zod3.25.76作为开发依赖用于构建与测试。这样用户无论使用 Zod 3 还是 Zod 4都不会出现重复的大版本依赖。值得注意的是目录内还保留了一份独立的 LICENSEISC 协议版权归属于 Stefan Terdell2020与 Vercel Inc.2025说明了这部分代码是采用 ISC 许可随仓库分发与仓库主体采用的 Apache-2.0 不同使用或再分发时需留意其许可条款。模块全景目录结构与核心入口整个模块位于packages/provider-utils/src/to-json-schema/zod3-to-json-schema/下结构非常清晰入口文件 index.ts 只做一件事export { zod3ToJsonSchema } from ./zod3-to-json-schema。主实现 zod3-to-json-schema.ts见 zod3-to-json-schema.ts组装顶层 schema、处理definitions与命名策略。options.tsOptions类型定义与默认值。refs.ts贯穿整个转换过程的“引用上下文”当前路径、已见过的定义等。parse-def.ts递归解析任意ZodTypeDef的统一入口。select-parser.ts按 Zod 类型名分发到具体解析器。parse-types.tsJSON Schema 7 各类节点类型的 TypeScript 联合类型。parsers/约 25 个针对单一 Zod 类型的解析器每个解析器都配了对应的*.test.ts单元测试。转换的整体流程是zod3ToJsonSchema拿到schema._def通过selectParser按typeName如ZodString、ZodObject分派到对应解析器解析器内部再递归调用parseDef处理嵌套定义最终产出一棵JsonSchema7Type树。核心 APIzod3ToJsonSchema 的签名与返回值主函数定义在 zod3-to-json-schema.ts签名如下const zod3ToJsonSchema ( schema: ZodSchemaany, options?: PartialOptions | string, ): JsonSchema7Type { $schema?: string; definitions?: { [key: string]: JsonSchema7Type }; };几个关键行为第二个参数既可以是配置对象也可以是字符串。当传入字符串时它被当作 schema 的name使用内部通过getDefaultOptions合并为{ ...defaultOptions, name: options }这为快速命名提供了一种简写。顶层固定输出$schema函数末尾会写入combined.$schema http://json-schema.org/draft-07/schema#即产物始终是 JSON Schema draft-07。名称策略nameStrategy当options.name存在且nameStrategy title时名字写入main.title否则按$ref策略生成顶层$ref指向definitions中的命名定义。name缺省时若提供了definitions则把 definitions 挂到definitions键下否则直接返回主体。definitions 的预注册options.definitions中预置的命名 schema 会在进入主解析前先各自解析一遍并放入definitions表供后续引用复用。配置选项全解析所有选项在 options.ts 中定义默认值在 options.ts 中集中给出。下表完整列出选项及其默认行为选项类型默认值说明namestring \| undefinedundefined顶层 schema 的命名配合definitions与$ref使用$refStrategyroot \| relative \| none \| seenroot重复/递归定义的引用生成策略见下文专节basePathstring[][#]所有$ref与路径的基础前缀effectStrategyinput \| anyinputz.effect()等效果类型解析输入侧还是任意侧pipeStrategyinput \| output \| allallz.pipe()流水线解析哪一侧dateStrategyDateStrategy \| DateStrategy[]format:date-time日期转换策略可传数组生成anyOf组合mapStrategyentries \| recordentriesz.map()转成数组条目还是 recordremoveAdditionalStrategypassthrough \| strictpassthrough对strip行为的对象additionalProperties的取舍方向allowedAdditionalPropertiestrue \| undefinedtruepassthrough 时additionalProperties的值rejectedAdditionalPropertiesfalse \| undefinedfalsestrict 时additionalProperties的值strictUnionsbooleanfalse联合类型中是否过滤掉空对象分支definitionPathstringdefinitions引用定义在产物 JSON 中的键名definitionsRecordstring, ZodSchema{}预注册的命名 schema 表errorMessagesbooleanfalse是否把 Zod 校验 message 写入errorMessage扩展键patternStrategyescape \| preserveescapestartsWith/endsWith/includes等字面量转正则时是否转义特殊字符applyRegexFlagsbooleanfalse是否尝试把z.string().regex()的i/m/s标志改写为无标志等价正则emailStrategyformat:email \| format:idn-email \| pattern:zodformat:emailemail 校验的表示方式base64Strategyformat:binary \| contentEncoding:base64 \| pattern:zodcontentEncoding:base64base64 校验的表示方式nameStrategyref \| titleref命名 schema 用$ref还是title表达overrideOverrideCallback无自定义覆盖解析回调见高级扩展节postProcessPostProcessCallback无解析后处理回调其中几个默认值值得结合源码说明其影响patternStrategy: escape在 string.ts 中startsWith/endsWith/includes这类字面量检查会先经过escapeLiteralCheckValue对非字母数字字符逐个加反斜杠转义再拼进正则避免字面量中的(,.,*等被误当作正则元字符。applyRegexFlags开启后string.ts 会逐字符扫描正则源码把i标志展开为[aA]式字符类、m标志改写为(^|(?[\r\n]))等若改写后的正则无法通过new RegExp编译会打印警告并回退到原始 source。emailStrategy/base64Strategy决定校验是表达为 JSON Schema 的format关键字email、idn-email、binary、contentEncoding还是内联 Zod 自己的正则模式zodPatterns.email、zodPatterns.base64等定义在 string.ts。选择pattern:zod可以绕过部分模型对format关键字支持不一的兼容性问题。strictUnions在 union.ts 的asAnyOf中开启后会过滤掉解析结果为空的联合分支。类型解析映射selectParser 分发机制selectParser是类型分发的核心见 select-parser.ts。它根据 Zod v3 的ZodFirstPartyTypeKind枚举进行 switch 分发完整映射如下Zod typeName处理方式ZodStringparseStringDefmin/max/format/pattern 全套字符串检查ZodNumberparseNumberDefint/min/max/multipleOfZodObjectparseObjectDefproperties/required/additionalPropertiesZodBigIntparseBigintDefZodBooleanparseBooleanDefZodDateparseDateDef受dateStrategy控制ZodUndefined/ZodNullparseUndefinedDef/parseNullDefZodArrayparseArrayDefitems/minItems/maxItemsZodUnion/ZodDiscriminatedUnionparseUnionDef智能合并为type数组或anyOfZodIntersectionparseIntersectionDef生成allOfZodTupleparseTupleDefZodRecordparseRecordDefZodLiteralparseLiteralDefZodEnum/ZodNativeEnumparseEnumDef/parseNativeEnumDefZodNullableparseNullableDefZodOptionalparseOptionalDefZodMapparseMapDefZodSetparseSetDefZodLazy返回() def.getter()._def惰性取值后递归ZodPromiseparsePromiseDefZodNaN/ZodNeverparseNeverDefZodEffectsparseEffectsDef受effectStrategy控制ZodAnyparseAnyDefZodUnknownparseUnknownDefZodDefaultparseDefaultDefZodBrandedparseBrandedDefZodReadonlyparseReadonlyDefZodCatchparseCatchDefZodPipelineparsePipelineDef受pipeStrategy控制ZodFunction/ZodVoid/ZodSymbol返回undefined无法表达则跳过从源码结构看这套分发刻意覆盖了 Zod v3 的全部第一方类型甚至包括ZodLazy这种需要惰性求值 inner def 的递归类型返回 getter 函数由 parse-def.ts 检测到函数返回值后再次递归调用parseDef。这种“分发 → 递归”的架构保证了任意嵌套的 schema 都能被展开成一颗完整的 JSON Schema 树。常见类型的转换行为详解结合各解析器源码可以确认以下几类高频类型的实际转换行为对象ZodObjectobject.ts 遍历def.shape()对每个属性递归parseDef非可选属性收集进required数组additionalProperties由decideAdditionalProperties决定存在catchall时用它作为additionalProperties的类型否则按unknownKeys取值——passthrough→allowedAdditionalProperties默认truestrict→rejectedAdditionalProperties默认falsestrip→ 依据removeAdditionalStrategy决定是true还是false。也就是说默认情况下 AI SDK 产出的对象 schema 会带上additionalProperties: false对strip对象这恰好符合工具调用对参数严格性的要求。字符串ZodStringstring.ts 会遍历def.checks把min/max/length映射为minLength/maxLength取最严格值email/url/uuid/datetime/date/time/duration/ip映射为formatregex/cuid/cuid2/base64/jwt/emoji/ulid/nanoid/startsWith/endsWith/includes映射为pattern。同一属性叠加多个 format 或多个 pattern 时会采用anyOf/allOf节点合并表达见addFormat与addPattern。数字ZodNumbernumber.ts 把z.int()映射为type: integermin在inclusive时生成minimum、否则生成exclusiveMinimummax同理multipleOf直接透传。联合类型ZodUnionunion.ts 做了三步“美化”优化当所有分支都是无检查的原语类型时合并为type: [string, number, ...]数组形式当所有分支都是字面量时合并为typeenum当所有分支都是ZodEnum时合并为一个stringenum。否则退化为anyOf。这能让产物更简洁也更利于模型理解。可空类型ZodNullablenullable.ts 对无检查的原语内层类型直接生成type: [string, null]其他情况生成anyOf: [base, { type: null }]。日期ZodDatedate.ts 依据dateStrategy输出format:date-time生成{ type: string, format: date-time }format:date生成format: dateinteger生成{ type: integer, format: unix-time }并把 min/max 检查转成minimum/maximum。传入数组策略时会生成anyOf组合。数组ZodArrayarray.ts 除items外把minLength/maxLength/exactLength映射为minItems/maxItemsexactLength会同时设置 min 与 max。引用与 $ref 策略root / relative / none / seen重复与递归 schema 的引用处理是这套转换器最精巧的部分。核心在 parse-def.ts 的get$ref与 refs.ts 的seen表seen表getRefs会维护一个MapZodTypeDef, Seen记录每个已解析定义的路径与产物用于检测重复出现如自引用对象。$refStrategy: root默认重复定义生成{ $ref: #/definitions/xxx }形式的绝对引用。relative通过getRelativePath计算当前路径到目标路径的相对$ref。none遇到已见过的定义直接返回undefined即不生成引用若检测到递归引用目标路径是当前路径的前缀打印警告并回退为any。seen类似none但递归场景直接输出any而不是undefined。引用策略与 AI SDK 的集成方式密切相关在 schema.ts 的zod3Schema中zod3ToJsonSchema(zodSchema, { $refStrategy: useReferences ? root : none })——useReferences默认false因为谷歌等提供商的 OpenAPI 转换不支持$ref引用源码注释也明确写了这一原因。高级扩展点override 与 postProcess模块提供了两个强大的自定义钩子其用法直接来自 zod3-to-json-schema.test.ts 中的“readme example”测试用例override在parseDef开头被调用见 parse-def.ts可对特定路径的 def 完全接管解析。测试中的示例是根据refs.currentPath.join(/)判断路径把#/properties/overrideThis覆盖为{ type: integer }对#/properties/removeThis返回undefined使其从结果中消失同时 required 数组也会自动剔除该属性其余情况必须返回ignoreOverride符号表示“交给默认解析器”。zod3ToJsonSchema( z.object({ ignoreThis: z.string(), overrideThis: z.string(), removeThis: z.string() }), { override: (def, refs) { const path refs.currentPath.join(/); if (path #/properties/overrideThis) return { type: integer }; if (path #/properties/removeThis) return undefined; return ignoreOverride; // 不要随意返回 undefined否则会移除该属性 }, }, );postProcess在每次parseDef解析完成后回调见 parse-def.ts可以对已生成的 schema 做统一加工。测试中的示例是结合jsonDescription工具定义在 options.ts把z.string().describe(JSON.stringify({...}))中序列化的 JSON 描述展开合并进 schema 节点从而让title、description、examples等字段进入产物const postProcess: PostProcessCallback (jsonSchema, def, refs) jsonDescription(jsonSchema, def, refs);ignoreOverride符号与OverrideCallback/PostProcessCallback的类型签名都定义在 options.ts。在 AI SDK 中的实际集成与 Zod v4 共存zod3ToJsonSchema的消费方是 packages/provider-utils/src/schema.ts这是 AI SDK 统一 schema 抽象的核心zodSchemaschema.ts根据isZod4Schema(zodSchema)通过_zod in zodSchema判断见 schema.ts自动分派——Zod 4 schema 走zod4Schema使用 Zod 4 自带的toJSONSchemaZod 3 schema 走zod3Schema即本文的zod3ToJsonSchema。这正回应了 README 开头“既要支持 zod4 又不想引入双版本依赖”的设计初衷。zod3Schemaschema.ts把zod3ToJsonSchema的结果包装成Schema对象jsonSchema采用惰性创建jsonSchema(() ...)只有真正需要时才执行转换降低库的启动开销validate则委托给zodSchema.safeParseAsync。lazySchemaschema.ts对延迟创建的 schema 做结果缓存避免重复初始化。asSchemaschema.ts统一把FlexibleSchema原生 Zod、Standard Schema、自定义 Schema 或惰性函数归一为内部SchemaZod 供应商的 Standard Schema 会被路由到zodSchema分支。也就是说最终用户在使用 AI SDK 的tool({ inputSchema: z.object({...}) })时如果传入的是 Zod v3 schema背后实际执行的正是zod3ToJsonSchema它生成的 draft-07 JSON Schema 会被透传给各模型提供商用于工具参数解析与结构化输出。测试与验证方式模块自带完善的 vitest 测试覆盖除主测试 zod3-to-json-schema.test.ts871 行覆盖 override、postProcess、$ref 策略等外parsers/目录下几乎每个解析器都有对应的*.test.ts如 object.test.ts、string.test.ts、union.test.ts另有 parse-def.test.ts 与 refs.test.ts 覆盖核心机制。可在仓库根目录运行以下命令执行pnpm --filter ai-sdk/provider-utils test或单独运行 Node 环境的测试pnpm --filter ai-sdk/provider-utils test:node许可与归属该子目录代码以 ISC 协议发布见 LICENSE版权归 Stefan Terdell2020与 Vercel Inc.2025所有允许无偿使用、复制、修改与分发但需保留版权声明与许可文本。这与仓库整体 Apache-2.0 的许可不同fork 或提取该模块时需单独遵守 ISC 条款。小结zod3-to-json-schema是 AI SDK 为化解 Zod v3/v4 依赖冲突而内置的 JSON Schema 转换器它完整继承了上游zod-to-json-schema的类型覆盖与配置体系支持 30 余种 Zod 类型的递归转换、四种$ref策略、override/postProcess扩展钩子并通过schema.ts与 Zod 4 的toJSONSchema按需分流。理解它的选项语义与转换规则能帮助你在使用 AI SDK 工具调用与结构化输出时精准预判模型收到的 schema 形态并借助override等钩子输出完全可控的工具参数定义。【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →