AI
用 void/ai 的 ai 在服务端代码中运行 Workers AI 模型与第三方提供方 API,提供方请求通过 Cloudflare 的 AI Gateway 发出。
预计阅读 6 分钟
本地开发
对于直连 Cloudflare 的项目,先连接你的账户再开始开发:
void connect --platform cloudflare
npm run dev
当应用导入 void/ai 时,Void 会在开发与预览期间启用远程 Workers AI 绑定。请求使用你的 Cloudflare 账户及其额度;Workers AI 没有本地模拟器。
开发与预览使用与 void connect 相同的 Cloudflare 登录;使用 void cloudflare login 登录。CLOUDFLARE_API_TOKEN 优先级更高,自动化环境中请使用它。
如果开发因为 Cloudflare 认证错误而停止,请以能够访问部署账户的用户在终端中运行 void cloudflare login(该账户由 void cloudflare status 展示),或设置 CLOUDFLARE_API_TOKEN。wrangler login 不影响开发。
对于团队平台,使用 void connect <platform-url> 并关联你的项目。开发请求使用该平台的账户与用量限制。
基本用法
用 ai.run() 传入模型名与输入。模型名与输入类型完全由 @cloudflare/workers-types 提供类型。
import { defineHandler } from 'void';
import { ai } from 'void/ai';
export const POST = defineHandler(async (c) => {
const { prompt } = await c.req.json();
const result = await ai.run('@cf/meta/llama-3.3-70b-instruct-fp8-fast', {
messages: [{ role: 'user', content: prompt }],
});
return c.json(result);
});
AI 方法返回 Promise。await 它们以获得结果,或者直接从处理器返回该 Promise。
你可以使用通过 Cloudflare AI 绑定可用的任何模型,包括 Workers AI 模型(如 @cf/meta/llama-3.3-70b-instruct-fp8-fast)以及 Cloudflare Gateway 模型(如 google/gemini-2.5-flash 或 openai/gpt-4.1-mini)。输入对象必须与所选 Cloudflare 模型的 schema 匹配。返回二进制数据的模型(例如生成的图像)会以 Blob 形式从 ai.run() 返回。
流式响应
用 ai.stream() 获得带 SSE 头的流式响应,可以直接从路由处理器返回:
import { defineHandler } from 'void';
import { ai } from 'void/ai';
export const POST = defineHandler(async (c) => {
const { prompt } = await c.req.json();
return ai.stream('@cf/meta/llama-3.3-70b-instruct-fp8-fast', {
messages: [{ role: 'user', content: prompt }],
});
});
列出模型
const models = await ai.models();
// 按任务筛选
const textModels = await ai.models({ task: 'Text Generation' });
文档转 Markdown
const result = await ai.toMarkdown([{ name: 'document.pdf', blob: pdfBytes }]);
用量限制
Workers AI 的用量以 neurons 计量。直接部署时,用量归属于你的 Cloudflare 账户。提供方原生请求同时使用你的提供方凭据及其计费条款。
团队平台使用自己的 Cloudflare 账户,并可能对每个用户施加限制。请向管理员了解可用额度。
用量限制会以 void/limits 中的 UsageLimit 拒绝该操作的 Promise。它包含 resource、reason 与可选的 retryAt 时间戳。在 Void 路由处理器与页面 action 中,未捕获的限制会产生带重试信息的结构化 HTTP 429;在队列、定时任务与其他服务端代码中,它仍是一个被拒绝的 Promise。
处理限制是可选的。当你想提供兜底逻辑或针对自己应用优化的提示时,使用 instanceof UsageLimit:
import { defineHandler } from 'void';
import { ai } from 'void/ai';
import { UsageLimit } from 'void/limits';
export const POST = defineHandler(async (c) => {
const { prompt } = await c.req.json();
try {
const result = await ai.run('@cf/meta/llama-3.3-70b-instruct-fp8-fast', {
messages: [{ role: 'user', content: prompt }],
});
return c.json(result);
} catch (error) {
if (error instanceof UsageLimit) {
return error.response({ message: '请稍后重试,你的提示已被保留。' });
}
throw error;
}
});
error.response() 会创建结构化的 HTTP 429,并接受一个可选的自定义 message。其他失败正常 reject。使用 fetchStream() 时,同样的 instanceof UsageLimit 检查能让客户端拿到该消息与重试信息。
Cloudflare Gateway 模型
ai.run() 与 Cloudflare 的 env.AI.run() 在模型命名与输入 schema 上保持一致。第三方模型使用 Cloudflare 模型 ID 与由 Cloudflare 管理的凭据。
const result = await ai.run('google/gemini-2.5-flash', {
contents: [
{
role: 'user',
parts: [{ text: '用一段话解释 Durable Objects。' }],
},
],
});
作为第三个参数传入 AI Gateway 选项:ai.run(model, inputs, { gateway: { skipCache: true } })。在团队平台上,网关由平台选择并设置其元数据与日志;skipCache、cacheTtl 等选项仍然生效。直接部署时,请为提供方原生请求配置 ai.gateway。
提供方原生请求
用 ai.provider(provider).fetch(path, init) 调用第三方提供方的原生 API,使用你自己的提供方密钥。请求会经过配置好的 Cloudflare AI Gateway,并保留提供方的原生 HTTP 结构。在团队平台上,它还会经过该安装的代理;cf-aig-cache-ttl、cf-aig-max-attempts 等 AI Gateway 缓存、超时与重试头仍然生效,平台会忽略日志、元数据与成本头。
import { defineHandler } from 'void';
import { ai } from 'void/ai';
export const POST = defineHandler(async (c) => {
const { prompt } = await c.req.json();
return ai.provider('openai').fetch('/chat/completions', {
body: {
model: 'gpt-4o',
messages: [{ role: 'user', content: prompt }],
max_tokens: 512,
},
});
});
const response = await ai
.provider('google-ai-studio')
.fetch('/v1/models/gemini-2.5-flash:generateContent', {
body: {
contents: [
{
role: 'user',
parts: [{ text: '什么是 Cloudflare?' }],
},
],
},
});
const response = await ai
.provider('custom-provider', {
apiKeyEnv: 'CUSTOM_PROVIDER_API_KEY',
apiKeyHeader: 'x-api-key',
apiKeyPrefix: '',
})
.fetch('/v1/respond', {
body: { prompt: '你好' },
});
图像生成
export const POST = defineHandler(async (c) => {
const { prompt } = await c.req.json();
return ai.image('@cf/black-forest-labs/flux-1-schnell', { prompt });
});
提供方原生的图像 API 使用 ai.provider().fetch(),注意匹配提供方的请求 schema:
export const POST = defineHandler(async (c) => {
const { prompt } = await c.req.json();
return ai.provider('openai').fetch('/images/generations', {
body: {
model: 'gpt-image-2.5-sunburst',
prompt,
size: '1024x1024',
},
});
});
对于 multipart 的提供方 API,传入 FormData:
export const POST = defineHandler(async (c) => {
const body = await c.req.parseBody();
const form = new FormData();
form.set('model', 'gpt-image-2.5-sunburst');
form.set('prompt', String(body.prompt));
form.set('image', body.image as Blob, 'source.png');
return ai.provider('openai').fetch('/images/edits', { body: form });
});
提供方密钥约定
提供方原生请求使用项目密钥,例如 OpenAI 用 OPENAI_API_KEY,Google AI Studio 用 GOOGLE_API_KEY。
OpenAI 风格的提供方使用 Authorization: Bearer <key>,Google AI Studio 使用 x-goog-api-key。自定义提供方请使用 apiKeyHeader 与 apiKeyPrefix。
生产环境中,把 API 密钥添加为项目密钥:
void secret put OPENAI_API_KEY=sk-...
本地开发时,把它加到项目根目录的 .env 中:
OPENAI_API_KEY=sk-...
提供方原生 API 的流式响应只需直接返回提供方的响应,例如在上面的 OpenAI 请求体中加入 stream: true 即可。