
Spring AI 面试题ChatClient 怎么落地把统一聊天接口、多模型路由、超时降级讲透很多人以为 Spring AI 的 ChatClient 只是一个更顺手的 SDK 包装层但真正上线后难点其实在统一入口、模型路由和治理能力。这篇我直接按 Java 项目怎么落地来拆既讲 ChatClient 怎么用也讲什么时候该回到底层 ChatModel 去接管路由。个人主页GitHub主页文章目录Spring AI 面试题ChatClient 怎么落地把统一聊天接口、多模型路由、超时降级讲透先看真实问题为什么很多团队接了 Spring AI最后还是把模型调用写散了一张表先看懂一个能上线的统一聊天入口最少要管住哪些事举个具体例子客服中心同时接 FAQ、工单总结、内部知识问答三类能力代码示例统一聊天接口 模型路由 超时降级Maven 依赖application.yml统一聊天服务ChatClient 做标准调用ChatModel 做精细路由系统设计时我会优先拆哪几层统一入口层路由与 Prompt 层治理层真正上线时最容易卡住的点监控和指标建议盯哪些如果面试官问我这块怎么设计我会这样答结语先看真实问题为什么很多团队接了 Spring AI最后还是把模型调用写散了很多 Java 团队一开始都是某个 service 直接注入一个模型 Bean然后哪里要问答就在哪里 call。一开始当然快但业务场景一多很快就会出现 Prompt 风格不一致、模型切换成本高、超时不好治理的问题。真正难的不是把回答跑出来而是把模型接入做成统一能力统一请求体、统一会话标识、统一模型路由、统一成本统计以及统一的超时降级策略。客服 FAQ、工单总结、内部知识问答需要的模型能力完全不一样有的场景更看效果有的场景更看成本不能所有流量都打到同一个模型如果没有统一入口审计、限流、日志和 token 归集最后都会散在业务代码里一张表先看懂一个能上线的统一聊天入口最少要管住哪些事维度怎么做为什么统一请求体Controller 只收 scene、sessionId、userMessage、attachments避免每个业务自己定义模型参数模型路由根据场景、预算、延迟、合规要求选模型把“用哪个模型”从业务代码里拿出来Prompt 策略系统提示词和输出规范做模板化同一类问题输出风格更稳定降级治理超时切备用模型再差切规则结果线上要先保证稳定再谈最优答案举个具体例子客服中心同时接 FAQ、工单总结、内部知识问答三类能力业务侧统一调用/ai/chat只告诉网关这是 FAQ、工单总结还是知识问答。FAQ 走便宜一点的模型工单总结走结构化输出更稳定的模型内部知识问答加上检索增强。如果主模型 RT 超过 3 秒就自动切备用模型如果备用模型也失败再降级到固定话术。每次调用都把 token、耗时、场景、用户、traceId 打到调用日志表里后面才能看成本和稳定性。代码示例统一聊天接口 模型路由 超时降级Maven 依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-openai/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencyapplication.ymlspring:ai:openai:api-key:${OPENAI_API_KEY}base-url:https://api.openai.comchat:options:model:gpt-4o-minitemperature:0.2management:endpoints:web:exposure:include:health,metrics,prometheus统一聊天服务ChatClient 做标准调用ChatModel 做精细路由ServiceRequiredArgsConstructorpublicclassUnifiedChatService{privatefinalChatClient.BuilderchatClientBuilder;privatefinalMapString,ChatModelchatModelRegistry;privatefinalModelCallLogServicemodelCallLogService;publicStringchat(ChatRequestrequest){longstartSystem.currentTimeMillis();ChatModelchatModelroute(request.scene());PromptpromptnewPrompt(List.of(newSystemMessage( 你是企业级AI助手。 当前场景: %s 回答要求: 1. 先给结论再给理由 2. 没有把握不要编造 3. 控制在 200 字内 .formatted(request.scene())),newUserMessage(request.question())));try{ChatResponseresponsechatModel.call(prompt);Stringanswerresponse.getResult().getOutput().getText();modelCallLogService.success(request,chatModel.getClass().getSimpleName(),System.currentTimeMillis()-start,answer);returnanswer;}catch(Exceptionex){returnfallback(request,ex,start);}}publicStringrewriteForRetrieval(Stringquestion){returnchatClientBuilder.build().prompt().system(你是查询改写助手只输出适合知识库检索的一句话).user(question).call().content();}privateChatModelroute(Stringscene){returnswitch(scene){caseFAQ-chatModelRegistry.get(cheapChatModel);caseTICKET_SUMMARY-chatModelRegistry.get(stableStructuredModel);caseRAG_QA-chatModelRegistry.get(knowledgeChatModel);default-chatModelRegistry.get(defaultChatModel);};}privateStringfallback(ChatRequestrequest,Exceptionex,longstart){modelCallLogService.fail(request,ex.getMessage(),System.currentTimeMillis()-start);if(FAQ.equals(request.scene())){return当前智能助手繁忙请稍后重试或者转人工处理。;}thrownewIllegalStateException(模型调用失败,ex);}publicrecordChatRequest(Stringscene,StringsessionId,Stringquestion){}}系统设计时我会优先拆哪几层统一入口层对外统一 REST / SSE 接口业务方不要直接碰底层模型 SDK请求里至少要有 scene、sessionId、traceId后面做日志和限流才有抓手路由与 Prompt 层scene 决定模型类型模板决定回答风格不要把两件事混在一起复杂场景可以先用 ChatClient 做 Prompt 组装再把最终 Prompt 下发给指定 ChatModel治理层统一做超时、限流、错误码映射、成本归集每次调用都要能查到是谁发起、走了哪个模型、为什么降级真正上线时最容易卡住的点把 ChatClient 当成唯一入口结果一碰到多模型路由就写不动了。真到复杂项目里ChatClient 和底层 ChatModel 往往要配合使用。没有按业务场景拆 Prompt 模板最后一个系统提示词想兼容所有场景效果一定很飘。没有统一调用日志月底只看到总账单却不知道哪个业务线把 token 烧掉了。监控和指标建议盯哪些模型调用成功率、P95/P99 RT各场景 token 消耗、平均每问成本超时降级触发率、熔断触发率主模型和备用模型的命中比例如果面试官问我这块怎么设计我会这样答如果面试官问我 Spring AI 的 ChatClient 怎么落地我不会只说“它比 SDK 好用”而是会先讲统一聊天入口再讲模型路由和治理。ChatClient 更适合做标准调用链路和 Prompt 组装但一旦涉及多模型路由、预算策略、降级兜底我会把 ChatModel 抽出来单独控制。也就是说ChatClient 解决的是易用性真正上线还要补齐治理能力。结语Spring AI 不是接上就结束了真正拉开差距的是你有没有把模型接入沉淀成统一入口而不是散落在几十个 service 里。你们项目里如果已经接了大模型更麻烦的是模型路由还是日志和成本治理这一点很适合继续往下聊。