周末造轮子:写了一个 LLM API Key 本地负载均衡器

最近因为一直在高强度使用各种 LLM 服务(OpenAI, Gemini, DeepSeek 等),遇到了一个很现实的痛点:贫穷

为了省钱,我申请了多个免费的 API Key(比如 Google Gemini 的 Free Tier,或者 DeepSeek 的赠送额度),但这些免费 Key 往往有严格的速率限制(RPM/TPM)。写代码写得正嗨,突然弹出一个 429 Too Many Requests,思路瞬间被打断,非常搞心态。

场景与需求

我的需求很简单:

  1. 多 Key 轮询:我有好几个 Key,希望能自动轮着用,这个限流了自动切下一个。
  2. 统一入口:我不想在每个 Client(Chatbox, Cursor, VSCode 插件)里分别填一堆 Key。我希望只填一个统一的 url,后端自动帮我处理复杂的鉴权和路由。
  3. 兼容性:必须完全兼容 OpenAI 格式,因为现在几乎所有工具都支持 OpenAI 协议。
  4. 可视化:我想知道哪个 Key 用得多,哪个 Key 经常报错,哪个 Key 还在冷却中。

市面上有很多强大的网关(如 OneAPI, NewAPI),但它们太重了。我不需要用户系统,不需要充值渠道,不需要复杂的数据库。我只需要一个跑在本地的小工具,最好是一个单一的可执行文件,甚至是一个 macOS App。

于是,趁着周末,我写了一个小工具:llm-api-lb

深色模式下,一个名为“llm-key-lb”的API Key管理界面,显示新增API Key表单和已管理Key列表,包含名称、厂商、Base URL、Model、权重、Key、状态和操作等字段。

灵感与设计

核心思路其实就是一个反向代理(Reverse Proxy)

  1. 拦截:拦截所有发往 /v1/* 的请求。
  2. 调度:在内存里维护一个 Key 列表,包含每个 Key 的状态(是否启用、是否在冷却中、失败次数等)。
  3. 转发:挑一个可用的 Key,替换掉请求头里的 Authorization,转发给上游(OpenAI/Google/DeepSeek)。
  4. 容错:如果上游返回 429 或 5xx,标记该 Key 进入“冷却期”,并自动重试下一个 Key。

技术栈选择了最简单的 Node.js + Express。 为什么不用 Go 或 Rust?因为我想顺便写一个简单的 Web 管理界面,Node.js 处理 HTTP 和 JSON 实在是太顺手了,而且配合 pkg 打包成单文件也非常方便。

实施过程

1. 核心逻辑

核心逻辑不到 1000 行代码。最关键的部分是“选 Key”和“错误处理”。

我实现了一个简单的 Round-Robin(轮询)算法,但加了被动冷却机制。一旦某个 Key 请求失败(429 限流或 401 鉴权失败),它会被暂时“关小黑屋”一段时间(比如 1 分钟)。在这 1 分钟内,流量会自动绕过它。

2. 打造 macOS App

我希望它不仅仅是一个黑乎乎的命令行工具,而是一个稍微优雅的 Menu Bar App(菜单栏应用)

我使用 Node.js 的脚本能力,配合 macOS 的系统命令,实现了一套“伪打包”流程:

  1. pkg 把 Node.js 代码打包成二进制可执行文件。
  2. 用 Swift 写了一个极简的 Launcher(启动器),负责调用这个二进制,并管理托盘图标和菜单。
  3. 把它们塞进标准的 .app 目录结构里。

遇到的一个坑是端口占用。如果用户电脑上 8787 端口被占了怎么办? 我在 Swift 启动器里加了逻辑:启动前先探测端口,如果被占用了,弹窗提示或自动寻找新端口。 为了体验更好,我还做了菜单栏常驻:点击红叉关闭窗口后,程序其实还在后台运行,随时可以通过顶部菜单栏唤醒。 任务栏图标

3. 图标与细节

为了让它看起来像个正经 App,我还专门画了个图标(我的审美很高,但 ChatGPT审美有限)。 遇到的一个小插曲是图标有白边,在 Dark Mode 下很难看。于是又写了个 Python 脚本,用 PIL 库把边缘像素做了透明度处理,终于顺眼了。

4. 监控与可视化

我在前端加了一个简易的监控面板。 利用 chart.js 画出了每个 Key 的请求量和耗时趋势。看着不同颜色的线条在走,心里有一种莫名的踏实感——我知道我的 Key 们正在努力工作,而且负载被均匀地分摊了。 深色背景的监控界面,上方表格展示g1和g2两个Key的总请求、成功、失败、平均耗时等数据,下方柱状图和折线图显示了g1、g2和平均耗时随时间的变化趋势。

总结

这个项目本身技术含量不高,但解决了我自己的痛点。 现在我写代码时,Base URL 填本机 http://localhost:8787/v1,Key 随便填一个。后台会自动帮我在 Gemini 的免费额度和 DeepSeek 之间反复横跳, 429 报错少了很多。

如果你也有类似的烦恼,或者对 Node.js 封装桌面应用感兴趣,欢迎去 GitHub 看看源码。

GitHub: https://github.com/weidussx/llm-api-lb

Happy Coding! 🚀


想跟进更新? RSS


相关内容