Spring AI 接入大模型后,为什么线上最先出问题的不是模型,而是超时、重试和限流

发布时间:2026/7/28 12:20:53
Spring AI 接入大模型后,为什么线上最先出问题的不是模型,而是超时、重试和限流 摘要很多人接入 Spring AI 后第一反应是研究模型效果和 Prompt。但真到线上最先暴露的往往不是“模型不会答”而是接口超时、重试放大流量、并发打满、费用失控、降级缺失。本文用 Java 后端的方式把 AI 调用当成一个不稳定的外部依赖来治理。1. 大模型接口不是普通 HTTP 接口传统后端调一个第三方接口通常关心状态码、超时、重试、熔断。接大模型时很多项目却容易忽略这些基础设施因为大家的注意力都被 Prompt 和模型参数吸走了。但模型接口有几个特点特点对系统的影响响应慢请求线程占用时间长输出长网络传输和解析耗时不可控费用按量重试不是免费动作限流严格并发上来后容易 429结果非确定重试不一定得到同一个结果所以 AI 服务上线时要先把它当成“慢、贵、不稳定、可能被限流”的外部系统处理。2. 推荐架构不要在 Controller 里直接调用模型。最小也应该隔一层网关服务。ControllerAiApplicationServicePromptBuilderAiGatewayTimeoutRateLimiterRetryCircuitBreakerModel Provider这样做的目的不是为了抽象好看而是把所有不稳定性集中在AiGateway里处理。后面换模型、加日志、加降级都不用改业务代码。3. 超时先定硬边界AI 接口没有超时线上迟早出事。尤其是流式输出用户看起来还在加载实际上后端线程、连接、网关资源都被占着。建议至少分三层超时类型建议值说明connectTimeout2-3 秒连不上就别等readTimeout30-60 秒看业务能接受多久businessTimeout业务自定义比如客服 15 秒报告生成 120 秒示例publicStringaskWithDeadline(Stringquestion){try{returnCompletableFuture.supplyAsync(()-aiGateway.ask(question),executor).get(20,TimeUnit.SECONDS);}catch(TimeoutExceptione){thrownewAiTimeoutException(AI 服务响应超时请稍后重试,e);}catch(Exceptione){thrownewAiServiceException(AI 服务暂不可用,e);}}超时文案也要注意。不要把供应商错误、内部 prompt、模型参数暴露给前端。4. 重试不是所有失败都应该重试重试是 AI 应用里最容易被滥用的功能。传统接口重试一次可能没事大模型重试一次可能意味着多花一倍 token 成本多占一倍并发额度把供应商限流打得更严重得到一个和第一次不同的答案建议只对这几类错误重试错误是否重试原因连接失败可以可能是瞬时网络问题读超时谨慎可能模型还在生成429 限流延迟后重试必须退避400 参数错误不重试重试也没用401/403 权限错误不重试配置或权限问题一个简单策略privatebooleanretryable(Throwablee){if(einstanceofBadRequestException){returnfalse;}if(einstanceofUnauthorizedException){returnfalse;}returneinstanceofIOException||einstanceofRateLimitedException;}如果使用 Spring Retry也不要配置无限重试。最多 1-2 次并且加退避。5. 限流保护模型也保护自己AI 接口限流不是供应商才需要关心的事。你自己的服务也要限流否则用户一刷新、前端一重连、定时任务一批量跑就可能把 token 和并发打爆。建议按三个维度限维度例子用户级单用户每分钟最多 10 次功能级报告生成接口并发最多 5 个全局级整个应用同时最多 50 个模型请求最简单的本地并发限制可以用SemaphoreprivatefinalSemaphoreaiPermitsnewSemaphore(20);publicStringask(Stringprompt){booleanacquiredaiPermits.tryAcquire();if(!acquired){thrownewAiBusyException(AI 服务繁忙请稍后再试);}try{returnmodelClient.call(prompt);}finally{aiPermits.release();}}这个实现不适合多实例全局限流但单机第一版很有效。多实例场景再换 Redis 或网关限流。6. 熔断模型挂了不要拖垮主业务很多 AI 功能本质上是增强能力不应该拖垮核心链路。比如智能摘要失败不应该影响原始详情页打开AI 推荐失败不应该影响工单创建知识库问答失败不应该影响人工搜索熔断的目标是当模型连续失败时短时间内不再继续打它而是走降级。是是否否用户请求AI 是否健康调用模型成功?返回 AI 结果记录失败返回降级结果降级可以很简单场景降级方式问答返回搜索结果列表摘要返回原文前几段分类进入人工处理建议返回规则引擎结果7. 流式输出也要治理SSE 或 WebSocket 接大模型时常见问题更多前端断开了后端还在生成客户端重复连接服务端重复扣费中途异常没有结束事件日志只记录了开头没有完整答案建议每个流式请求至少有字段作用requestId串起前后端日志userId做权限和限流startTime统计耗时tokenCount估算成本cancelFlag用户断开后取消流式接口要处理客户端断开publicvoidstream(Stringquestion,SseEmitteremitter){AtomicBooleancancellednewAtomicBoolean(false);emitter.onCompletion(()-cancelled.set(true));emitter.onTimeout(()-cancelled.set(true));emitter.onError(error-cancelled.set(true));aiGateway.stream(question,chunk-{if(cancelled.get()){return;}emitter.send(chunk);});}真实项目里还要进一步取消上游模型请求否则只是停止向前端写并没有停止成本。8. 日志不要只记最终答案AI 调用日志至少记录这些字段字段是否建议记录说明requestId必须串联链路model必须方便排查模型差异promptVersion必须Prompt 变更可追踪latencyMs必须性能分析inputTokens/outputTokens建议成本分析finishReason建议是否被截断errorCode必须失败分类注意日志不要直接明文记录用户敏感信息。能脱敏就脱敏能只存 hash 就只存 hash。9. 上线检查清单上线前建议过一遍是否设置连接超时和读取超时是否限制最大输出 token是否对 429 做退避是否避免无限重试是否有用户级和全局限流是否有降级方案是否记录 requestId、模型、Prompt 版本是否能查单次请求成本是否处理流式连接断开是否对错误信息做脱敏这些东西看起来普通但比“Prompt 再优化 10%”更能救线上。