开篇痛点段
在上一篇我们搭建了多厂商统一LLM调用客户端,做到了模型厂商无感切换。 但这里有一个极易被忽略的致命问题:大模型接口和普通HTTP接口完全不是一回事。 普通接口几十毫秒返回,LLM动辄1~5秒,遇到厂商侧抖动、服务故障,响应会更久。
很多同学只加了重试逻辑:接口超时就重试2次。 这个方案,只能解决瞬时抖动(比如一次网络闪断)。 但如果上游大模型服务挂了5分钟、大面积超时报错会发生什么? 用户请求源源不断进来 → 每一次都去调用LLM → 每一次都超时卡住线程 → 线程池快速打满 → 所有依赖这个线程池的接口(查询、提交、其他业务)全部阻塞,直接雪崩。
我们需要一层"保险丝":当模型服务持续异常/持续慢,直接切断流量,不再放行新请求去打LLM,也就是熔断降级。 这就是Sentinel在LLM场景里的核心价值:慢调用熔断 + 异常统计 + 快速失败,故障的时候保护我们自己的业务,而不是被动被上游拖死。
前置回顾:本篇依赖第2篇的
ILlmService、LlmServiceFactory统一底座。 核心认知先行:熔断 ≠ 重试,二者是搭档,顺序绝对不能颠倒。 正确顺序:单次请求内部先做有限重试(应对瞬时抖动)→ 重试依然失败 → 本次结果计入Sentinel的统计窗口 → 达到阈值触发熔断,一段时间内直接快速降级,不再访问LLM。
一、引入依赖
使用Spring Cloud Alibaba Sentinel,适配SpringBoot3环境:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2023.0.1.0</version>
</dependency>
补充说明:SpringBoot3请选用2023.0.x版本,不要用老的2022版本,会存在注解、自动装配兼容问题。
二、封装业务调用层,增加Sentinel资源注解
我们单独抽出LlmBizService作为AI业务门面,把LLM调用标记为Sentinel资源,分开两个处理器:
-
blockHandler:Sentinel限流、熔断、排队规则触发时执行(平台流量管控类拦截) -
fallback:业务本身抛出异常(调用LLM报错、返回异常)的兜底降级 很多新手踩坑:分不清block和fallback,全部写在一个方法里,故障排查根本分不清是被熔断了,还是LLM本身报错。import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.stereotype.Service;@Service
public class LlmBizService {private final LlmServiceFactory factory; public LlmBizService(LlmServiceFactory factory) { this.factory = factory; } /** * Sentinel资源:llm_chat_api * blockHandler:熔断/限流触发的拦截逻辑 * fallback:业务调用异常兜底 */ @SentinelResource(value = "llm_chat_api", blockHandler = "blockHandler", fallback = "fallbackHandler") public ChatResponse chat(String modelKey, String prompt, LlmRequestParam param) { ILlmService llm = factory.getService(modelKey); return llm.chat(prompt, param); } /** * 熔断、限流触发:属于流量管控,短时间不允许放行请求 */ public ChatResponse blockHandler(String modelKey, String prompt, LlmRequestParam param, BlockException e) { // 生产建议:返回标准化VO,给前端友好提示,而不是直接抛原生异常 throw new RuntimeException("当前AI服务压力过高,已开启熔断保护,请稍后再尝试提问"); } /** * LLM调用业务异常兜底:超时、厂商返回报错、鉴权失败等 */ public ChatResponse fallbackHandler(String modelKey, String prompt, LlmRequestParam param, Exception e) { // 可以在这里扩展:自动切换备用模型,而不是直接报错! throw new RuntimeException("AI模型调用暂时异常,请稍后重试"); }}
👉 扩展点 : fallback里面不要只抛异常!你可以在这里复用之前的工厂,实现主模型熔断自动切备用模型: 主模型触发异常进入fallback → 自动传入backup的modelKey,调用备用服务商,给用户无感容灾。 示例思路(伪代码,方便你后续拓展):
// fallback内容灾逻辑
if("tongyi".equals(modelKey)){
return factory.getService("deepseek").chat(prompt,param);
}
三、代码方式配置熔断规则(慢调用比例熔断)
Sentinel有两种配置模式:代码硬编码、控制台动态推送。 代码方式适合本地调试、小体量项目;线上正式环境优先控制台。 这里我们配置LLM场景最适合的:慢请求比例熔断,而不是异常比例熔断。
为什么LLM优先慢调用熔断? 很多时候模型没有抛报错,只是响应极慢,线程卡死,这种场景异常数是0,异常熔断完全感知不到,慢调用熔断刚好捕获这类隐形风险。
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleType;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
public class SentinelRuleConfig {
@PostConstruct
public void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule rule = new DegradeRule();
// 和@SentinelResource的value保持一致,资源名必须匹配
rule.setResource("llm_chat_api");
// LLM场景:超过2000ms判定为慢调用,普通接口一般是几百ms,这里要单独放大阈值
rule.setSlowRtThreshold(2000);
// 统计窗口:10s内的数据用来统计
rule.setStatIntervalMs(10000);
// 慢调用占比超过50%,触发熔断
rule.setSlowRatioThreshold(0.5);
// 最小请求数:10s内至少有5个请求才做统计,避免少量请求误熔断
rule.setMinRequestAmount(5);
// 熔断时长:10秒。熔断开启后,10s内所有新请求直接走blockHandler快速失败,不调用LLM
rule.setTimeWindow(10);
// 规则类型:慢调用比例熔断
rule.setDegradeRuleType(DegradeRuleType.SLOW_REQUEST_RATIO);
rules.add(rule);
DegradeRuleManager.loadRules(rules);
}
}
四、核心时序图

flowchart LR
A[用户请求进入] --> B[本地重试逻辑(最多N次,解决瞬时抖动)]
B --> C{重试成功?}
C --成功--> Z[返回结果]
C --全部重试失败--> D[请求进入Sentinel资源统计]
D --> E{是否已经熔断打开?}
E --已熔断--> F[执行blockHandler,快速降级返回]
E --未熔断--> G[发起真实LLM远程调用]
G --> H{调用正常返回?}
H --正常--> I[统计正常,返回结果]
H --超时/报错/慢--> J[计入慢调用/异常统计]
J --> K{达到熔断阈值?}
K --达到--> L[开启熔断窗口,timeWindow时间内拦截新流量]
K --未达到--> M[继续放行下一次请求]
五、LLM专属踩坑清单
- 阈值不能照搬普通接口 LLM接口RT天生高,普通后端接口500ms算慢,LLM起步建议2~3s作为慢调用阈值。业务是长文本生成、Agent多轮调用的场景,甚至要放到4s,阈值太小会频繁误熔断。
- 熔断降级返回要标准化,面向前端友好 不要直接抛出框架原生英文异常、堆栈信息暴露给前端。统一封装返回体,区分两类提示:
- block(熔断限流):服务繁忙保护提示
- fallback(模型报错):模型调用异常提示 前端可以根据错误码展示不同UI,甚至展示排队弹窗。
- 顺序红线:重试在内,熔断在外,绝对不能反过来 如果先熔断再重试:熔断打开的时候,重试还不断发起调用,熔断完全失效,雪崩依旧发生。 正确设计:重试是单次请求内部的自救;熔断是宏观窗口级别的流量保护。
- 线上强烈推荐接入Sentinel控制台 代码写死规则只适合测试环境。接入控制台后,可以在线实时看QPS、慢调用占比、熔断状态;动态修改RT阈值、熔断时长,不用重启服务。 生产LLM业务波动大,大促、营销活动的时候,随时调参非常关键。
- 熔断窗口内不是永久拒绝 timeWindow是熔断持续时间,时间到之后,Sentinel会进入半开状态:放行少量探测请求。探测请求成功,自动关闭熔断;探测继续失败,重新打开熔断,自动恢复逻辑不用自己写。
- 多模型资源隔离 如果同时有通义、DeepSeek多个模型,不要共用同一个Sentinel资源名。 一个厂商挂了,不要把另外一个正常的模型一起熔断,分开资源、分开规则,做到厂商之间故障隔离。
六、小结
到这里,我们通过Sentinel慢调用熔断,给LLM调用链路装上了保险丝。当上游模型持续变慢、故障时,自动挡住源源不断的用户请求,避免线程池耗尽、服务雪崩。 熔断解决了"故障的时候保护服务",但是还有另外一类场景:营销活动、推广引流,瞬间涌入大量用户提问。哪怕模型本身是健康的,并发量直接打满厂商Token额度、接口QPS上限,瞬间被厂商限流封禁。 下一章,限流 & 排队策略:控制LLM的并发请求数量,平滑流量尖峰,守住厂商额度上限。
本专栏持续更新Java+SpringAI生产落地实战,全部代码可直接改造上线,收藏不迷路。如果你正在搭建内部知识库、智能客服AI能力,欢迎持续跟进。