惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
腾讯CDC
J
Java Code Geeks
博客园 - 【当耐特】
Microsoft Azure Blog
Microsoft Azure Blog
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
博客园 - Franky
博客园 - 聂微东
阮一峰的网络日志
阮一峰的网络日志
美团技术团队
云风的 BLOG
云风的 BLOG
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
U
Unit 42
雷峰网
雷峰网
B
Blog RSS Feed
博客园_首页
量子位
F
Fortinet All Blogs
罗磊的独立博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog

iPotato

iPotato Intention Is All You Need Intention Is All You Need 使用 Cloudflare Workers 搭建轻量级 LLM API 网关 如何利用全 SaaS 阵容从零免费搭建一个博客? 如何利用全 SaaS 阵容从零免费搭建一个博客? ThinkPad X1 Carbon x Arch Linux ThinkPad X1 Carbon x Arch Linux Fly.io 初体验之博客搬家 Fly.io 初体验之博客搬家 TiKV Region Split 全流程分析 TiKV Region Split 全流程分析 韩寒的四海 韩寒的四海 浅谈《开端》在剧作上的瑕疵 浅谈《开端》在剧作上的瑕疵 Rust 的 async/await 语法是怎样工作的 Rust 的 async/await 语法是怎样工作的 我为什么不再喜欢 Go 了 我为什么不再喜欢 Go 了 TiDB 5.0 事务分布式授时模块 TiDB 5.0 事务分布式授时模块 PD 授时服务 TSO 设计简析 PD 授时服务 TSO 设计简析 如何在面试中筛选/不做一个「背题家」 如何在面试中筛选/不做一个「背题家」 在读研 & 工作中选择后者 在读研 & 工作中选择后者 几个实用的 Visual Studio Code 插件推荐 几个实用的 Visual Studio Code 插件推荐
使用 Cloudflare Workers 搭建轻量级 LLM API 网关
JmPotato · 2025-03-04 · via iPotato

在这个 LLM 服务商们每天都在进行军备竞赛的时代,对我们这种面向 LLM 编程的程序员来说,最常见的一个痛点莫过于管理一大堆 API Endpoint 和 Secret Key 了,再加上:

  • 不同的服务商 Host 了相同或不同的模型。
  • 在不同的服务商里都撒了币。
  • 不同服务商的 SLA 可能相去甚远。
  • 要在不同的软件里重复配置这些相同的内容。

这一系列问题的解决方案自然是一个统一的 LLM API Gateway,原理上看也并不复杂,只消维护 Model 和 API Provider 之间的映射规则,然后按需转发即可。

{"model": "claude"}
    ⬇️
LLM API Gateway
    ⬇️
{"model": "claude-3-7-sonnet-latest"}
    ⬇️            ⬇️
Anthropic    AWS Bedrock

实际上市面上也早已有成熟的开源方案,例如 songquanpeng/one-api。但对于我来说,部署这么一套管理系统显得有些太重了,作为个人使用,似乎不太需要额外的租户管理和账单系统,加之如果想要进行远端部署,产生额外的服务器、域名等维护成本也有些令人抗拒,所以“造轮子”似乎又成了最终的选择。

比起年轻气盛时动不动就想“万丈高楼平地起”地从零开始造轮子,成年人造轮子的哲学则是“应拼尽拼”,能用现成的预制零件快速拼出来的轮子也是好轮子——于是开始整理造这么一个私人 LLM API Gateway 的基本要求:

  • 易于维护,部署成本要尽可能的低,最好能用现成的 SaaS。
  • 开箱即用,使用和配置方式简单,即暴露一个统一的 API 接口,可以自由配置模型的转发映射。
  • 安全,有基本的鉴权以防止滥用。
  • 通用,适配主流的 LLM API Provider 格式。

首先,作为一个几乎无状态的 API Gateway,最核心的逻辑就是转发 HTTP 请求,所以立马出现在选品单上的就是 Cloudflare Workers,其提供的 Severless 应用部署非常适合写这种 Proxy,再加上配套的 Cloudflare Workers KV,转发配置需要持久化存储的需求也被满足了。于是我基于官方的 Rust SDK worker-rs 实现了 one-united,仅需简单的配置,就可以把一个轻量级的 LLM API Gateway 部署到 Cloudflare Workers 上。

部署方式

因为官方提供了非常齐全的配套,整个部署过程需要做的准备仅需提前安装上较新版本的 Rustnpm 即可。

首先把项目拉到本地,然后开始编辑我们的 wrangler.toml

git clone https://github.com/one-united/one-united.git
cp wrangler.example.toml wrangler.toml

其实这里要做的就是创建一个 KV namespace,一条命令就能搞定:

npx wrangler kv:namespace create config

运行成功后把输出中提供的 kv_namespaces 部分粘贴到 wrangler.toml 文件中即可,格式类似于:

[[kv_namespaces]]
binding = "config"
id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

然后就是用最后一条命令完成最终部署:

npx wrangler deploy

然后你的服务就跑在 https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev 上可供访问了!

配置文件

刚部署好的 one-united 自然是没有配置任何模型转发的,项目里提供了一个规则模板,其格式还是比较直观的,我以此为例展示一个我自己的使用场景,来看看具体如何配置自己的模型转发。

我最常用 LLM 的一个场景就是翻译,例如 Bob 的 AI 翻译服务。

可以看到我定义了一个名为 translator 的模型,其转发逻辑的配置如下:

rules:
  - model: translator
    providers:
      - identifier: oh-my-gpt
        models:
          - gpt-4o-mini
      - identifier: openrouter
        models:
          - openai/gpt-4o-mini
      - identifier: dailyio
        models:
          - gpt-4o-mini
          - meta-llama/Llama-3.3-70B-Instruct-Turbo

不难发现对于翻译服务,我使用的都是主流模型中 Token 价格较低的模型,如此一来在使用较为频繁的翻译场景下,可以在保证质量的前提下尽可能节省 Token。providers 的配置字段都比较直接,在此不表,按需添加和配置自己的提供商即可。

目前 one-united 还没有图形化界面,所以更新配置需要用 curl 直接把 config.json 扔给接口:

curl -X POST https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/config \
-H "Content-Type: application/yaml" \
--data-binary @config.yaml

一些提升体验的功能

在简单转发的基础上,我也根据平时使用的一些经验和习惯加了一些必要的功能和优化。

设置 API KEY

虽然说整个流程属于私人部署,但也不免存在接口泄漏的可能,避免被他人滥用导致 Token 额度被迅速消耗完,可以给自己的 Gateway 也设置上 API Key。这里有两个操作办法, 一个是直接通过命令行设置 ONE_API_KEY

npx wrangler secret put ONE_API_KEY

也可以到 Cloudflare 的 Workers 后台界面添加:

此后所有的 curl 请求都可以带上 -H "Authorization: Bearer $ONE_API_KEY" 进行鉴权了,同样,在类似 Chat Bot 的 API 配置中,也需要填上 $ONE_API_KEY 方可正常调用。

负载均衡

当同一个模型名配置了多个不同的 (Provider, Model) 映射时,为了保证尽可能好的延迟表现,每次会通过负载均衡机制在不同映射间进行切换,并记录每次请求的耗时,最终尽可能地选择转发至延迟较低的提供商。

目前这个策略还比较简陋,我还在考虑是否要添加诸如基于权重或者 Token 成本的负载均衡策略。

常用的接口

one-united 一共提供了以下几个接口:

WorkerRouter::new()
    .get_async("/config", get_config)
    .post_async("/config", save_config)
    .get_async("/stats", get_stats)
    .get_async("/v1/models", get_models)
    .post_async("/v1/chat/completions", route_chat_completions)
    .run(req, env)
    .await

其中 /v1/models/v1/chat/completions 都是 OpenAI 兼容的常用接口,后者不用说,就是最常用的 LLM 使用接入口。前者则是 List Models 接口,对于一些提供了自动获取模型信息功能的软件来说,可以方便的通过这个接口一键添加所有当前可用的模型信息:

前面一个小节提到过 one-united 存在负载均衡机制,通过 /stats 这个接口可以看到当前所请求 Workers 实例内的延迟统计信息,方便判断不同服务商的延迟表现如何:

❯ curl -s -H "Authorization: Bearer $ONE_API_KEY" https://<YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev/stats | jq
{
  "created_at": "2025-03-06T04:22:13.862Z",
  "hash": "362c5ee09afe8b5c82f132161496c00072ce850e3a39d204315bf823e8311de8",
  "latency": [
    {
      "identifier": "cf-openrouter",
      "model": "anthropic/claude-3.7-sonnet",
      "ms": 1473
    }
  ],
  "lifetime": "3m 42s 685ms"
}

OpenRouter 统计适配

如果你搭配 OpenRouter 使用的话,可以看到在 OpenRouter 的 Activity 界面上是可以识别到 one-united 转发来的请求标识的,方便掌握具体的用量。

这个也是根据 OpenRouter 官方的文档加的请求识别头来实现的:

// "HTTP-Referer" and "X-Title" will be used by service like OpenRouter to identify the request.
headers.set("HTTP-Referer", "https://github.com/JmPotato/one-united")?;
headers.set("X-Title", "one-united")?;

Bypass Rule

如果你想 Bypass 掉规则,直接请求对应 Provider 的某个模型,可以使用 model@@provider_identifier 这个语法,例如直接请求配置中来自 OpenRouter 的 GPT-4o mini:openai/gpt-4o-mini@@openrouter,请求就会直接发给 OpenRouter,而不会经过负载均衡中转,指哪打哪。