ARTICLE DETAIL

资讯详情

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

从零搭建基于Cloudflare Workers的AI聚合网关

从零搭建基于Cloudflare Workers的AI聚合网关 AI 聚合网关做的是这样一件事把多个大模型 API 统一收敛到一个入口对外暴露一个标准接口内部再根据模型名、上游地址、鉴权密钥和响应格式转发到不同服务商。配合 Cloudflare Workers 的边缘运行能力网关本身不需要购买服务器日常流量也可以放在免费额度内运行。标题里说的“白嫖”指的就是网关程序本身不产生服务器费用而不是上游大模型 API 不收费。下面从零搭建一个最小可用的 AI 聚合网关把它部署到 Cloudflare 云上并验证转发、鉴权、流式响应和调用计数这些核心能力。1. 为什么个人开发者需要一个 AI 聚合网关1.1 多模型接入带来的四个问题当项目只接一个模型服务商时事情很简单在代码里配置一个 API Key请求一个 URL解析一个 JSON 就结束了。但实际开发中团队或个人往往会同时使用多个模型做对比测试、A/B 实验或降级方案。这时候问题会迅速暴露出来第一是密钥分散。每个服务商都有自己的 API Key前端直接调用大模型时密钥只能暴露在客户端不同项目复制来复制去一旦泄漏需要在多个平台逐个撤销。第二是请求格式不统一。虽然很多服务商已经兼容 OpenAI 的/chat/completions格式但 Anthropic 的 Messages API、Google 的 Gemini API 各自有独立的请求结构和响应结构。业务代码每换一个供应商就要重写一层客户端适配。第三是切换成本高。模型的 prompt 调好之后代码里如果到处硬编码openai.chat.completions.create(...)想换成 DeepSeek 或通义千问就要改很多文件。第四是观测能力缺失。谁在什么时候调用了哪个模型、消耗了多少 token、哪个请求失败了如果没有统一入口这些信息只能从每个服务商的独立控制台去拼凑。AI 聚合网关解决的就是这组接入层问题。它不是一个模型训练工具也不是聊天客户端而是一个部署在业务和模型之间的 HTTP API 转发层。1.2 聚合网关的价值边界做一个聚合网关并不是为了让模型调用变得更神奇而是把“路由、鉴权、限流、日志、计量”这五类重复工作集中起来。在网关层可以统一做这样几件事统一鉴权客户端只持有网关的 API Key不需要接触任何上游模型的密钥。模型路由请求里写model: gpt-4o-mini网关负责转发到 OpenAI写model: deepseek-chat转发到 DeepSeek。格式转换上游如果用的是 Anthropic 或 Gemini 协议网关负责把 OpenAI 格式转成上游格式再把响应转回来。限流与计量按网关 Key、按模型、按时间窗口统计调用次数避免某个应用异常刷量。日志与追踪记录每次请求的状态码、耗时、输入输出 token供后续排查和成本分析。同时要明确它的边界。聚合网关不管模型质量不管 prompt 调优不管训练和微调也不负责解决上游服务商的故障。它的目标只有一个让业务侧把模型调用当成一次普通 HTTP 请求来处理。1.3 为什么选择 Cloudflare 作为免费运行底座部署一个需要长期运行的 HTTP 服务传统做法是租一台云服务器或者用容器平台托管。这需要考虑域名、公网 IP、进程守护、日志采集、端口安全等一系列问题。对于 AI 聚合网关这种轻量转发服务其实不需要完整的服务器环境。Cloudflare Workers 是边缘函数运行平台优势在于不需要自己管理操作系统和进程代码上传后由平台调度执行。天然支持 HTTPS可以绑定自定义域名。免费计划下提供每日一定数量请求额度适合个人项目和原型验证具体数值以 Cloudflare 控制台为准。支持 JavaScript 和 TypeScript社区生态成熟Hono、itty-router 等轻量框架都能直接运行。部署链路简单通过wrangler命令或 GitHub Actions 就能发布。需要说明的是Cloudflare 免费额度承担的是“网关程序运行成本”上游大模型服务商仍然会按照各自的价格收取 API 费用。网关的意义是把“运行成本和集成成本”降下来而不是让模型调用本身变成零成本。2. 网关的整体设计先理解一条请求要经过哪些环节2.1 请求从客户端到上游模型的完整链路一个比较标准的 AI 聚合网关请求链路如下客户端向网关的/v1/chat/completions发起POST请求。请求头携带网关 API Key请求体带上model、messages、stream等参数。网关先做鉴权再解析模型名。网关根据模型路由表找到对应的上游服务商配置。网关按照上游协议组装请求转发到真实模型 API。网关读取上游响应如果是流式响应则透传 SSE 数据流。网关记录调用计数把结果返回给客户端。在这个链路中对客户端来说网关就是一个“山寨版 OpenAI 服务”对上游模型 API 来说网关只是一个普通调用方。这种模式的最大好处是业务层可以保持稳定即使后续新增模型客户端代码也几乎不用改。2.2 OpenAI 兼容协议是聚合层的关键约定在做协议设计时最省力的方式是把“对外 API 协议”定义为 OpenAI 兼容协议。原因是生态成熟大量模型服务商都提供了 OpenAI 兼容端点客户端 SDK 也很丰富。对外协议一旦确定就可以复用以下标准语义参数作用示例model模型名决定路由目标gpt-4o-mini、deepseek-chatmessages对话上下文[{role:user,content:hello}]stream是否流式返回true或falsetemperature采样温度0.7max_tokens最大生成 token 数1024网关不需要关心每个参数的业务含义它只需要把这些参数原样透传给上游。真正需要做转换的是那些协议不兼容的上游。比如 Anthropic 的/v1/messages使用system字段和max_tokens必填规则和 OpenAI 格式不同。最小 MVP 阶段可以先只接入 OpenAI 兼容服务后续再逐步补齐非兼容协议。2.3 免费计划下的资源边界与取舍在设计阶段就要清楚免费计划的边界否则上线后容易出问题。Cloudflare Workers 免费计划通常关注这几个方面资源项需要关注的点落地建议每日请求数有免费额度上限先用于个人项目、小流量应用或接口测试CPU 时间每个请求有执行时间限制网关不要做大量本地计算转发逻辑要精简KV 操作数按日有读写次数限制计数逻辑控制频率不要每次请求都写大对象脚本数量账号下有数量限制不要把多个功能拆成过多独立 Worker上游调用时长请求整体耗时会占用 Worker 时间给上游设置合理 timeout避免长时间挂起这里的核心取舍是网关层保持轻量。不要在 Worker 里做复杂的数据清洗、文件处理或模型推理只做路由、鉴权、转发和计数。这样免费额度才能支撑更多真实请求。3. 环境准备与工程初始化3.1 本机需要准备的工具开始写代码前先把本机环境对齐。开发这个项目需要以下工具Node.js 18 或更高版本用于安装依赖和执行wrangler命令。npm 或 pnpm用于初始化项目和安装 Hono。Cloudflare 账号用于创建 Workers 服务、KV 命名空间和获取 API Token。Git 和 GitHub 账号用于后续接入自动化部署。curl 命令用于本地和线上接口验证。版本要求不是绝对的如果使用的是更高版本的 Node.js 或 npm通常也能正常运行。但安装前最好确认一下node -v和npm -v避免后面运行wrangler时出现版本兼容问题。3.2 用 Hono 初始化一个 Workers 项目选择 Hono 作为框架是因为它专门适配边缘运行环境体积小、写法简洁并且对 TypeScript 支持好。直接在项目目录执行npm create cloudflarelatest ai-gateway交互式命令行会询问初始化模板这里选择Hello World或TypeScript模板都可以。创建完成后进入项目目录cd ai-gateway npm install hono然后修改src/index.ts引入 Hono 并创建一个最小服务import { Hono } from hono; type Bindings { GATEWAY_API_KEY: string; OPENAI_API_KEY: string; KV: KVNamespace; }; const app new Hono{ Bindings: Bindings }(); app.get(/, (c) c.text(AI Gateway is running)); export default app;这一步的目的是先确认项目能够在本地跑起来再逐步增加功能。修改完代码后执行npm run dev如果看到本地开发服务器成功启动说明 Hono 和 wrangler 的配合正常。3.3 配置 KV 命名空间和本地密钥后续需要用 KV 记录调用计数所以先创建 KV 命名空间。执行wrangler kv namespace create KV命令执行后控制台会输出一个id将它写入wrangler.tomlname ai-gateway main src/index.ts compatibility_date 2024-11-01 [[kv_namespaces]] binding KV id 这里填写创建出来的KV命名空间ID真实的上游 API Key 不要直接写在wrangler.toml中因为该文件会被提交到 Git 仓库。本地开发时在项目根目录创建.dev.vars文件GATEWAY_API_KEYlocal-gateway-key OPENAI_API_KEYsk-your-openai-key.dev.vars会被 wrangler 在本地开发时自动读取并且应该加入.gitignore。这样可以避免密钥误提交到公开仓库。4. 核心代码实现从一个能转发请求的最小网关开始4.1 模型路由表把模型名映射到上游服务网关的第一个核心能力是“路由”。在src/下新建providers.ts维护一个模型到上游服务的映射表export interface ProviderProfile { baseUrl: string; apiKeyEnv: string; } export const providerProfiles: Recordstring, ProviderProfile { openai: { baseUrl: https://api.openai.com/v1, apiKeyEnv: OPENAI_API_KEY, }, deepseek: { baseUrl: https://api.deepseek.com/v1, apiKeyEnv: DEEPSEEK_API_KEY, }, }; export const modelToProvider: Recordstring, string { gpt-4o-mini: openai, deepseek-chat: deepseek, };这段配置的核心思想是把“模型名”和“上游服务商”分开维护。新增模型时只需要在modelToProvider中加一行新增服务商时在providerProfiles中加一条配置。业务代码不需要跟着改。如果某个上游服务商没有提供 OpenAI 兼容接口例如 Anthropic则需要单独处理。最简单的方式是在providerProfiles中增加一个protocol字段然后针对anthropic协议写一个转换函数。最小版本可以暂时不接这类非兼容协议。4.2 网关鉴权用统一密钥保护整个入口网关必须保护统一入口否则任何人拿到地址都能消耗上游 API 余额。在src/index.ts中添加一个中间件拦截所有/v1/*请求app.use(/v1/*, async (c, next) { const auth c.req.header(Authorization); const expected Bearer ${c.env.GATEWAY_API_KEY}; if (!auth || auth ! expected) { return c.json( { error: { message: Invalid API key, type: invalid_request_error, }, }, 401 ); } await next(); });这里的鉴权逻辑是同步比较请求头中的Authorization和配置的网关密钥。生产环境建议使用随机生成的强密钥长度至少 32 位并且定期轮换。密钥不要写死在代码里。这个设计的好处是客户端只需要保存一个网关密钥就能访问网关后面的所有模型。上游密钥全部保存在网关环境变量中不会暴露给业务层。4.3 转发逻辑兼容流式与非流式响应鉴权之后核心转发逻辑写在POST /v1/chat/completions处理器中app.post(/v1/chat/completions, async (c) { const body await c.req.json(); const model body.model as string; const providerId modelToProvider[model]; if (!providerId) { return c.json( { error: { message: Model ${model} is not supported, type: invalid_request_error, }, }, 404 ); } const profile providerProfiles[providerId]; const upstreamApiKey c.env[profile.apiKeyEnv as keyof Bindings]; if (!upstreamApiKey) { return c.json( { error: { message: Upstream API key for ${providerId} is not configured, type: server_error, }, }, 500 ); } const upstreamUrl ${profile.baseUrl}/chat/completions; const upstreamResp await fetch(upstreamUrl, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${upstreamApiKey}, }, body: JSON.stringify(body), }); return new Response(upstreamResp.body, { status: upstreamResp.status, headers: { Content-Type: upstreamResp.headers.get(Content-Type) ?? application/json, }, }); });这段代码最关键的地方是没有对请求体内的messages、temperature、max_tokens等参数做任何假设而是直接把body转发给上游。这样做的另一个好处是天然兼容流式响应。上游返回text/event-stream时upstreamResp.body是一个ReadableStreamnew Response(upstreamResp.body)会把它原样流式传给客户端。只要在返回头中带上上游的Content-Type客户端 SDK 就能正确解析 SSE 数据。4.4 用 KV 记录调用次数为限流打基础在网关中增加一个简化版的调用计数器。它的目的不是实现精确限流而是让后续做速率限制时有数据基础。app.post(/v1/chat/completions, async (c) { const auth c.req.header(Authorization) ?? ; const key auth.replace(Bearer , ); const hourBucket new Date().toISOString().slice(0, 13); const counterKey calls:${key}:${hourBucket}; const current Number((await c.env.KV.get(counterKey)) ?? 0); if (current 100) { return c.json( { error: { message: Rate limit exceeded, type: rate_limit_error, }, }, 429 ); } await c.env.KV.put(counterKey, String(current 1), { expirationTtl: 3600, }); // 这里再执行上一小节的转发逻辑 });这个按小时分桶的计数方案在个人项目中已经足够。需要指出的是Cloudflare KV 是最终一致性存储计数可能不是绝对精确所以它更适合做“超过阈值后拒绝”的粗粒度保护。如果业务上要求严格的毫秒级限流需要用 Durable Objects 或自建限流服务但那样会增加复杂度。5. 一键部署到 Cloudflare 的完整流程5.1 本地运行与部署验证写完代码后先执行本地验证npm run dev确认本地服务能启动后执行部署命令npx wrangler login npm run deploywrangler login会打开浏览器完成账号授权。npm run deploy会把当前代码打包上传到 Cloudflare Workers。部署成功后控制台会输出一个形如https://ai-gateway.你的子域.workers.dev的域名。这一步验证通过意味着网关已经运行在 Cloudflare 的云上不再依赖本地机器。5.2 把敏感配置转为线上 Secret本地开发时使用.dev.vars存放密钥线上部署时不能使用这种方式。需要把密钥写入 Cloudflare 的环境变量或 Secret 中。推荐使用wrangler secret命令npx wrangler secret put GATEWAY_API_KEY npx wrangler secret put OPENAI_API_KEY执行命令后终端会提示输入密钥值。Secret 与[vars]的区别在于Secret 不会被写入明文配置也不容易随着代码仓库泄露。非敏感配置比如compatibility_date可以放在wrangler.toml中。上线前检查一下是否所有上游 API Key 都已经通过 Secret 写入否则线上请求会因为缺少密钥而返回 500。5.3 接入 GitHub Actions 实现自动部署把项目推送到 GitHub 仓库后可以配置 GitHub Actions让每次推送代码到主分支时自动部署。在仓库中创建.github/workflows/deploy.ymlname: Deploy Worker on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm ci - name: Deploy to Cloudflare Workers uses: cloudflare/wrangler-actionv3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}为了让这个工作流运行起来需要在 GitHub 仓库的 Settings - Secrets and variables - Actions 中配置两个变量Secret 名称说明CLOUDFLARE_API_TOKENCloudflare API Token需要包含 Workers 脚本编辑权限CLOUDFLARE_ACCOUNT_ID当前 Cloudflare 账号的 Account ID配置完成后第一次推送代码GitHub Actions 会自动拉取依赖、认证 Cloudflare、执行部署。之后更新网关代码只需要正常git push即可。5.4 一键部署入口是怎么工作的所谓一键部署本质上是由一个外部部署面板接管“认证、读取仓库、安装依赖、触发 wrangler”这些步骤。Cloudflare 官方提供基于 GitHub 仓库的快速部署入口用户点击部署链接后会进入 Cloudflare 控制台授权自己的 GitHub 账号和仓库再填写必要的环境变量系统会自动完成部署。这个能力依赖 Cloudflare 当前控制台提供的集成具体入口形式可能随产品迭代变化落地时以 Cloudflare 官方文档为准。为了避免完全依赖平台按钮项目的 README 中也可以同时提供两种方式普通开发者直接执行npm run deploy。不想手动装环境的用户通过部署按钮走可视化流程。这样“一键”和“手动”并存适配更多使用场景。6. 运行验证用 curl 检查转发、鉴权和流式结果6.1 验证非流式对话补全部署完成后用 curl 发送一个普通对话请求。假设网关域名是https://ai-gateway.你的子域.workers.devcurl -X POST https://ai-gateway.你的子域.workers.dev/v1/chat/completions \ -H Authorization: Bearer $GATEWAY_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 你好用一句话介绍自己}], stream: false }正常返回的 JSON 结构应该是 OpenAI 风格的choices数组。如果模型名写成deepseek-chat网关会把请求转发到 DeepSeek。这种验证方式确认了路由、鉴权、上游密钥读取和 JSON 透传都正常工作。6.2 验证流式对话补全把请求体中的stream改为truecurl -X POST https://ai-gateway.你的子域.workers.dev/v1/chat/completions \ -H Authorization: Bearer $GATEWAY_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 从1数到5}], stream: true }正常情况下会连续输出多行data: {...}格式的 SSE 数据最后以data: [DONE]结束。如果看到这个结果说明流式透传逻辑正确。6.3 验证鉴权失败、模型不存在和限流分支分别验证异常分支curl -X POST https://ai-gateway.你的子域.workers.dev/v1/chat/completions \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:hi}]}没有携带Authorization头时应该返回401和Invalid API key。curl -X POST https://ai-gateway.你的子域.workers.dev/v1/chat/completions \ -H Authorization: Bearer $GATEWAY_API_KEY \ -H Content-Type: application/json \ -d {model:not-exist-model,messages:[{role:user,content:hi}]}模型名不在路由表中时应该返回404和Model not supported。限流分支需要短时间内连续请求同样的网关 Key当当前小时窗口内计数达到阈值后会返回429。验证时可以把阈值临时调低例如改成3避免真的等满一小时。7. 上线前必看的排查清单7.1 本地能通线上 401 或 500现象是本地开发时请求正常部署到线上后出现401或500。优先检查环境变量。线上密钥是通过wrangler secret put写入的如果某个 Secret 没有设置运行时读取到的是undefined鉴权中间件会直接拒绝请求。另外wrangler.toml中的[vars]和 Secret 不要同名冲突避免出现“改了 Secret 但线上仍使用旧值”的情况。检查方式npx wrangler secret list确认所有需要的 Secret 都在列表中并且键名与代码中c.env.xxx的变量名完全一致。7.2 上游模型返回非 OpenAI 兼容格式如果路由的是一家非 OpenAI 兼容服务商直接把请求体透传过去通常无法工作。例如 Anthropic 的/v1/messages不识别messages数组中带systemrole 的写法响应结构也完全不同。解决办法是不要强求“一个透传打天下”。在providerProfiles中增加协议类型然后针对不同协议写转换函数。MVP 阶段建议先只接 OpenAI 兼容服务等核心流程稳定后再逐步扩展。7.3 请求超时、CORS 和请求体大小限制Workers 运行在边缘节点但上游 API 可能分布在海外或不同区域。请求耗时过长时要检查两个方向上游响应慢还是网关处理逻辑有阻塞。另外如果前端页面直接调用网关接口需要处理 CORS 预检请求。在 Hono 中可以增加 CORS 中间件允许指定域名访问import { cors } from hono/cors; app.use(/v1/*, cors());生产环境不要使用全开放 CORS建议把origin限制为可信的前端域名。同时要注意平台对请求体大小的限制。正常对话请求不会太大但如果业务中接入了超长文档过大的请求体会被平台拒绝。遇到这种情况应该把文档处理逻辑放到网关之外而不是让网关承担大文件转发。7.4 常见问题速查表问题现象常见原因检查方式处理建议线上请求返回 401缺少GATEWAY_API_KEY或请求头错误检查 Secret 列表和 curl 请求头重新wrangler secret put确认Bearer前缀返回 500提示上游 Key 未配置只配置了本地.dev.vars没有配置线上 Secretwrangler secret list为每个上游服务商配置对应 Secret模型不存在返回 404路由表中没有该模型名检查modelToProvider配置添加模型映射或返回更清晰的错误信息流式响应异常或乱码返回头没有透传Content-Type检查 HTTP 响应头使用上游的Content-Type必要时透传其他头CORS 预检失败浏览器先发OPTIONS请求服务端没有处理查看浏览器控制台和请求网络日志配置hono/cors中间件KV 计数不准KV 是最终一致性存储连续快速请求观察计数接受粗粒度统计或改用 Durable Objects8. 从一周原型到可用服务最佳实践与扩展方向8.1 免费计划适合什么不适合什么通过 Cloudflare 免费计划部署的 AI 聚合网关适合个人学习、内部工具、低流量应用、原型验证和小范围实验。不要把它直接当作大型生产系统的核心链路除非已经做好付费计划、多区域容灾、完整监控和上游降级方案。免费计划下需要为“增长”留好退路。当请求量增长到接近额度上限可以考虑升级 Cloudflare Workers 付费计划以获得更高配额。增加网关缓存层对重复 prompt 和相同结果做短时间缓存。接入限流和告警防止异常流量消耗完整月额度。把日志和计量数据写入外部对象存储避免长期占用 KV 操作额度。8.2 一周内完成的最小版本范围如果只有一周时间建议按下面的顺序完成不要一开始就追求完整商业版功能阶段任务验收标准第 1-2 天搭建 Workers 工程接入 Hono实现鉴权和单上游转发curl 能通过网关调用一个真实模型第 3-4 天增加模型路由表接入两个 OpenAI 兼容服务切模型名可以访问不同上游第 5 天增加 KV 调用计数配置 CORS同一个 Key 超限后返回 429第 6 天接入 GitHub Actions部署到线上推送代码后自动更新线上 Worker第 7 天写 README、补充环境变量说明、整理部署入口新开发者按文档能在 15 分钟内完成部署这个范围的意义在于每一步都能独立验证。即使第七天没有时间做扩展得到的依然是一个可以真实使用的网关。8.3 可继续扩展的功能清单网关稳定运行后可以考虑增加以下能力请求体和响应体压缩减少网络传输消耗。多上游负载均衡同一个模型配置多个服务商实现降级切换。按用户、按项目、按模型分别计量生成成本报表。接入自定义域名和 CDN 策略提升国内访问体验。增加缓存层对相同 system prompt 和固定问题返回缓存结果。增加 Prometheus 指标把网关请求量、错误率、p95 耗时接入监控。其中优先建议做“多上游降级”和“计量报表”。前者能在某个服务商故障时保命后者能让你真正知道每个业务线在模型 API 上花了多少钱。AI 聚合网关的价值不在于代码复杂度而在于把“多模型接入”这个重复问题收敛成一份配置和一段可复用代码。部署在 Cloudflare Workers 上让网关的运行成本近乎为零也让这个项目天然具备云上部署、自动化发布和边缘接入的特点。先把最小闭环跑起来再根据真实使用情况决定要不要扩展限流、缓存、监控和计费这条路会比一开始就设计一个大而全的系统更可靠。
返回列表