当我们设计 JieGou 的 LLM 层时,我们有一个大多数平台没有的限制:客户应该能够使用自己的 API 金钥,而我们不应该在静态状态下看到明文金钥。本文将介绍我们的自带金钥(BYOK)系统如何运作、加密方案、供应商路由架构,以及保持一切可靠运行的保护机制。
为什么 BYOK 很重要
大多数 AI 平台会透过他们自己的 API 金钥代理您的呼叫。这意味着您的资料流经他们的帐户,您的使用量受限于他们的速率限制,而且您无法控制使用哪些模型或端点。
使用 BYOK,每个客户都连接自己的 Anthropic、OpenAI 或 Google API 金钥。呼叫使用客户的凭证直接传送到供应商。JieGou 编排工作流程,但在使用 BYOK 金钥时不会看到请求或回应的有效负载。
金钥加密:AES-256-GCM
API 金钥在静态时使用 AES-256-GCM 加密,具有 12 位元组的初始化向量和 16 位元组的验证标签。加密金钥是从储存为环境变数的 64 字元十六进位字串衍生的 256 位元值 — 它永远不会接触资料库。
储存格式是 IV + authTag + ciphertext 的 Base64 编码串接。我们将 8 字元的安全前缀(“sk-proj…”)一同储存用于显示,让使用者无需解密即可识别储存的金钥。
金钥储存在 Firestore 的 account_api_keys 集合中,包含帐户 ID、供应商名称、加密金钥 blob 和有效性标志等栏位。
金钥解析流程
当工作流程步骤需要呼叫 LLM 时,金钥解析器会执行以下序列:
- 方案闸控 — 检查帐户的订阅是否允许 BYOK(在 Redis 中快取,TTL 为 10 分钟)。
- Redis 快取查找 — 解密的金钥快取 5 分钟。哨兵值(
__none__)表示之前查找过该金钥但不存在,避免重复的 Firestore 读取。 - Firestore 查找 — 如果快取未命中,从
account_api_keys撷取。 - 有效性检查 — 跳过已被自动失效系统标记为无效的金钥。
- 解密 — AES-256-GCM 解密在记忆体中即时进行。
- 故障开放 — 如果任何步骤出现问题,回退到平台自己的 API 金钥。永远不降低使用者体验。
故障开放设计是刻意为之。如果 Redis 当机、解密失败、Firestore 读取错误 — 工作流程仍然执行,只是使用平台金钥。使用者看到他们的工作完成,而不是收到难以理解的错误。
供应商路由
LLM 层建立在 Vercel AI SDK 之上,具有支援 Anthropic、OpenAI 和 Google 的供应商抽象。每个供应商有两种实例化路径:
平台金钥(单例) — 在启动时创建的共用实例,用于免费方案帐户或作为 BYOK 的回退。
BYOK(临时) — 每次呼叫使用客户解密的金钥创建新的供应商实例。此实例不会快取 — 它用于一次请求后就被丢弃,因此解密的金钥不会在记忆体中滞留。
工作流程可以为每个步骤指定不同的模型。内容管道可能在步骤 1 使用 Claude 进行细致的写作,在步骤 2 使用 GPT 进行结构化资料撷取。供应商路由会透明地处理这一点。
自动失效
当 LLM 呼叫返回验证错误(HTTP 401、402 或 403,或回应主体符合「invalid api key」或「unauthorized」等模式)时,系统会自动在 Firestore 中将该金钥标记为无效,并从 Redis 快取中移除。
使用者会收到清楚的讯息:「您的 {Provider} API 金钥无效或已被撤销。请在帐户设定中更新您的 API 金钥。」后续呼叫会回退到平台金钥,直到使用者提供新金钥。
我们检查跨供应商的 11 种已知错误模式。这可以捕获轮换的金钥、撤销的金钥和已超过支出限额的金钥。
断路器
每个 LLM 供应商都有一个按供应商的断路器(不是按帐户 — 单一供应商当机会影响所有人)。
在 60 秒窗口内出现 5 次错误后,断路器会跳闸。一旦打开,它会保持开启状态 30 秒,然后允许单个探测请求(半开状态)。如果探测成功,断路器关闭。
只有伺服器端故障会计数:5xx 回应、逾时和连接错误。客户端错误(4xx)如无效 API 金钥不会触发断路器 — 这些由自动失效处理。
断路器本身是故障开放的。如果 Redis 无法用于状态追踪,所有请求都会被允许通过。这与我们的整体理念一致:当基础设施降级时,让使用者的工作继续进行。
并发控制
每个帐户透过基于 Redis 的信号量限制为 10 个并发 LLM 呼叫。这可以防止单个帐户的大批次执行消耗所有可用的供应商连接。
信号量使用 INCR/DECR,具有 5 分钟的 TTL 安全网(如果处理程序崩溃而未递减,计数器会自动过期)。当容量超出时,计数器会立即递减以避免泄漏。与其他所有内容一样,在 Redis 错误时它是故障开放的。
经验教训
故障开放是可选功能的正确预设值。 BYOK 是一种增强功能,而非必需功能。如果加密管道、快取层或金钥解析失败,使用者仍应该能够执行他们的工作流程。我们记录故障以供调查,但永远不会阻止执行。
快取哨兵值可防止惊群效应。 如果没有 __none__ 哨兵,没有 BYOK 金钥的帐户在每次 LLM 呼叫时都会访问 Firestore。快取负面结果 5 分钟可以保持 Firestore 读取的可预测性。
临时供应商实例可防止金钥泄漏。 透过每次呼叫创建新的供应商实例并让它被垃圾回收,我们最小化了解密金钥存在于记忆体中的时间窗口。虽然不如硬体安全模组强大,但对于 SaaS 应用程式来说,这是对攻击面的有意义的减少。
按供应商的断路器配合按帐户的并发是正确的粒度。 供应商中断是全局事件;并发是按租户的问题。混合它们要么太激进(一个帐户中断会为所有人触发断路器),要么太宽松(无法防止供应商范围的故障)。