大模型应用的服务分级:从核心链路到实验功能的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 请求,而是按层次递进:

  1. 第一层:模型降级。 Tier 2 功能从 GPT-4o 切换到 GPT-4o-mini,牺牲质量换取可用性。请求不拒绝,但使用更轻量的模型。
  2. 第二层:功能裁剪。 例如搜索 AI 摘要从「全文摘要」降级为「关键句提取」,减少输出 Token 数量,降低推理延迟。
  3. 第三层:请求拒绝。 前两层无法保住核心链路时,直接对 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 全局降级信号 + 定时资源水位检测,三件套缺一不可。

当你的大模型应用还在「所有请求一视同仁」时,下一次流量洪峰就是你补这一课的时候。服务分级不是可选的锦上添花,而是生产级的准入条件。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐