AI SDK 的 @ai-sdk/openai-compatible 包:从 ChangeLog 看 OpenAI 兼容 Provider 的演进与技术实现
2026/9/12 12:48:15 网站建设 项目流程

AI SDK 的 @ai-sdk/openai-compatible 包:从 ChangeLog 看 OpenAI 兼容 Provider 的演进与技术实现

【免费下载链接】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

本文以当前仓库中 packages/openai-compatible/CHANGELOG.md 为主线,系统梳理@ai-sdk/openai-compatible包的核心能力、版本演进与底层实现:它如何以一套轻量的createOpenAICompatible工厂方法对接所有遵循 OpenAI API 形态的第三方服务,以及流式工具调用、token 用量解析、推理流(reasoning)、结构化输出等关键特性在源码中是如何落地的。读完本文,你将掌握该包的配置全貌、常用 providerOptions,并能从 CHANGELOG 与源码的对应关系出发,理解 OpenAI 兼容生态中常见的兼容性坑及其修复思路。

一、包定位:AI SDK 中的 OpenAI 兼容 Provider 基座

@ai-sdk/openai-compatible是整个 AI SDK monorepo(本仓库packages/openai-compatible/)中承担"OpenAI 兼容协议适配"职责的基础包。其定位在 README 中有明确说明:

  • 它为实现任何暴露 OpenAI 兼容 API 的 Provider提供统一的基座与工厂方法;
  • 与功能更丰富、包含 OpenAI 专属实验与遗留特性的 @ai-sdk/openai 相比,本包更轻量,聚焦核心的 OpenAI 兼容能力;
  • 社区中大量基于 OpenAI 协议二次封装的服务(如各类代理网关、自建推理服务、兼容层)都可以通过它快速接入。

从 package.json 可以看到,包的运行时依赖仅有@ai-sdk/provider@ai-sdk/provider-utils两个 workspace 包,peerDependencies 为zod ^3.25.76 || ^4.1.8,运行时要求 Node.js >= 22(CHANGELOG 3.0.0 中7fc6bd6明确:最低支持 Node.js 22,支持版本为 22、24、26)。其构建产物为 ESM-only("type": "module"),CHANGELOG 3.0.0 的ef992f8变更即移除了所有 CommonJS 导出。

包的源码结构(src 目录)清晰地划分为五类模型能力:

src/ ├── chat/ # Chat 语言模型(OpenAICompatibleChatLanguageModel) ├── completion/ # Completion 语言模型(OpenAICompatibleCompletionLanguageModel) ├── embedding/ # Embedding 模型(OpenAICompatibleEmbeddingModel) ├── image/ # 图像生成模型(OpenAICompatibleImageModel) ├── utils/ # providerOptions key 的 camelCase 转换等工具 ├── openai-compatible-provider.ts # createOpenAICompatible 工厂 └── openai-compatible-error.ts # 错误结构解析

这一架构在 CHANGELOG 1.0.10(7ca3aee:"move models into folders")中成形,并在后续版本中持续演进。

二、快速上手:createOpenAICompatible 工厂与四类模型

2.1 基础用法

按 README 的标准示例,安装并创建 Provider 实例:

npm i @ai-sdk/openai-compatible
import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { generateText } from 'ai'; const { text } = await generateText({ model: createOpenAICompatible({ baseURL: 'https://api.example.com/v1', name: 'example', apiKey: process.env.MY_API_KEY, }).chatModel('meta-llama/Llama-3-70b-chat-hf'), prompt: 'Write a vegetarian lasagna recipe for 4 people.', });

也可以通过headers自定义鉴权方式(例如不使用apiKey选项而自行拼接Authorization):

import { createOpenAICompatible } from '@ai-sdk/openai-compatible'; import { generateText } from 'ai'; const { text } = await generateText({ model: createOpenAICompatible({ baseURL: 'https://api.example.com/v1', name: 'example', headers: { Authorization: `Bearer ${process.env.MY_API_KEY}`, }, }).chatModel('meta-llama/Llama-3-70b-chat-hf'), prompt: 'Write a vegetarian lasagna recipe for 4 people.', });

2.2 工厂方法产出的四类模型

从 openai-compatible-provider.ts 的OpenAICompatibleProvider接口可见,一个 Provider 实例对外暴露以下模型创建方法:

方法模型类型说明
chatModel(modelId)/ 直接调用(modelId)LanguageModelV4聊天补全模型,走/chat/completions语义
completionModel(modelId)LanguageModelV4文本补全模型
embeddingModel(modelId)EmbeddingModelV4向量嵌入模型(textEmbeddingModel为已废弃别名)
imageModel(modelId)ImageModelV4图像生成模型

createOpenAICompatible支持四个泛型参数,分别约束上述四类模型的 ID,从而在调用chatModel等时获得模型 ID 的自动补全(README 中给出了完整示例):

type ExampleChatModelIds = | 'meta-llama/Llama-3-70b-chat-hf' | (string & {}); const model = createOpenAICompatible< ExampleChatModelIds, string, // completion 模型 ID string, // embedding 模型 ID string // image 模型 ID >({ baseURL: 'https://api.example.com/v1', name: 'example', apiKey: process.env.MY_API_KEY, });

从源码看,createOpenAICompatible内部做了几件关键的统一处理(openai-compatible-provider.ts):

  • baseURL会经withoutTrailingSlash去掉尾部斜杠;
  • 请求头统一合并apiKey(自动加Bearer前缀)与自定义headers,并用withUserAgentSuffix附加ai-sdk/openai-compatible/${VERSION}的 User-Agent(对应 CHANGELOG 1.0.17 的3aed04c变更);
  • 支持queryParams向请求 URL 追加自定义查询参数(对应 CHANGELOG 0.0.17 的ae57beb变更);
  • specificationVersion = 'v4',即实现的是 AI SDK Provider v4 规范。

2.3 Provider 配置项全表

OpenAICompatibleProviderSettings 定义了完整的配置项,下表汇总各字段的作用与来源:

配置项类型说明引入版本(CHANGELOG)
baseURLstring(必填)API 基础地址,如https://api.example.com/v10.0.1
namestring(必填)Provider 名称,用于 provider 元数据与 providerOptions 命名空间0.0.1
apiKeystring自动生成Authorization: Bearer <key>0.0.14(43b37f7
headersRecord<string, string>自定义请求头0.0.1
queryParamsRecord<string, string>追加到请求 URL 的查询参数0.0.17(ae57beb
fetchFetchFunction自定义 fetch 实现(测试、拦截中间件)0.0.1
includeUsageboolean流式响应中是否包含 usage 信息1.0.0(737f1e2
supportsStructuredOutputsbooleanChat 模型是否支持结构化输出(JSON Schema 约束解码)1.0.18(28363da
transformRequestBodyfunction发送前转换请求体,适用于代理类 Provider2.0.12(78a133a
metadataExtractorMetadataExtractor从响应中提取 Provider 专属元数据0.1.2(ed012d2)、2.0.19(6900916
supportedUrlsfunctionChat 模型支持的 URL 列表由源码结构推断的扩展点
convertUsagefunction自定义 token 用量转换器,适配记账语义不同的 Provider由源码结构推断的扩展点

三、3.0.0 大版本:面向 v7 的破坏性变更

CHANGELOG 中 3.0.0 是内容最丰富的一个版本节点,其中的 Major Changes 定义了 v7 时代的整体方向:

3.1 ESM-only 与 Node 版本门槛

  • ef992f8:所有包移除 CommonJS 导出,全面转为 ESM-only。使用require()的消费者必须切换到 ESMimport语法;
  • 7fc6bd6:最低 Node.js 版本提升到 22,支持 22、24、26。

3.2 顶层 reasoning 参数与 Provider 规范升级

  • 74d520f:各 Provider 迁移到新的顶层reasoning参数;
  • 8f3e1da:openai-compat 的 v3 规范升级到 v4;
  • c29a26f:支持 Provider 引用(provider references)与按 Provider 能力上传文件;
  • 04e9009:统一 Provider 实现的代码模式,重命名了部分导出符号(旧名称通过 deprecated alias 继续可用)。

3.3 工作流(Workflow)序列化支持

b3976a2为所有 Provider 模型增加了跨工作流步骤边界的序列化能力:

  • @ai-sdk/provider-utils新增serializeModel()助手,只提取模型实例中可序列化的属性(过滤函数及包含函数的对象);
  • 所有 Provider 模型类新增静态方法WORKFLOW_SERIALIZEWORKFLOW_DESERIALIZE
  • Provider 配置类型中headers变为可选——当模型从工作流步骤边界反序列化、鉴权由外部单独提供时,可以省略headers

这一设计在 openai-compatible-chat-language-model.ts 中有直接实现:OpenAICompatibleChatLanguageModel通过serializeModelOptions序列化modelIdconfig

四、流式工具调用:StreamingToolCallTracker 与安全修复演进

流式工具调用是 OpenAI 兼容生态中最容易出现兼容性问题的环节之一,CHANGELOG 围绕它有多轮修复,均可在 openai-compatible-chat-language-model.ts 中找到对应实现(StreamingToolCallTracker在约第 470、548、697、718 行处被实例化、注册与flush)。

4.1 防止"可解析的部分 JSON"提前终结工具调用(安全修复)

3.0.6ac306ed)与3.0.0中的45b3d76记录了一个关键的安全修复:

流式工具调用的参数此前使用isParsableJson()作为"是否完成"的启发式判断。如果累积的部分 JSON 恰好是合法 JSON(但它可能只是更长参数串的前缀),工具调用就会被提前执行——用不完整的参数执行。

修复方案:工具调用的终结(finalize)只在flush()中、流被完全消费后发生。f807e45进一步将StreamingToolCallTracker抽取到@ai-sdk/provider-utils,在 OpenAI 兼容 Provider 之间去重流式工具调用处理逻辑,并确保所有 Provider 在流 flush 时终结未完成的工具调用。

4.2 工具调用 delta 的缓冲与索引兼容

  • 3.0.0ab81968):缓冲工具调用 delta,直到function.name到达后再处理——因为部分 Provider 会先发id/index再发name
  • 3.0.231bec07d):修复了非零、非连续、复用或缺失索引的流式工具调用;
  • 3.0.32e6087c9):处理空字符串的工具调用 ID(toolCallId);
  • 3.0.44e5a22f0):当 delta 包含空的工具调用数组时,保持 reasoning 流的连续性;
  • 3.0.55c5c0f5):为转录模型(如 OpenAIgpt-realtime-whisper、xAI WebSocket STT)增加实验性流式转录支持。

4.3 流式语义细节

  • 2.0.878fcb18):流式输出中先发reasoning-end再发text-start
  • 3.0.09f1e1ba):接受 OpenAI 兼容 Provider 流式 delta 块中的空字符串role
  • 1.0.8515c891):修复某些场景下tool-input-start重复发送的问题;
  • 1.0.2b499112):过滤空 content 以保证 chunk 顺序正确。

五、Token 用量解析:usage.raw、宽松 Schema 与推理 token 归零

5.1 从非标准响应中宽松解析 usage

OpenAI 兼容生态的 Provider 在usage字段上差异极大,CHANGELOG 对此有持续投入:

  • 2.0.279e490ad)与2.0.5d54c380):将 usage 相关 Schema 从z.object改为z.looseObject,以兼容非标准的 OpenAI 兼容 API;
  • 1.0.45f4c71f/da314cd):当顶层没有usage时,回退到在choices中查找 usage;
  • 3.0.3186892f3):保留未映射的 usage 字段到usage.raw——将嵌套的prompt_tokens_detailscompletion_tokens_details也改为宽松解析。此前 Provider 在这些嵌套对象中返回的区分性信息(如audio_tokensimage_tokenstext_tokens)会被丢弃,且 completion 模型的 usage Schema 此前一直是严格模式。该变更只影响usage.raw,映射后的 token 计数不受影响。

5.2 默认 usage 转换的源码实现

默认的转换逻辑在 convert-openai-compatible-chat-usage.ts:

export function convertOpenAICompatibleChatUsage(usage) { if (usage == null) return createNullLanguageModelUsage(); const promptTokens = usage.prompt_tokens ?? 0; const completionTokens = usage.completion_tokens ?? 0; const cacheReadTokens = usage.prompt_tokens_details?.cached_tokens ?? 0; const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? 0; return { inputTokens: { total: promptTokens, noCache: promptTokens - cacheReadTokens, cacheRead: cacheReadTokens, cacheWrite: undefined, }, outputTokens: { total: completionTokens, text: Math.max(0, completionTokens - reasoningTokens), reasoning: reasoningTokens, }, raw: usage, }; }

两个值得注意的细节与 CHANGELOG 直接对应:

  • text: Math.max(0, completionTokens - reasoningTokens)3.0.2883e6510)的修复:当 Provider 报告的completion_tokens_details.reasoning_tokens大于completion_tokens时(Baseten 托管推理模型在推理中途命中长度上限时会出现),把outputTokens.text钳制在 0,文本部分的完成 token 数不可能为负,而totalreasoning保持 Provider 原始报告值;
  • raw: usage保留完整原始结构,配合 3.0.31 的宽松解析,确保 Provider 特有信息不丢失。

5.3 其他 usage 相关变更

  • 0.1.10a699f1):新增推理 token 支持;
  • 0.2.5d186cca):增加额外 token 用量指标;
  • 1.0.0cf8280e):修复 xAI 流式返回 NaN 的问题,改为返回真实 usage;
  • 3.0.205fc7da5/93b2acd):将空 usage 的创建与响应元数据转换集中到 provider-utils;
  • 3.0.3499989ba):为图像生成报告 token 用量。

六、推理流(Reasoning)与 thought 兼容

推理类模型是 OpenAI 兼容 Provider 的重头戏,CHANGELOG 记录了以下能力演进:

  • 0.1.10a699f1):推理 token 支持;
  • 1.0.3a0934f8):除reasoning_content外,也支持在reasoning字段中查找推理内容;
  • 2.0.7cd7bb0e):为 Google 模型增加thoughtSignature处理(Gemini 的思考签名);
  • 2.0.20a1a0175):多轮工具调用时,在助手消息中包含reasoning_content——确保携带推理内容的对话上下文在后续轮次不丢失;
  • 3.0.36ece5bdb):当顶层 reasoning 被禁用时,发送reasoning_effort: "none"
  • 3.0.322f77de8):为自定义命名的 OpenAI 兼容 Provider 保留 Gemini thought 签名;
  • 1.0.14818f021):避免请求体中出现冗余的reasoningEffort字段(统一使用reasoning_effort);
  • 1.0.042e32b0/7b069ed):新增reasoningEffortprovider option,且允许任意字符串值。

6.1 Chat 模型的 providerOptions

openai-compatible-chat-language-model-options.ts 定义了 Chat 模型可用的 providerOptions(通过providerOptions.openaiCompatible传入):

选项类型默认值说明
userstring终端用户唯一标识,帮助 Provider 监控与防滥用
reasoningEffortstringmedium推理模型的推理强度
textVerbositystringmedium生成文本的详细程度(2.0.0 的b689220引入)
strictJsonSchemabooleantrue是否使用严格 JSON Schema 校验(约束解码保证 Schema 合规),仅在 Provider 支持结构化输出且提供了 Schema 时生效(2.0.9 的bc02a3c引入)

6.2 providerOptions 的 key 命名演进

CHANGELOG 记录了 providerOptions key 从 kebab-case 到 camelCase 的完整迁移:

  • 2.0.157116ef3):统一使用 camelCase 的openaiCompatiblekey,kebab-case 的openai-compatible废弃但仍支持(带 console 警告);
  • 3.0.0-beta.19008271d):使用 kebab-case 时发出警告;
  • 3.0.0816ff67):在 chat 与 completion 模型中同时尊重 camelCase 的 providerOptions key;
  • 2.0.1678555ad):接受非 OpenAI 的 Provider 选项。

七、图像模型与多模态内容

7.1 图像生成的 providerOptions

openai-compatible-image-model-options.ts 定义了图像模型的公共 providerOptions,使用z.looseObject以便额外 Provider 专属选项透传:

选项类型说明
sizestring生成图像尺寸,取值范围取决于 Provider 与模型
qualitystring生成图像质量
output_formatstring输出文件格式
output_compressionnumber(0–100)JPEG/WebP 压缩级别
backgroundstring背景行为

3.0.138b52503)为图像模型请求增加了可扩展的providerOptions类型,并停止强制发送response_format

7.2 图像设置迁移(1.0.0 破坏性变更)

1.0.0 的516be5b将图像模型设置移入 generate options,maxImagesPerCall直接传给generateImage(),其余设置通过providerOptions传入。CHANGELOG 给出了迁移前后对照:

// 迁移前:设置挂在模型实例上 await generateImage({ model: luma.image('photon-flash-1', { maxImagesPerCall: 5, pollIntervalMillis: 500, }), prompt, n: 10, }); // 迁移后:maxImagesPerCall 直接传入,其余走 providerOptions await generateImage({ model: luma.image('photon-flash-1'), prompt, n: 10, maxImagesPerCall: 5, providerOptions: { luma: { pollIntervalMillis: 5 }, }, });

7.3 多模态内容转换

  • 3.0.357dd9ec3):将视频文件 part 转换为video_urlcontent part;
  • 1.0.58f8a521):使用convertToBase64Uint8Array图像 part 转为合法的 data URL,同时保留 mediaType 归一化与 URL 直通;
  • 3.0.4123eb659):数组式 chat completion content 支持文本与思考 part,并忽略未知 part 类型;
  • 2.0.141612a57):支持一次传递多种文件类型;
  • 2.0.3389caf28):解码 base64 字符串数据。

八、错误处理与兼容性细节

8.1 流式与错误语义

  • 3.0.110b61267):保留 chat completion SSE 流中的结构化错误数据;
  • 3.0.46ccb8952):当 chat completion 的 choices 为空时,返回 AI SDK 错误(而非静默吞掉);
  • 3.0.33d68139c):将截断的 chat 流报告为错误;
  • 3.0.06fd51c0):在getErrorMessage中保留错误类型前缀。

错误结构由 openai-compatible-error.ts 提供,OpenAICompatibleErrorDataProviderErrorStructure也通过 src/index.ts 对外导出,便于自定义错误解析。

8.2 消息转换细节

  • 3.0.0cd9c311):仅对带工具调用的助手消息发送content: null
  • 3.0.0-beta.31bfb756d):对纯工具助手消息发送content: null而非空字符串;
  • 0.0.1270003b8):允许通过 metadata 扩展消息;
  • 0.0.3a9a19cb):防止发送重复的工具调用。

8.3 其他值得注意的变更

  • 0.0.86faab13)引入、1.0.0(6db02c9)移除的模拟流式设置(simulateStreaming);
  • 1.0.0b9a6121):将tool_call类型 Schema 改为 nullish,允许 Provider 不指定 function 类型(1b101e1);
  • 1.0.0737f1e2):createOpenAICompatible的可选includeUsage选项;
  • 0.1.7f2c6c37):在generateText/streamText中支持 providerOptions;
  • 0.1.13e1d3d42):在generateTextgenerateObject中暴露原始响应体;
  • 0.0.136564812):导出更多自定义扩展点;
  • 2.0.03bd2689):扩展 token 用量模型;0c4822d:新增EmbeddingModelV3(2.0.0 的8d9e8adtextEmbeddingModel泛型化调用改为embeddingModel)。

九、从 CHANGELOG 到工程实践的三点启示

综合来看,这份 CHANGELOG 本身就是一份难得的"OpenAI 兼容协议踩坑手册",可以提炼出三条对开发者有直接价值的经验:

  1. 兼容性问题的重灾区是流式工具调用:参数缓冲(等待function.name)、索引乱序(非零/非连续/复用)、部分 JSON 提前终结——这些问题在本包中被系统性修复,并最终收敛为StreamingToolCallTracker统一处理。如果你在自研兼容 Provider,应优先对齐这套行为。
  2. usage 解析必须"宽松进、严格出"z.looseObjectchoices回退、usage.raw保留原始字段,共同保证非标准 Provider 的 token 信息不丢失,同时映射后的inputTokens/outputTokens语义(cacheReadreasoningtext)保持 AI SDK 的统一口径。
  3. 命名与规范要跟随 v7 大版本:ESM-only、Node 22+、顶层reasoning参数、embeddingModel命名、camelCase 的openaiCompatibleproviderOptions key——升级到 v3/v7 时需要重点检查这些破坏性变更点。

如果需要进一步探索实现细节,可以直接阅读 聊天模型实现、usage 转换、provider 工厂 以及对应的 测试用例,其中__fixtures__目录下还保留了 xAI、Anthropic 回退等真实 SSE 流样本,可作为理解协议细节的第一手资料。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询