news 2026/7/24 23:00:08

05 调大模型API和调支付宝接口一模一样

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
05 调大模型API和调支付宝接口一模一样

摘要:本文系统阐述了大模型API调用中的容错与高可用设计。核心思路是将大模型API视为不可靠的外部依赖,通过四层防护机制保障系统稳定性:1)线程池隔离,避免慢响应拖垮业务线程;2)智能重试,针对超时和限流进行指数退避重试;3)熔断降级,当失败率过高时自动切断调用链路;4)多Provider切换,在主模型不可用时自动降级到备用模型。文章结合Spring生态的@Retryable、Resilience4j CircuitBreaker等工具,给出了完整的Java代码实现,并提供了面试场景的标准回答模板。

这篇聊一个面试必问、但大部分人准备不足的话题。

你调大模型 API 的时候,考虑过它挂了怎么办吗?

很多人没想过。Demo 阶段嘛,调一次成功一次,没出过问题。但我问你个场景:

你的知识库上线了,用了 GPT-4o。某天下午三点,OpenAI 的某个节点出问题了——不是你一个人的问题是全球性的。你的用户正在往系统里问问题,突然全部返回超时错误。

你怎么办?

有人说:我代码里没处理超时,默认 30 秒连接超时。用户等 30 秒,拿到一个白屏,刷新一下再等 30 秒。然后老板的微信来了:"你的系统坏了。"

有人说:我用 try-catch 包了一下,超时了返了个"服务繁忙"。比上一位好点,但用户在你这拿不到答案,转头就去问别的同事了,你的系统慢慢被弃用。

这两种情况我都见过。而且说句实话,第二种已经算不错了——至少没让用户看到异常堆栈。

我打个比喻你们感受一下:

调大模型 API,跟你在美团点外卖一模一样。你下单了,等着骑手把饭送来。但这个骑手可能路上摔跤了(请求超时)、可能拿错了餐(返回乱码)、可能点了个已取消的商家(API 挂了)、可能堵路上了(响应特别慢)。

你是点餐的人,你能怎么办?

你等一会儿再点一次——重试。你换一家店点——降级到另一个模型。你设置最长等待时间——超时。你觉得今天这家店不行直接不吃了——熔断。

一模一样。没有任何本质区别。你平时调支付宝、调微信支付、调短信通道,怎么做的兜底策略,调大模型 API 就怎么做。


先说核心:线程池独立

这是 90% 的人踩的第一个坑。

大模型 API 的响应时间是不可控的。好的时候 1 秒,慢的时候 10 秒,挂了的时候 30秒超时才回错误。如果不做隔离,你的业务线程会被大模型的慢响应拖死。

举个真实例子:

你的系统是个 Web 服务,Tomcat 默认 200 个线程。突然来了一波用户,每人问一个很长的 Prompt。大模型卡住了,200 个线程全卡在等待 API 返回上。

这时候新请求来了,线程池满了,Tomcat 拒绝连接。你的整个系统挂了——不是因为你的业务逻辑有问题,是因为调大模型 API 把线程池占完了。

这不是假设。我亲耳听过一个案例,他们用默认的 RestTemplate 调 OpenAI,生产上 400 并发,直接全部 503。

解决方案:大模型的 API 调用必须走独立的线程池。

@Configuration public class LlmThreadPoolConfig { @Bean("llmTaskExecutor") public ThreadPoolTaskExecutor llmTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心线程:大模型慢,并发不宜太高 executor.setCorePoolSize(10); // 最大线程:最多允许 20 个并发请求同时等大模型 executor.setMaxPoolSize(20); // 队列容量:最多排队 100 个请求 executor.setQueueCapacity(100); // 线程名前缀,方便排查 executor.setThreadNamePrefix("llm-worker-"); // 任务拒绝策略:直接抛异常,让调用方感知到限流了 executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy() ); executor.initialize(); return executor; } }

注意几个关键点:

corePoolSize = 10—— 核心线程数。为什么设这么小?因为大模型 API 的瓶颈通常不在你的机器上,在远端 API 的并发限制上。很多大模型 API 对单个 IP 有 QPS 限制,你起 100 个线程去请求,95 个被限流返回 429。

queueCapacity = 100—— 队列容量。超过 100 个就在入口处拒绝,不要让你的系统死在大模型手上。

CallerRunsPolicy—— 当线程池满了,让调用者线程自己跑。这个策略很聪明:Web 请求的线程被卡在大模型调用上,相当于它自己替大模型扛了一部分并发。比AbortPolicy(直接抛异常)更温和。


@Retryable 重试——别一次失败就放弃

有时候大模型 API 挂了不是真挂了,是短暂波动。过几秒又好了。

比如网络抖了一下、API Gateway 重启、你 API Key 的配额刚好到期需要刷新。这些情况,重试一次就能搞定。

Spring 的@Retryable注解一行就搞定了:

@Service public class LlmRetryService { @Retryable( retryFor = {TimeoutException.class, HttpClientErrorException.TooManyRequests.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2) ) public String callLlm(String prompt) { ResponseEntity<String> response = restTemplate.postForEntity( openAiUrl, buildRequest(prompt), String.class ); return response.getBody(); } @Recover public String recover(Throwable e, String prompt) { // 三次重试都失败后做兜底 return "系统暂时繁忙,请稍后再试"; } }

retryFor—— 什么异常触发重试?超时和限流(429)值得重试。4xx 其他错误(比如 401 认证失败)不值得,重试一百次也没用。

backoff = @Backoff(delay = 1000, multiplier = 2)—— 重试间隔。第一次等 1 秒,第二次等 2 秒。为什么递增?因为对端如果正在压力恢复中,你疯狂重试反而会加重对端负载。指数退避是对双方都友好的策略。

@Recover—— 三次全失败后调这个方法。你在这里做降级:返回一个友好的提示、或者走缓存、或者调一个更便宜的备用模型。


Resilience4j 熔断——别让错误连锁反应

重试对短时波动有效。但如果大模型真的挂了(比如 API 提供商宕机了),重试只会让你的线程池雪上加霜。

这时候需要熔断。一句话解释:你连续失败了很多次之后,就别再试了,直接走降级。

Resilience4j 的 CircuitBreaker 是 Spring Cloud 生态里的标配:

@Bean public CircuitBreaker llmCircuitBreaker() { CircuitBreakerConfig config = CircuitBreakerConfig.custom() // 10 秒窗口内,超过 50% 的请求失败就熔断 .failureRateThreshold(50) .slidingWindowSize(10) // 熔断后等待 30 秒再尝试恢复 .waitDurationInOpenState(Duration.ofSeconds(30)) // 半开状态允许 3 个请求试探 .permittedNumberOfCallsInHalfOpenState(3) .build(); return CircuitBreakerRegistry.of(config) .circuitBreaker("llm-api", config); }

参数含义:

failureRateThreshold(50)—— 失败率阈值 50%。窗口内 10 个请求有 5 个失败就熔断。

slidingWindowSize(10)—— 滑动窗口大小 10 个请求。注意是最后一个请求开始往前数 10 个,不是固定的时间窗口。这样更能反映当前状态。

waitDurationInOpenState(30)—— 熔断后等 30 秒才能进入半开状态。给对端足够时间恢复。

permittedNumberOfCallsInHalfOpenState(3)—— 半开状态只放 3 个请求去试探。如果这 3 个都成功了,电路关闭恢复正常。如果还有失败的,继续熔断。

使用方式:

@Service public class LlmApiService { @Autowired private CircuitBreaker llmCircuitBreaker; private final RestTemplate restTemplate; public String callWithCircuitBreaker(String prompt) { return llmCircuitBreaker.executeSupplier(() -> { // 熔断状态下,这一行不会被执行 // 会直接抛出 CircuitBreakerOpenException return restTemplate.postForEntity( openAiUrl, buildRequest(prompt), String.class ).getBody(); }); } }

当熔断器打开时,executeSupplier不会真的发起 HTTP 请求,而是直接抛出异常。你可以在这个异常的地方捕获,走降级。


多 provider 切换——别在一棵树上吊死

靠模型提供商活着的系统,最怕的是它的 API 挂了。但你只有一个 API Key。

正确答案是:多备几个 provider,自动切换。

@Component public class LlmRouter { private final List<LlmProvider> providers; private final CircuitBreaker circuitBreaker; public String call(String prompt) { for (LlmProvider provider : providers) { if (!provider.isAvailable()) { log.warn("{} 不可用,切换到下一个", provider.name()); continue; } try { return circuitBreaker.executeSupplier( () -> provider.call(prompt) ); } catch (Exception e) { log.warn("{} 调用失败,切换到下一个", provider.name(), e); } } // 所有 provider 都挂了,最后的降级 return fallback(prompt); } private String fallback(String prompt) { // 你可以选择走本地小模型,或者返回缓存 return localModel.call(prompt); } }

LlmProvider接口抽象了模型调用:

public interface LlmProvider { String name(); boolean isAvailable(); String call(String prompt); }

你可以给 OpenAI 一个实现、给通义千问一个实现、再给本地部署的 Ollama 一个实现。排好优先级,失败了自动按顺序往下走。

fallback方法调用localModel—— 这可以是你本地部署的一个小模型,比如 Qwen2.5 7B。性能不如 GPT,但至少不会让用户空手而归。


综合:完整的调用链路

把上面的东西串在一起,实际的调用链路是这样的:

@Service public class LlmResilientService { @Autowired @Qualifier("llmTaskExecutor") private ThreadPoolTaskExecutor executor; @Autowired private LlmRouter router; public CompletableFuture<String> ask(String prompt) { // 异步提交到独立线程池,不阻塞业务线程 return CompletableFuture.supplyAsync(() -> { try { return router.call(prompt); } catch (Exception e) { log.error("所有模型调用都失败了", e); return "系统繁忙,请稍后重试"; } }, executor) // 给整个调用设置超时:最多等 15 秒 .orTimeout(15, TimeUnit.SECONDS) .exceptionally(ex -> { log.warn("LLM 调用超时", ex); return "回答超时,请简化后重试"; }); } }

这个类做的事情:

1. 把请求丢到独立的 LLM 线程池,不占 Tomcat 的线程

2. 用 LlmRouter 自动切换多个 provider,A 不行换 B

3. 每个 provider 调用都有 Resilience4j 熔断器保护

4. 设置了全局超时 15 秒

你给前端返回CompletableFuture,前端可以展示 loading 图标,等结果回来再刷新。不会让用户干等。


🎯 面试官视角的标准回答

如果面试官问:"大模型 API 挂了,你怎么保证系统可用性?"

我把它当作一个外部依赖来处理,和调支付宝没区别。从四个层面做:<br><br>第一是线程隔离。大模型 API 的响应时间不可控,必须走独立的线程池。我设了 10 个核心线程、100 个排队上限,超过的直接拒绝,不占 Tomcat 的 worker 线程。<br><br>第二是超时和重试。必须显式设置连接超时和读取超时,默认的 infinite 是生产大忌。超时后用 @Retryable 做指数退避重试,最多 3 次。<br><br>第三是熔断降级。用 Resilience4j 的 CircuitBreaker,50% 失败率触发熔断,30 秒后自动恢复。熔断期间走降级逻辑,比如返回缓存数据或友好提示。<br><br>第四是多 provider 切换。主备模型策略,OpenAI 挂了自动切到通义千问,再不行切到本地 Ollama。保证不管怎么出问题,用户都不会拿到白屏。<br><br>核心就一句话:任何外部依赖都不可靠,你要做的不是防它不挂,是它挂了你的系统还能跑。

下一篇是这个系列的最后一篇:RAG 调优。chunk 到底切多大?top_k 设多少?怎么评估你的 RAG 效果好不好?

私信回复「666」,一次性领走:

面试宝典:Java 高频考点速查表、HashMap/ConcurrentHashMap 源码笔记、JVM 调优案例、Spring Boot 面试 50 问

AI 编程工具箱:Cursor/Copilot/Codex 六工具对比表、10 个 Prompt 模板、Debug 万能公式、Cursor 速查手册、AI 图片生成入门、30+ 效率工具包

一份资料包,两个专栏都能用。「唠点键盘之外的」,只讲干货。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/24 22:59:39

Linux系统篇:基本指令Chapter 1:对文件的操作和认识

观众老爷们大家好 这里是邪修KING的独家频道本文属于系列Linux系统篇 ——操作指令一起学Linux的小伙伴可订阅专栏&#xff1a; Linux系统篇 前置准备&#xff1a;下载安装 XShell&#xff0c;购买云服务器&#xff0c;用XShell登陆主机进行远程操作&#xff0c;具体教程可参考…

作者头像 李华
网站建设 2026/7/24 22:58:09

如何在3分钟内搞定网易云音乐NCM文件转换:ncmdumpGUI完整教程

如何在3分钟内搞定网易云音乐NCM文件转换&#xff1a;ncmdumpGUI完整教程 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换&#xff0c;Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否遇到过这样的情况&#xff1a;…

作者头像 李华
网站建设 2026/7/24 22:54:16

为什么 SPACE 不占用目标文件的大小?

难度:★★ 本文首发于我的嵌入式技术号「OneChan」,未经授权禁止转载。 在启动文件里,你一定见过这样的代码: Stack_Size EQU 0x00000400AREA STACK, NOINIT, READWRITE, ALIGN=3 Stack_Mem SPACE Stack_Size __initial_sp这定义了一个 1KB 的栈空间。…

作者头像 李华
网站建设 2026/7/24 22:51:27

su-03t离线语音模块与stm32单片机通信方法

手把手教程&#xff0c;基础薄弱的也能看懂&#xff01;由于关于此模块连接stm32的教程较少&#xff0c;避免自己忘记特此记录一下。1.搜索智能公元并进行登录2.选择产品管理中的所有产品并创建一个产品3.产品类别选择其他--其他产品4.场景选择纯离线方案5.模组选择su-03t&…

作者头像 李华
网站建设 2026/7/24 22:50:51

零基础掌握AI股票分析:3步打造个人智能投资系统

零基础掌握AI股票分析&#xff1a;3步打造个人智能投资系统 在信息爆炸的股票市场中&#xff0c;你是否面临这样的困境&#xff1a;每天花费数小时盯盘看新闻&#xff0c;却依然难以把握市场脉络&#xff1f;面对海量数据和技术指标&#xff0c;不知如何筛选有效信息&#xff…

作者头像 李华
网站建设 2026/7/24 22:47:09

5070≥4090!黄仁勋引爆科技春晚,NVIDIA要做机器人界的ChatGPT

“女士们、先生们&#xff0c;欢迎来到英伟达。你现在身处我们的数字孪生世界中。此处所有内容均由人工智能生成。” 穿着标志性皮衣的英伟达 CEO 黄仁勋踌躇满志。刚刚&#xff0c;这位身价千亿的科技巨子在人称“科技界春晚”的 CES 2025&#xff08;国际消费类电子产品展览会…

作者头像 李华