LLM API 网关设计:限流、熔断与多模型路由的工程实践
一、大模型调用洪峰:当 API 网关成为系统咽喉
大模型服务的调用模式与传统微服务有本质区别。一次 LLM 推理请求的延迟通常在 2-30 秒,Token 生成期间服务端持续占用 GPU 资源。当业务侧并发请求突增时,GPU 显存和推理队列迅速饱和,延迟飙升甚至触发 OOM。更棘手的是,多数团队同时接入多个模型供应商(OpenAI、Anthropic、国产大模型),不同模型的限额、延迟和计费模式各异,网关层必须承担统一路由、限流和降级的职责。
传统微服务网关的限流策略(如令牌桶、滑动窗口)直接套用到大模型场景会出现两个问题:其一,按请求数限流无法反映实际资源消耗——一个 4000 Token 的请求和一个 500 Token 的请求占用的 GPU 时间差异巨大;其二,流式响应(SSE)的连接时长远超普通 HTTP 请求,连接数限流和带宽限流需要分别设计。
二、多模型路由与限流架构:从请求到推理的资源管控
LLM API 网关的核心职责是将请求路由到合适的模型实例,同时在多个维度实施限流保护。架构上分为三层:路由层负责模型选择和负载均衡,限流层负责 Token 级别和连接级别的流量控制,熔断层负责异常模型实例的隔离和恢复。
flowchart TB A[客户端请求] --> B[路由层] B --> C{模型选择策略} C -->|按模型类型| D[GPT-4 路由] C -->|按成本优先| E[国产模型路由] C -->|按延迟优先| F[Claude 路由] D --> G[Token 限流器] E --> G F --> G G --> H{限流判定} H -->|通过| I[请求转发] H -->|拒绝| J[降级响应] I --> K[熔断器] K -->|正常| L[模型推理] K -->|熔断| M[备用模型切换] L --> N[响应返回] M --> N路由策略的设计需要考虑三个维度:模型能力匹配(复杂推理走 GPT-4,简单摘要走轻量模型)、成本优化(同等能力下优先选择单价更低的供应商)、延迟敏感度(实时对话场景优先路由到低延迟实例)。限流器则需要在 Token 维度和连接维度同时生效,Token 限流控制单位时间内的总 Token 消耗,连接限流控制同时进行的流式请求数。
三、生产级代码实现:多维度限流与自适应路由
3.1 Token 维度限流器
@Component public class TokenRateLimiter { private final RedisTemplate<String, String> redisTemplate; // 基于 Redis 的滑动窗口限流,窗口粒度为分钟 // 为什么用滑动窗口而非令牌桶:Token 消耗速率不均匀, // 滑动窗口能更精确地反映时间窗口内的实际消耗 public boolean tryAcquire(String modelId, int requestTokens, int limitPerMinute) { String key = "rate_limit:token:" + modelId; long now = System.currentTimeMillis(); long windowStart = now - 60_000; // 移除窗口外的记录 redisTemplate.opsForZSet().removeRangeByScore(key, 0, windowStart); // 计算当前窗口已消耗的 Token 总量 Long consumed = redisTemplate.opsForZSet().zCard(key); int totalConsumed = consumed != null ? consumed.intValue() : 0; if (totalConsumed + requestTokens > limitPerMinute) { return false; } // 记录本次请求的 Token 消耗 redisTemplate.opsForZSet().add(key, now + ":" + requestTokens, now); // 设置 Key 过期时间,防止僵尸数据堆积 redisTemplate.expire(key, 120, TimeUnit.SECONDS); return true; } }3.2 多模型路由与降级
@Service public class ModelRouter { private final List<ModelProvider> providers; private final CircuitBreakerRegistry breakerRegistry; public Flux<ChatResponse> route(ChatRequest request) { // 按优先级排序:能力匹配 > 延迟 > 成本 List<ModelProvider> candidates = providers.stream() .filter(p -> p.supports(request.getModel())) .sorted(Comparator .comparing(ModelProvider::getAvgLatency) .thenComparing(ModelProvider::getCostPerToken)) .toList(); // 逐个尝试,熔断的实例自动跳过 for (ModelProvider provider : candidates) { CircuitBreaker breaker = breakerRegistry .breaker(provider.getName()); if (breaker.getState() == CircuitBreaker.State.OPEN) { log.warn("模型 {} 处于熔断状态,跳过", provider.getName()); continue; } return breaker.executeSupplier(() -> provider.chat(request) .onErrorResume(WebClientException.class, e -> { log.error("模型 {} 调用失败: {}", provider.getName(), e.getMessage()); // 当前实例失败,尝试下一个候选 return tryNext(request, candidates, provider); }) ); } // 所有模型均不可用,返回降级响应 return Flux.just(ChatResponse.fallback( "当前所有模型服务繁忙,请稍后重试")); } }3.3 连接级别限流
@Component public class ConnectionLimiter { private final AtomicInteger activeConnections = new AtomicInteger(0); private final int maxConnections; public ConnectionLimiter( @Value("${llm.gateway.max-connections:200}") int maxConnections) { this.maxConnections = maxConnections; } public <T> Flux<T> executeWithLimit(Supplier<Flux<T>> fluxSupplier) { int current = activeConnections.incrementAndGet(); if (current > maxConnections) { activeConnections.decrementAndGet(); return Flux.error(new RateLimitExceededException( "并发连接数已达上限: " + maxConnections)); } return fluxSupplier.get() .doFinally(signal -> activeConnections.decrementAndGet()); } }四、架构权衡:限流精度、降级策略与成本控制
Token 限流的精度与开销:基于 Redis 滑动窗口的 Token 限流能精确控制每分钟消耗量,但每次请求需要两次 Redis 交互(清理 + 查询 + 写入),在高并发场景下 Redis 本身可能成为瓶颈。替代方案是本地令牌桶,精度略低但延迟更可控。生产环境建议采用"本地令牌桶预判 + Redis 滑动窗口校准"的混合策略,本地桶做快速放行,Redis 做周期性校准。
降级策略的业务影响:当所有高能力模型不可用时,降级到轻量模型意味着输出质量下降。对话场景中,用户能感知到回答质量的差异;但在摘要、分类等任务中,轻量模型的输出通常可接受。降级策略应根据业务场景差异化配置,而非一刀切。
多供应商路由的一致性问题:不同供应商的 API 响应格式、错误码和流式协议存在差异。网关层需要做协议适配,将不同供应商的响应统一为内部标准格式。适配层的维护成本随供应商数量线性增长,建议限制同时接入的供应商数量在 3-5 个。
成本监控的盲区:Token 限流控制了速率,但不直接控制成本。某些模型按输入/输出 Token 差异计费,网关层需要维护每个请求的实际费用记录,并设置日/月级别的费用上限,防止异常调用导致账单失控。
五、总结
LLM API 网关的设计核心是在"可用性"和"成本"之间找到平衡点。Token 维度限流比请求维度限流更贴合 GPU 资源消耗特征,连接维度限流则保护了流式场景下的服务端资源。多模型路由通过优先级排序和熔断机制实现自动降级,但降级策略必须与业务场景对齐。落地时建议优先实现 Token 限流和连接限流两个基础能力,再逐步引入多模型路由和自适应降级。监控方面,务必建立 Token 消耗、连接数和费用的三维看板,这是网关稳定运行的前提。