关于spring AI调用大模型的几种方案实践
关于spring AI调用大模型的几种方案实践
背景介绍:
spring AI 是java的ai框架,旨在简化应用程序的开发过程,在不增加不必要的复杂性的前提下整合 AI(人工智能)功能。我这里提供我平时调用的大模型的方法,供初学者参考。
具体方案
1、使用自动注入的方式调用
我们可以通过引入对应依赖,配置application.yml文件实现多个大模型配置
(1)导入对应依赖
<!-- 阿里的灵积 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId><version>1.0.0.2</version></dependency><!-- openai --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId><version>1.0.1</version></dependency><!-- deepseek --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-deepseek</artifactId><version>1.0.1</version></dependency><!-- lombok方便日志输出 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.38</version </dependency>具体你要调哪个平台的你也可以直接去看spring AI、springAI alibaba 的官方文档,都有详细说明导入对应的SDK,有很多平台的模型都是兼容openai的,你只需要填写对应的base-url即可。这个版本我是自己看官方文档填的。
(2)配置application.yml文件
spring:application:name: xxx ai:dashscope:base-url: https://dashscope.aliyuncs.com/compatible-mode/v1 api-key: your-key chat:options:model: qwen-plus deepseek:base-url: https://api.deepseek.com/v1 api-key: your-key chat:options:model: deepseek-chat openai:base-url: https://api.siliconflow.cn api-key: your-key chat:options:model: deepseek-ai/DeepSeek-V3.1 server:port:8080上面分别配置了阿里灵积、deepseek、硅基流动的模型,除了deepseek,其他平台都是有免费额度的。
(3)controller调用
/** * @author szq **/@RestController@Slf4j@RequestMapping("/modelTest")publicclass modelTestController {privatefinalChatClient dashCopeChatClient;privatefinalChatClient deepSeekChatClient;privatefinalChatClient openAiChatClient;//建议采用构造的方法注入publicmodelTestController(@Qualifier("dashscopeChatModel")ChatModel dashCopeChatModel,@Qualifier("deepSeekChatModel")ChatModel deepSeekChatModel,@Qualifier("openAiChatModel")ChatModel openAiChatModel ){this.dashCopeChatClient =ChatClient.builder(dashCopeChatModel).build();this.deepSeekChatClient =ChatClient.builder(deepSeekChatModel).build();this.openAiChatClient =ChatClient.builder(openAiChatModel).build();}@GetMapping("/test-dashScopeClient")publicStringtestDashScopeClient(@RequestParam(value ="userQuestion",defaultValue ="先告诉我你是谁,简短评价两眼一睁就是“瓦”")String userQuestion){ log.info("用户问题:{}",userQuestion);String result = dashCopeChatClient.prompt().user(userQuestion).call().content(); log.info("模型结果:{}",result);return result;}@GetMapping("/test-deepSeekClient")publicStringtestDeepSeekChatClient(@RequestParam(value ="userQuestion",defaultValue ="先告诉我你是谁,简短评价两眼一睁就是“瓦”")String userQuestion){ log.info("用户问题:{}",userQuestion);String result = deepSeekChatClient.prompt().user(userQuestion).call().content(); log.info("模型结果:{}",result);return result;}@GetMapping("/test-openAiClient")publicStringtestOpenAiChatClient(@RequestParam(value ="userQuestion",defaultValue ="先告诉我你是谁,简短评价两眼一睁就是“瓦”")String userQuestion){ log.info("用户问题:{}",userQuestion);String result = openAiChatClient.prompt().user(userQuestion).call().content(); log.info("模型结果:{}",result);return result;}}结果演示:



都能正常调用,但话说,两眼一睁就是“瓦”,不应该是打瓦吗! 哈哈哈哈
tips:
这里说一下自己踩过的坑
通过导入对应的依赖,我们可以看到ChatModel有了对应的实现

由于是一个接口多个实现,我采用@Qualifier(“名称”)的方式注入,但"dashScopeChatModel"注入不进来,其他两个都可以,整得我一脸懵。

后面我决定看一下对应的bean到底叫什么名字,写了一个配置
/** * 打印所有 ChatModel Bean 的名称 */@ConfigurationpublicclassBeanNamePrinter{@BeanpublicCommandLineRunnerprintBeans(ApplicationContext applicationContext){return args ->{System.out.println("\n========== 所有的 ChatModel Bean ==========");String[] beanNames = applicationContext.getBeanNamesForType(ChatModel.class);for(String beanName : beanNames){System.out.println("找到 Bean: "+ beanName +" - 类型: "+ applicationContext.getBean(beanName).getClass().getSimpleName());}System.out.println("总共找到 "+ beanNames.length +" 个 ChatModel Bean");System.out.println("==========================================\n");};}}运行结果:

我也是服了,灵积这个没有采用驼峰命名全是小写(裂开)。
2、自己注册bean的方式
这个方式更加灵活,尤其是你在一个平台需要调用多个模型时,最好关闭自动配置(spring.ai.chat.client.enabled=false 来禁用 ChatClient.Builder bean 的自动配置)。
具体实现:
(1)写好对应的配置,我这里把ApiConfig和ClientConfig分开写的
@ConfigurationpublicclassMyApiConfiguration{@Value("${spring.ai.dashscope.api-key}")privateString myDashScopeApiKey;@Value("${spring.ai.dashscope.base-url}")privateString myDashScopeBaseUrl;@Value("${spring.ai.deepseek.api-key}")privateString myDeepSeekApiKey;@Value("${spring.ai.deepseek.base-url}")privateString myDeepSeekBaseUrl;@Value("${spring.ai.openai.api-key}")privateString myOpenAiApiKey;@Value("${spring.ai.openai.base-url}")privateString myOpenAiBaseUrl;/** *灵积 */@Bean("myDashScopeApi")publicDashScopeApidashScopeApi(){returnDashScopeApi.builder().apiKey(myDashScopeApiKey).baseUrl(myDashScopeBaseUrl).build();}/** *deepseek */@Bean("myDeepSeekApi")publicDeepSeekApideepSeekApi(){returnDeepSeekApi.builder().apiKey(myDeepSeekApiKey).baseUrl(myDeepSeekBaseUrl).build();}/** *硅基流动 */@Bean("myOpenAiApi")publicOpenAiApiopenAiApi(){returnOpenAiApi.builder().apiKey(myOpenAiApiKey).baseUrl(myOpenAiBaseUrl).build();}}@ConfigurationpublicclassMyClientConfig{@Value("${spring.ai.dashscope.chat.options.model}")privateString dashScopeModel;@Value("${spring.ai.deepseek.chat.options.model}")privateString deepSeekModel;@Value("${spring.ai.openai.chat.options.model}")privateString openAiModel;/** *灵积 */@Bean("myDashScopeChatModel")publicDashScopeChatModeldashScopeChatModel(@Qualifier("myDashScopeApi")DashScopeApi dashScopeApi){returnDashScopeChatModel.builder().dashScopeApi(dashScopeApi).defaultOptions(DashScopeChatOptions.builder().withModel(dashScopeModel).build()).build();}/** *deepseek */@Bean("myDeepSeekChatModel")publicDeepSeekChatModeldeepseekChatModel(@Qualifier("myDeepSeekApi")DeepSeekApi deepSeekApi){returnDeepSeekChatModel.builder().deepSeekApi(deepSeekApi).defaultOptions(DeepSeekChatOptions.builder().model(deepSeekModel).build()).build();}/** *硅基流动 */@Bean("myOpenAiChatModel")publicOpenAiChatModelopenAiChatModel(@Qualifier("myOpenAiApi")OpenAiApi openAiApi){returnOpenAiChatModel.builder().openAiApi(openAiApi).defaultOptions(OpenAiChatOptions.builder().model(openAiModel).build()).build();}}(2)controller里面使用
//建议采用构造的方法注入publicmodelTestController(@Qualifier("myDashScopeChatModel")ChatModel dashCopeChatModel,@Qualifier("myDeepSeekChatModel")ChatModel deepSeekChatModel,@Qualifier("myOpenAiChatModel")ChatModel openAiChatModel ){this.dashCopeChatClient =ChatClient.builder(dashCopeChatModel).build();this.deepSeekChatClient =ChatClient.builder(deepSeekChatModel).build();this.openAiChatClient =ChatClient.builder(openAiChatModel).build();}tips:
1、我在使用中尝试过不禁用 ChatClient.Builder bean 的自动配置,发现只要你定义了同类名的bean,就会略过自动配置。下面明显可以看到只有自己注册的三个bean。

2、自己注册bean时像deepseek、dashscope我们引入的是官方依赖,它可以自动识别配置里面的base-url、model,所以可以通过下面的方式注册。
@Bean("myDashScopeApi")publicDashScopeApidashScopeApi(){returnDashScopeApi.builder().apiKey(myDashScopeApiKey).build();}@Bean("myDeepSeekApi")publicDeepSeekApideepSeekApi(){returnDeepSeekApi.builder().apiKey(myDeepSeekApiKey).build();}@Bean("myDashScopeChatModel")publicDashScopeChatModeldashScopeChatModel(@Qualifier("myDashScopeApi")DashScopeApi dashScopeApi){returnDashScopeChatModel.builder().dashScopeApi(dashScopeApi).build();}@Bean("myDeepSeekChatModel")publicDeepSeekChatModeldeepseekChatModel(@Qualifier("myDeepSeekApi")DeepSeekApi deepSeekApi){returnDeepSeekChatModel.builder().deepSeekApi(deepSeekApi).build();}注意: 硅基流动等使用非官方提供SDK,他无法自动读取配置里面的base-url、model 那么他会调用它默认地址。例如openai会调用:https://api.openai.com,模型名称也会不对,调用模型就会失败。所以你必须指定这些信息。
我之前就遇到了一直显示模型名称不存在。
400-{"code":20012,"message":"Model does not exist. Please check it carefully.","data":null}总结
1、我这里列举了两种方式调用大模型,基本上是满足日常使用了,当初我刚接触AI时特别想找一个这样的文章+代码,可惜没看到。现在自己会了就分享出来,后续也会多写一些demo,感觉上传到网上,比自己写笔记好很多,毕竟知识共享嘛,希望可以帮助到需要的人。
2、这是这个demo的github地址,感兴趣的也可以直接下载(后续也会继续完善)。