大模型应用的服务分级:从核心链路到实验功能的SLO差异化设计
大模型应用的服务分级:从核心链路到实验功能的SLO差异化设计
当一个大模型应用承载了 50 个 AI 能力,而 GPU 资源只够保障其中 15 个稳定运行时,架构师的第一反应不应该是「加机器」,而是「分等级」。
一、为什么大模型应用必须做服务分级
在一个典型的大模型应用中,API 网关后面往往挂着几十个模型调用链路:核心对话、智能搜索、文档摘要、推荐理由生成、AI 评论审核、表情包生成……它们共用同一批 GPU 推理节点,共享同一个 Token 配额池。当流量洪峰到来——比如大促期间智能客服被疯狂调用——所有链路一起争抢资源,结果往往是最重要的核心对话也开始超时报错。
这就是「资源争抢的扁平化灾难」:没有优先级区分,所有请求一视同仁,最终导致系统整体不可用。传统微服务治理中,服务分级(Service Tiering)是标准做法,但到了大模型应用场景,这个方法论需要针对 LLM 的独特属性做一次「适配升级」。
核心差异在哪里?三个维度:
| 维度 | 传统微服务 | 大模型应用 |
|---|---|---|
| 资源瓶颈 | CPU/内存/网络 | GPU 显存/推理 Token |
| 延迟特性 | 毫秒级,可预测 | 秒级到十秒级,随 Token 数波动 |
| 故障模式 | 超时/错误码明确 | 输出质量退化、幻觉增加(非二值失败) |
| 成本模型 | 按实例计费 | 按 Token 计费 + GPU 机时 |
这意味着大模型服务分级不仅要考虑「能不能用」,还要考虑「生成质量」和「推理成本」两个额外维度。
二、三级服务等级(Tier 0/1/2)的划分标准
结合我们在生产环境的实践,推荐按如下标准将 AI 能力划分为三个等级:
graph TD
A[AI 能力评估入口] --> B{影响用户核心体验?}
B -->|是| C{故障导致营收损失?}
B -->|否| D{有独立用户价值?}
C -->|是, >5%% 收入影响| T0[Tier 0: 核心链路]
C -->|否, 间接影响| T1[Tier 1: 重要功能]
D -->|是| T1
D -->|否| T2[Tier 2: 实验功能]
T0 --> SLO0["SLO: 99.95% 可用性\nP99 < 3s\n优先级: 最高"]
T1 --> SLO1["SLO: 99.5% 可用性\nP99 < 8s\n优先级: 中"]
T2 --> SLO2["SLO: 99.0% 可用性\nP99 < 15s\n优先级: 低"]
style T0 fill:#f96,stroke:#333,stroke-width:3px
style T1 fill:#fc6,stroke:#333,stroke-width:2px
style T2 fill:#9cf,stroke:#333,stroke-width:1px
Tier 0 — 核心链路(约占 AI 能力的 15%~20%)
典型场景:主对话流、支付风控 AI 判定、实时的交易异常检测。这些能力一旦不可用,用户的核心体验直接断裂。SLO 目标:可用性 ≥ 99.95%,P99 延迟 < 3s(端到端,含模型推理)。资源保障上,Tier 0 独占最小保障 GPU 配额(Guaranteed Resource),不允许被其他等级抢占。
Tier 1 — 重要功能(约占 30%~40%)
典型场景:搜索结果 AI 摘要、个性化推荐理由、智能工单分类。这些功能失效会让体验变差,但用户可以绕过或容忍。SLO 目标:可用性 ≥ 99.5%,P99 < 8s。资源保障上采用 Burstable 模式——平时共享资源池,资源紧张时可被 Tier 0 抢占。
Tier 2 — 实验功能(约占 40%~50%)
典型场景:AI 表情包生成、花絮内容摘要、A/B 测试中的新功能。这些是「锦上添花」,降级成本极低。SLO 目标:可用性 ≥ 99.0%,P99 < 15s。资源模式为 Best-Effort,系统高负载时首批被降级。
三、生产级 SLO 监控与资源隔离实现
以下代码展示了基于 Spring Boot + Redis 的 Tier 级别限流与降级实现。核心思路是:为每个 Tier 分配独立的令牌桶,Tier 0 的令牌桶容量和填充速率远高于 Tier 2,当资源水位告警时,Tier 2 的令牌桶被主动清空。
package com.example.aigateway.tier;
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.Bucket;
import io.github.bucket4j.Refill;
import io.github.bucket4j.local.SynchronizationStrategy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* 基于 Tier 的分布式限流器。
* 核心逻辑:Tier 0 拥有最大令牌配额且不可被降级,
* Tier 2 在高负载时主动触发令牌清空,实现软降级。
*/
@Component
public class TieredRateLimiter {
private final RedisTemplate<String, String> redisTemplate;
// 每 Tier 每模型的本地令牌桶缓存(减少 Redis 往返)
private final Map<String, Bucket> localBucketCache = new ConcurrentHashMap<>();
// 降级信号 Key,由资源监控模块写入
private static final String DEGRADATION_SIGNAL_KEY = "ai:degradation:level";
// Tier → 每分钟请求上限
private static final Map<Integer, Long> TIER_QUOTA = Map.of(
0, 10_000L, // Tier 0: 10000 req/min — 核心链路高保障
1, 3_000L, // Tier 1: 3000 req/min
2, 500L // Tier 2: 500 req/min
);
public TieredRateLimiter(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 获取指定模型与 Tier 的令牌。
*
* @param modelId 模型标识(如 "gpt-4o-mini")
* @param tier 服务等级:0-核心 / 1-重要 / 2-实验
* @return true 表示允许调用,false 表示限流
*/
public boolean tryAcquire(String modelId, int tier) {
// 检查全局降级信号 —— 当资源水位超过阈值时直接拒绝低等级请求
String degradationLevel = redisTemplate.opsForValue()
.get(DEGRADATION_SIGNAL_KEY);
if (degradationLevel != null) {
int currentDegLevel = Integer.parseInt(degradationLevel);
// degradationLevel = 0 表示全局限流,= 1 表示仅 Tier 1/2 限流
if (currentDegLevel <= tier) {
return false; // 该 Tier 已被降级,直接拒绝
}
}
String bucketKey = "rate_limit:" + modelId + ":tier:" + tier;
Bucket bucket = localBucketCache.computeIfAbsent(bucketKey, k ->
Bucket.builder()
.addLimit(Bandwidth.classic(
TIER_QUOTA.getOrDefault(tier, 500L),
Refill.greedy(TIER_QUOTA.getOrDefault(tier, 500L),
Duration.ofMinutes(1))))
.withSynchronizationStrategy(SynchronizationStrategy.LOCK_FREE)
.build()
);
return bucket.tryConsume(1);
}
}
配合一个资源监控组件,当 GPU 集群的平均利用率超过 85% 或推理队列积压超过阈值时,自动触发降级信号:
@Component
public class ResourceMonitor {
private final RedisTemplate<String, String> redisTemplate;
private static final double GPU_UTILIZATION_THRESHOLD = 0.85;
private static final int QUEUE_BACKLOG_THRESHOLD = 500;
private static final String DEGRADATION_SIGNAL_KEY = "ai:degradation:level";
public ResourceMonitor(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 定时任务:每 15 秒检查资源水位并更新降级信号。
* 生产环境中建议通过 Prometheus + AlertManager 触发,此处展示核心逻辑。
*/
// @Scheduled(fixedDelay = 15_000)
public void evaluateResourceWatermark() {
double gpuUtil = fetchGpuUtilization(); // 从 K8s metrics API 获取
int queueDepth = fetchInferenceQueueDepth(); // 从 Redis 推理队列获取
try {
if (gpuUtil > 0.95 || queueDepth > 1000) {
// 严重告警:仅保留 Tier 0
redisTemplate.opsForValue().set(
DEGRADATION_SIGNAL_KEY, "0", 30, TimeUnit.SECONDS);
} else if (gpuUtil > GPU_UTILIZATION_THRESHOLD || queueDepth > QUEUE_BACKLOG_THRESHOLD) {
// 一般告警:降级 Tier 2
redisTemplate.opsForValue().set(
DEGRADATION_SIGNAL_KEY, "1", 30, TimeUnit.SECONDS);
} else {
// 资源正常,解除所有降级
redisTemplate.delete(DEGRADATION_SIGNAL_KEY);
}
} catch (Exception e) {
// Redis 不可用时使用本地默认策略:保守降级
// 记录告警日志供 SRE 团队排查
// logger.error("Failed to update degradation signal, using conservative defaults", e);
}
}
private double fetchGpuUtilization() {
// 伪代码:实际通过 K8s Metrics API 或 Prometheus 查询
return 0.0;
}
private int fetchInferenceQueueDepth() {
// 从 Redis 推理队列获取等待长度
Long size = redisTemplate.opsForList().size("ai:inference:queue");
return size != null ? size.intValue() : 0;
}
}
关键设计点:降级信号通过 Redis 写入而非本地内存,确保多网关实例的一致性。TTL 设为 30 秒,避免 Redis 故障导致「永久降级」——信号过期后自动恢复到未降级状态,这是一个「fail-open」的设计。
四、降级策略的层次化执行
当降级发生时,不是一刀切地拒绝所有 Tier 2 请求,而是按层次递进:
- 第一层:模型降级。 Tier 2 功能从 GPT-4o 切换到 GPT-4o-mini,牺牲质量换取可用性。请求不拒绝,但使用更轻量的模型。
- 第二层:功能裁剪。 例如搜索 AI 摘要从「全文摘要」降级为「关键句提取」,减少输出 Token 数量,降低推理延迟。
- 第三层:请求拒绝。 前两层无法保住核心链路时,直接对 Tier 2 返回预设的静态兜底结果。
这个层次化降级的关键价值在于:不是「有没有」的二进制切换,而是「有多好」的渐进式衰减。这在用户体验上远比直接报错优雅。
/**
* 层次化降级配置。
* 每一层是一个降级策略,按 order 升序执行。
* 实际项目中通过配置中心(如 Nacos)动态下发,无需重启。
*/
public enum DegradationAction {
// 第一层:模型降级 —— 切换到更轻量的模型
MODEL_FALLBACK(
1, "model_fallback",
"gpt-4o → gpt-4o-mini"
),
// 第二层:功能裁剪 —— 减少输出复杂度
FEATURE_REDUCE(
2, "feature_reduce",
"全文摘要 → 关键句提取"
),
// 第三层:静态兜底 —— 返回预计算结果或缓存
STATIC_FALLBACK(
3, "static_fallback",
"返回预设兜底文案"
);
public final int order;
public final String actionCode;
public final String description;
DegradationAction(int order, String actionCode, String description) {
this.order = order;
this.actionCode = actionCode;
this.description = description;
}
}
五、总结
大模型应用的服务分级不是传统微服务治理的简单平移,而是在 GPU 资源稀缺性、Token 成本敏感性和输出质量渐进性三个维度上的重新设计。核心要点可以归纳为:
- 三级划分有据可依:以「影响核心体验 + 导致营收损失」作为 Tier 0 的硬标准,避免主观划分导致的「都是 P0」膨胀。
- SLO 差异化是分级的核心产物:不同 Tier 在可用性、延迟、资源保障上的目标必须量化,否则分级只是纸上谈兵。
- 降级不是开关,是渐进:模型降级 → 功能裁剪 → 静态兜底,让用户感知到的不是「崩了」而是「变慢了/变简单了」。
- 资源隔离靠工具链闭环:令牌桶限流 + Redis 全局降级信号 + 定时资源水位检测,三件套缺一不可。
当你的大模型应用还在「所有请求一视同仁」时,下一次流量洪峰就是你补这一课的时候。服务分级不是可选的锦上添花,而是生产级的准入条件。
更多推荐




所有评论(0)