如何为多模型 LLM API 构建提供商中立的限速经纪商
一种实用的架构,用于标准化提供商配额、保留请求和令牌容量、强制租户公平以及处理 429 和 503 响应,而无需跨 SDK 和网关进行多次重试。
当多个团队共享多个 LLM 提供商时,速率限制就不再是提供商集成的细节。这成为一个共享容量问题。一个提供商可以限制请求和输入令牌,另一个提供商可以分离输入和输出令牌,第三个提供商可以在项目级别或跨滚动支出窗口应用配额。每个 SDK 内的重试循环无法协调租户、应用程序、合作伙伴密钥和模型路由之间的这些约束。
实用的解决方案是网关处的中央速率限制代理。代理估计需求,在调度前预留容量,根据策略排队或拒绝工作,并在完成后将预留与实际使用情况进行核对。然后,提供商的响应会优化代理对可用容量的看法,而不是触发独立的重试风暴。
此架构对于任何需要跨内部团队、生产应用程序、自动化代理或外部合作伙伴实现可预测吞吐量的企业 LLM API 非常有用。
为什么提供商速率限制不能降低到每分钟请求数
事实:提供商配额使用不同的维度和范围。常见维度包括每分钟请求数、每分钟输入令牌数、每分钟输出令牌数、总令牌数、每天请求数、并发性、支出窗口以及加速或斜坡率限制。同一提供商可以针对组织、项目、工作区、模型或API产品公开不同的限制。
例如,提供商文档描述了如下组合:
- 请求和令牌限制以及响应标头中的剩余容量和重置信息。
- 消息 API 的单独输入令牌和输出令牌限制。
- 项目级配额,而不是附加到各个 API 键的配额。
- 每日请求限制在提供商定义的时间重置。
- 滚动基于支出的窗口,即使请求和令牌率看起来可以接受,也可以拒绝流量。
- 即使稳态使用量低于公布的配额,加速限制也会对流量急剧增加做出反应。
仅存储一个名为提供商 RPM 的数字的网关最终会在一个维度上过度接纳流量,或在另一维度上使用不足的容量。它还无法解释拒绝是否来自租户政策、提供商项目配额、每日限制或过载响应。
速率限制代理的参考架构
将代理放在请求路径中提供程序适配器之前。每个请求都应通过相同的预留流,无论它是通过 SDK、内部服务、自动化代理还是合作伙伴 API 密钥到达。
- 规范身份。解析组织、租户、团队、应用程序、环境、合作伙伴、API密钥、模型路由和工作负载类。
- 估算需求。计算预期输入令牌、最大输出令牌、预计支出和任何并发成本。
- 评估政策。检查租户预算、队列截止时间、路由资格、优先级和后备规则。
- 预留容量。自动预留相关内部存储桶和面向提供商的存储桶中的容量。
- 调度。仅在预订成功后发送请求。
- 协调。将估计值替换为实际使用情况,释放未使用的预留,并记录提供程序标头和响应分类。
- 决定下一步操作。返回结果、对工作进行排队、集中重试、回退或根据工作负载合同拒绝它。
预订服务应可水平扩展,但其决策对于每个请求都必须是原子的。允许两个工作人员观察相同剩余容量的分布式计数器可以在网关内重现提供程序 429 问题。
使用规范配额模型而不隐藏提供商差异
定义一个规范模型,该模型可以表示特定于提供程序的约束,而不是强制每个提供程序采用同一个抽象。
| 维度 | 它控制什么 | 典型代理操作 |
|---|---|---|
| 请求 | 时间窗口内的调度次数 | 预留一个请求单元 |
| 输入令牌 | 提示和上下文吞吐量 | 保留估计的提示令牌 |
| 输出令牌 | 生成吞吐量 | 保留请求的或政策上限的最大值 |
| 令牌总数 | 提示和完成的组合使用 | 保留特定于提供商的总数 |
| 每日请求 | 长期请求配额 | 每日池耗尽时拒绝或重定向 |
| 支出窗口 | 滚动间隔内的成本 | 保留安全裕度的估算成本 |
| 并发 | 同时处于活动状态的请求 | 获取租约,直至完成或超时 |
| 斜坡速率 | 流量在短时间内增加 | 即使存储桶有空间也限制入场 |
将每个限制表示为一个具有范围、容量、填充或重置规则、单位和来源的存储桶。提供者项目存储桶可能包含请求和输入令牌。工作区存储桶可能包含输出令牌。内部合作伙伴策略可能会增加并发和支出限制。只有所有必需的预约都成功后,录取决定才算成功。
不要将提供商标头视为完整的事实来源。使用它们来纠正代理的估计,但保留配置的模型以限制不会在每个响应中公开。标头名称、可用性和重置语义因提供商和路由而异。
在分配之前预留令牌,然后协调它们
令牌预留是代理和重试包装器之间最重要的区别。代理在发送请求之前需要进行需求估算。
对于输入标记,根据序列化消息、工具定义、结构化输出架构和任何检索到的上下文进行估计。对于输出令牌,请在可用时使用请求最大值,或者在客户端未提供时使用特定于模型和工作负载的估计值。将估算值附在预订中,以便稍后与实际使用情况进行比较。
简单的预订记录可以包含:
- 唯一的请求和预订 ID。
- 租户、应用程序、API密钥、路由和工作负载类。
- 估计输入代币、输出代币、总代币和支出。
- 按预订收费的每个存储桶。
- 创建时间、到期时间、队列截止时间和幂等性密钥。
- 最终实际使用量以及对账期间释放或收取的金额。
保守估计会减少提供商 429 响应,但可能会浪费容量。通过模型、路线、提示族、上下文长度和结构化输出模式来测量估计误差。然后使用有界修正来调整估计值,而不是允许单个异常请求扭曲整个模型。
流式传输需要特定的政策。您可以保留最大输出限额并在流结束时释放未使用的部分,或者在令牌到达时以较小的增量保留输出容量。第一种方法更容易推理;第二种可以提高利用率,但需要可靠的取消、超时和断开连接处理。
分层实施配额
应从最窄的政策到最广泛的共享资源检查容量。典型的层次结构是:
- API密钥或服务身份。
- 应用程序和环境。
- 团队或客户租户。
- 合作伙伴或转销商帐户。
- 提供商工作区或子帐户。
- 提供商项目或组织。
- 模型和路线。
因此,来自合作伙伴应用程序的请求可能需要四次成功的预留:合作伙伴的并发政策、客户租户的令牌预算、网关的路由分配以及提供商项目的可用配额。如果任何预留失败,请释放已获取的预留并应用失败存储桶的决策。
为了公平起见,请使用加权公平排队或赤字循环法,而不是允许先到达的工作线程使用共享池。为生产流量分配较高的权重,为后台作业分配较低的权重,同时保留每个租户的突发信用。硬分区更容易解释,但当一个租户安静时可能会导致容量闲置。加权共享通常可以更有效地利用容量,前提是嘈杂的租户具有有限的突发限制。
围绕工作负载合约设计队列
队列并不自动成为可靠性功能。它可以把看得见的429变成看不见的十分钟延误。每个队列类都需要截止时间、取消行为、最大深度和过载操作。
- 交互式:截止时间短、队列小、可预测的拒绝或容量不可用时模型降级。
- 生产背景:更长的期限、持久的队列、幂等性密钥和受控的重试预算。
- 合作伙伴:特定于租户的配额、已发布的响应元数据,并且无法访问其他租户的队列状态。
- 可批处理:在工作负载允许的情况下,延迟执行、更大的队列以及可选路由至提供程序批处理API。
队列准入应返回明确的决定。根据 API 协定,公开 429 或特定于网关的过载响应,其中包含重试后值、队列标识符和原因代码。不要承诺完成时间,除非系统可以强制执行该承诺。
批处理可以从同步能力中删除非交互式工作,但它会改变结果计时、重试行为、取消和协调。将其视为单独的执行路径,而不是简单地将同步请求放在很长的队列中。对于后台工作负载,将操作权衡与 AI API 成本控制策略和现有批量操作进行比较。
集中重试和过载处理
事实: 临时速率限制响应通常使用 HTTP 429,而提供商过载情况可能使用 503 或提供商特定的错误代码。一些提供程序返回 Retry-After 标头,提供程序文档建议在存在时尊重它。快速的流量斜坡还可以产生加速或减速行为,而不会出现普通的存储桶耗尽情况。
建议:将 Retry-After 视为下限,而不是可选建议。在此之前暂停受影响的提供程序范围,添加有界抖动以防止同步唤醒,并让代理决定哪些排队请求可以使用恢复的容量。
当 Retry-After 不存在或无效时,请使用带有抖动的上限指数退避。将重试预算保留在代理中,而不是单独保存在每个 SDK 和提供程序适配器中。否则,一个逻辑请求可能会产生网关重试、SDK 重试、HTTP 客户端重试和提供商端重试。
重试前对错误进行分类:
- 可重试容量:临时 429 或记录的临时配额响应。
- 可重试过载:临时 503 或等效的提供程序过载信号。
- 不可重试的策略失败:每日配额、支出上限、已停用的项目或租户限制。
- 不可重试的请求失败:架构无效、参数不受支持、身份验证失败或输入格式错误。
- 截止日期失败:请求的剩余用户或工作流程截止时间短于下一次安全尝试。
回退是一个单独的决定。不同的提供者可能有不同的输出行为、定价、延迟、驻留或上下文限制。仅当路由策略确认工作负载合同可以容忍这些差异时才使用回退。
公开决策并衡量饱和度
如果网关仅返回通用 429,团队就无法对限制进行故障排除。返回安全元数据,例如适用的限制、剩余容量、重置时间、队列决策、工作负载类别和拒绝原因。避免暴露其他租户的使用情况或原始提供商凭据。
至少监控:
- 按租户、路线和存储桶划分的预订成功率和拒绝率。
- 队列深度、队列等待时间、截止日期和取消。
- 提供商 429 和 503 速率、重试频率和斜坡速率拒绝。
- 估计与实际令牌使用量以及因过度预留而浪费的容量。
- 并发饱和度和每个租户消耗的容量份额。
- 每个逻辑请求的重试尝试和回退频率。
- 每日配额和支出窗口空间。
负载测试应包括突发流量、长上下文请求、最大输出请求、流式传输断开、每日配额耗尽、提供商 429 和 503 响应以及与生产流量竞争的一个嘈杂租户。不仅验证请求是否最终完成,还验证队列截止时间、公平性和重试预算是否保持不变。
实施清单
- 定义规范维度,而不放弃特定于提供商的限制。
- 为每个请求分配标准化租户、路由、工作负载类和幂等性密钥。
- 在分派之前估计并保留输入、输出、总代币、支出、请求和并发性。
- 使多存储桶预留原子化并安全地使放弃的预留过期。
- 每次尝试后协调实际提供程序使用情况和响应标头。
- 使用加权公平、突发积分和明确的优先级。
- 为每个队列指定截止时间、最大深度和过载操作。
- 集中重试并尊重提供商的 Retry-After 值。
- 将临时容量错误与永久政策和请求错误分开。
- 发布限制元数据并按租户和路由监控饱和度。
- 测试提供商配额耗尽、斜坡限制、流式传输、回退和嘈杂邻居行为。
结论
多模型网关应将提供商配额作为共享基础架构容量进行管理,而不是作为独立的SDK设置的集合。提供商中立的速率限制经纪人为平台团队提供一种准入路径、一项公平政策、一项重试预算以及一个使估算与现实相一致的位置。
该设计确实需要的不仅仅是通用令牌桶。它必须代表请求、输入和输出令牌、每日配额、支出窗口、并发性、提供者范围和爬升率。一旦这些维度明确,网关就可以做出可预测的选择:立即调度、按截止日期排队、放弃工作、集中重试或使用合约安全的后备。这就是吞吐量控制如何成为一种运营能力,而不是生产 429 和 503 事件的重复来源的原因。