当前位置: 首页 > news >正文

解决springai 项目中引入多个chatModel存在冲突问题

报错:
Parameter 1 of method chatClientBuilder in org.springframework.ai.model.chat.client.autoconfigure.ChatClientAutoConfiguration required a single bean, but 3 were found:- alibabaOpenAiChatModel: defined by method 'alibabaOpenAiChatModel' in class path resource [com/spring/springai/config/CommonConfiguration.class]- ollamaChatModel: defined by method 'ollamaChatModel' in class path resource [org/springframework/ai/model/ollama/autoconfigure/OllamaChatAutoConfiguration.class]- openAiChatModel: defined by method 'openAiChatModel' in class path resource [org/springframework/ai/model/openai/autoconfigure/OpenAiChatAutoConfiguration.class]This may be due to missing parameter name informationAction:Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
问题原因:

这个错误是因为 Spring 容器中存在多个 ChatModel 类型的 bean,但 ChatClientAutoConfiguration 只需要一个。

方案一:使用 @Primary 注解(推荐)

在公共配置文件 CommonConfiguration.java 中给 alibabaOpenAiChatModel使用 @Primary 注解,

例如:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.ai.chat.model.ChatModel;@Configuration
public class CommonConfiguration {@Bean@Primary  // 添加这个注解public ChatModel alibabaOpenAiChatModel() {// 你的配置代码return ...;}
}

完整代码如下

package com.spring.springai.config;import com.spring.springai.constants.SystemConstants;
import com.spring.springai.model.AlibabaOpenAiChatModel;
import com.spring.springai.tools.CourseTools;
import io.micrometer.observation.ObservationRegistry;
import org.apache.pdfbox.util.Vector;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemoryRepository;
import org.springframework.ai.chat.memory.MessageWindowChatMemory;
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.model.SimpleApiKey;
import org.springframework.ai.model.tool.ToolCallingManager;
import org.springframework.ai.model.openai.autoconfigure.OpenAiChatProperties;
import org.springframework.ai.model.openai.autoconfigure.OpenAiConnectionProperties;
import org.springframework.ai.observation.conventions.VectorStoreProvider;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiEmbeddingModel;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
//import org.springframework.ai.vectorstore.redis.RedisVectorStore;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestClient;
import org.springframework.web.reactive.function.client.WebClient;import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
//import redis.clients.jedis.JedisPooled;@Configuration
public class CommonConfiguration {/*** pdf 问答** @param model* @param chatMemory* @param vectorStore* @return*/@Beanpublic ChatClient pdfChatClient(OpenAiChatModel model, ChatMemory chatMemory, VectorStore vectorStore) {return ChatClient.builder(model).defaultSystem("请根据上下文回答问题,遇到上下文没有的问题,不要随意编造。").defaultAdvisors(new SimpleLoggerAdvisor())//配置日志advisor,添加日志记录.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())// 添加会话记忆功能.defaultAdvisors(QuestionAnswerAdvisor.builder(vectorStore).// 添加向量库searchRequest(SearchRequest.builder().similarityThreshold(0.6).// 设置相似度阈值topK(2).// 设置返回文档数量build()).build()).build();}/*** 解析拆分PDF* 这是使用的是基于内存的 SimpleVectorStore向量库** @param embeddingModel* @return*/@Beanpublic VectorStore vectorStore(OpenAiEmbeddingModel embeddingModel) {return SimpleVectorStore.builder(embeddingModel).build();}//    @Bean
//    public RedisVectorStore redisVectorStore(JedisPooled jedis,OpenAiEmbeddingModel embeddingModel) {
//        return RedisVectorStore.builder(jedis,embeddingModel).build();
//    }/*** 定义记忆存储方式,注册ChatMemory对象* 与视频讲解中不同的是,SpirngAI中,ChatMemory的实现,现在统一为:MessageWindowChatMemory* return new InMemoryChatMemoryRepository();** @return*/@Beanpublic ChatMemory chatMemory() {return MessageWindowChatMemory.builder().chatMemoryRepository(new InMemoryChatMemoryRepository()) // 设置存储库.maxMessages(20) // 记忆窗口大小(保留最近的10条消息).build();}//这个用不到@Beanpublic ChatMemory chatMemory2() {// 使用 MessageWindowChatMemory 作为默认内存策略(窗口消息保留)// 默认使用的存储库就是InMemory,默认窗口大小是20return MessageWindowChatMemory.builder().build();}//智能机器人@Beanpublic ChatClient chatClient(AlibabaOpenAiChatModel model, ChatMemory chatMemory) {return ChatClient.builder(model).defaultOptions(ChatOptions.builder().model("qwen-omni-turbo-latest").build()) //单独设置用这个全模态模型.defaultSystem("你是热心、可爱的智能助手,你的名字叫小团团,请以小团团的身份和语气回答问题.").defaultAdvisors(new SimpleLoggerAdvisor())//配置日志advisor,添加日志记录.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())// 添加会话记忆功能.build();}//女友哄哄模拟器 客户端@Beanpublic ChatClient gameChatClient(OpenAiChatModel model, ChatMemory chatMemory) {return ChatClient.builder(model).defaultSystem(SystemConstants.GAME_SYSTEM_PROMPT).defaultAdvisors(new SimpleLoggerAdvisor())//配置日志advisor,添加日志记录.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())// 添加会话记忆功能.build();}//智能客服@Beanpublic ChatClient serviceChatClient(OpenAiChatModel model, ChatMemory chatMemory, CourseTools courseTools) {return ChatClient.builder(model).defaultSystem(SystemConstants.SERVICE_SYSTEM_PROMPT_3).defaultAdvisors(new SimpleLoggerAdvisor())//配置日志advisor,添加日志记录.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build())// 添加会话记忆功能.defaultTools(courseTools).build();}//阿里巴巴模型 兼容springAi 对 音频文件的处理@Bean@Primary  // 添加这个注解public AlibabaOpenAiChatModel alibabaOpenAiChatModel(OpenAiConnectionProperties commonProperties,OpenAiChatProperties chatProperties,ObjectProvider<RestClient.Builder> restClientBuilderProvider,ObjectProvider<WebClient.Builder> webClientBuilderProvider,ToolCallingManager toolCallingManager,RetryTemplate retryTemplate,ResponseErrorHandler responseErrorHandler,ObjectProvider<ObservationRegistry> observationRegistry,ObjectProvider<ChatModelObservationConvention> observationConvention) {// 配置基础参数String baseUrl = StringUtils.hasText(chatProperties.getBaseUrl()) ?chatProperties.getBaseUrl() : commonProperties.getBaseUrl();String apiKey = StringUtils.hasText(chatProperties.getApiKey()) ?chatProperties.getApiKey() : commonProperties.getApiKey();String projectId = StringUtils.hasText(chatProperties.getProjectId()) ?chatProperties.getProjectId() : commonProperties.getProjectId();String organizationId = StringUtils.hasText(chatProperties.getOrganizationId()) ?chatProperties.getOrganizationId() : commonProperties.getOrganizationId();// 构建连接头信息Map<String, List<String>> connectionHeaders = new HashMap<>();if (StringUtils.hasText(projectId)) {connectionHeaders.put("OpenAI-Project", List.of(projectId));}if (StringUtils.hasText(organizationId)) {connectionHeaders.put("OpenAI-Organization", List.of(organizationId));}// 获取HTTP客户端构建器RestClient.Builder restClientBuilder =restClientBuilderProvider.getIfAvailable(RestClient::builder);WebClient.Builder webClientBuilder =webClientBuilderProvider.getIfAvailable(WebClient::builder);// 构建OpenAI API客户端OpenAiApi openAiApi = OpenAiApi.builder().baseUrl(baseUrl).apiKey(new SimpleApiKey(apiKey)).headers(CollectionUtils.toMultiValueMap(connectionHeaders)).completionsPath(chatProperties.getCompletionsPath()).embeddingsPath("/v1/embeddings").restClientBuilder(restClientBuilder).webClientBuilder(webClientBuilder).responseErrorHandler(responseErrorHandler).build();// 构建自定义聊天模型AlibabaOpenAiChatModel chatModel = AlibabaOpenAiChatModel.builder().openAiApi(openAiApi).defaultOptions(chatProperties.getOptions()).toolCallingManager(toolCallingManager).retryTemplate(retryTemplate).observationRegistry(observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP)).build();// 设置观察约定observationConvention.ifAvailable(chatModel::setObservationConvention);return chatModel;}
}
方案二:使用 @Qualifier 注解

在需要注入的地方指定具体的 bean 名称:

chatServiceImpl.java 完整代码如下

package com.spring.springai.service.impl;import com.spring.springai.service.ChatService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;/*** 实现类*/
@Service
public class ChatServiceImpl implements ChatService {private ChatClient chatClient;//构造函数 构造器注入,自动配置方式(推荐)public ChatServiceImpl(@Qualifier("openAiChatModel") ChatModel chatModel) {this.chatClient = ChatClient.builder(chatModel).defaultSystem("你是一个非常聪明的人工智能助手,可以帮我解决很多问题,我为你取一个好听的名字叫'旺仔'").build();}@Overridepublic String chatTest(String prompt) {return chatClient.prompt(prompt).call().content();}
}

http://www.dtcms.com/a/342205.html

相关文章:

  • 服务器间大文件迁移
  • SparkSQL、FlinkSQL与普通sql比较
  • Git项目报错git@gitlab.com: Permission denied (publickey).【已解决】
  • Jenkins+GitLab在CentOS7上的自动化部署方案
  • iOS混淆工具实战 金融支付类 App 的安全防护与合规落地
  • 飞牛系统总是死机,安装个工具查看一下日志
  • Python爬虫的基础启航
  • 微算法科技(NASDAQ:MLGO)构建去中性化区块链预言机,实现跨链信息互通
  • 消息中间件(RocketMQ+RabbitMQ+Kafka)
  • 14. 多线程(进阶1) --- 常见的锁策略和锁的特性
  • 大模型自我进化框架SE-Agent:开启软件工程自动化新时代
  • Confluent 实时代理:基于 Kafka 流数据的创新实践
  • git 常用命令整理
  • 拂去尘埃,静待花开:科技之笔,勾勒城市新生
  • Linux基础(1) Linux基本指令(二)
  • 大模型推理并行
  • 机器学习7
  • 以往内容梳理--HRD与MRD
  • 《深入探索 Java IO 流进阶:缓冲流、转换流、序列化与工具类引言》
  • 事件驱动流程链——EPC
  • Metrics1:Intersection over union交并比
  • tail -f与less的区别
  • Python Excel 通用筛选函数
  • 【C++】模板(进阶)
  • Rancher 管理的 K8S 集群中部署常见应用(MySQL、Redis、RabbitMQ)并支持扩缩容的操作
  • ubuntu编译ijkplayer版本k0.8.8(ffmpeg4.0)
  • Spring Boot整合Amazon SNS实战:邮件订阅通知系统开发
  • 将windows 的路径挂载到Ubuntu上进行直接访问
  • C++---辗转相除法
  • VB.NET发送邮件给OUTLOOK.COM的用户,用OUTLOOK.COM邮箱账号登录给别人发邮件