[控场AI]
· 6 分钟阅读· 3,224 字

Palimpsest Gateway:开源LLM密钥池网关,自动故障转移实战

Palimpsest Gateway:开源LLM密钥池网关,自动故障转移实战

Palimpsest Gateway是自托管LLM密钥网关,统一池化多厂商密钥并在故障转移时保持对话连续。

Palimpsest Gateway是一个开源、自托管的LLM API网关,用一句`docker compose up`即可运行,解决开发者在管理多厂商API密钥时面临的三大痛点:密钥耗尽导致应用崩溃、密钥散落难以管理、跨请求缺乏可观测性。其核心设计包括:在内存中缓冲完整流式响应、再切换密钥重试,确保客户端永不收到残缺响应;将会话历史存入Redis并在故障转移时随上下文一并携带,使用户感知不到厂商切换;以Fernet主密钥对所有厂商密钥静态加密;以及优先消耗免费配额、付费密钥兜底的选择算法。项目采用MIT协议,兼容标准OpenAI客户端,应用无需改动代码即可接入。

构建LLM应用的开发者几乎都撞过同一堵墙:手里攥着几把来自不同厂商的API密钥——两个OpenAI免费额度、一个付费版、一个Anthropic、再加一个Gemini——然后发现每个应用都得自己写一套逻辑来处理限流和配额耗尽。一旦某把密钥触顶,应用就直接挂掉,除非你在每一个应用里都重复实现一遍故障转移逻辑。密钥散落在各个.env文件里,共享方式不安全,想轮换一把还得担心会不会把别的东西搞崩。

一位开发者把这个问题想透之后得出结论:这根本不是应用层的问题,而是基础设施问题。于是他做出了 Palimpsest Gateway——一个自托管、兼容OpenAI接口的网关,坐镇在所有LLM密钥前面,统一池化、自动故障转移,并在切换过程中保持对话连续。项目采用MIT协议开源,基于Python/FastAPI编写,一句docker compose up即可运行。

问题所在:密钥耗尽,应用崩溃

凡是把LLM应用做到一定规模的人,都对这几个痛点深有体会。免费额度密钥撞上429状态码,应用崩溃,就算你捕获异常、休眠重试,用户早就跑了。月度花费封顶或当日免费额度用完时,没有任何预警,只有冷冰冰的402/429。更麻烦的是密钥蔓延——5个应用乘以3个厂商,就是分散在15个.env文件里的15把密钥,轮换其中一把等于一次部署。

Palimpsest Gateway 项目概览

除了混乱,还有可观测性的缺失。你不知道哪把密钥服务了哪个请求、花了多少钱、某个请求为何失败。作者想要的其实很简单:一个统一的端点,接受标准OpenAI客户端调用(零代码改动),在背后池化所有厂商密钥,在触限或报错时透明切换,并保留对话上下文让用户感知不到切换,同时运行在自己的硬件上、密钥静态加密、还配一个能看清全局的仪表盘。

架构:实际运行的是什么

整套系统的核心由网关本体加Redis构成。应用(OpenAI客户端)将请求发往Palimpsest Gateway,网关完成鉴权与准入、密钥选择、故障转移循环、会话记忆、用量计量和加密存储,再以厂商原生格式转发给OpenAI、Anthropic、Google Gemini或OpenRouter。Redis则承担密钥注册表、会话历史、用量计数器和审计日志的职责。

请求流程清晰且环环相扣:应用发送网关密钥(pgw_live_...),绝不触碰真实的厂商密钥;网关检查用户日配额与池容量,完成准入;若带有X-Session-ID,则从存储中拉取历史上下文,应用只需发送新消息;接着从服务目标模型的活跃密钥中挑选,优先用还有余量的受限密钥;以厂商原生格式转发调用;一旦遇到限流、宕机或坏密钥,就把该密钥标记为休眠/耗尽/挂起,并在下一把密钥上重试(同一次调用,上下文随行);最后返回OpenAI格式的响应,保存本轮对话,用量只计一次。

真正的难点以及解法

流式故障转移且不破坏客户端

这是整个项目最棘手的部分。当厂商返回流式响应时,你不能简单地“在另一把密钥上重试”——客户端已经在接收token了。作者的解法是:网关在向客户端发送任何内容之前,先把整个厂商流完整缓冲在内存里。如果厂商在流中途失败,网关带着完整上下文(系统提示 + 最近N轮 + 当前消息)在下一把密钥上重试。客户端始终只看到一个完整、合法的OpenAI流。

核心洞察一句话概括:缓冲整个流,在任何字节离开网关之前完成故障转移,客户端永远不会收到残缺的响应。故障转移循环会对异常进行分类——瞬时错误(transient)标记冷却后换下一把,耗尽(exhausted)标记后换下一把,被拒(rejected)则挂起该密钥,只有致命错误才真正抛出。

跨厂商的上下文接续

故障转移发生时,接替的厂商需要对话历史,但每家厂商的上下文窗口大小和消息格式各不相同。网关的做法是把每一轮对话按会话存入Redis,故障转移时重建一个“逐字窗口”——默认取最近4轮,原样发送,再加上系统提示与当前消息。这既能塞进任何合理的上下文窗口,又能保住对话主线。

能挺过重启的加密密钥存储

厂商密钥是最核心的资产,必须静态加密、绝不记录日志、创建后绝不回传,但网关又需要在请求时解密它们。解法是在首次启动时生成一个主密钥(Fernet),持久化到Docker卷中。每把厂商密钥在写入Redis前都用它加密,而主密钥永不离开容器。轮换主密钥是一个破坏性操作(make rotate-secrets),这是刻意的设计。

尊重你意图的密钥选择

你手里既有带日配额的免费密钥,也有不限量的付费密钥,自然希望先用免费,付费兜底。选择算法据此排序:先排有请求上限且有余量的密钥(余量多者优先),再排无上限的密钥;在每组内部,优先选用服务过该会话此前几轮的厂商,以保持局部性。这套排序逻辑简单却恰好对齐了成本意图。

60秒上手

上手门槛被压到极低。克隆仓库后执行docker compose up -d --wait即可。首次启动时它会生成主密钥和操作员密钥、持久化到Docker卷,并在http://localhost:8000启动API。随后把厂商密钥写入.env(或通过仪表盘添加),在仪表盘里创建用户拿到一把pgw_live_...密钥,就能用任意OpenAI客户端把base_url指向本地网关直接调用。只要在请求头带上X-Session-ID,对话历史就会在服务端持续维护。

实际使用中的样子

仪表盘几乎暴露了一切细节:池内密钥的健康度、用量、配额、重置计划与冷却状态;利用率与故障转移事件、重试链路;按账户的用量、活跃会话与配额消耗;按模型/用户/日的花费(价格由你自己录入,不捆绑任何预设);低容量、密钥异常、错误率告警并支持webhook;以及每一次操作员动作都被记录的审计日志,附带用量、请求、审计的CSV导出。

一条典型的请求日志能把故障转移讲清楚:某次请求的chain字段显示先命中key_openai_free_1,被限流后转到key_openai_paid,attempts为2,上下文随行,最终outcome为success。免费密钥限流→切付费密钥→上下文接续→成功,整条链路一目了然。

为何叫“Palimpsest”

Palimpsest指的是一种被反复书写的手稿页——写过、刮净、再写,底下旧字迹仍隐约可见。这正是网关的隐喻:它把对话历史层层叠加在厂商切换之上,即便底层密钥换了,新厂商看到的仍是“旧字迹”般的上下文。这个命名颇为贴切地点出了产品的核心价值——连续性。

下一步与写在最后

项目的路线图包括:多网关集群(多实例置于负载均衡之后,共享Redis)、厂商配额同步(OpenRouter已支持读取真实配额,而非手动设上限)、请求变换(跨厂商归一化工具调用、注入系统提示),以及留给社区贡献者的 good first issue。

对于正在为多密钥管理、限流兜底和成本可观测性发愁的团队,Palimpsest Gateway提供了一个值得参考的开源范式——它把散落在应用层的重复逻辑收敛进基础设施,用缓冲式流转移、会话级上下文重建和静态加密三件事,解决了LLM网关中最容易被忽视的硬骨头。项目地址为 github.com/hammrouni/palimpsest-gateway,MIT协议,可通过docker pull ghcr.io/hammrouni/palimpsest-gateway:latest直接拉取镜像。

#LLM网关#密钥池#故障转移#开源#OpenAI兼容#Palimpsest Gateway#API密钥管理#FastAPI
分享:

相关推荐