agents/models/ai-sdk 是面向 Workers AI 与 AI Gateway 的 AI SDK ↗ 提供程序。createAI 返回完整的 ProviderV4,因此其模型可用于 AI SDK 接受模型的任何地方:generateText、streamText、工具、结构化输出以及 Think。
此提供程序接受两种模型。两种模型都通过 AI 绑定运行,也可以通过 HTTP 搭配账户 ID 和 API token使用:
// A string runs on env.AI.run.
ai("@cf/zai-org/glm-4.7-flash"); // Workers AI
ai("anthropic/claude-opus-5.5"); // AI Gateway catalog
ai("dynamic/support"); // AI Gateway dynamic route
// A vendor's own model object goes to AI Gateway's provider-native endpoint.
ai(anthropic("claude-opus-5-5"));字符串无需供应商软件包或供应商密钥。模型对象会保留供应商自己的请求构建器和解析器。
createAI 取代了 workers-ai-provider 和 ai-gateway-provider。对于 AI Search,请使用 ai-search-provider。
该提供程序需要 ai@^7 与 @ai-sdk/provider@^4。二者都是 agents 的可选 peer dependency:
npm i agents ai @ai-sdk/provideryarn add agents ai @ai-sdk/providerpnpm add agents ai @ai-sdk/providerbun add agents ai @ai-sdk/provider只有在传递供应商的模型对象时才添加其 AI SDK 提供程序,例如 @ai-sdk/anthropic 或 @ai-sdk/openai。目录 ID 无需供应商软件包。
将 AI 绑定添加到 Wrangler 配置:
{
"ai": {
"binding": "AI",
},
}[ai]
binding = "AI"要使用其他账户中的网关,或从 Worker 外部调用,请传递 accountId 和 apiToken,而不是 binding:
const ai = createAI({
accountId: "<ACCOUNT_ID>",
apiToken: env.CLOUDFLARE_API_TOKEN,
gateway: "my-gateway",
});调用方式和选项相同,网关仍默认使用 default。字符串会发送到 AI Gateway 的 REST API,其运行方式与 env.AI.run() 相同。模型对象会发送到 gateway.ai.cloudflare.com 上相应的供应商原生端点,并在 cf-aig-authorization 标头中携带 token。token 只会发送到这两个主机。
创建带有 Workers AI Read 权限的 API token以调用字符串模型;调用模型对象则需要 AI Gateway Run 权限。
传入 @cf/ ID。模型 ID 会根据 @cloudflare/workers-types 自动补全:
import { createAI } from "agents/models/ai-sdk";
import { generateText } from "ai";
export default {
async fetch(request, env) {
const ai = createAI({ binding: env.AI });
const { text } = await generateText({
model: ai("@cf/zai-org/glm-4.7-flash"),
prompt: "Say hello in three words",
});
return Response.json({ text });
},
};import { createAI } from "agents/models/ai-sdk";
import { generateText } from "ai";
export default {
async fetch(request: Request, env: Env) {
const ai = createAI({ binding: env.AI });
const { text } = await generateText({
model: ai("@cf/zai-org/glm-4.7-flash"),
prompt: "Say hello in three words",
});
return Response.json({ text });
},
};如果字符串不是 Workers AI ID、目录 ID 或动态路由,则会抛出 TypeError,并指出这三种格式。
传递模型目录中的 <author>/<model> ID。无需供应商软件包或密钥:
import { createAI } from "agents/models/ai-sdk";
import { generateText } from "ai";
export default {
async fetch(request, env) {
const ai = createAI({ binding: env.AI, id: "my-gateway" });
const { text } = await generateText({
model: ai("anthropic/claude-opus-5.5"),
prompt: "Say hello in three words",
});
return Response.json({ text });
},
};import { createAI } from "agents/models/ai-sdk";
import { generateText } from "ai";
export default {
async fetch(request: Request, env: Env) {
const ai = createAI({ binding: env.AI, id: "my-gateway" });
const { text } = await generateText({
model: ai("anthropic/claude-opus-5.5"),
prompt: "Say hello in three words",
});
return Response.json({ text });
},
};请使用目录中的 ID 拼写,而不是供应商的拼写。AI Gateway 会按目录中的确切名称查找模型,因此 anthropic/claude-opus-5.5 有效,而 anthropic/claude-opus-5-5 无效。其他示例包括 openai/gpt-5.5 和 cloudflare/auto。
请求会通过 env.AI.run() 发送到 AI Gateway。提供程序会以 OpenAI chat completions 格式发送请求,AI Gateway 则会在此格式与模型服务提供程序的格式之间进行转换。网关还会处理:
- 凭据。 Unified Billing 会将模型费用计入你的 Cloudflare 账户。如果已在网关中存储密钥,则会改用该密钥。
- 提供程序。 一个目录模型可以有多个提供程序。AI Gateway 会选择其中一个,并在它们之间重试。
- 错误。 遇到未知模型、账户未付款或上游故障时,会抛出
CloudflareAIError,与 Workers AI 故障使用相同的错误类型。
Unified Billing 要求网关启用身份验证。否则请求会因错误 2049 而失败。
reasoningEffort 会作为 reasoning_effort 发送。chatTemplateKwargs 是 Workers AI 选项,因此提供程序会发出警告并将其丢弃。
AI Gateway 动态路由的名称格式为 dynamic/<route>。你在网关中配置的路由会选择模型,并可应用条件、百分比、速率和预算限制以及自己的回退模型:
const ai = createAI({ binding: env.AI, id: "my-gateway" });
await generateText({ model: ai("dynamic/support"), prompt: "Hi" });路由属于单个网关,因此请设置创建该路由的网关 id。路由会以所选模型的 chat completions 格式响应。与目录模型类似,它会发出警告并丢弃 chatTemplateKwargs。动态路由仅支持语言模型;嵌入、图像、语音、转录和重排方法不接受此类路由。
使用供应商自己的 AI SDK 提供程序构建模型,然后将其传递给 ai()。AI Gateway 会持有凭据,因此供应商的 apiKey 只是占位值:
import { createAnthropic } from "@ai-sdk/anthropic";
import { createOpenAI } from "@ai-sdk/openai";
import { createAI } from "agents/models/ai-sdk";
import { generateText } from "ai";
export default {
async fetch(request, env) {
const ai = createAI({ binding: env.AI });
const anthropic = createAnthropic({ apiKey: "cloudflare" });
const openai = createOpenAI({ apiKey: "cloudflare" });
const claude = await generateText({
model: ai(anthropic("claude-opus-5-5")),
prompt: "Say hello in three words",
});
const gpt = await generateText({
model: ai(openai.responses("gpt-5-mini")),
prompt: "Say hello in three words",
});
return Response.json({ claude: claude.text, gpt: gpt.text });
},
};import { createAnthropic } from "@ai-sdk/anthropic";
import { createOpenAI } from "@ai-sdk/openai";
import { createAI } from "agents/models/ai-sdk";
import { generateText } from "ai";
export default {
async fetch(request: Request, env: Env) {
const ai = createAI({ binding: env.AI });
const anthropic = createAnthropic({ apiKey: "cloudflare" });
const openai = createOpenAI({ apiKey: "cloudflare" });
const claude = await generateText({
model: ai(anthropic("claude-opus-5-5")),
prompt: "Say hello in three words",
});
const gpt = await generateText({
model: ai(openai.responses("gpt-5-mini")),
prompt: "Say hello in three words",
});
return Response.json({ claude: claude.text, gpt: gpt.text });
},
};供应商软件包负责构建请求和解析响应。提供程序会替换模型的 fetch,并通过绑定将相同方法、标头和正文的请求发送到 AI Gateway 上该供应商的原生提供程序端点:
https://workers-binding.ai/ai-gateway/gateways/{gateway}/{provider}/{endpoint}提供程序根据请求主机确定网关提供程序。例如,api.anthropic.com 对应 anthropic,api.openai.com 对应 openai。如果 AI Gateway 没有相应提供程序,则会抛出 TypeError。网关选项会作为 cf-aig-* 标头传递。支持多部分正文,例如用于转录的文件上传。
使用供应商自己的模型 ID,例如 claude-opus-5-5。供应商软件包会据此读取模型能力。
统一计费(Unified Billing) 上的提供程序无需你自己的密钥即可应答。对于其他提供程序,请在网关上存储密钥。在此之前,厂商自己的错误会原样返回。
ai() 每次调用都会克隆模型,且从不修改你传入的对象。如果要添加中间件,请先用 ai() 包装模型:
wrapLanguageModel({ model: ai(anthropic("claude-opus-5-5")), middleware });已经用中间件包装过的模型会隐藏提供程序所需的设置,因此 ai() 会拒绝它。
默认情况下,提供程序会移除供应商凭据标头(authorization、x-api-key、x-goog-api-key 或 api-key),由 AI Gateway 提供密钥。若要使用自己持有的密钥,请将其传递给供应商提供程序,并在模型上设置 vendorKey: "request":
const anthropic = createAnthropic({ apiKey: env.ANTHROPIC_API_KEY });
const model = ai(anthropic("claude-opus-5-5"), { vendorKey: "request" });vendorKey 仅作用于设置它的模型。回退模型不会继承此设置,因此一个链可以混用使用你自有密钥的模型和使用 Unified Billing 的模型。
如果网关为同一个提供程序存储了多个密钥,byokAlias 会按别名选择一个已存储的密钥。对于目录模型和模型对象,提供程序会通过 cf-aig-byok-alias 发送该别名。
zdr 可针对某次 Unified Billing 请求开启 (true) 或关闭 (false) Zero Data Retention,无论网关自身如何设置。提供程序会通过 cf-aig-zdr 发送此选项。它仅适用于模型对象,因为目录模型和动态路由不会读取此选项。
const model = ai(anthropic("claude-opus-5-5"), {
byokAlias: "production",
zdr: true,
});所有类型的模型都可用于所有 AI SDK 调用:
import { createAI } from "agents/models/ai-sdk";
import { generateText, isStepCount, Output, streamText, tool } from "ai";
import { z } from "zod";
const getWeather = tool({
description: "Get the current weather for a city.",
inputSchema: z.object({ city: z.string() }),
execute: ({ city }) => ({ city, conditions: "clear", temperatureC: 21 }),
});
export default {
async fetch(request, env) {
const ai = createAI({ binding: env.AI });
const model = ai("@cf/zai-org/glm-4.7-flash");
const { pathname } = new URL(request.url);
if (pathname === "/stream") {
const result = streamText({
model,
prompt: "Write a haiku about Durable Objects",
});
return result.toTextStreamResponse();
}
if (pathname === "/tools") {
const { text } = await generateText({
model,
prompt: "What is the weather in Lisbon?",
tools: { getWeather },
stopWhen: isStepCount(3),
});
return Response.json({ text });
}
const { output } = await generateText({
model,
prompt: "One surprising fact about octopuses.",
output: Output.object({ schema: z.object({ fact: z.string() }) }),
});
return Response.json(output);
},
};import { createAI } from "agents/models/ai-sdk";
import { generateText, isStepCount, Output, streamText, tool } from "ai";
import { z } from "zod";
const getWeather = tool({
description: "Get the current weather for a city.",
inputSchema: z.object({ city: z.string() }),
execute: ({ city }) => ({ city, conditions: "clear", temperatureC: 21 }),
});
export default {
async fetch(request: Request, env: Env) {
const ai = createAI({ binding: env.AI });
const model = ai("@cf/zai-org/glm-4.7-flash");
const { pathname } = new URL(request.url);
if (pathname === "/stream") {
const result = streamText({
model,
prompt: "Write a haiku about Durable Objects",
});
return result.toTextStreamResponse();
}
if (pathname === "/tools") {
const { text } = await generateText({
model,
prompt: "What is the weather in Lisbon?",
tools: { getWeather },
stopWhen: isStepCount(3),
});
return Response.json({ text });
}
const { output } = await generateText({
model,
prompt: "One surprising fact about octopuses.",
output: Output.object({ schema: z.object({ fact: z.string() }) }),
});
return Response.json(output);
},
};通过绑定,目录模型或动态路由的流在连接中断后可以恢复。无需配置任何内容:
const result = streamText({
model: ai("anthropic/claude-opus-5.5"),
prompt: "Write a haiku about Durable Objects",
});
// If the connection drops, result.textStream keeps going.AI Gateway 会在 cf-aig-run-id 标头中为每个流式运行命名,并保留其事件。如果连接在流式传输过程中断开,提供程序会通过绑定重新连接,并从最后一个完整事件开始重放该次运行。流会继续传输,不会丢失或重复内容。连接中断期间,网关上的运行会继续,因此恢复后的流会继续返回同一答案。
如果单次流中断五次,或网关不再保留该次运行,提供程序会停止重试并抛出 CloudflareAIError。运行结束后,网关还会保留几分钟。中止调用后不会恢复该运行。
Workers AI @cf/ 流和模型对象没有运行 ID,因此不会恢复。运行 ID 位于 providerMetadata.cloudflare.runId 中。
从 getModel() 返回模型:
import { Think } from "@cloudflare/think";
import { createAI } from "agents/models/ai-sdk";
export class Assistant extends Think {
getModel() {
return createAI({ binding: this.env.AI })("@cf/moonshotai/kimi-k2.7-code");
}
}import { Think } from "@cloudflare/think";
import { createAI } from "agents/models/ai-sdk";
export class Assistant extends Think<Env> {
getModel() {
return createAI({ binding: this.env.AI })("@cf/moonshotai/kimi-k2.7-code");
}
}AI Gateway 可以缓存响应。以秒为单位设置 cacheTtl,可选设置 cacheKey。在某次调用上传递 skipCache: true 可绕过缓存:
const ai = createAI({ binding: env.AI, id: "prod", cacheTtl: 60 });
// A longer TTL for one model.
const faq = ai("@cf/zai-org/glm-4.7-flash", {
cacheTtl: 3600,
cacheKey: "faq-v1",
});
// Skip the cache for one call.
await generateText({
model: faq,
prompt: "What changed today?",
providerOptions: { cloudflare: { skipCache: true } },
});将 metadata 附加到网关日志条目。可在提供程序上设置一次,并按调用追加。元数据按键合并:
const ai = createAI({ binding: env.AI, metadata: { app: "support-bot" } });
await generateText({
model: ai(anthropic("claude-opus-5-5")),
prompt: "Summarize this ticket",
providerOptions: {
cloudflare: { metadata: { userId: "u_123" }, eventId: "ticket-42" },
},
});eventId 将若干请求归入同一个网关事件,例如一次 Agent 轮次中的所有模型调用。
如果主模型在生成任何输出前失败,fallback 会按顺序列出要尝试的模型。回退模型可以是 Workers AI ID、目录 ID、动态路由或模型对象:
const model = ai(anthropic("claude-opus-5-5"), {
fallback: ["openai/gpt-5.5", "dynamic/support", "@cf/zai-org/glm-4.7-flash"],
});列表中的模型对象会发送到供应商原生端点,例如 ai(model)。
被厂商拒绝的请求会回退。在产生第一个输出分片之前失败的流也会回退。一旦模型已产生输出,其应答即为最终结果,包括错误。providerMetadata.cloudflare.model 标识实际应答的模型。
每个回退模型都会使用链的网关选项。链的 id、cacheTtl 和其他网关选项优先于回退模型自身的设置,而 metadata 会合并。构建回退模型时使用的 headers、Workers AI 选项和 vendorKey 仍使用各自的设置。
回退逻辑在 Worker 中运行,并会依次尝试多个模型。对于单个目录模型,AI Gateway 已会在该模型的多个提供程序之间重试;动态路由则会在网关上运行自己的回退逻辑。
可在提供程序上、模型上,或每次调用的 providerOptions.cloudflare 下设置网关选项。每次调用的选项优先于每个模型的选项,后者优先于提供程序的选项:
// Provider
const ai = createAI({ binding: env.AI, id: "prod", metadata: { app: "demo" } });
// Model
const model = ai("anthropic/claude-opus-5.5", { cacheTtl: 3600 });
// Call
await generateText({
model,
prompt: "hi",
providerOptions: {
cloudflare: { skipCache: true, metadata: { userId: "u1" } },
},
});提供程序会在调用到达厂商模型之前移除 providerOptions.cloudflare,因此厂商永远看不到它。
网关选项可以扁平或嵌套给出:{ cacheTtl: 60 } 与 { gateway: { cacheTtl: 60 } } 相同。
| 选项 | 类型 | 描述 |
|---|---|---|
binding |
Ai |
AI 绑定。仅限提供程序。 |
accountId |
string |
用于账户 ID 和 API token的账户。仅限提供程序。 |
apiToken |
string |
该账户的 Cloudflare API token。仅限提供程序。 |
id |
string |
网关 ID。默认为 "default",首次使用时会创建。 |
gateway |
string | GatewayOptions |
网关 ID,或嵌套的网关选项。 |
skipCache |
boolean |
绕过网关缓存。 |
cacheTtl |
number |
缓存生存时间(秒)。 |
cacheKey |
string |
使用该缓存键,而不是从请求派生的键。 |
collectLog |
boolean |
网关是否将请求与响应存入日志。 |
metadata |
Record<string, string | number | boolean | null> |
附加到网关日志条目的值。 |
eventId |
string |
将若干请求归入同一个网关事件。 |
requestTimeoutMs |
number |
上游请求超时。 |
retries |
{ maxAttempts, retryDelayMs, backoff } |
上游调用的网关重试策略。maxAttempts 为 1 到 5。 |
byokAlias |
string |
按别名指定的已存储 BYOK 密钥。适用于目录模型和模型对象。 |
zdr |
boolean |
针对 Unified Billing 请求开启或关闭 Zero Data Retention。仅适用于模型对象。 |
vendorKey |
"gateway" | "request" |
"request" 会在请求中转发供应商密钥。仅对每个模型对象单独生效。 |
fallback |
(CloudflareLanguageModelId | LanguageModelV4)[] |
按顺序尝试的模型。仅限模型与调用。 |
headers |
Record<string, string> |
额外请求头,最后合并。仅限模型与调用。 |
sessionAffinity |
string |
仅 Workers AI。将相同键的请求发送到同一副本以实现前缀缓存。 |
reasoningEffort |
"low" | "medium" | "high" | null |
作为 reasoning_effort 发送。对于支持此选项的模型,null 会关闭推理。 |
chatTemplateKwargs |
Record<string, unknown> |
仅 Workers AI。作为 chat_template_kwargs 发送,例如 { enable_thinking: false }。 |
reasoningEffort 适用于 Workers AI 模型、目录模型和动态路由。未设置时,AI SDK 的 reasoning 调用选项会映射到此选项。对于模型对象,请使用 AI SDK 的 reasoning 调用选项或供应商自己的 providerOptions 请求推理。提供程序会忽略模型对象上的 reasoningEffort 和 chatTemplateKwargs,并发出警告。
每个结果以及每个流的 finish 分片都携带 providerMetadata.cloudflare。对于厂商模型,它与厂商自己的元数据并列:
const { providerMetadata } = await generateText({
model: ai(anthropic("claude-opus-5-5")),
prompt: "hi",
});
providerMetadata?.cloudflare;
// {
// model: "claude-opus-5-5",
// provider: "anthropic",
// gateway: "default",
// logId: "019a7b3e-5f2c-7c41-9d3e-2b8f6a1c4e07",
// cacheStatus: "MISS",
// ...
// }| 字段 | 描述 |
|---|---|
model |
应答的模型,经过任意回退之后。 |
gateway |
如果网关处理了请求,则为网关 ID。 |
provider |
对于模型对象,为网关提供程序。 |
logId |
网关日志条目,来自 cf-aig-log-id。 |
eventId |
网关事件,来自 cf-aig-event-id。 |
requestId |
网关请求 ID,来自 cf-aig-request-id。 |
traceId |
该请求所属的 trace,来自 cf-aig-trace-id。 |
runId |
对于目录模型或动态路由,为 cf-aig-run-id 中的流式运行 ID。 |
cacheStatus |
HIT 或 MISS,来自 cf-aig-cache-status。 |
step |
应答的网关路由步骤,来自 cf-aig-step。 |
始终存在的只有 model。使用其他字段前,请先检查它们是否存在。
对于 Workers AI 故障、AI Gateway 故障、流恢复失败以及所有模型均失败的回退链,提供程序会抛出 CloudflareAIError,该错误继承自 AI SDK 的 APICallError。AI SDK 的重试循环会读取其 isRetryable 标志:
import { CloudflareAIError } from "agents/models/ai-sdk";
try {
await generateText({ model: ai("@cf/zai-org/glm-4.7-flash"), prompt: "hi" });
} catch (error) {
if (error instanceof CloudflareAIError) {
console.log(error.status, error.code, error.logId, error.model);
// error.attempts lists every fallback model that failed.
}
}code 为 "auth"、"rate-limit"、"not-found"、"bad-request"、"provider-error"、"gateway-error" 或 "unknown" 之一。
对于模型对象,CloudflareAIError 涵盖网关自身的故障,例如网关缺失或账户未付费。供应商自身的错误(例如模型 ID 无效或触发速率限制)则由供应商提供程序以其自己的错误类型返回。
嵌入、图像、语音、转录与重排序使用同一提供程序中的 Workers AI 模型。每种方法也有其 ProviderV4 名称,例如 ai.embeddingModel():
import {
embedMany,
generateImage,
generateSpeech,
rerank,
transcribe,
} from "ai";
const { embeddings } = await embedMany({
model: ai.embedding("@cf/baai/bge-base-en-v1.5"),
values: ["hello", "world"],
});
const { image } = await generateImage({
model: ai.image("@cf/black-forest-labs/flux-1-schnell"),
prompt: "A cyberpunk lizard",
});
const { audio } = await generateSpeech({
model: ai.speech("@cf/deepgram/aura-1"),
text: "Hello from Cloudflare.",
});
const { text } = await transcribe({
model: ai.transcription("@cf/openai/whisper-large-v3-turbo"),
audio: audio.uint8Array,
});
const { rerankedDocuments } = await rerank({
model: ai.reranking("@cf/baai/bge-reranker-base"),
documents: ["a cyberpunk lizard", "a rainy Tuesday"],
query: "Which one is cooler?",
});模型特定设置放在 providerOptions.cloudflare 下:
| 模态 | 使用的调用选项 | providerOptions.cloudflare |
|---|---|---|
| 图像 | prompt, n, size, seed, files, mask |
steps, guidance, negativePrompt, strength |
| 语音 | text、voice(作为 speaker)、outputFormat(作为 encoding)、language(仅 MeloTTS) |
无 |
| 转录 | audio, mediaType |
language, task, initialPrompt, prefix, vadFilter |
| 重排序 | query、documents、topN(作为 top_k) |
无 |
模型不接受的选项会列在结果的 warnings 中,而不会发送。例如,flux-1-schnell 只接受提示词和 steps,而 @cf/deepgram/nova-3 接受 language,但不接受仅适用于 Whisper 的转录选项。图像生成每个请求只生成一张图像,因此 generateImage 中较大的 n 会发送并行请求。
这些方法仅接受 Workers AI 的 @cf/ ID,fallback 中也一样。若要通过 AI Gateway 路由供应商自己的嵌入、图像、语音或转录模型,请将其传递给 ai.routed(model)。它会像 ai(model) 一样使用供应商原生端点。ai.routed() 接受网关选项、headers、sessionAffinity 和 vendorKey。
createAI 返回 ProviderV4,因此可与 createProviderRegistry 配合,并作为 AI SDK 的全局默认提供程序:
import { createProviderRegistry, generateText } from "ai";
const registry = createProviderRegistry({ cloudflare: ai });
await generateText({
model: registry.languageModel("cloudflare:anthropic/claude-opus-5.5"),
prompt: "Hi",
});
// Bare strings now resolve through this provider.
globalThis.AI_SDK_DEFAULT_PROVIDER = createAI({ binding: env.AI });
await generateText({ model: "@cf/zai-org/glm-4.7-flash", prompt: "Hi" });字符串可以是 Workers AI ID、目录 ID 或动态路由。
@cf/deepgram/flux仅接受 websocket 连接,因此会在发送请求前抛出CloudflareAIError。转录请使用@cf/deepgram/nova-3或@cf/openai/whisper-large-v3-turbo。chatTemplateKwargs和sessionAffinity仅适用于 Workers AI 模型。zdr仅适用于模型对象。- Workers AI 流和模型对象流在连接断开后不会恢复。