Java 程序员第 44 阶段09:大模型微服务拆分,独立服务解耦便于扩容维护,大模型路由网关:统一流量调度与负载均衡
- 为什么需要大模型路由网关
- 路由网关的核心职责
- 多模型、多供应商的路由策略
- 负载均衡与故障转移
- 限流、降级与熔断
- 基于 Spring Cloud Gateway 的实现
- 统一协议适配与请求转换
- 可观测性与成本治理
- 安全与合规
- 总结与展望
1.1 多模型、多供应商成为常态
随着大模型技术的快速发展,企业内部往往不会只依赖单一模型或单一供应商。实际生产环境中,常见的模型来源包括:
- 公有云大模型:OpenAI GPT-4、Azure OpenAI、Anthropic Claude、Google Gemini、阿里云通义、百度文心、讯飞星火等。
- 私有化大模型:基于 Llama、ChatGLM、Qwen、Baichuan 等开源模型在企业内部部署的服务。
- 垂直领域模型:针对代码、法律、医疗、客服等场景微调后的专用模型。
- 多尺寸模型:同一个供应商提供 7B、13B、70B 等不同参数规模的模型,用于平衡成本与效果。
如果每个业务服务都自行维护对多个模型供应商的调用逻辑,很快就会出现:
- 重复封装:每个服务都写一遍 HTTP 调用、鉴权、超时、重试。
- 配置散落:模型密钥、地址、配额分散在各个服务的配置文件中。
- 路由僵硬:某个模型不可用时,只能业务侧自己处理 fallback。
- 成本不可控:无法统一统计各模型调用量和费用。
- 安全审计困难:模型调用的输入输出没有集中留存和分析。
1.2 网关独立化的收益
把大模型调用统一收口到一个独立网关,能够获得:
|
维度 |
分散调用 |
统一路由网关 |
|
--- |
--- |
--- |
|
接入成本 |
每个服务重复开发 |
一次接入,全服务复用 |
|
路由灵活性 |
硬编码 |
按模型/业务/成本动态路由 |
|
故障恢复 |
各自实现 |
统一熔断、降级、重试 |
|
限流配额 |
难以协调 |
统一限流,防止供应商超限 |
|
成本统计 |
分散 |
统一账单,细粒度分析 |
|
安全审计 |
困难 |
统一记录输入输出 |
大模型路由网关的本质,是在业务服务与大模型供应商之间增加一个智能调度层。它既是流量入口,也是治理中枢。
2.1 功能边界
大模型路由网关应聚焦于大模型流量的统一接入与调度,核心职责包括:
- **协议适配**:把不同供应商的 API 格式统一为企业内部标准协议。
- **智能路由**:根据请求特征选择合适的模型或供应商。
- **负载均衡**:在多个模型实例或账号之间分配流量。
- **故障转移**:某个模型异常时自动切换到备用模型。
- **限流与配额**:控制请求速率,避免触发供应商限流或产生高额费用。
- **熔断与降级**:失败率达到阈值时快速失败或返回兜底内容。
- **成本治理**:统计 Token 用量、请求次数、模型费用。
- **安全审计**:记录请求与响应内容,支持敏感信息检测。
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 程序员在实现网关时,应重点关注:
- 路由策略的可配置性与可扩展性。
- 多供应商协议差异的适配与统一。
- 流式响应的稳定转发与转换。
- 限流、熔断、降级的细粒度控制。
- 成本与质量的动态平衡。
- 安全审计与合规要求。
下一篇文章,我们将讨论**安全审计服务**的独立化,探讨如何在敏感词过滤、内容合规、输入输出审计等方面建立统一的安全防线。敬请期待。
更多推荐




所有评论(0)