最近在做一个多模型接入的小项目,发现每次对接不同的 AI 服务商都要写一堆适配代码,密钥管理也散落各处,临时想统一走一个入口却找不到趁手的工具。花了一周时间,我直接自己搓了一个轻量级 AI 聚合网关,并且利用 Cloudflare 的免费额度完成了云上部署,整个过程没有买服务器、没有备案,成本几乎为零。
这篇文章会把整个思路和实现过程完整记录下来,从核心概念、环境准备、网关代码实现,到一键部署、自动发布、常见排错,一次讲清楚。不管是想自己搭一个 AI 网关,还是想白嫖云资源做个人项目,这篇文章都值得收藏。
1. 背景与核心概念
1.1 什么是 AI 聚合网关
先来说说 AI 聚合网关到底是干什么的。
正常情况下,一个应用如果同时对接多个 AI 模型提供方,比如 OpenAI、Anthropic、Google Gemini,以及国内的一些大模型服务,你需要分别处理各家不同的接口地址、认证方式、请求格式、限流策略。一旦模型数量变多,代码会变得非常臃肿,维护成本也很高。
AI 聚合网关做的事情就是把这些差异都屏蔽掉,对外提供一个统一、稳定的 API 入口。客户端只需要按照一套标准格式发起请求,网关负责将请求转发到正确的模型服务商,并把响应结果返回给客户端。
用通俗的话来说,网关就像是一个前台中转站。你不用再记住每个公司的门牌号和接待方式,只需要跟前台说一句“我要找谁”,后面的事情由前台来处理。
1.2 AI 聚合网关的核心功能
一个完整的 AI 聚合网关通常包含以下能力:
| 功能模块 | 说明 |
|---|---|
| 统一 API 入口 | 对外提供标准接口,客户端无需关心每个上游服务的差异 |
| 模型路由 | 根据请求中的模型名称,自动转发到对应的服务商 |
| 密钥管理 | 多个上游服务的 API Key 统一存放在网关侧,不暴露给客户端 |
| 参数转换 | 将统一格式的请求转换为各服务商要求的格式 |
| 错误处理与重试 | 上游故障时返回友好提示,可选自动重试 |
| 限流与权限校验 | 控制调用频率,防止接口被滥用 |
| 日志与统计 | 记录请求量、延迟、失败率,便于观察和排错 |
这些能力如果自己从零去写,工作量不小。但如果利用 Cloudflare Workers 这样的边缘计算服务,配合第三方开源模型,网关的骨架可以在很短时间内搭出来。
1.3 为什么选择 Cloudflare 作为部署平台
Cloudflare 不是一家传统的云服务器厂商,它的核心优势在于全球边缘网络。你写的一段代码可以部署到离用户最近的节点上,用户访问时延迟更低。
对于个人开发者来说,Cloudflare 最有吸引力的其实是免费额度:
- Workers 免费计划每天有 10 万次请求额度,个人项目完全够用。
- 免费提供 HTTPS 证书,可以绑定自定义域名。
- 提供 Workers KV 存储,可以存放配置数据。
- 配合 GitHub 可以进行自动化部署。
换句话说,你不需要购买任何云服务器,也不需要为流量付费,只要代码量不大、请求量在免费额度内,这个网关可以长期“零成本”运行。
2. 整体架构与方案设计
2.1 免费云上部署的整体架构
在动手之前,先把整体架构想清楚,后面写代码时思路会顺畅很多。
本文实现的 AI 聚合网关采用如下架构:
- 客户端发送标准 OpenAI 兼容格式的请求到 Cloudflare Workers 网关地址。
- Workers 中的网关程序解析请求,提取模型名称和消息内容。
- 网关根据模型名称,匹配上游服务配置,替换 API Key,转换请求格式。
- 通过
fetch转发到真实的 AI 服务商接口。 - 获取上游响应,转换回统一格式,返回给客户端。
整个链路中,只有网关这一个入口是暴露在外的,所有上游服务的密钥都保存在 Cloudflare Workers 的环境变量或 KV 存储中。
2.2 Cloudflare 免费额度说明
Cloudflare 的免费计划对个人项目非常友好。以 Workers 为例:
- 每天 10 万次请求。
- 每天 30 分钟 CPU 时间。
- 支持 Workers KV,每天上限 10 万次读操作。
- 免费绑定自定义域名,并启用 CDN 加速。
- 自带基础防护能力。
需要注意的是,免费额度是每日计算的,如果某一天请求量突然暴增,可能会触发用量限制,这时请求会返回错误。对于个人学习项目和小流量应用来说,这个额度已经非常宽裕了。
2.3 项目目录结构
在写代码之前,我先列出项目的完整目录结构,让你有一个整体感知:
ai-gateway/ ├── .github/ │ └── workflows/ │ └── deploy.yml # GitHub Actions 自动部署配置 ├── src/ │ ├── gateway.js # Worker 主入口,路由分发 │ ├── config.js # 上游服务配置 │ ├── providers/ │ │ ├── openai.js # OpenAI 适配器 │ │ ├── anthropic.js # Anthropic 适配器 │ │ └── gemini.js # 自定义模型适配器 │ └── utils/ │ ├── response.js # 统一响应处理 │ └── crypto.js # 签名校验工具 ├── dashboard/ │ ├── index.html # 简单管理面板 │ └── app.js # 面板前端逻辑 ├── .dev.vars # 本地开发环境变量 └── wrangler.toml # Cloudflare Workers 配置这个目录结构并不是死的,你可以根据自己的实际需要增删。核心是src目录下的网关逻辑,其他都可以灵活调整。
3. 环境准备与账号配置
3.1 本地开发环境
开始之前,先确保本地环境满足以下要求。版本需要根据你的实际项目情况调整,本文示例以常见环境为例,重点演示配置思路。
- Node.js 18 或以上版本。
- npm 或 pnpm 包管理器。
- Git 命令行工具。
- 一个 GitHub 账号,用来存储代码和触发自动部署。
- 一个 Cloudflare 账号,用来部署 Workers。
如果你还没有安装 Node.js,可以去官网下载 LTS 版本,安装完成后在终端验证一下:
node -v npm -v3.2 Cloudflare 账号准备
登录 Cloudflare 控制台后,不需要做太复杂的配置。你需要拿到两个关键信息:
- Account ID:在控制台首页右侧可以找到。
- API Token:在右上角头像 -> My Profile -> API Tokens 中创建。
创建 API Token 时,选择Edit Cloudflare Workers模板,权限范围只需要包含 Workers 即可。生成的 Token 只会显示一次,一定要保存好。
3.3 安装 Wrangler CLI
Wrangler 是 Cloudflare 官方提供的命令行工具,用来开发、调试、部署 Workers。安装方式很简单:
npm install -g wrangler安装完成后,验证一下版本:
wrangler --version然后登录 Cloudflare 账号:
wrangler login执行后浏览器会打开授权页面,点击允许即可。登录成功后在终端会看到对应的提示。
如果不想全局安装,也可以作为项目依赖安装,这样团队协作时版本更统一:
npm install -D wrangler4. 核心代码:AI 聚合网关 Worker 实线
4.1 创建 Worker 项目
使用 Wrangler 初始化一个项目:
mkdir ai-gateway cd ai-gateway wrangler init在初始化过程中,Wrangler 会询问是否创建基础代码和配置文件,按需选择即可。最终项目里会生成一个wrangler.toml文件和src/目录。
接下来,我们需要安装路由处理相关的依赖。为了保证网关代码足够轻量,我只引入一个用于 URL 匹配的库:
npm install itty-routeritty-router是一个轻量级路由库,非常适合 Cloudflare Workers 环境,体积小、语法简单。
4.2 配置 wrangler.toml
wrangler.toml是 Cloudflare Workers 的核心配置文件。我的参考配置如下:
name = "ai-gateway" main = "src/gateway.js" compatibility_date = "2024-09-01" workers_dev = true [vars] GATEWAY_TOKEN = "your-gateway-token" # 以 OpenAI 为例,其他服务商的密钥也可以放在这里 OPENAI_API_KEY = "sk-your-openai-key" # 如果用到 KV 存储,开下面这行 # [[kv_namespaces]] # binding = "GATEWAY_KV" # id = "your-kv-namespace-id"配置说明:
name:Worker 服务名称,会作为默认子域名的一部分。main:入口文件路径。compatibility_date:Cloudflare 运行时兼容性日期。vars:环境变量,可以在代码中直接读取。
有一点要特别提醒:你的 API Key 如果写在这个配置文件里,那么上传到 GitHub 时一定要确保仓库是私有的。更安全的做法是使用.dev.vars存放本地密钥,生产环境的密钥通过 Cloudflare 控制台或 GitHub Actions Secrets 注入。
4.3 编写网关主入口
网关主入口是整篇文章的核心,它负责接收所有请求,并转发到对应的上游 AI 服务。
先来看一个简化版的主入口代码:
// 文件路径:src/gateway.js import { Router } from 'itty-router'; import { handleChatCompletion } from './routes/chat'; import { handleModels } from './routes/models'; import { authMiddleware } from './middleware/auth'; const router = Router(); // 所有请求都要经过鉴权中间件 router.all('*', authMiddleware); // 获取模型列表 router.get('/v1/models', handleModels); // 对话补全接口 router.post('/v1/chat/completions', handleChatCompletion); // 健康检查 router.get('/health', () => new Response('OK', { status: 200 })); export default { async fetch(request, env, ctx) { try { return await router.handle(request, env, ctx); } catch (err) { return new Response( JSON.stringify({ error: { message: err.message || 'Internal Server Error', type: 'internal_error' } }), { status: 500, headers: { 'Content-Type': 'application/json' } } ); } } };这段代码的职责非常清晰:
- 使用
itty-router注册路由规则。 - 对所有请求先执行鉴权中间件。
- 对不同的路径分发到对应的处理函数。
- 全局捕获异常,统一返回 JSON 格式错误。
4.4 实现鉴权中间件
既然是网关,就不能让所有拿到地址的人随便调用。我给网关加了一个简单的 Token 鉴权机制。
// 文件路径:src/middleware/auth.js export async function authMiddleware(request, env) { // 健康检查不需要鉴权 if (new URL(request.url).pathname === '/health') { return; } const authHeader = request.headers.get('Authorization') || ''; const token = authHeader.replace('Bearer ', ''); if (!token || token !== env.GATEWAY_TOKEN) { return new Response( JSON.stringify({ error: { message: 'Unauthorized', type: 'auth_error' } }), { status: 401, headers: { 'Content-Type': 'application/json' } } ); } }这个中间件的逻辑很简单:请求头里必须携带Authorization: Bearer <token>,并且 token 要和环境变量GATEWAY_TOKEN一致,否则直接返回 401。
在实际项目中,这里可以升级为 JWT 校验、API Key 轮换、按用户维度限流等能力,本文先保持最简实现。
4.5 实现对话补全路由
对话补全接口是网关的核心。下面是一个能实际工作的简化版本,逻辑是:根据请求里的模型名称,把请求转发给 OpenAI 的 Chat Completions 接口。
// 文件路径:src/routes/chat.js const OPENAI_CHAT_URL = 'https://api.openai.com/v1/chat/completions'; export async function handleChatCompletion(request, env) { const body = await request.json(); const model = body.model; if (!model) { return new Response( JSON.stringify({ error: { message: 'Missing model parameter', type: 'invalid_request_error' } }), { status: 400, headers: { 'Content-Type': 'application/json' } } ); } // 这里可以做模型路由,根据 model 名称转发到不同服务商 // 为了演示,这里统一走 OpenAI const upstreamResponse = await fetch(OPENAI_CHAT_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${env.OPENAI_API_KEY}` }, body: JSON.stringify(body) }); const data = await upstreamResponse.json(); return new Response(JSON.stringify(data), { status: upstreamResponse.status, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }); }在上面的例子里,网关做的事情其实就是“透传”。客户端发什么,网关就原样转发给 OpenAI。注意,这只是一个演示版本,实际项目中还需要处理以下问题:
- 不同服务商的接口格式不同,需要做参数转换。
- 请求失败时需要返回更明确的错误信息。
- 响应需要统一格式,方便客户端处理。
4.6 实现 OpenAI 兼容接口
为了让上游服务格式不统一的问题得到解决,我在网关内部设计了一个“适配器”概念。
每个上游服务商实现一个chat方法,负责将统一请求体转换为该服务商要求的格式。
以 OpenAI 适配器为例:
// 文件路径:src/providers/openai.js export async function chat(messages, options, env) { const url = options.baseUrl || 'https://api.openai.com/v1/chat/completions'; const apiKey = env.OPENAI_API_KEY; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify({ model: options.model || 'gpt-4o-mini', messages, temperature: options.temperature ?? 0.7, max_tokens: options.maxTokens || 1000 }) }); if (!response.ok) { const errorText = await response.text(); throw new Error(`OpenAI upstream error: ${response.status} ${errorText}`); } return await response.json(); }再看一个自定义模型的适配器示例,假设上游接口是兼容 OpenAI 格式的,但接口地址和密钥不同:
// 文件路径:src/providers/custom.js export async function chat(messages, options, env) { const url = env.CUSTOM_BASE_URL || 'https://custom-ai.example.com/v1/chat/completions'; const apiKey = env.CUSTOM_API_KEY; const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify({ model: options.model, messages, temperature: options.temperature ?? 0.7 }) }); if (!response.ok) { const errorText = await response.text(); throw new Error(`Custom upstream error: ${response.status} ${errorText}`); } return await response.json(); }有了适配器之后,路由层就变得更灵活了。在chat.js里做一个简单的模型映射即可:
// 文件路径:src/routes/chat.js(升级版) import { chat as openaiChat } from '../providers/openai'; import { chat as customChat } from '../providers/custom'; const modelProviderMap = { 'gpt-4o-mini': 'openai', 'gpt-4o': 'openai', 'custom-model-1': 'custom' }; export async function handleChatCompletion(request, env) { const body = await request.json(); const { messages, model } = body; if (!model || !messages) { return new Response( JSON.stringify({ error: { message: 'model and messages are required', type: 'invalid_request_error' } }), { status: 400, headers: { 'Content-Type': 'application/json' } } ); } const providerName = modelProviderMap[model]; if (!providerName) { return new Response( JSON.stringify({ error: { message: `Unsupported model: ${model}`, type: 'invalid_request_error' } }), { status: 400, headers: { 'Content-Type': 'application/json' } } ); } let result; if (providerName === 'openai') { result = await openaiChat(messages, { model }, env); } else if (providerName === 'custom') { result = await customChat(messages, { model }, env); } return new Response(JSON.stringify(result), { status: 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }); }这段代码采用了一张简单的映射表,将不同模型名称指向不同的处理器。当新增模型服务商时,只需要新增适配器并更新映射表,主流程代码不需要改动。
实际生产项目中,模型映射表可以放到 Workers KV 中,这样你可以在不发布新代码的情况下,动态修改模型路由规则。
4.7 添加 CORS 支持
如果你的网关会从浏览器端调用,必须处理跨域问题。可以在入口处统一添加响应头:
// 文件路径:src/utils/cors.js export const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization' }; export function handleOptions(request) { if (request.method === 'OPTIONS') { return new Response(null, { status: 204, headers: corsHeaders }); } }在入口文件中,针对 OPTIONS 请求直接返回:
import { handleOptions, corsHeaders } from './utils/cors'; const router = Router(); router.all('*', (request) => { if (request.method === 'OPTIONS') { return handleOptions(request); } });4.8 统一响应格式
为了让客户端处理响应时更简单,我将成功和失败两种情况统一格式。
成功响应示例:
{ "success": true, "data": { "id": "chatcmpl-123", "object": "chat.completion", "model": "gpt-4o-mini", "choices": [...] } }失败响应示例:
{ "success": false, "error": { "message": "上游服务超时", "type": "upstream_timeout" } }这样设计的好处是,客户端只需要检查success字段就可以判断请求是否成功,不需要去解析 HTTP 状态码。
5. 一键部署到 Cloudflare Workers
5.1 本地调试
在部署到线上之前,先在本地启动开发服务器调试:
wrangler dev启动后,Wrangler 会在本地开启一个端口,比如http://localhost:8787。你可以用 curl 测试接口:
curl -X POST http://localhost:8787/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-gateway-token" \ -d '{ "model": "gpt-4o-mini", "messages": [ { "role": "user", "content": "你好,介绍一下你自己" } ] }'如果一切正常,你会收到来自模型服务商的响应内容。
5.2 手动部署
本地调试通过后,直接执行部署命令:
wrangler deploy执行完成后,终端会输出一个 Workers 域名,形如:
https://ai-gateway.your-subdomain.workers.dev这个地址就是网关的公网入口。用浏览器打开/health路径,能看到一个简单的 OK 响应。
5.3 配置 GitHub Actions 自动部署
手动部署每次都要在本地执行命令,不够自动化。更推荐的做法是配置 GitHub Actions,在每次 push 到 main 分支时自动部署。
首先,在 GitHub 仓库的Settings -> Secrets and variables -> Actions中配置以下 Secrets:
CLOUDFLARE_API_TOKEN:你之前创建的 API Token。CLOUDFLARE_ACCOUNT_ID:Cloudflare 控制台中的 Account ID。
然后创建文件.github/workflows/deploy.yml:
name: Deploy Worker on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm ci - name: Deploy to Cloudflare Workers run: npx wrangler deploy env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}这个工作流的逻辑很清晰:
- 监听 main 分支的 push 事件。
- 签出代码。
- 安装 Node.js 环境。
- 安装依赖。
- 执行
wrangler deploy部署。
以后你只需要把代码 push 到 GitHub 仓库的 main 分支,GitHub Actions 会自动完成部署,真正实现“一键云上部署”。
5.4 配置自定义域名
如果你有自己的域名,并且域名托管在 Cloudflare,可以在控制台为 Worker 绑定自定义域名。
在 Cloudflare 控制台中进入你的 Worker 服务,点击Settings -> Domains & Routes -> Add,输入你想绑定的域名,比如ai-api.example.com,保存后等待 DNS 生效即可。
绑定成功后,你访问的地址就变成了你自己的域名,不再需要通过workers.dev子域名对外提供服务。
6. 前端管理面板
6.1 为什么需要管理面板
网关上线后,总不能每次看日志都去 Cloudflare 控制台。这里我顺手做了一个极简管理面板,部署在 Cloudflare Pages 上,用来展示网关的基本状态和调用统计。
6.2 面板页面示例
管理面板只包含一个简单的 HTML 页面:
<!-- 文件路径:dashboard/index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>AI Gateway Dashboard</title> <style> body { font-family: system-ui, sans-serif; max-width: 800px; margin: 0 auto; padding: 24px; } .card { border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; margin-bottom: 16px; } .status { font-weight: bold; } .online { color: #16a34a; } .offline { color: #dc2626; } </style> </head> <body> <h1>AI Gateway Dashboard</h1> <div class="card"> <h2>网关状态</h2> <p class="status" id="healthStatus">检测中...</p> </div> <div class="card"> <h2>模型配置</h2> <ul id="modelList"> <li>gpt-4o-mini -> OpenAI</li> <li>gpt-4o -> OpenAI</li> <li>custom-model-1 -> Custom</li> </ul> </div> <script src="./app.js"></script> </body> </html>6.3 面板前端逻辑
// 文件路径:dashboard/app.js async function checkHealth() { try { const response = await fetch('/health'); const statusEl = document.getElementById('healthStatus'); if (response.ok) { statusEl.textContent = '在线'; statusEl.classList.add('online'); } else { statusEl.textContent = '异常'; statusEl.classList.add('offline'); } } catch (err) { const statusEl = document.getElementById('healthStatus'); statusEl.textContent = '离线'; statusEl.classList.add('offline'); } } checkHealth();这个页面非常简单,实际项目中可以扩展为请求量图表、错误率统计、模型调用占比等更丰富的展示。把dashboard目录部署到 Cloudflare Pages 即可。
7. 常见问题与排查思路
7.1 常见问题速查表
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
部署时提示Missing API Token | CLI 未登录或未配置 Token | 执行wrangler login,或在 CI 中配置 Secrets |
| 调用返回 401 Unauthorized | 网关 Token 不匹配 | 检查请求头 Authorization 是否携带正确的 Bearer Token |
返回Model not found | 模型名称未在映射表中配置 | 检查modelProviderMap,确认模型名与上游一致 |
| 上游请求超时 | 第三方接口响应慢或网络不稳 | 增加超时处理,适当重试,查看上游状态页 |
| 部署后代码未生效 | 自动部署失败或环境变量未更新 | 查看 GitHub Actions 日志,确认 Secrets 是否配置 |
| 浏览器跨域报错 | 缺少 CORS 头 | 在响应中增加Access-Control-Allow-Origin |
| 免费额度被耗尽 | 请求量超过每日限制 | 进入控制台查看用量,考虑升级计划或加限流 |
7.2 详细排查步骤
案例一:部署后访问返回 500
出现 500 错误,首先查看 Worker 的日志。在 Cloudflare 控制台进入 Worker,点击Logs菜单,可以看到实时的请求日志和异常堆栈。
常见原因是环境变量没有读取到。检查wrangler.toml中的vars是否已经包含所有需要的变量;如果是通过 CI 部署,需要确认 GitHub Secrets 是否配置正确。
案例二:请求 OpenAI 时报 401
这种情况通常是OPENAI_API_KEY配置错误。可以在本地环境变量文件.dev.vars中确认一下:
OPENAI_API_KEY=sk-xxxxxxxx GATEWAY_TOKEN=my-gateway-token另外注意,某些服务商的密钥需要通过不同的请求头传递。有的要求Authorization: Bearer,有的要求自定义请求头,这些细节需要查阅上游文档。
案例三:模型请求速度很慢
如果网关本身逻辑很简单,但请求延迟很高,大概率是上游服务本身的响应时间慢。可以在前端上报请求开始和结束时间,对比一下直连上游和通过网关访问的耗时差距。
也有可能是 Cloudflare Workers 节点距离上游服务商的接口较远,导致的网络延迟。这种情况可以尝试在fetch请求中指定cf参数,或者调整 Worker 的访问地区设置。
8. 最佳实践与安全建议
8.1 密钥管理:永远不要把密钥写死在代码里
这是最容易犯的错误,也是后果最严重的问题。
开发阶段可以把密钥放到.dev.vars中,这个文件不要提交到 Git;生产环境的密钥通过 Cloudflare 控制台设置,或者在 GitHub Actions 中通过 Secrets 注入。
一旦发现密钥泄露,立即到上游服务商的控制台吊销并重新生成,同时更新网关配置。
8.2 添加访问控制与限流
对外的网关上,至少要有两层保护:
- 第一层是网关自身的 Token 鉴权,拒绝未授权的请求。
- 第二层是按调用方维度限流,防止某个调用方消耗全部额度。
Cloudflare 提供了 Rate Limiting 规则,可以在控制台中针对/v1/chat/completions路径配置速率限制。免费计划有一定的配额,个人项目完全够用。
生产环境如果并发量大,建议将网关 Token 升级为短期 JWT,并配合签名校验机制。
8.3 日志与监控
Cloudflare Workers 自带日志功能,但只能保留最近一段时间的数据,无法做长期趋势分析。
建议在网关代码中主动记录结构化日志,例如:
{ "time": "2025-01-01T12:00:00Z", "path": "/v1/chat/completions", "model": "gpt-4o-mini", "status": 200, "latency_ms": 340 }如果你的项目运行量不大,也可以直接把关键指标发送到免费的可观测性平台,或者用 Workers KV 做简单的计数统计。
8.4 合理使用上游模型
聚合网关最大的优势是灵活性,但这不代表可以滥用。
一些上游服务商对单账号的请求速率有限制,网关层如果只是单纯转发,多个客户端同时调用时仍然可能触发上游限流。这时可以在网关层做两件事:
- 对同一上游做排队或节流。
- 在多个上游 Key 之间做负载均衡。
本文的示例没有覆盖这两点,但如果你的网关流量逐步增长,这些是下一步值得研究和实现的方向。
8.5 代码可维护性
网关的代码量虽然不大,但涉及到多个上游服务商时,很容易变成一堆 if-else。建议从第一天开始就使用适配器模式,每个上游服务商一个文件,保持主流程干净。
另外,给每个适配器补充清晰的注释,标明接口地址、认证方式、返回差异,方便后续维护。
9. 总结与下一步方向
这篇文章实现了以下几件事:
- 用一个 Worker 代码,搭建了兼容 OpenAI 格式的 AI 聚合网关。
- 实现了模型路由、鉴权、统一错误处理、CORS 支持。
- 支持手动部署和 GitHub Actions 自动部署。
- 通过 Cloudflare 免费额度,实现了零成本云上部署。
- 给出了常见问题的排查思路和工程级安全建议。
如果你的目标只是个人学习和使用,目前这个网关已经可以满足大部分需求。下一步可以考虑的方向包括:
- 将模型映射配置搬进 Workers KV,实现动态路由。
- 增加请求日志落库,分析调用趋势。
- 增加缓存层,对重复请求直接返回缓存结果,节省上游调用费用。
- 集成更多模型服务商,比如 Anthropic、Gemini 等。
- 增加多 Key 自动轮询机制,提升上游可用性。
动手搭一个属于你自己的 AI 聚合网关,是理解 API 网关设计、边缘计算部署和服务治理的很好项目实践。如果这篇文章对你有帮助,可以先收藏备用,后续遇到部署或使用问题随时回来查阅。