两个 Cloudflare 网关:把 Workers AI 包成 OpenAI 接口,再把新协议翻译回去

番星

Cloudflare 有两样东西挺好用:Workers AI 的免费额度,和 Workers 本身。但它们和现有的 AI 客户端之间隔着两层协议。

于是写了两个网关,一个往上包,一个往下翻。

cloudflare-open:把 Workers AI 包成 OpenAI 接口

cloudflare-open 把 Workers AI 封装成 OpenAI 兼容的多模态 API,零服务器成本,绑个自定义域名国内也能直连。

支持五类能力,覆盖 53 个模型:

  • POST /v1/chat/completions — 对话,支持 SSE 流式、tools 函数调用、response_format、视觉模型的 image_url
  • POST /v1/images/generations — 文生图,返回 data[].b64_json
  • POST /v1/audio/speech — TTS,mp3/wav/pcm/opus/aac/flac
  • POST /v1/audio/transcriptions — STT,multipart 直传
  • POST /v1/embeddings — 文本向量

另外还有 /v1/models、/health 存活探针、Bearer 鉴权(SHA-256 摘要后逐位比对,不做短路)、CORS 预检,以及一个跟着访问域名自动渲染的在线文档页。

踩得最狠的坑:入参要按模型裁剪

Workers AI 各家模型的 input schema 完全不一样,Cloudflare 对没声明的键要么报错要么静默忽略。实测遇到的:

情况正确写法
flux-1-schnell 步数steps(上限 8),不是 num_steps,而且不吃 width/height/guidance
SDXL / Leonardo 系步数num_steps
aura 音色speaker 枚举,没有 lang
中文语音只能用 @cf/myshell-ai/melotts(prompt + lang: "zh")
bge-m3 向量query / contexts[],不是 text
老版 whisper 音频0–255 的字节数组

所以网关里做了一张按模型的参数映射表,而不是简单透传。这是整个项目最费时间的部分。

cf-api-switch:把新协议翻译回旧格式

cf-api-switch 解决的是反方向的问题。

现在很多客户端开始用 OpenAI 新的 /v1/responses 协议,但手上那些中转站(DeepSeek、火山方舟、各种 NewAPI / one-api)只认老的 chat/completions。

这个 Worker 在中间做翻译:

1
2
3
4
5
客户端                          Worker                              上游
/v1/responses ┐ 解析路径:<渠道名>/v1/<端点> DeepSeek
/<渠道名>/v1/responses ├─────▶ 入站协议 → 内部中间表示 ──▶ 火山方舟
/v1/chat/completions │ 内部表示 → 该渠道原生格式 NewAPI
/v1/messages ┘ 响应按入站协议翻译回去 OpenAI

路由规则很简单:https://你的域名/<渠道名>/v1/<端点>,第一段是渠道标识,后面是标准端点。渠道配置存在 Workers KV 里,有个 /_admin 面板可以增删改。

好处是客户端不用改,新协议能力直接用;坏处是中间表示层要覆盖的字段不少,流式响应的转换尤其容易出边界问题。

两个项目的关系

一个把平台能力「翻译成标准」,一个把标准「翻译成平台能听懂的」。方向相反,问题同源:协议不统一。

如果你也在这两者之间来回折腾,这两个仓库可以直接拿去改。

  • 标题: 两个 Cloudflare 网关:把 Workers AI 包成 OpenAI 接口,再把新协议翻译回去
  • 作者: 番星
  • 创建于 : 2026-10-16 21:00:00
  • 更新于 : 2026-10-21 20:11:26
  • 链接: https://xingbox.me/cloudflare-ai-gateways/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。