前言
在做 Spring AI 项目的时候,如果想引入多个大模型,会发现似乎无法直接通过单一配置实现。
当然,这里指的是只导入 Spring AI 框架的东西,不引入各个大模型自家的 SDK 情况下,并且两个大模型的协议还是相同的。
原因很简单:同一个 ChatModel 的实现类仅能实现一个。比如我们都知道的,千问其实可以用 OpenAI 的 API 协议,引入 open-ai 的 maven,在配置文件配置千问的参数即可。
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
但是,如果你还要再使用 ChatGPT 模型呢?那我怎么配置?很明显这时候就不行了。虽然这概率不是很大,但是这也确确实实是我团队的项目中遇到的一个障碍点。
问题原因
(这里不讲太深,不细扒底层源码,讲一下大致的流程和用到的类而已)
在 Spring AI 框架中,调用大模型 API 的流程其实就是你配置一个客户端 ChatClient,ChatClient 会配置 ChatModel,真正发起大模型调用的是这个 ChatModel,在 ChatModel 会按照自家的 API 协议封装请求体,比如 OpenAI API 协议用的是 org.springframework.ai.openai.api.OpenAiApi。调用完成后,再封装成 Spring AI 框架的 ChatResponse 返回。
以上是最简单的流程。如果我同时要实现 ChatGPT 的调用和千问的调用,发现用的都是 OpenAI 协议,而使用这个协议的 ChatModel 目前只有 OpenAiChatModel。你不能通过配置文件实现两个 OpenAiChatModel。你要么配置 ChatGPT 的配置,要么配置 Qwen 的配置。最终 Spring 框架也只会自动给你注入一个 Bean(这块在 Spring AI 框架中的 OpenAIChatAutoConfiguration 中)。
下面就来说说怎么解决。
解决后的效果
配置文件跟原生配置方式一样一点都不用变。
配置客户端的时候直接用我们写好的 QwenChatModel 即可,跟使用 OpenAIChatModel 一样,自动装配的,无需操心。这样子你的项目里既可以有调用 GPT 的 ChatClient 也可以再有一个调用 Qwen 的 ChatClient 了。而且非常简单方便,完全都是原生相同的操作。
接下来我们看看实现方式吧
实现方式
核心是我们再实现一个同样适用 OpenAIAPI 接口的 ChatModel 实现类,且自动装配要按照我们自己的前缀 (不能使用 openai 前缀不然就冲突了)
理解其实就很简单了,撸起袖子加油干!
配置类
首先看一下 Spring 原来的 OpenAIChatModel 是怎么自动装配的:
org.springframework.ai.model.openai.autoconfigure.OpenAiChatAutoConfiguration
关键在他的装配条件:
@ConditionalOnClass(OpenAiApi.class)
@EnableConfigurationProperties({ OpenAiConnectionProperties.class, OpenAiChatProperties.class })
@ConditionalOnProperty(name = SpringAIModelProperties.CHAT_MODEL, havingValue = SpringAIModels.OPENAI, matchIfMissing = true)

