agents/models/pi-ai 是面向 Workers AI 与 AI Gateway 的 Pi AI ↗ 提供程序。它与 AI SDK 提供程序 使用相同的 createAI 工厂函数与选项,并返回 Pi AI Model 对象。可与 Pi AI 的 stream 和 complete、Pi Durable ↗、Pi 执行框架,或任何基于 Pi AI Models 注册表构建的框架一起使用。
此提供程序需要 @earendil-works/pi-ai@~1.4.0,这是 agents 的可选 peer dependency:
npm i agents @earendil-works/pi-aiyarn add agents @earendil-works/pi-aipnpm add agents @earendil-works/pi-aibun add agents @earendil-works/pi-ai将 AI 绑定添加到 Wrangler 配置:
{
"ai": {
"binding": "AI",
},
}[ai]
binding = "AI"若要在另一个账户中使用网关,或从 Worker 外部调用,请传入 accountId 和 apiToken,而不是 binding。其他设置相同,网关默认值仍为 default:
const ai = createAI({
accountId: "<ACCOUNT_ID>",
apiToken: env.CLOUDFLARE_API_TOKEN,
gateway: "my-gateway",
});使用 Workers AI Read 和 AI Gateway Run 权限创建 API 令牌。令牌只会发送到 AI Gateway REST API 和 gateway.ai.cloudflare.com。
提供程序携带 Pi AI 的入口点,因此不会在全局注册任何内容:
import { createAI } from "agents/models/pi-ai";
export default {
async fetch(request, env) {
const ai = createAI({ binding: env.AI });
const reply = await ai.complete(ai("@cf/zai-org/glm-5.3-flash"), {
messages: [{ role: "user", content: "Hello", timestamp: Date.now() }],
});
// `content` holds text, thinking, and tool call parts.
const text = reply.content
.filter((part) => part.type === "text")
.map((part) => part.text)
.join("");
return Response.json({ text });
},
};import { createAI } from "agents/models/pi-ai";
export default {
async fetch(request: Request, env: Env) {
const ai = createAI({ binding: env.AI });
const reply = await ai.complete(ai("@cf/zai-org/glm-5.3-flash"), {
messages: [{ role: "user", content: "Hello", timestamp: Date.now() }],
});
// `content` holds text, thinking, and tool call parts.
const text = reply.content
.filter((part) => part.type === "text")
.map((part) => part.text)
.join("");
return Response.json({ text });
},
};ai.stream() 返回 Pi AI 的 AssistantMessageEvent 流。ai.completeSimple() 与 ai.streamSimple() 接受 Pi AI 的简单选项,例如 reasoning 级别与 maxTokens:
const model = ai("anthropic/claude-opus-5.5");
const context = {
messages: [{ role: "user", content: "Hi", timestamp: Date.now() }],
};
for await (const event of ai.stream(model, context)) {
// text_delta, thinking_delta, toolcall_*, done, error
}
await ai.completeSimple(model, context, { reasoning: "low" });ai.streamFn 是绑定后的 streamSimple,供接受 stream 函数的框架使用,例如 pi-agent-core 的 Agent({ streamFn })。
模型有四种命名方式:
import { createAI } from "agents/models/pi-ai";
import { getBuiltinModel } from "@earendil-works/pi-ai/providers/all";
const ai = createAI({ binding: env.AI, id: "my-gateway" });
// 1. A Workers AI model, by its @cf/ id.
ai("@cf/zai-org/glm-5.3-flash");
// 2. An AI Gateway dynamic route, by dynamic/<route>.
ai("dynamic/support");
// 3. A model from Pi AI's Cloudflare AI Gateway catalog, by <provider>/<id>.
ai("anthropic/claude-opus-5.5");
ai("openai/gpt-5.4");
// 4. Any Pi AI model object, from any Pi AI registry.
ai(getBuiltinModel("anthropic", "claude-opus-5-5"));任何其他字符串都会抛出 TypeError。提供程序不会猜测前缀含义。
动态路由会在你创建它的网关下通过 env.AI.run() 运行,因此请设置该网关的 id。路由会选择模型,并以 chat completions 格式返回响应。它接受与 Workers AI ID 相同的元数据默认值和覆盖项。
目录 ID 使用 AI Gateway 目录中的拼写,例如 anthropic/claude-opus-5.5。Pi AI 自己的列表会按 Anthropic 的方式拼写 Claude ID(claude-opus-5-5),因此提供程序会按目录中的拼写列出它们。供应商注册表中的模型对象则保留供应商自己的拼写。
第三种和第四种形式会保留 Pi AI 的模型元数据,包括 api、compat、thinkingLevelMap、成本、上下文窗口和最大令牌数。这些元数据决定了向各供应商请求推理的方式。例如,Claude Opus 会收到 thinking: { type: "adaptive" },GPT-5 会收到 reasoning.effort。ai(model) 不会更改你传入的对象。
第三方模型会通过 AI Gateway 路由;网关通过统一计费或存储在网关上的密钥保管凭据。你的 Worker 不会持有供应商密钥。统一计费要求在网关上进行身份验证。
Pi Durable 的 Harness 接受 Pi AI Models 注册表。先在其中一个上注册提供程序,再将 ai() 的模型传给 Pi 执行框架:
import { createModels } from "@earendil-works/pi-ai/models";
import { createAI } from "agents/models/pi-ai";
const ai = createAI({ binding: env.AI });
const models = createModels();
models.setProvider(ai.provider);
// In PiHarness options:
// defaults: { model: ai("@cf/zai-org/glm-5.3-flash") }
// For one session:
await session.setModel(ai("anthropic/claude-opus-5.5"));Pi 会话只存储模型的提供程序和 ID,然后在 Models 注册表中查找模型。请在此使用 @cf/、dynamic/ 和 <provider>/<id> 形式。这些形式属于你注册的 cloudflare 提供程序 (CLOUDFLARE_PROVIDER_ID)。模型对象会保留其供应商的提供程序 ID,而该注册表不认识此 ID。传递给 ai(model, options) 的选项不会传入会话。请改为在 createAI 上设置这些选项。
如果模型流中断,或在 streamIdleTimeoutMs 指定的时间内没有发送内容,Pi AI 的 isRetryableAssistantError() 会将其视为暂时性错误。Pi harness 会根据重试设置重新尝试此轮,而不是将其判定为失败。
提供程序的模型列表包含 Pi AI 认识的所有 Workers AI 模型,以及 Pi AI 的 AI Gateway 目录中的所有 <provider>/<id>。因此,models.getModel("cloudflare", "anthropic/claude-opus-5.5") 可以解析模型。
网关选项可放在 createAI、模型或调用上。它们可以扁平,也可以嵌套在 gateway 下:
const ai = createAI({ binding: env.AI, id: "prod", cacheTtl: 60 });
const model = ai("anthropic/claude-opus-5.5", {
cacheTtl: 3600,
cacheKey: "greeting-v1",
metadata: { team: "growth" },
eventId: "turn-17",
requestTimeoutMs: 30_000,
retries: { maxAttempts: 3, backoff: "exponential", retryDelayMs: 500 },
byokAlias: "production",
});选项与 AI SDK 提供程序的选项相同:id、skipCache、cacheTtl、cacheKey、collectLog、metadata、eventId、requestTimeoutMs、retries、byokAlias、zdr、fallback、headers、sessionAffinity、reasoningEffort 和 chatTemplateKwargs。vendorKey 仅适用于 AI SDK。
当网关为某个提供程序保管多个密钥时,byokAlias 会按别名选择一个已存储密钥。对于目录模型和模型对象,提供程序会将别名作为 cf-aig-byok-alias 发送。zdr 可为统一计费请求启用或停用零数据保留。它仅适用于 Pi AI 网关目录之外的模型对象,因为目录模型不会读取此选项。
Pi AI 自己的调用选项会映射到它们。headers 最后合并,metadata 加入网关元数据,sessionId 设置会话亲和性,reasoning 通过模型自己的 thinkingLevelMap 映射。调用选项优先于模型选项,后者优先于 createAI。
@cf/ 模型还接受 Pi AI 元数据覆盖:name、contextWindow、maxTokens、reasoning、input、cost 与 streamIdleTimeoutMs。Pi AI 未列出的 Workers AI ID 会以 128,000 token 上下文窗口、8,192 输出 token 与零成本解析,因此在你知道真实值时请传入覆盖。
Pi AI 模型是普通数据。每个模型的选项以 symbol 键存储,JSON.stringify 与 structuredClone 会丢弃它们。存储后再读回的模型仍会路由到其厂商,但会丢失选项。加载后请用 ai(model, options) 再次传入。
ai(getBuiltinModel("anthropic", "claude-opus-5-5"), {
fallback: ["@cf/zai-org/glm-5.3-flash"],
});回退模型可以是 Workers AI ID、动态路由、<provider>/<id> 字符串或模型对象。提供程序会按顺序尝试这些模型。如果某个流在产生任何输出前以 error 结束,就会继续尝试下一个模型。一旦模型产生输出,其响应即为最终结果。
应答消息带有 cloudflare-fallback 诊断,列出失败的尝试,message.model 标识实际应答的模型。
回退模型使用该链的网关选项。以 @cf/ ID 命名的回退模型没有自己的选项,因此也会采用链的 headers、会话亲和性与 Workers AI 选项。它不会采用链的模型元数据,例如 cost 或 contextWindow。
每条 assistant 消息都有带有其响应网关详情的 cloudflare 诊断:
const message = await ai.complete(model, context);
const cloudflare = message.diagnostics?.find(
(d) => d.type === "cloudflare",
)?.details;
// { model, gateway, provider?, specifier?, logId?, eventId?, cacheStatus?,
// step?, traceId?, runId? }失败的请求以 error 事件结束流。其消息带有包含 status、code 与 logId 的 cloudflare-error 诊断。onResponse 会收到每个请求的状态与头。
网关自身的失败(例如缺失网关或未付费账户)会变成 CloudflareAIError。来自厂商的错误会按厂商发送的原样返回。
通过绑定发送的目录模型或动态路由流在连接断开后会恢复。无需进行任何配置。
AI Gateway 会在 cf-aig-run-id 标头中为每次流式运行命名,并保留其事件。如果连接断开,提供程序会通过绑定重新连接,并从最后一个完整事件开始重放该运行。流会继续传输,不会丢失或重复内容。
如果单个流中断 5 次,或网关不再保留该运行,提供程序就会放弃恢复。运行结束后,网关会保留运行信息几分钟。中止调用后不会恢复。Workers AI @cf/ 流以及目录之外的模型对象没有运行 ID,因此不会恢复。运行 ID 会显示在 cloudflare 诊断信息的 runId 中。
提供程序会通过 AI 绑定路由每个请求,或通过 HTTP 和账户 ID、API 令牌路由:
| 模型 | api |
通过绑定 | 使用账户 ID 和令牌 |
|---|---|---|---|
@cf/ 模型和动态路由 |
cloudflare-ai |
env.AI.run(),带 Cloudflare 兼容层 |
AI Gateway REST API,并使用相同的兼容层 |
| 来自 Pi AI 网关目录的 Anthropic 模型 | anthropic-messages |
env.AI.run() 将请求发送到 AI Gateway,使用 Anthropic Messages 格式 |
REST API 的 /ai/v1/messages,使用相同格式 |
| 来自 Pi AI 网关目录的 OpenAI 模型 | openai-responses |
env.AI.run() 将请求发送到 AI Gateway,使用 OpenAI Responses 格式 |
REST API 的 /ai/v1/responses,使用相同格式 |
| 任何其他模型对象,例如 Anthropic、OpenAI 或 Groq | 其自身的 api |
绑定的 fetch 会请求 AI Gateway 的供应商原生端点 |
gateway.ai.cloudflare.com,即供应商原生端点 |
来自 Pi AI Cloudflare AI Gateway 目录的模型会使用其目录 ID,通过 env.AI.run() 以模型原生格式运行。AI Gateway 不会进行转换,因此 Pi AI 自身的流处理程序会读取响应。网关会选择提供程序,并通过统一计费或存储在网关上的密钥计费。
任何其他模型对象都会通过绑定的 fetch 请求 AI Gateway 的供应商原生端点。提供程序会根据模型 baseUrl 的主机名确定网关提供程序。Pi AI 自带的转换器会构建供应商请求正文,Pi AI 则解析供应商的响应流。
无论采用哪种方式,供应商凭据都不会离开 Worker。提供程序绝不会重写模型的 api、provider 或 id,因此推理签名和加密推理条目可在下一轮继续使用。
提供程序支持以下四种 api 值路由:cloudflare-ai、anthropic-messages、openai-responses 和 openai-completions。Pi AI 多个注册表中的模型使用其他值,目前无法路由,包括 mistral-conversations、google-generative-ai、google-vertex、amazon-bedrock、azure-openai-responses 和 openai-codex。此类模型的流会以 error 事件结束,并指出其 api。如果 AI Gateway 没有为模型 baseUrl 的主机名提供程序,模型流也会如此结束。
在 openai-completions 线路上,提供程序仅以 OpenAI 的 reasoning_effort 发送推理。若模型的 compat.thinkingFormat 是其他值(例如 deepseek、qwen 或 openrouter),其推理级别会被丢弃。消息上的 cloudflare-compat 诊断会记录该丢弃。若需要该厂商的思考格式,请使用 Pi AI 自己的提供程序。
reasoningEffort 与 chatTemplateKwargs 是 Workers AI 选项。在第三方模型上它们会被丢弃,并记录在 cloudflare-compat 诊断中。请改用 Pi AI 的 reasoning 级别。
图像生成使用 Workers AI 模型:
const images = ai.images("@cf/black-forest-labs/flux-1-schnell", { steps: 8 });
const result = await ai.generateImages(images, {
input: [{ type: "text", text: "A red bicycle" }],
});flux-1-schnell 只接受 prompt 与 steps。对它而言,width、height、seed、guidance 与 negativePrompt 会被丢弃,并列在 cloudflare-compat 诊断中。目录中的其他图像模型接受所有这些选项。