ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Flue Provider API 完全指南:providers 配置、setProvider() 与 Cloudflare Workers AI 绑定 Provider

Flue Provider API 完全指南:providers 配置、setProvider() 与 Cloudflare Workers AI 绑定 Provider Flue Provider API 完全指南providers 配置、setProvider() 与 Cloudflare Workers AI 绑定 Provider【免费下载链接】flueThe sandbox agent framework.项目地址: https://gitcode.com/GitHub_Trending/flue1/flueFlue 的模型层直接复用 Piearendil-works/pi-ai的 Provider 协议一个 Provider 就是一个 PiProvider对象运行时持有唯一的 PiModels注册表所有模型调用都针对该注册表解析。Flue 在此基础上仅补充了三样东西——构建期的providers配置、运行时注册 Provider 的setProvider()、以及面向 Workers AI 的cloudflareBindingProvider()。读完本文你将掌握模型说明符provider-id/model-id的完整解析契约、如何通过配置与代码两种途径接入内置/自定义模型供应商、如何在 Cloudflare 目标上通过env.AI绑定零密钥调用模型并精细控制 AI Gateway 路由以及 Provider 遥测命名规范。本文对应的完整文档为 provider-api.md配套实战讲解见 Models — Custom providers。核心导出与引入方式Provider API 的全部公共入口如下import { setProvider } from flue/runtime; import { cloudflareBindingProvider, type CloudflareAIBinding, type CloudflareBindingProviderOptions, } from flue/runtime/cloudflare/workers-ai; import { type CloudflareGatewayOptions } from flue/runtime/cloudflare; // Provider 构造是 Pi 自己的 API直接使用 import { createProvider, envApiKeyAuth } from earendil-works/pi-ai; import { anthropicProvider } from earendil-works/pi-ai/providers/anthropic;注意两点导入细节cloudflareBindingProvider及其类型单独从子路径flue/runtime/cloudflare/workers-ai导出而非flue/runtime/cloudflare这个 barrel。这是刻意设计——在 workers-ai-provider.ts 的文件头注释中写明导入该工厂才是把绑定分发代码打进入构建产物所以它不随 barrel 一起被捎带避免在不需要 Workers AI 的构建中引入这段代码。Provider 的构造属于 Pi 的 API 范畴createProvider、envApiKeyAuth、各厂商工厂如anthropicProvider()Flue 不做二次封装直接透传。providers配置构建期选择内置 Provider基本用法与语义// vite.config.ts flue({ providers: [anthropic, openai] });该字段按 Provider ID 选择生成的服务器入口要注册哪些 Provider。每个条目对应生成入口里的一条earendil-works/pi-ai/providers/id工厂导入——唯一的例外是cloudflare它选中 Flue 自己的 Workers AI 绑定 Provider——因此只有列出的 Provider其目录与懒加载的协议实现会进入构建产物。从生成机制看providers-module.ts 的generateProvidersModule()负责产出名为virtual:flue/providers的虚拟模块先剔除列表中的cloudflare它不映射到 Pi 工厂再为其余每个 ID 生成import * as __flue_provider_N__ from earendil-works/pi-ai/providers/id最后统一调用registerBuiltinProviderModule(id, namespace)。五项行为契约省略该字段所有内置 Provider 都注册Cloudflare 目标上还包含 Workers AI 绑定 Provider。默认行为保证了零配置解析——Pi 目录中的任意provider/model-id说明符都可用凭据来自各 Provider 的环境变量ANTHROPIC_API_KEY、OPENAI_API_KEY等。设置该字段列表是穷尽式的。引用未列出 Provider 的说明符会在模型解析时报错在 Cloudflare 目标上只有列表含cloudflare时才注册绑定 Provider。在 Node 目标上写cloudflare属于配置错误绑定只存在于 Workers 上。自定义 Provider 不受影响——那些要用setProvider()注册。未知 ID 直接构建失败。生成的导入earendil-works/pi-ai/providers/id无法解析构建错误会点名该 ID。底层registerBuiltinProviderModule()providers.ts还会做两道校验要求该模块恰好导出一个*Provider工厂且工厂产出的provider.id与配置的 ID 一致否则抛出带指引的错误。用户注册优先。生成的注册会跳过任何已注册的 Provider ID因此app.ts里的setProvider()无论模块求值顺序如何都能覆盖列表中的内置项。flue run忽略该列表。它只加载 Agent 模块——不加载app.ts也没有生成入口——并且总是注册完整的内置集合。列表收窄只影响服务器构建。字段来源优先级同一字段也接受在flue.config.ts中配置内联插件选项按字段胜出。详见 Configuration 参考。setProvider()运行时注册 Provider签名与最小示例function setProvider(provider: Provider): void;以provider.id为键把 PiProvider注册进运行时执行setProvider(p)且p.id acme之后说明符acme/some-model就通过它解析。它接受任意Provider——内置工厂anthropicProvider()、自定义端点的createProvider(...)、cloudflareBindingProvider(...)、测试里的假 Provider 的.provider。典型自定义 Provider 示例如接入本地 Ollamaimport { createProvider, envApiKeyAuth } from earendil-works/pi-ai; import { openAICompletionsApi } from earendil-works/pi-ai/api/openai-completions.lazy; import { setProvider } from flue/runtime; setProvider( createProvider({ id: ollama, auth: { apiKey: { name: Ollama (keyless), resolve: async () ({ auth: {} }) } }, models: [/* Model 对象每个模型自带 baseUrl */], api: openAICompletionsApi(), }), );从源码看setProvider()的实现非常薄——只是把调用转发给模块级Models实例的models.setProvider(provider)。运行时还配套提供了hasProvider()检查某 ID 是否已注册与getRuntimeModels()内部给 Session 的流式/补全调用使用等工具函数。行为契约每次调用替换该 ID 之前的 Provider。调用不累积、不合并同一 ID 最近一次setProvider()生效包括覆盖生成入口的内置注册它们会跳过已注册的 ID。注册表是模块作用域、纯内存的。要在任何 Agent 运行前、于模块顶层调用setProvider()。Node.js 目标上一个进程承载所有 Agent所以app.ts里注册一次即全局生效Cloudflare 目标上每个 Agent 会话运行在自己的 Durable Object isolate 里app.ts在每个 isolate 中都会被求值因此顶层注册处处生效。flue run只加载 Agent 模块、绝不加载app.ts——需要在flue run下也生效的注册必须放进 Agent 模块里。注册是声明式、延迟生效的。调用本身不产生任何网络 I/O也不做凭据校验错误的端点或密钥会在第一次模型请求时以 Provider 错误的形式暴露。没有公开的注销函数。凭据通过 Provider 自己的auth解析。内置工厂自带 Pi 的环境变量解析envApiKeyAuth自定义 Provider 声明自己的解析器——固定密钥、读环境变量或动态交换。Flue 在其上不叠加凭据层。参见 Pi — Authentication。模型解析Model resolution解析步骤模型说明符是provider-id/model-id在第一个/处切分。每次模型调用时针对当前注册表实时解析Provider ID 必须已注册——通过providers配置 的默认值或setProvider()。未知 Provider ID 抛错并点名已注册的 ID 与两条注册路径。Model ID 必须是该 Provider 声明的模型provider.getModels()。未知 Model ID 抛错并列出已声明的 ID。例外携带动态模型模板的 Provider——Flue 只内置了cloudflareBindingProvider()这一个——允许解析未声明的模型 ID但元数据为零reasoning: false转发的thinkingLevel会被丢弃、input: [text]图片块被替换为(image omitted)占位符、contextWindow: 0视为未知压缩compaction无法介入、maxTokens: 0、成本全零。网关厂商 IDanthropic/…、openai/…命中该回退时会按 ID 一次性打印警告点名模型与降级内容——通常的修复方式是升级到目录已收录该模型的 pi-ai 版本cf/…ID 则静默按此解析因为它们的线上格式不需要目录条目。源码视角的解析实现resolveModel()完整实现了上述三步先indexOf(/)检查是否有/没有则抛错提示使用provider-id/model-id格式例如anthropic/claude-haiku-4-5再切出 providerId 与 modelIdmodels.getProvider(providerId)为空时抛错并附上按字母排序的已注册 Provider 列表与两条注册路径提示modelId为空串acme/也视为非法最后models.getModel()解析失败时检查 Provider 是否携带DYNAMIC_MODEL_TEMPLATESymbol.for(flue.dynamicModelTemplate)标记定义见 providers.ts有则合成zeroMetadataModel()否则抛错并列出最多 8 个已声明模型 ID。要点解析失败抛出的是普通Error不是FlueError分类发生在模型调用解析说明符的时刻。模型元数据——上下文窗口、成本、推理能力、输入模态、按模型头——都活在 Provider 声明的Model对象上。要覆盖内置 Provider 的元数据就注册一个模型携带所需值的替换 Provider见 Models — Custom providers没有独立的覆盖接口。cloudflareBindingProvider()Workers AI 绑定 Provider签名与选项function cloudflareBindingProvider(options: CloudflareBindingProviderOptions): Provider; interface CloudflareBindingProviderOptions { binding: CloudflareAIBinding; // env.AI gateway?: CloudflareGatewayOptions | false; streamIdleTimeoutMs?: number; }构建cloudflareProviderPi 模型通过 Workers AI 绑定 的run(modelId, payload, options)进程内分发——没有baseUrl、没有apiKey、没有 HTTP 端点。绑定与解析后的网关选项被捕获进 Provider 的闭包。binding—— 捕获的env.AI引用。gateway—— 通过该 Provider 的每次run调用的 AI Gateway 路由。三态省略时走 Cloudflare 默认 AI Gateway选项对象{ id: default }绑定会按需为该账户开通传入CloudflareGatewayOptions对象则替换默认值false表示退出——不向run传任何网关选项。streamIdleTimeoutMs—— 模型流在交付一个字节之前允许空闲的上限超时则请求作为可重试中断失败回合在瞬时错误预算下重试。默认五分钟——这是刻意宽松的因为长思考模型在没有 keepalive 或推理 delta 流式输出时可能合法静默。0禁用该保护。从源码看cloudflareBindingProvider()先把三态网关解析为gateway false ? undefined : (gateway ?? { id: default })空闲超时默认取DEFAULT_STREAM_IDLE_TIMEOUT_MS 300_0005 分钟源码注释提到这是为「返回 200 后从此不再说话」的病态流准备的见 workers-ai-provider.ts然后构造一个ProviderIDcloudflare、名称Cloudflare Workers AI、无密钥auth的 resolver 直接返回空auth因为绑定本身就是凭据、models 来自两个目录见下文「元数据水合」并额外通过Object.assign挂上DYNAMIC_MODEL_TEMPLATE标记。流式函数把绑定与流配置捕获进闭包后统一走streamCloudflareWorkersAi分发。注册时机Cloudflare 目标当providers配置 省略或列出cloudflare时生成的 Worker 入口执行setProvider(cloudflareBindingProvider({ binding: env.AI }))——除非cloudflareID 的 Provider 已被注册。app.ts的导入被提升到生成入口体之上所以用户注册总是优先这正是项目指定命名网关、调缓存或退出的方式。providers列表不含cloudflare时既不发注册也不发导入。参见 Models — Cloudflare Workers AI 与 Cloudflare 目标指南。生成端逻辑见 cloudflare-entry.ts 的includeBindingProvider判断。元数据水合Provider 声明 Pi 的cloudflare-workers-ai目录重新打上cloudflareID 标签并加入 Pi 的cloudflare-ai-gateway目录网关条目的裸模型 ID 会加上其网关 URL 路径段中的厂商前缀gpt-5.6-terra→openai/gpt-5.6-terra与绑定寻址方式一致因此网关模型携带真实的上下文窗口、成本、推理能力thinkingLevelMap、输入模态与线上格式api。网关/compat条目被跳过——它们别名化 Workers AI 目录已声明的cf/…ID。任何其他 ID 仍可解析绑定接受任意模型 ID但使用模型解析一节所述的零元数据默认值。源码实现workers-ai-provider.tsbindingCatalogModels()取cloudflareWorkersAIProvider().getModels()并把每个模型重写为api: cloudflare-ai-binding标记、provider: cloudflare、空baseUrl、清空compatgatewayCatalogModels()则遍历cloudflareAIGatewayProvider().getModels()从baseUrl末尾段提取厂商compat直接丢弃把id改写为vendor/${model.id}。线上格式Wire format分发按模型选择序列化方式优先水合目录的api目录未知的 ID 按厂商前缀anthropic/…→ Anthropic Messagesopenai/…→ OpenAI Responsescf/…ID 与未知厂商走 OpenAI 兼容的 chat-completions 形态。Responses 分支把协议处理委托给 pi-ai 导出的原语通过模型的目录thinkingLevelMap映射推理努力级别并为无状态重放请求加密推理内容。目录api没有绑定分支的模型会得到显式流错误而非静默的错误载荷。每种形态都经binding.run发送携带returnRawResponse: true与解析后的gateway选项请求体不携带model字段——目标由run()的参数命名。具体到 源码 的bindingWireFormat()api anthropic-messages或以anthropic/开头走 Anthropic Messagesapi openai-responses或以openai/开头走 OpenAI Responsesapi openai-completions或等于cloudflare-ai-binding标记走 chat-completions其余返回undefined交给unsupportedWireFormatStream()产出显式错误流。chat-completions 分支还硬编码了一份WORKERS_AI_COMPAT兼容性配置L67-L94其中maxTokensField: max_completion_tokens、thinkingFormat: openai等字段决定了消息转换与 token 上限字段名。失败处理非 OK 的绑定响应抛出CloudflareAIBindingErrortype: cloudflare_ai_binding_error从flue/runtime/cloudflare导出413 响应额外携带meta.reason: request_too_large并触发压缩恢复。见 Errors —CloudflareAIBindingError。源码实现errors.ts把状态码与响应体嵌入错误消息而不仅是details因为只有消息能到达助手消息的errorMessage溢出分类读取的正是它——413 时还会追加WORKERS_AI_OVERFLOW_MARKER标记让上下文溢出恢复压缩 重试得以触发meta.reason则为遥测提供结构化的「会话超出供应商限制」信号无需解析消息即可区分可自愈的溢出与真实故障。此外流在两种情形下会被标记为可重试中断RETRYABLE_INTERRUPTION_MARKER (retryable_interruption)见 errors.tschat-completions 流结束却没有finish_reason以及 Responses 流干净结束却没有终结事件——二者都是传输层截断而非模型结果。Node 导入安全工厂及其类型在 Node.js 上可导入绑定形状是结构化的只有通过它实际调用模型才需要真实绑定。CloudflareGatewayOptionsAI Gateway 选项interface CloudflareGatewayOptions { id: string; skipCache?: boolean; cacheTtl?: number; cacheKey?: string; metadata?: Recordstring, number | string | boolean | null | bigint; collectLog?: boolean; eventId?: string; requestTimeoutMs?: number; }这是应用到每次经cloudflareBindingProvider()路由的binding.run(...)调用的 AI Gateway 选项。形状与 Cloudflare 的 Worker 绑定方法文档 一致各字段的供应商侧语义由 Cloudflare 定义除requestTimeoutMs外每个字段都原样转发进gateway选项。从flue/runtime/cloudflare导出。id—— 路由目标 AI Gateway IDslug。指定网关选项时必填。skipCache—— 本次请求绕过网关缓存。cacheTtl—— 缓存 TTL 覆盖单位秒。cacheKey—— 缓存键覆盖。metadata—— 显示在网关日志条目上的任意元数据。collectLog—— 强制收集或不收集请求日志。eventId—— 用于日志关联的自定义事件 ID。requestTimeoutMs—— 网关强制的首字节响应时限毫秒不是总时长——中段停滞要用streamIdleTimeoutMs配合。绑定没有等价字段因此它以请求头cf-aig-request-timeout发出而非转发在gateway选项中。从源码看gateway.ts 的注释确认了该形状与 Cloudflare 文档的对应关系并特别说明requestTimeoutMs的「头字段」实现。运行时在gatewayRunOptions()中把requestTimeoutMs从其余字段中剥离前者转为cf-aig-request-timeout请求头后者作为gateway对象传给ai.run。另外绑定 Provider 会从响应头的cf-aig-log-id读取本次响应自己的网关日志 ID绝不使用env.AI.aiGatewayLogId——那反映的是绑定最近一次请求并发下会错误归因并挂到 Provider 响应诊断上。CloudflareAIBinding绑定的结构化形状interface CloudflareAIBinding { run( modelId: string, inputs: Recordstring, unknown, options?: Recordstring, unknown, ): PromiseResponse | Recordstring, unknown; }Workers AI 绑定的最小结构化形状从flue/runtime/cloudflare导出。它刻意是结构化的——不是 Cloudflare 的Ai类型——这样工厂在 Node.js 上仍可导入。把真实的env.AI绑定作为CloudflareBindingProviderOptions的binding传入即可。源码 workers-ai-provider.ts 中该接口即上文所见的run(modelId, inputs, options)形状工厂内部把它断言为Ai后交给各流式分支。Provider 遥测模型回合可观测性事件turn_request.request与turn.request通过把 Provider ID 固定规范化为可观测性约定ModelRequestInfo.providerName来标识 Provider表外的 ID 原样透传。上报的服务器主机与端口从已解析模型的baseUrl解析。Provider IDproviderNameamazon-bedrockaws.bedrockazure-openai-responsesazure.ai.openaigooglegcp.geminigoogle-vertexgcp.vertex_aimistralmistral_aimoonshotai,moonshotai-cnmoonshot_aixaix_ai同样的事件始终把 Provider ID 原样上报为ModelRequestInfo.providerId。源码视角providers.tsproviderTelemetryName()是一张纯映射表按 OpenTelemetry GenAI 语义约定semconvgen_ai.system的 well-known 值把上述 ID 归一化未列出的 ID 走?? providerId原样返回。文档表格只列了需要改写的 ID源码中anthropic、deepseek、groq、openai等因为映射到自身anthropic → anthropic等而无需出现在规范表中。注册不改变什么Pi 的目录本身。注册只在解析时遮蔽一个 Provider ID绝不增删或修改目录条目。任何持久化内容。注册只活在当前模块作用域的进程内存里。不持久化、不跨进程或 isolate 共享每次启动都由模块顶层代码重建。其他 Provider ID 的早期注册。每次调用只影响恰好一个 Provider ID。把这一点与setProvider()的「替换而非合并」语义结合就形成了 Flue 的完整心智模型providers配置决定构建期默认注册谁setProvider()决定运行期注册表里谁生效两者叠加构成每个模型调用解析时的唯一事实来源而cloudflareBindingProvider()是唯一把「进程内绑定分发」而非 HTTP 端点暴露给该解析器的 Provider 实现。【免费下载链接】flueThe sandbox agent framework.项目地址: https://gitcode.com/GitHub_Trending/flue1/flue创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表