1. 为什么需要大模型路由网关
  2. 路由网关的核心职责
  3. 多模型、多供应商的路由策略
  4. 负载均衡与故障转移
  5. 限流、降级与熔断
  6. 基于 Spring Cloud Gateway 的实现
  7. 统一协议适配与请求转换
  8. 可观测性与成本治理
  9. 安全与合规
  10. 总结与展望

1.1 多模型、多供应商成为常态

随着大模型技术的快速发展,企业内部往往不会只依赖单一模型或单一供应商。实际生产环境中,常见的模型来源包括:

  • 公有云大模型:OpenAI GPT-4、Azure OpenAI、Anthropic Claude、Google Gemini、阿里云通义、百度文心、讯飞星火等。
  • 私有化大模型:基于 Llama、ChatGLM、Qwen、Baichuan 等开源模型在企业内部部署的服务。
  • 垂直领域模型:针对代码、法律、医疗、客服等场景微调后的专用模型。
  • 多尺寸模型:同一个供应商提供 7B、13B、70B 等不同参数规模的模型,用于平衡成本与效果。

如果每个业务服务都自行维护对多个模型供应商的调用逻辑,很快就会出现:

  • 重复封装:每个服务都写一遍 HTTP 调用、鉴权、超时、重试。
  • 配置散落:模型密钥、地址、配额分散在各个服务的配置文件中。
  • 路由僵硬:某个模型不可用时,只能业务侧自己处理 fallback。
  • 成本不可控:无法统一统计各模型调用量和费用。
  • 安全审计困难:模型调用的输入输出没有集中留存和分析。

1.2 网关独立化的收益

把大模型调用统一收口到一个独立网关,能够获得:

维度

分散调用

统一路由网关

---

---

---

接入成本

每个服务重复开发

一次接入,全服务复用

路由灵活性

硬编码

按模型/业务/成本动态路由

故障恢复

各自实现

统一熔断、降级、重试

限流配额

难以协调

统一限流,防止供应商超限

成本统计

分散

统一账单,细粒度分析

安全审计

困难

统一记录输入输出

大模型路由网关的本质,是在业务服务与大模型供应商之间增加一个智能调度层。它既是流量入口,也是治理中枢。

2.1 功能边界

大模型路由网关应聚焦于大模型流量的统一接入与调度,核心职责包括:

  1. **协议适配**:把不同供应商的 API 格式统一为企业内部标准协议。
  2. **智能路由**:根据请求特征选择合适的模型或供应商。
  3. **负载均衡**:在多个模型实例或账号之间分配流量。
  4. **故障转移**:某个模型异常时自动切换到备用模型。
  5. **限流与配额**:控制请求速率,避免触发供应商限流或产生高额费用。
  6. **熔断与降级**:失败率达到阈值时快速失败或返回兜底内容。
  7. **成本治理**:统计 Token 用量、请求次数、模型费用。
  8. **安全审计**:记录请求与响应内容,支持敏感信息检测。

2.2 在微服务架构中的位置

┌─────────────────────────────────────────────────────────────────┐
│                           业务服务层                              │
│   客服 │ 编程助手 │ 文案生成 │ 数据分析 │ 多 Agent 系统            │
└───────────────────────────┬─────────────────────────────────────┘
                            │ 统一 LLM API
                            ▼
                ┌─────────────────────────────┐
                │      大模型路由网关          │
                │  路由 · 负载均衡 · 限流 · 审计 │
                └─────────────┬───────────────┘
                              │
        ┌─────────┬───────────┼───────────┬─────────┐
        ▼         ▼           ▼           ▼         ▼
   ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
   │ GPT-4  │ │ Claude │ │ 私有化 │ │ 文心   │ │ 通义   │
   │ OpenAI │ │  AWS   │ │ vLLM   │ │ 百度   │ │ 阿里   │
   └────────┘ └────────┘ └────────┘ └────────┘ └────────┘

3.1 按模型名称路由

最简单的路由策略是根据请求中的 `model` 字段直接转发到对应供应商:

{
  "model": "gpt-4",
  "messages": [...]
}

网关维护一张路由表:

模型标识

供应商

后端地址

优先级

---

---

---

---

gpt-4

OpenAI

https://api.openai.com

1

gpt-4

Azure OpenAI

https://xxx.openai.azure.com

2

claude-3

Anthropic

https://api.anthropic.com

1

qwen-max

阿里云

https://dashscope.aliyuncs.com

1

3.2 按业务场景路由

不同业务对延迟、成本、质量的要求不同。可以在请求头或请求体中携带业务标识:

X-Business-Code: customer-service

网关根据业务码路由:

  • 客服场景:优先使用稳定、中文效果好的模型。
  • 代码场景:优先使用 Codex、CodeLlama 等代码模型。
  • 文案生成:使用成本较低、创意性强的模型。
  • 数据分析:使用逻辑推理能力强的模型。

3.3 按成本与质量动态路由

更高级的策略是结合成本和实时质量进行动态选择:

  • 简单问题路由到便宜的小模型。
  • 复杂问题路由到能力更强的大模型。
  • 根据历史响应评分,自动调整路由权重。
  • 高峰期优先使用本地部署模型,避免公有云限流。

public class CostAwareRouter implements LlmRouter {
    public RouteTarget route(LlmRequest request) {
        if (request.getComplexityScore() < 0.3) {
            return new RouteTarget("qwen-turbo", "aliyun");
        }
        if (request.getComplexityScore() < 0.7) {
            return new RouteTarget("gpt-3.5-turbo", "openai");
        }
        return new RouteTarget("gpt-4", "openai");
    }
}

3.4 灰度与 A/B 测试

新模型上线时,可以通过网关做灰度发布:

  • 5% 流量切到新模型,95% 保持原模型。
  • 对比延迟、Token 消耗、业务满意度指标。
  • 逐步扩大新模型流量,最终全量切换。

4.1 多账号负载均衡

同一个供应商可能有多个 API Key 或账号,用于分散配额限制。网关可以在多个账号之间轮询或加权随机:

public class ApiKeyLoadBalancer {
    private final List<String> keys;
    private final AtomicInteger counter = new AtomicInteger(0);
    public String selectKey() {
        int idx = counter.getAndIncrement() % keys.size();
        return keys.get(idx);
    }
}

4.2 故障转移策略

当某个供应商返回 5xx 或超时时,网关应快速切换到备用供应商:

public Mono<LlmResponse> callWithFallback(LlmRequest request) {
    List<RouteTarget> targets = router.selectTargets(request);
    return Mono.fromCallable(() -> call(targets.get(0)))
        .onErrorResume(e -> {
            log.warn("Primary provider failed, trying fallback", e);
            return Mono.fromCallable(() -> call(targets.get(1)));
        })
        .onErrorResume(e -> {
            log.error("All providers failed", e);
            return Mono.just(LlmResponse.fallback("服务暂时繁忙,请稍后重试"));
        });
}

4.3 健康检查

网关应定期探测各模型后端的健康状态:

  • 发送低成本的 probe 请求,例如 "hi"。
  • 检测响应延迟和错误率。
  • 动态维护可用后端列表,摘除异常节点。

5.1 限流策略

限流可以从多个维度进行:

  • **全局限流**:保护后端模型服务,防止总流量过大。
  • **租户限流**:每个租户分配独立的配额,避免某个租户占用全部资源。
  • **模型限流**:针对某个供应商或模型的 RPM/TPM 限制。
  • **用户限流**:防止单个用户高频刷接口。

Spring Cloud Gateway 可以配合 Redis 使用令牌桶限流:

spring:
  cloud:
    gateway:
      routes:
        - id: llm-route
          uri: lb://llm-backend
          predicates:
            - Path=/api/v1/llm/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 100
                redis-rate-limiter.burstCapacity: 200
                key-resolver: "#{@tenantKeyResolver}"

5.2 熔断策略

当某个模型后端持续失败时,熔断器应打开,避免无效请求继续打到故障节点:

CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)
    .waitDurationInOpenState(Duration.ofSeconds(30))
    .slidingWindowSize(100)
    .build();

5.3 降级策略

降级可以在不同层次发生:

  • 模型降级:从 GPT-4 降级到 GPT-3.5,或从公有云降级到私有化模型。
  • 响应降级:返回预设文案或缓存结果,避免完全失败。
  • 功能降级:关闭部分非核心功能,如关闭流式输出、减少上下文长度。

6.1 项目依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>
    <dependency>
        <groupId>io.github.resilience4j</groupId>
        <artifactId>resilience4j-spring-boot3</artifactId>
    </dependency>
</dependencies>

6.2 自定义路由过滤器

在 Spring Cloud Gateway 中,可以通过自定义 GlobalFilter 实现智能路由:

@Component
@Order(-1)
public class LlmRoutingFilter implements GlobalFilter {
    private final RouterService routerService;
    private final LlmProviderClientFactory clientFactory;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();
        if (!path.startsWith("/api/v1/llm")) {
            return chain.filter(exchange);
        }
        return DataBufferUtils.join(request.getBody())
            .flatMap(buffer -> {
                String body = buffer.toString(StandardCharsets.UTF_8);
                LlmRequest llmRequest = JsonUtils.fromJson(body, LlmRequest.class);
                RouteTarget target = routerService.route(llmRequest);
                LlmProviderClient client = clientFactory.getClient(target);
                ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
                    .uri(URI.create(target.getUrl()))
                    .header("Authorization", "Bearer " + target.getApiKey())
                    .build();
                return client.forward(mutatedRequest, llmRequest, exchange, chain);
            });
    }
}

6.3 路由配置

路由配置可以放在配置中心,支持动态刷新:

llm:
  routes:
    - model: gpt-4
      provider: openai
      url: https://api.openai.com/v1/chat/completions
      apiKeys: [sk-xxx1, sk-xxx2]
      priority: 1
      rateLimit:
        rpm: 500
        tpm: 100000
    - model: claude-3
      provider: anthropic
      url: https://api.anthropic.com/v1/messages
      apiKeys: [sk-ant-xxx]
      priority: 2

7.1 内部标准协议

企业内部可以定义统一的大模型请求协议,屏蔽各供应商差异:

{
  "requestId": "req_001",
  "model": "gpt-4",
  "messages": [
    {"role": "system", "content": "你是客服助手"},
    {"role": "user", "content": "如何退款?"}
  ],
  "temperature": 0.7,
  "maxTokens": 1024,
  "stream": false,
  "businessCode": "customer-service"
}

7.2 供应商适配器

每个供应商实现一个适配器,把内部协议转换为供应商格式:

public interface LlmProviderAdapter {
    String getProvider();
    Object toProviderRequest(LlmRequest request);
    LlmResponse toStandardResponse(Object providerResponse, String requestId);
}
@Component
public class OpenAiAdapter implements LlmProviderAdapter {
    @Override
    public String getProvider() { return "openai"; }
    @Override
    public Object toProviderRequest(LlmRequest request) {
        return Map.of(
            "model", request.getModel(),
            "messages", request.getMessages(),
            "temperature", request.getTemperature(),
            "max_tokens", request.getMaxTokens(),
            "stream", request.isStream()
        );
    }
    @Override
    public LlmResponse toStandardResponse(Object response, String requestId) {
        OpenAiResponse r = (OpenAiResponse) response;
        return LlmResponse.builder()
            .requestId(requestId)
            .content(r.getChoices().get(0).getMessage().getContent())
            .model(r.getModel())
            .promptTokens(r.getUsage().getPromptTokens())
            .completionTokens(r.getUsage().getCompletionTokens())
            .build();
    }
}

7.3 流式响应适配

大模型流式输出(SSE)在不同供应商之间格式差异较大,网关需要统一转换为企业内部 SSE 格式,让前端无需关心后端模型来源。

8.1 关键指标

网关应暴露以下指标:

指标

说明

---

---

llm_request_total

按模型/供应商/业务统计请求数

llm_latency_seconds

按模型统计请求延迟

llm_tokens_input_total

输入 Token 总数

llm_tokens_output_total

输出 Token 总数

llm_cost_usd_total

估算费用

llm_errors_total

按错误类型统计失败数

llm_circuit_breaker_state

熔断器状态

llm_rate_limited_total

限流触发次数

8.2 成本核算

不同模型价格差异巨大,网关可以基于 usage 实时估算费用:

public class CostCalculator {
    private final Map<String, BigDecimal> inputPricePer1k;
    private final Map<String, BigDecimal> outputPricePer1k;
    public BigDecimal calculate(String model, int inputTokens, int outputTokens) {
        BigDecimal inputCost = inputPricePer1k.getOrDefault(model, BigDecimal.ZERO)
            .multiply(BigDecimal.valueOf(inputTokens)).divide(BigDecimal.valueOf(1000));
        BigDecimal outputCost = outputPricePer1k.getOrDefault(model, BigDecimal.ZERO)
            .multiply(BigDecimal.valueOf(outputTokens)).divide(BigDecimal.valueOf(1000));
        return inputCost.add(outputCost);
    }
}

8.3 成本优化策略

  • 对简单请求优先使用小模型。
  • 对可缓存的常见问题返回缓存结果。
  • 设置单用户、单租户、单模型的月度预算上限。
  • 非必要时不使用流式输出,减少连接消耗。

9.1 密钥管理

模型 API Key 不应硬编码在代码或配置中,应使用:

  • 环境变量注入。
  • Kubernetes Secret。
  • Vault、AWS KMS、阿里云 KMS 等密钥管理系统。
  • 网关定期轮换 API Key。

9.2 输入输出审计

网关应记录所有模型调用的请求和响应:

  • 请求 ID、时间、用户、租户、模型、Token 数。
  • 请求内容(注意脱敏)。
  • 响应内容(注意脱敏)。
  • 响应延迟和费用。

审计日志可以写入 Kafka,再由安全审计服务消费做进一步分析。

9.3 敏感信息过滤

网关可以集成安全审计服务,对请求内容做敏感信息检测:

  • 身份证号、手机号、银行卡号。
  • 企业机密信息、源代码。
  • 涉及违法犯罪、歧视、暴力的内容。

敏感内容可以拦截、替换或打标签后放行。

大模型路由网关是大模型微服务体系中的“流量中枢”。通过统一接入、智能路由、负载均衡、限流熔断、协议适配、成本治理和安全审计,它让企业能够以可控、可观测、可扩展的方式使用多模型、多供应商的大模型能力。

Java 程序员在实现网关时,应重点关注:

  • 路由策略的可配置性与可扩展性。
  • 多供应商协议差异的适配与统一。
  • 流式响应的稳定转发与转换。
  • 限流、熔断、降级的细粒度控制。
  • 成本与质量的动态平衡。
  • 安全审计与合规要求。

下一篇文章,我们将讨论**安全审计服务**的独立化,探讨如何在敏感词过滤、内容合规、输入输出审计等方面建立统一的安全防线。敬请期待。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐