• 欢迎访问少将全栈,学会感恩,乐于付出,珍惜缘份,成就彼此、推荐使用最新版火狐浏览器和Chrome浏览器访问本网站。
  • 吐槽,投稿,删稿,交个朋友
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏少将全栈吧

用 Hono + Cloudflare Workers 搭建 AI API 聚合层:一份可直接复用的模板

可复用技术资产 admin 59分钟前 3次浏览 已收录 扫描二维码

Meta: 不需要后端服务器,用 Hono + Cloudflare Workers 搭建 AI API 聚合层,统一管理 OpenAI、Claude、Gemini 调用。附可部署模板。

为什么要自己搭 AI API 聚合层

做 AI 产品时,你大概率会遇到这几个问题:

  • 需要切换不同的 AI 模型(GPT-4o 写代码、Claude 做分析、Gemini 处理图片)
  • 每个 API 的认证方式、请求格式、错误处理都不一样
  • 同一个功能,生产环境用 GPT-4o,开发环境想用更便宜的模型
  • 不想在多个服务里重复写 API Key 管理和错误重试逻辑

一个 API 聚合层能解决上面所有问题。而 Hono + Cloudflare Workers 是 2026 年搭这个层最轻量的选择——不需要服务器,不需要管理基础设施,部署只需要一条命令,免费套餐每天 10 万次请求。

以下是一份可以直接部署的模板代码。

项目结构

ai-api-gateway/
├── src/
│   ├── index.ts
│   ├── providers/
│   │   ├── openai.ts
│   │   ├── claude.ts
│   │   └── gemini.ts
│   ├── utils/
│   │   ├── cache.ts
│   │   └── retry.ts
│   └── types.ts
├── wrangler.toml
├── package.json
└── tsconfig.json

第一步:初始化项目

用 Hono 的官方脚手架创建 Workers 项目:

npm create hono@latest ai-api-gateway -- --template cloudflare-workers
cd ai-api-gateway
npm install

第二步:核心路由和服务

先定义统一的消息格式:

// src/types.ts
export interface ChatMessage {
  role: "system" | "user" | "assistant"
  content: string
}

export interface ChatRequest {
  model: string
  messages: ChatMessage[]
  temperature?: number
  max_tokens?: number
  provider?: "openai" | "claude" | "gemini"
}

然后写路由入口:

// src/index.ts
import { Hono } from "hono"
import { cors } from "hono/cors"

const app = new Hono()
app.use("/*", cors())

app.get("/", (c) => c.json({ status: "ok" }))

app.post("/chat", async (c) => {
  const body = await c.req.json()
  const provider = body.provider || detectProvider(body.model)
  // route to handler
})

function detectProvider(model: string): string {
  if (model.startsWith("gpt-") || model.startsWith("o")) return "openai"
  if (model.startsWith("claude")) return "claude"
  if (model.startsWith("gemini")) return "gemini"
  return "openai"
}

export default app

第三步:Provider 适配器

以 OpenAI 为例:

// src/providers/openai.ts
import { Context } from "hono"

export async function openaiHandler(c: Context, body: ChatRequest) {
  const apiKey = c.env.OPENAI_API_KEY
  if (!apiKey) return c.json({ error: "key missing" }, 500)

  const response = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${apiKey}`
    },
    body: JSON.stringify({
      model: body.model,
      messages: body.messages,
      temperature: body.temperature ?? 0.7
    })
  })

  if (!response.ok) {
    const error = await response.text()
    return c.json({ error: `OpenAI error: ${error}` }, response.status)
  }

  const data = await response.json()
  return c.json({
    content: data.choices[0].message.content,
    model: data.model,
    provider: "openai",
    usage: data.usage
  })
}

Claude 适配器注意 system prompt 是独立字段:

// src/providers/claude.ts
export async function claudeHandler(c: Context, body: ChatRequest) {
  const apiKey = c.env.CLAUDE_API_KEY
  const systemMsg = body.messages.find(m => m.role === "system")
  const userMessages = body.messages
    .filter(m => m.role !== "system")
    .map(m => ({ role: m.role, content: m.content }))

  const response = await fetch("https://api.anthropic.com/v1/messages", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": apiKey,
      "anthropic-version": "2023-06-01"
    },
    body: JSON.stringify({
      model: body.model,
      messages: userMessages,
      system: systemMsg?.content,
      max_tokens: body.max_tokens ?? 4096
    })
  })

  const data = await response.json()
  return c.json({
    content: data.content[0].text,
    model: data.model,
    provider: "claude"
  })
}

第四步:重试和缓存

// src/utils/retry.ts
export async function withRetry(fn, options = {}) {
  const { maxRetries = 3, baseDelayMs = 1000 } = options
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try { return await fn() }
    catch (error) {
      if (attempt === maxRetries - 1) throw error
      await new Promise(r => setTimeout(r, baseDelayMs * Math.pow(2, attempt)))
    }
  }
}
// src/utils/cache.ts
export async function getCachedResponse(kv, key) {
  return await kv.get(key)
}
export async function setCachedResponse(kv, key, value, ttlSeconds = 3600) {
  await kv.put(key, value, { expirationTtl: ttlSeconds })
}

第五步:部署

npx wrangler secret put OPENAI_API_KEY
npx wrangler secret put CLAUDE_API_KEY
npx wrangler secret put GEMINI_API_KEY
npx wrangler deploy

一些实际使用的经验

冷启动问题

免费计划 Workers 闲置几分钟后冷启动,首次请求延迟约 200-500ms。聊天类应用可接受,实时场景建议付费计划($5/mo)。

免费额度

每天 10 万次请求。Cloudflare 文档说明 CPU 上限 30 秒(免费)/ 60 秒(付费)。个人项目完全够用。

KV 缓存命中率

对常见 prompt 做缓存,命中率约 15-25%。每次命中节省一次 API 调用和几百毫秒延迟。

错误处理

指数退避重试是起点,生产环境建议加 circuit breaker——连续失败超阈值后直接短路。

完整代码

GitHub: github.com/sxyseo/hono-ai-gateway

直接 fork 改一下就能用。


参考来源:Hono 官方文档(https://hono.dev/docs/getting-started/cloudflare-workers);Cloudflare Workers 文档(https://developers.cloudflare.com/workers/);OpenAI API 文档(https://platform.openai.com/docs/api-reference);Anthropic Messages API 文档(https://docs.anthropic.com/en/api/messages)。

喜欢 (0)
[🍬谢谢你请我吃糖果🍬🍬~]
分享 (0)
关于作者:
少将,关注Web全栈开发、项目管理,持续不断的学习、努力成为一个更棒的开发,做最好的自己,让世界因你不同。