AI SDK 集成 Baseten Provider:语言模型与嵌入模型的完整接入指南
AI SDK 集成 Baseten Provider:语言模型与嵌入模型的完整接入指南
导读
本文介绍 AI SDK(The AI Toolkit for TypeScript)官方提供的 Baseten Provider——@ai-sdk/baseten,它让开发者能够通过统一的 AI SDK 接口调用 Baseten 推理平台上的前沿开源模型(如 DeepSeek、Kimi、Qwen、GLM 等),同时支持文本生成与嵌入向量两种能力。读完本文,你将掌握该 Provider 的安装、默认实例与自定义实例的创建、generateText/streamText 文本生成、专用部署的 modelURL 接入、嵌入模型调用,以及可选原生性能客户端的进阶用法,并能从源码层面理解其基于 OpenAI 兼容协议实现的底层原理。
概览:Baseten Provider 是什么
Baseten 是一个推理平台,用于通过 API 对外提供前沿级、企业级开源 AI 模型的托管服务。@ai-sdk/baseten 是 AI SDK 的官方 Provider 包,为 Baseten 平台提供语言模型(language model)与嵌入模型(embedding model)支持,即同时覆盖文本生成与向量化两类场景。
从源码结构看,该 Provider 没有从零实现协议,而是构建在 @ai-sdk/openai-compatible 之上:在 baseten-provider.ts 中,聊天模型实例化自 OpenAICompatibleChatLanguageModel,嵌入模型实例化自 OpenAICompatibleEmbeddingModel,其依赖关系也在 package.json 中体现(依赖 @ai-sdk/openai-compatible、@ai-sdk/provider、@ai-sdk/provider-utils)。这意味着所有 Baseten 请求都走 OpenAI 兼容协议,Provider 层主要负责任何 URL 拼接、鉴权头、错误结构与批处理策略。
安装
Baseten Provider 位于 @ai-sdk/baseten 模块,通过 npm 安装:
npm i @ai-sdk/baseten
该包以 ESM 方式发布("type": "module",入口为 dist/index.js),要求 Node.js >= 22,并声明 zod 为 peerDependency(^3.25.76 || ^4.1.8)。安装后建议在环境中配置 Baseten API Key:
export BASETEN_API_KEY=your_api_key_here
Provider 实例
默认实例
可以直接从 @ai-sdk/baseten 导入默认的 provider 实例 baseten:
import { baseten } from '@ai-sdk/baseten';
该默认实例由源码底部的 export const baseten = createBaseten(); 创建(见 baseten-provider.ts),使用全部默认配置。
自定义实例
如果默认配置不满足需求(例如要接入专用模型部署),可以通过 createBaseten 创建带自定义设置的实例:
import { createBaseten } from '@ai-sdk/baseten';
const baseten = createBaseten({
apiKey: process.env.BASETEN_API_KEY ?? '',
});
可选配置项
createBaseten 接受 BasetenProviderSettings 对象,源码接口定义于 baseten-provider.ts,各配置项如下:
| 配置项 | 类型 | 说明 |
|---|---|---|
apiKey |
string |
Baseten API Key,通过 Authorization: Bearer 头发送。默认读取 BASETEN_API_KEY 环境变量 |
baseURL |
string |
API 调用地址前缀,可用于代理服务器等场景。默认值为 https://inference.baseten.co/v1 |
modelURL |
string |
专用模型(聊天或嵌入)的 URL。未提供时走默认 Model APIs |
headers |
Record<string, string> |
附加的自定义请求头,会与鉴权头合并发送 |
fetch |
(input, init) => Promise<Response> |
自定义 fetch 实现,可拦截请求或用于测试 |
performanceClient |
PerformanceClient 构造函数 |
可选接入 Baseten 原生性能客户端(仅嵌入模型),见下文 |
从源码看,baseURL 会经过 withoutTrailingSlash 处理去除末尾斜杠;请求头由 withUserAgentSuffix 附加 ai-sdk/baseten/${VERSION} 的 User-Agent 标识,版本号由构建期注入(见 version.ts)。这些行为均有对应单元测试验证(见 baseten-provider.unit.test.ts 的 "Headers" 与 "URL construction" 分组)。
使用语言模型(Model APIs)
Baseten 提供托管的 Model APIs,可以直接用模型 ID 选中模型。Provider 本身可被直接调用(baseten(modelId)),也暴露了 chatModel(modelId) 与 languageModel(modelId) 两个等价的工厂方法。
源码中定义的内置聊天模型 ID 列表见 baseten-chat-options.ts,当前支持(Model APIs 之外的自有模型也可通过 string & {} 放宽类型传入):
deepseek-ai/DeepSeek-R1-0528deepseek-ai/DeepSeek-V3-0324deepseek-ai/DeepSeek-V3.1moonshotai/Kimi-K2-Instruct-0905moonshotai/Kimi-K2-ThinkingQwen/Qwen3-235B-A22B-Instruct-2507Qwen/Qwen3-Coder-480B-A35B-Instructopenai/gpt-oss-120bzai-org/GLM-4.6zai-org/GLM-4.7
文本生成示例
使用 generateText 生成文本:
import { baseten } from '@ai-sdk/baseten';
import { generateText } from 'ai';
const { text } = await generateText({
model: baseten('deepseek-ai/DeepSeek-V3-0324'),
prompt: 'What is the meaning of life? Answer in one sentence.',
});
Baseten 语言模型同样可用于 streamText 流式生成(相关核心概念可参考仓库中的 AI SDK Core 文档)。
源码层面的两个关键开关
在 baseten-provider.ts 中,聊天模型统一配置了 includeUsage: true 与 supportsStructuredOutputs: true:
includeUsage:OpenAI 兼容服务默认不会在流式响应中附带 usage(token 用量),除非请求携带stream_options.include_usage。该开关保证流式输出也能统计用量。supportsStructuredOutputs:缺少该开关时,OpenAI 兼容层会把response_format: json_schema改写为json_object,静默丢弃 schema、name 与 strict 标志。开启后结构化输出(JSON Schema)可原样透传。
这两个开关对默认 Model APIs 路径和专用 /sync/v1 部署路径均生效,由测试分别验证(见 baseten-provider.unit.test.ts 的 includeUsage 与 supportsStructuredOutputs 分组)。
接入专用模型部署(Dedicated Models)
除了托管的 Model APIs,Baseten 还支持通过专用模型 URL 接入自定义部署的聊天模型与嵌入模型。此时需要在创建 provider 时指定 modelURL。
OpenAI 兼容端点(/sync/v1)
对使用 Baseten OpenAI 兼容端点部署的模型:
import { createBaseten } from '@ai-sdk/baseten';
import { generateText } from 'ai';
const baseten = createBaseten({
modelURL: 'https://model-{MODEL_ID}.api.baseten.co/sync/v1',
});
// 指定 modelURL 后无需再传 modelId
const model = baseten();
const { text } = await generateText({
model: model,
prompt: 'Say hello from a Baseten chat model!',
});
从源码看,当 modelURL 包含 /sync/v1 时,provider 会以占位 modelId 'placeholder' 构造模型,实际请求 URL 由 modelURL + path 拼接而成,例如 .../sync/v1/chat/completions(测试见 baseten-provider.unit.test.ts)。
/predict 端点(不支持聊天)
/predict 端点目前不支持聊天模型,聊天功能必须使用 /sync/v1 端点。若传入包含 /predict 的 modelURL 并调用聊天模型,源码会抛出:
Not supported. You must use a /sync/v1 endpoint for chat models.
使用嵌入模型(Embedding Models)
通过 .embeddingModel() 工厂方法可创建调用 Baseten 嵌入 API 的模型。Baseten Embeddings Inference(BEI)部署天然兼容 OpenAI 协议,因此嵌入模型默认走普通 HTTP,无需额外依赖。
重要:嵌入模型必须使用专用部署并配置
modelURL。与聊天模型不同,嵌入模型无法使用 Baseten 默认的 Model APIs。
import { createBaseten } from '@ai-sdk/baseten';
import { embed, embedMany } from 'ai';
const baseten = createBaseten({
modelURL: 'https://model-{MODEL_ID}.api.baseten.co/sync',
});
const embeddingModel = baseten.embeddingModel();
// 单个嵌入
const { embedding } = await embed({
model: embeddingModel,
value: 'sunny day at the beach',
});
// 批量嵌入
const { embeddings } = await embedMany({
model: embeddingModel,
values: [
'sunny day at the beach',
'rainy afternoon in the city',
'snowy mountain peak',
],
});
端点的 URL 拼接规则
源码中嵌入模型的 URL 构造包含一处细节处理(baseten-provider.ts 的 getCommonModelConfig):
- 传入
/sync端点(不含/v1):自动追加/v1,最终请求形如.../sync/v1/embeddings; - 传入
/sync/v1端点:直接拼接,不会重复/v1; - 传入
/predict端点:不支持,抛出Not supported. You must use a /sync or /sync/v1 endpoint for embeddings.
批量上限与自动分片
每次请求最多发送 128 个值(源码常量 MAX_EMBEDDINGS_PER_CALL = 128,对应 Baseten 服务端 413 batch size N > maximum allowed batch size 128 的限制)。embedMany 会将更大的输入按此大小自动分片并并行发送,因此你可以放心传入任意数量的值。对应的测试在 baseten-embedding-model.test.ts 中验证了 128 个值可正常通过、129 个值直接调用 doEmbed 会抛出 TooManyEmbeddingValuesForCallError。
实际请求体遵循 OpenAI 嵌入接口形状(input、model、encoding_format: 'float'),token 用量从响应中的 prompt_tokens 提取(见 baseten-embedding-model.test.ts)。
可选:原生性能客户端(Native Performance Client)
Baseten 额外发布了 @basetenlabs/performance-client 原生客户端,它能在你部署已有的服务端动态批处理之上,再叠加客户端批处理(client-side batching)与请求对冲(request hedging)。
需要特别注意的是:该客户端默认不安装。因为它是原生插件(native addon),在边缘运行时(edge runtime)中无法加载,打包工具也无法解析其平台二进制文件。
如需使用,需自行安装并把构造函数传入 provider:
npm i @basetenlabs/performance-client
import { createBaseten } from '@ai-sdk/baseten';
import { PerformanceClient } from '@basetenlabs/performance-client';
const baseten = createBaseten({
modelURL:
'https://model-{MODEL_ID}.api.baseten.co/environments/production/sync',
performanceClient: PerformanceClient,
});
接入后,批处理交由客户端自行处理:maxEmbeddingsPerCall 被设为 Infinity,embedMany 将全部值作为一次调用交给性能客户端,而不再按 128 分片。源码通过结构类型(structural typing)声明了该客户端的最小接口(embed(input, model) 方法),使其不进入包的依赖与类型图;传给客户端的 baseUrl 会去掉 /v1 后缀(因为客户端会自行追加 /v1)。相关行为均有单元测试覆盖(见 baseten-provider.unit.test.ts 的 opt-in performance client path 分组)。
错误处理
Provider 内置了对常见 API 错误的处理逻辑。先看基本用法:
import { baseten } from '@ai-sdk/baseten';
import { generateText } from 'ai';
try {
const { text } = await generateText({
model: baseten('moonshotai/Kimi-K2-Instruct-0905'),
prompt: 'Hello, world!',
});
} catch (error) {
console.error('Baseten API error:', error.message);
}
双形态错误信封的解析
源码中值得注意的实现细节是:Baseten 会返回两种不同的错误信封——Model APIs 返回纯字符串(如 {"error":"please check the model you provided"}),而专用部署透传其服务端的 OpenAI 形态对象。因此 baseten-provider.ts 中的 basetenErrorSchema 使用 z.union 同时接受两种形态,errorToMessage 则按类型提取可读消息。若两种形态都无法解析,错误消息会退化为 HTTP 原因短语(HTTP/1.1 下为 "Not Found",HTTP/2 下可能为空)。该行为在单元测试的 errorStructure 分组与嵌入模型的 HTTP 测试中均有覆盖(见 baseten-provider.unit.test.ts、baseten-embedding-model.test.ts)。
常见错误场景
// 1. 嵌入模型必须配置 modelURL
try {
baseten.embeddingModel();
} catch (error) {
// Error: "No model URL provided for embeddings. Please set modelURL option for embeddings."
}
// 2. 聊天模型不支持 /predict 端点
try {
const baseten = createBaseten({
modelURL:
'https://model-{MODEL_ID}.api.baseten.co/environments/production/predict',
});
baseten(); // 会抛出错误
} catch (error) {
// Error: "Not supported. You must use a /sync/v1 endpoint for chat models."
}
// 3. /sync/v1 端点对嵌入模型可用
const baseten = createBaseten({
modelURL:
'https://model-{MODEL_ID}.api.baseten.co/environments/production/sync/v1',
});
const embeddingModel = baseten.embeddingModel(); // 正常工作
// 4. 嵌入模型不支持 /predict 端点
try {
const baseten = createBaseten({
modelURL:
'https://model-{MODEL_ID}.api.baseten.co/environments/production/predict',
});
baseten.embeddingModel(); // 会抛出错误
} catch (error) {
// Error: "Not supported. You must use a /sync or /sync/v1 endpoint for embeddings."
}
// 5. 图像模型不受支持
try {
baseten.imageModel('test-model');
} catch (error) {
// Error: NoSuchModelError for imageModel
}
从源码看,图像模型通过 provider.imageModel 直接抛出 NoSuchModelError(见 baseten-provider.ts 与 baseten-provider.unit.test.ts 的 imageModel 分组),Provider 明确只覆盖文本与嵌入两类能力。
与 OpenAI 兼容层的关系(原理小结)
Baseten Provider 是 AI SDK 生态中"协议复用"思路的典型代表:它没有自建传输层,而是把 Baseten 的 Model APIs 与专用部署统一建模为 OpenAI 兼容端点,从而直接复用 @ai-sdk/openai-compatible 的聊天/嵌入实现。Provider 自身的核心工作集中在四件事上:
- 端点归一化:默认
baseURL与专用modelURL的拼接、/sync→/sync/v1的自动补全; - 鉴权与标识:
BASETEN_API_KEY加载、Bearer头与ai-sdk/baseten/<version>User-Agent; - 能力开关:
includeUsage、supportsStructuredOutputs等针对 Baseten 服务特性的适配; - 错误语义化:兼容字符串/对象两种错误信封并提取可读消息。
需要进一步研究实现时,可阅读 baseten-provider.ts(Provider 主实现)、baseten-provider.unit.test.ts(配置与 URL 构造测试)、baseten-embedding-model.test.ts(真实 HTTP 嵌入链路测试),以及包的出口 index.ts(对外导出的类型与工厂函数)。