如何在 Spring Boot 应用中配置多个 Spring AI 的 LLM 客户端

news/2025/10/10 20:27:34/文章来源:https://www.cnblogs.com/didispace/p/19133808

1. 概述

越来越多的现代应用开始集成大型语言模型(LLM),以构建更智能的功能。如何使用Spring AI快速整合LLM能力到自己的Spring Boot应用,在之前的博文中有过很多篇关于使用Spring AI使用不同供应商LLM的整合案例。虽然一个 LLM 能胜任多种任务,但只依赖单一模型并不总是最优。

不同模型各有侧重:有的擅长技术分析,有的更适合创意写作。简单任务更适合轻量、性价比高的模型;复杂任务则交给更强大的模型。

本文将演示如何借助 Spring AI,在 Spring Boot 应用中集成多个 LLM。

我们既会配置来自不同供应商的模型,也会配置同一供应商下的多个模型。随后基于这些配置,构建一个具备弹性的聊天机器人,在故障时可自动在模型间切换。

2. 配置不同供应商的 LLM

我们先在应用中配置来自不同供应商的两个 LLM。

在本文示例中,我们将使用 OpenAI 和 Anthropic 作为 AI 模型提供商

2.1. 配置主 LLM

我们先将一个 OpenAI 模型配置为主 LLM。

首先,在项目的 pom.xml 文件中添加所需依赖:

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId><version>1.0.2</version>
</dependency>

该 OpenAI Starter 依赖 是对 OpenAI Chat Completions API 的封装,使我们能够在应用中与 OpenAI 模型交互。

接着,在 application.yaml 中配置我们的 OpenAI API Key 和聊天模型:

spring:ai:open-ai:api-key: ${OPENAI_API_KEY}chat:options:model: ${PRIMARY_LLM}temperature: 1

我们使用 ${} 属性占位符从环境变量中加载属性值。另外,我们将温度设置为 1,因为较新的 OpenAI 模型只接受这个默认值。

在完成上述属性配置后,Spring AI 会自动创建一个 OpenAiChatModel 类型的 bean。我们使用它来定义一个 ChatClient bean,作为与 LLM 交互的主要入口

@Configuration
class ChatbotConfiguration {@Bean@PrimaryChatClient primaryChatClient(OpenAiChatModel chatModel) {return ChatClient.create(chatModel);}
}

ChatbotConfiguration 类中,我们使用 OpenAiChatModel bean 创建了主 LLM 的 ChatClient

我们使用 @Primary 注解标记该 bean。当在组件中注入 ChatClient 且未使用 Qualifier 时,Spring Boot 会自动注入它。

2.2. 配置次级 LLM

现在,我们将配置一个来自 Anthropic 的模型作为次级 LLM。

首先,在 pom.xml 中添加 Anthropic Starter 依赖:

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-anthropic</artifactId><version>1.0.2</version>
</dependency>

该依赖是对 Anthropic Message API 的封装,提供了与 Anthropic 模型建立连接并交互所需的类。

接着,为次级模型定义配置属性:

spring:ai:anthropic:api-key: ${ANTHROPIC_API_KEY}chat:options:model: ${SECONDARY_LLM}

与主 LLM 的配置类似,我们从环境变量中加载 Anthropic API Key 和模型 ID。

最后,为次级模型创建一个专用的 ChatClient bean

@Bean
ChatClient secondaryChatClient(AnthropicChatModel chatModel) {return ChatClient.create(chatModel);
}

这里,我们使用 Spring AI 自动配置的 AnthropicChatModel bean 创建了 secondaryChatClient

3. 配置同一供应商的多个 LLM

很多时候,我们需要配置的多个 LLM 可能来自同一 AI 供应商

Spring AI 并不原生支持这种场景,其自动配置每个供应商只会创建一个 ChatModel bean。因此,对于额外的模型,我们需要手动定义 ChatModel bean。

让我们来看看具体过程,并在应用中配置第二个 Anthropic 模型

spring:ai:anthropic:chat:options:tertiary-model: ${TERTIARY_LLM}

application.yaml 的 Anthropic 配置下,我们添加了一个自定义属性来保存第三个(tertiary)LLM 的模型名称

接着,为第三个 LLM 定义必要的 bean:

@Bean
ChatModel tertiaryChatModel(AnthropicApi anthropicApi,AnthropicChatModel anthropicChatModel,@Value("${spring.ai.anthropic.chat.options.tertiary-model}") String tertiaryModelName
) {AnthropicChatOptions chatOptions = anthropicChatModel.getDefaultOptions().copy();chatOptions.setModel(tertiaryModelName);return AnthropicChatModel.builder().anthropicApi(anthropicApi).defaultOptions(chatOptions).build();
}@Bean
ChatClient tertiaryChatClient(@Qualifier("tertiaryChatModel") ChatModel tertiaryChatModel) {return ChatClient.create(tertiaryChatModel);
}

首先,为创建自定义的 ChatModel bean,我们注入自动配置的 AnthropicApi bean、用于创建次级 LLM 的默认 AnthropicChatModel bean,并通过 @Value 注入第三个模型的名称属性。

我们复制现有 AnthropicChatModel 的默认选项,并仅覆盖其中的模型名称

该设置假定两个 Anthropic 模型共享同一个 API Key 及其他配置。如果需要不同的属性,可以进一步自定义 AnthropicChatOptions

最后,我们使用自定义的 tertiaryChatModel 在配置类中创建第三个 ChatClient bean。

4. 探索一个实用用例

在完成多模型配置后,让我们实现一个实用用例。我们将构建一个具备弹性的聊天机器人,当主模型出现故障时可按顺序自动回退到替代模型

4.1. 构建具备弹性的聊天机器人

为实现回退逻辑,我们将使用 Spring Retry。

创建一个新的 ChatbotService 类,并注入我们定义的三个 ChatClient。接着,定义一个入口方法使用主 LLM:

@Retryable(retryFor = Exception.class, maxAttempts = 3)
String chat(String prompt) {logger.debug("Attempting to process prompt '{}' with primary LLM. Attempt #{}",prompt, RetrySynchronizationManager.getContext().getRetryCount() + 1);return primaryChatClient.prompt(prompt).call().content();
}

这里,我们创建了一个使用 primaryChatClientchat() 方法。该方法使用 @Retryable 注解,在遇到任意 Exception 时最多重试三次。

接着,定义一个恢复方法:

@Recover
String chat(Exception exception, String prompt) {logger.warn("Primary LLM failure. Error received: {}", exception.getMessage());logger.debug("Attempting to process prompt '{}' with secondary LLM", prompt);try {return secondaryChatClient.prompt(prompt).call().content();} catch (Exception e) {logger.warn("Secondary LLM failure: {}", e.getMessage());logger.debug("Attempting to process prompt '{}' with tertiary LLM", prompt);return tertiaryChatClient.prompt(prompt).call().content();}
}

使用 @Recover 注解标记的重载 chat() 方法将作为原始 chat() 方法失败并耗尽重试后的回退处理

我们首先尝试通过 secondaryChatClient 获取响应;如果仍失败,则最后再尝试使用 tertiaryChatClient

这里使用了简单的 try-catch 实现,因为 Spring Retry 每个方法签名只允许一个恢复方法。但在生产应用中,我们应考虑使用更完善的方案,例如 Resilience4j。

在完成服务层实现后,我们再对外暴露一个 REST API

@PostMapping("/api/chatbot/chat")
ChatResponse chat(@RequestBody ChatRequest request) {String response = chatbotService.chat(request.prompt);return new ChatResponse(response);
}record ChatRequest(String prompt) {}
record ChatResponse(String response) {}

这里定义了一个 POST 接口 /api/chatbot/chat,接收 prompt,将其传递到服务层,最后把 response 包装在 ChatResponse record 中返回。

4.2. 测试我们的聊天机器人

最后,我们来测试聊天机器人,验证回退机制是否正常工作

通过环境变量启动应用:为主、次级 LLM 设置无效模型名称,同时为第三个 LLM 设置一个有效的模型名称:

OPENAI_API_KEY=.... \
ANTHROPIC_API_KEY=.... \
PRIMARY_LLM=gpt-100 \
SECONDARY_LLM=claude-opus-200 \
TERTIARY_LLM=claude-3-haiku-20240307 \
mvn spring-boot:run

在上述命令中,gpt-100claude-opus-200 是无效的模型名称,会导致 API 错误;而 claude-3-haiku-20240307 是 Anthropic 提供的有效模型

接着,使用 HTTPie CLI 调用接口,与聊天机器人交互:

http POST :8080/api/chatbot/chat prompt="What is the capital of France?"

这里我们向聊天机器人发送一个简单的提示词,看看返回结果:

{"response": "The capital of France is Paris."
}

可以看到,尽管主、次级 LLM 的配置为无效模型,聊天机器人仍返回了正确响应,这验证了系统成功回退到了第三个 LLM

为了更直观地看到回退逻辑的执行过程,我们再来看一下应用日志:

[2025-09-30 12:56:03] [DEBUG] [com.baeldung.multillm.ChatbotService] - Attempting to process prompt 'What is the capital of France?' with primary LLM. Attempt #1
[2025-09-30 12:56:05] [DEBUG] [com.baeldung.multillm.ChatbotService] - Attempting to process prompt 'What is the capital of France?' with primary LLM. Attempt #2
[2025-09-30 12:56:06] [DEBUG] [com.baeldung.multillm.ChatbotService] - Attempting to process prompt 'What is the capital of France?' with primary LLM. Attempt #3
[2025-09-30 12:56:07] [WARN] [com.baeldung.multillm.ChatbotService] - Primary LLM failure. Error received: HTTP 404 - {"error": {"message": "The model `gpt-100` does not exist or you do not have access to it.","type": "invalid_request_error","param": null,"code": "model_not_found"}
}
[2025-09-30 12:56:07] [DEBUG] [com.baeldung.multillm.ChatbotService] - Attempting to process prompt 'What is the capital of France?' with secondary LLM
[2025-09-30 12:56:07] [WARN] [com.baeldung.multillm.ChatbotService] - Secondary LLM failure: HTTP 404 - {"type":"error","error":{"type":"not_found_error","message":"model: claude-opus-200"},"request_id":"req_011CTeBrAY8rstsSPiJyv3sj"}
[2025-09-30 12:56:07] [DEBUG] [com.baeldung.multillm.ChatbotService] - Attempting to process prompt 'What is the capital of France?' with tertiary LLM

日志清晰地展示了请求的执行流程。

可以看到,主 LLM 连续三次尝试失败;随后服务尝试使用次级 LLM,仍然失败;最终调用第三个 LLM 处理提示词并返回了我们看到的响应

这表明回退机制按设计正常工作,即使多个 LLM 同时失败,聊天机器人仍保持可用。

5. 小结

本文探讨了如何在单个 Spring AI 应用中集成多个 LLM。首先,我们演示了 Spring AI 的抽象层如何简化来自不同供应商(如 OpenAI 与 Anthropic)的模型配置。随后,我们解决了更复杂的场景:在同一供应商下配置多个模型,并在 Spring AI 的自动配置不够用时创建自定义 bean。最后,我们利用多模型配置构建了一个具有高可用性的弹性聊天机器人。借助 Spring Retry,我们实现了级联回退模式,在发生故障时可在不同 LLM 间自动切换。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/934385.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Azure APIM】解答REST API实现禁用自签名证书的证书链验证中的backends参数值从那里取值的问题?

问题描述 使用APIM服务时候,因为后端的API需要使用自签名证书进行验证。如果通过浏览器直接访问后端API返回正常,但是APIM请求的时候返回为500报错。 在开启Trace后,发现报错信息为:error message :The underlyin…

2025 AI 进化图谱:技术突破、场景落地与产业重构 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

题解:P14065 [PO Final 2022] 对弈 / Laserschack

题目传送门 先警示后人: 我在看题目的时候看成了 \(1 \le r,c \le 4000\) 然后被迫想了一个 \(\operatorname{O}(\operatorname{RC} \ \operatorname{log} \ \operatorname{RC})\) 发现好像有点玄 最后乱加一堆优化跑…

[Git] 放弃暂存区的修改

1 需求描述在使用 Git 进行版本控制时,有时我们会在暂存区(staging area)中暂存了一些修改,但后来发现这些修改是不需要的,想要放弃这些修改并恢复到上一次提交的状态。Git 提供了几种方法来实现这一操作。2 解决…

前端里面transform和transition 属性的区别

transform 和 transition 都是用于在 HTML 中控制元素的视觉效果和动画的 CSS 属性,但它们的作用和功能不同。下面详细解释这两个属性的区别: 1. transform 属性 transform 属性允许你对元素进行 2D 或 3D 转换(即对…

【MAC环境】安装多个 JDK - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

CF2064E Mycraft Sand Sort

Sol 首先 \(c\) 不能变,否则第一列就会改变。 然后注意到 \(i,j(i<j)\) 能交换当且仅当满足以下任意一条:\(\displaystyle\max_{k=i+1}^{j-1}a_k<\min(a_i,a_j)\) i+1=j那么考虑从小到大做,每次把小的数删除,…

使用eBPF技术保护FastAPI安全

本文详细介绍如何利用eBPF技术保护面向互联网的API安全,包括FastAPI、Flask、Django等框架。通过secimport工具实现Python代码的实时追踪、沙箱策略构建和运行时监控,有效防御远程代码执行等安全威胁。使用eBPF保护F…

项目案例作业2:对案例进行面向对象分析

学生管理系统面向对象分析报告 小组成员:李天瑞 202421336012 目录学生管理系统面向对象分析报告1. 案例中哪里体现出了封装性及其好处?封装性的体现封装性带来的好处2. 案例中的setter/getter模式与封装性什么是set…

20251010周五日记

20251010周五日记今天十点多回学校了,好不容易不下雨了。没想到国庆还真加了那么多天班= = 今日: 1.早上吃完早饭收拾东西慢慢悠悠回来了,打印朋辈表多亏师哥妙手回春。准备去开学代会,说来又要翘课了。 2.中午吃了…

k8s 主节点重启后 从节点 get 异常 - 教程

k8s 主节点重启后 从节点 get 异常 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "…

多维索引技术优化数据湖查询性能

本文介绍了一种通过多维索引技术优化数据湖查询性能的解决方案。该技术可直接集成到现有数据湖架构中,支持跨列复杂过滤,提升查询速度最高达6倍,同时降低70%计算成本,兼容主流计算引擎无需重构数据管道。Qbeast获7…

训练笔记:博弈杂题

[7-/7] A. 黎明\(1\sim n\) 排成一个环进行约瑟夫(隔一个删一个),求有多少个时刻,被删除的数的异或和为 \(0\)。 多测 \(10^5\) 组,\(n<10^{18}\)。hint:考虑把约瑟夫的过程分解为 \(\lceil\log n\rceil\) 个…

HTML5拖放API核心功能解析

好的,我们来详细解析一下 HTML5 拖放 API 的核心功能。 HTML5 拖放 API 允许用户在浏览器中抓取一个元素,并将其拖放到另一个位置。它原生支持在浏览器标签页、甚至不同浏览器、乃至桌面应用之间拖放,是现代 Web 应…

[USACO07NOV] Telephone Wire G

dp题,做法有点套路但是一开始没想到。 设 \(dp{_i}_j\) 表示第 \(i\) 位为 \(j\) 的最小花费。 然后直接往下转移就好了。点击查看代码 #include<bits/stdc++.h> #define fir first #define sec second #define…

springboot配置多个数据源

springboot配置多个数据源在我们的实际业务中可能会遇到;在一个项目里面读取多个数据库的数据来进行展示,spring对同时配置多个数据源是支持的。 使用到的框架:springboot+mybatis 方法:在配置文件中配置多个数据源…

Umi-OCR_文字识别工具 免安装使用教程(附下载安装包)!永久免费,开源离线OCR识别软件下载

软件介绍 在外面日常工作汇中,我们经常需要将图片、截图中的文字转换为可编辑文本。Umi-OCR应运而生——这是一款完全开源免费的离线OCR识别工具,无需联网即可本地完成高精度文字识别,保护你的数据隐私同时确保高效…

常量指针 和 指针常量

常量指针 和 指针常量Posted on 2025-10-10 19:52 steve.z 阅读(0) 评论(0) 收藏 举报如何牢记 “常量指针” 和 “指针常量” 的区别?🧩 一、先看词序规律:「前修后主」 在汉语里:前面的词修饰后面的词。比…

PyTorch 神经网络工具箱完全指南 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …