Spring AI Alibaba 模型全家桶:接入通义、百川、LLaMA 等第三方 LLM
上篇我们学会了用工作流编排多个 AI 任务,但有一个问题遗留了下来:所有 AI 节点都共用同一个模型。如果我想让逻辑推理用 DeepSeek,中文润色用通义千问,本地快速响应用 LLaMA,怎么办?今天这篇就是答案——用 Spring AI Alibaba 的多模型切换能力,让你在一套代码里自由组合各大模型,真正做到“一个项目,全家桶模型随心配”。
Spring AI 设计的核心原则之一就是“统一 API,灵活适配”。你在前几篇中学到的 ChatClient、Prompt、Stream 等调用方式,在与不同模型交互时完全一致。Spring AI Alibaba 不仅原生集成了通义千问,还通过 Spring AI 的抽象层兼容了 OpenAI 格式的云端模型(如百川、Moonshot)和本地 Ollama 模型(如 LLaMA)。今天我们就来搭建一个“模型全家桶”项目,让同一套业务代码可以根据需求动态选择底层大模型。
一、痛点场景:一家模型不够用的时候
场景一:多模型对比选型
你们团队想评估通义千问、百川和本地 LLaMA 在客服场景下的表现。如果用三套不同的代码分别对接,不仅开发量大,而且业务逻辑一旦调整,三套代码都得改。
场景二:按任务分派模型
你的应用中有三种任务:复杂推理交给 DeepSeek,中文内容生成交给通义千问,而一些简单的本地分类任务为了节约成本使用 LLaMA 3。你需要一个“调度中心”能根据任务类型自动路由到不同模型。
场景三:容灾与降级
当某个云端模型服务出现故障或触发限流时,你希望自动切换到备用模型,保证服务可用性。这要求你的代码和模型之间是完全解耦的。
这些需求都可以用 Spring AI 的多模型管理能力优雅解决。思路是:为每个模型创建不同的 ChatClient Bean,然后通过一个路由层根据策略选择调用哪一个。 业务代码只需要和路由层交互,完全不用关心底层是哪个模型。
二、核心概念快览
2.1 Spring AI 的统一模型抽象
无论是 OpenAI、Azure OpenAI、Ollama 还是 DashScope,只要它们实现了 ChatModel 接口,Spring AI 就能将它们作为“可插拔”的组件集成。ChatClient 是对 ChatModel 的再封装,提供流式调用和 Advisor 支持。我们之前一直使用的就是 ChatClient。
2.2 Spring AI Alibaba 中的 DashScope 模型
spring-ai-alibaba-starter-dashscope 会自动创建 DashScopeChatModel 并注册为 ChatModel 和 ChatClient Bean。这就是通义千问的接入方式。
2.3 兼容 OpenAI 接口的第三方模型
百川、Moonshot、DeepSeek、零一万物等大量国产模型提供商都提供与 OpenAI 兼容的 HTTP API。在 Spring AI 中,只要它们返回的 JSON 格式兼容 OpenAI Chat Completions 协议,我们就可以使用 spring-ai-starter-model-openai 来接入,只需更改 base-url 和 api-key。
2.4 本地 Ollama 模型
之前第 7 篇我们详细讲过。它通过 spring-ai-starter-model-ollama 接入,同样产生一个 ChatModel 实现。
2.5 多模型路由策略
最简单的路由是基于模型名称手动选择。你可以创建一个 Map<String, ChatClient>,根据前端传来的参数或任务类型,从 Map 中取出对应的 ChatClient 调用。更高级的玩法是利用 Spring AI 的未来功能(如 ModelRouter),但目前用 Map 已经足够实用。
三、环境准备
3.1 API Key 汇总
由于要同时接入多个云端模型,你需要准备至少两个 API Key:
- 通义千问(百炼):
DASHSCOPE_API_KEY - 百川(或其他兼容 OpenAI 的模型):
BAICHUAN_API_KEY
百川、Moonshot 等平台的 API Key 获取方式类似,在各自开放平台注册即可。本地 LLaMA 则需要安装 Ollama 并拉取模型(参考第 7 篇)。
3.2 Maven 依赖
我们需要在一个项目中同时引入 DashScope、OpenAI 和 Ollama 三个 starter,而且还要管理好它们的版本。核心依赖:
<properties>
<spring-ai.version>1.1.6</spring-ai.version>
<spring-ai-alibaba.version>1.1.2.0</spring-ai-alibaba.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- DashScope Starter:通义千问 -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
<version>${spring-ai-alibaba.version}</version>
</dependency>
<!-- OpenAI Starter:用于百川等兼容 OpenAI 的模型 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
<!-- Ollama Starter:本地 LLaMA 等 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
注意:这三个 starter 会分别注册各自的自动配置,包括
ChatModel和ChatClientBean。为了防止冲突,我们不能直接通过@Autowired ChatClient注入(那样会因为有多个 Bean 而报错)。我们需要使用@Qualifier或者更简单的方式:手动为每个模型创建独立的ChatClientBean,并给予有意义的名字。
3.3 多模型配置文件
在 application.yml 中,我们必须为不同的模型使用不同的配置前缀。由于 Spring AI 只允许一套 spring.ai.openai 和一套 spring.ai.ollama,而我们接入百川也要用 OpenAI 的 starter,这就需要用不同的环境配置或手动创建 Bean 来区分。最简单的方法是:不为百川使用自动配置,而是手动构造一个 OpenAiChatModel,指定独立的 base-url 和 api-key。
因此,配置文件里只保留 DashScope 和 Ollama 的自动配置,百川的配置我们通过硬编码(从环境变量读取)在 Bean 中创建。
spring:
ai:
dashscope:
api-key: ${DASHSCOPE_API_KEY}
chat:
options:
model: qwen-plus
temperature: 0.7
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama3:8b
temperature: 0.7
四、代码实战
4.1 创建多个 ChatClient Bean
新建 MultiModelConfig.java:
package com.example.springaihelloworld.config;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.openai.OpenAiChatModel;
import org.springframework.ai.openai.OpenAiChatOptions;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MultiModelConfig {
// 自动配置的 ChatModel Bean 名称
// DashScope ChatModel Bean 名称为 "dashScopeChatModel"
// Ollama ChatModel Bean 名称为 "ollamaChatModel"
/**
* 通义千问 ChatClient(使用 DashScope 自动配置的 ChatModel)
*/
@Bean
public ChatClient qwenChatClient(@Qualifier("dashScopeChatModel") ChatModel chatModel) {
return ChatClient.create(chatModel);
}
/**
* 百川 ChatClient(手动构建 OpenAiChatModel,使用百川兼容 API)
*/
@Bean
public ChatClient baichuanChatClient() {
String apiKey = System.getenv("BAICHUAN_API_KEY");
if (apiKey == null) {
throw new IllegalStateException("BAICHUAN_API_KEY 环境变量未设置");
}
OpenAiApi baichuanApi = new OpenAiApi("https://api.baichuan-ai.com/v1", apiKey);
ChatModel baichuanModel = OpenAiChatModel.builder()
.openAiApi(baichuanApi)
.defaultOptions(OpenAiChatOptions.builder()
.withModel("Baichuan4") // 百川模型名
.withTemperature(0.7f)
.build())
.build();
return ChatClient.create(baichuanModel);
}
/**
* 本地 LLaMA ChatClient(使用 Ollama 自动配置的 ChatModel)
*/
@Bean
public ChatClient llamaChatClient(@Qualifier("ollamaChatModel") ChatModel chatModel) {
return ChatClient.create(chatModel);
}
}
关键点解读:
- 通过
@Qualifier指定要注入哪一个ChatModelBean。自动配置的 Bean 名称通常在官方文档中会有说明,或者你可以通过查看DashScopeAutoConfiguration和OllamaAutoConfiguration源码来确认。这里假设 DashScope 的 ChatModel Bean 名为dashScopeChatModel,Ollama 的为ollamaChatModel。如果名称不同,请根据实际情况调整,或者直接@Autowired Map<String, ChatModel>查看所有 Bean 名称。 - 百川的接入没有使用自动配置,而是手动构建
OpenAiApi和OpenAiChatModel,这样就不会和默认的 OpenAI 配置冲突,且可以自由指定 base-url 和 api-key。
4.2 创建模型路由服务
新建 ModelRoutingService.java,用 Map 存储所有模型对应的 ChatClient:
package com.example.springaihelloworld.service;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import java.util.Map;
@Service
public class ModelRoutingService {
private final Map<String, ChatClient> modelMap;
/**
* 构造器注入所有 ChatClient Bean,通过名字区分
*/
public ModelRoutingService(ChatClient qwenChatClient,
ChatClient baichuanChatClient,
ChatClient llamaChatClient) {
this.modelMap = Map.of(
"qwen", qwenChatClient,
"baichuan", baichuanChatClient,
"llama", llamaChatClient
);
}
/**
* 同步对话
* @param model 模型标识:qwen / baichuan / llama
*/
public String chat(String model, String message) {
ChatClient client = getClient(model);
return client.prompt()
.user(message)
.call()
.content();
}
/**
* 流式对话
*/
public Flux<String> streamChat(String model, String message) {
ChatClient client = getClient(model);
return client.prompt()
.user(message)
.stream()
.content();
}
private ChatClient getClient(String model) {
ChatClient client = modelMap.get(model);
if (client == null) {
throw new IllegalArgumentException("不支持的模型: " + model +
",可用模型: " + modelMap.keySet());
}
return client;
}
}
4.3 创建路由 Controller
package com.example.springaihelloworld.controller;
import com.example.springaihelloworld.service.ModelRoutingService;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
@RestController
public class ModelRoutingController {
private final ModelRoutingService routingService;
public ModelRoutingController(ModelRoutingService routingService) {
this.routingService = routingService;
}
/**
* 统一对话入口,通过 model 参数切换底层模型
* GET /chat?model=qwen&msg=你好
*/
@GetMapping("/chat")
public String chat(@RequestParam(defaultValue = "qwen") String model,
@RequestParam String msg) {
return routingService.chat(model, msg);
}
/**
* 流式对话入口
* GET /chat/stream?model=baichuan&msg=你好
*/
@GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamChat(@RequestParam String model,
@RequestParam String msg) {
return routingService.streamChat(model, msg);
}
}
现在,调用者只需在请求中指定 model 参数,就能在通义千问、百川、本地 LLaMA 之间自由切换。对业务代码来说,切换模型就是一个参数的选择,没有任何 if-else 的侵入。
五、运行与演示
5.1 启动项目
确保 DASHSCOPE_API_KEY、BAICHUAN_API_KEY 已设置,Ollama 本地服务已启动且已拉取 llama3:8b 模型。
启动 Spring Boot。
5.2 分别测试三个模型
通义千问:
http://localhost:8080/chat?model=qwen&msg=简单介绍你自己
返回类似:
我是通义千问,由阿里云自主研发的大语言模型...
百川:
http://localhost:8080/chat?model=baichuan&msg=简单介绍你自己
返回类似:
我是百川智能研发的大语言模型...
本地 LLaMA:
http://localhost:8080/chat?model=llama&msg=简单介绍你自己
返回类似:
I am LLaMA, an AI assistant created by Meta...
可以看到,同一个接口 /chat,只是改变 model 参数,底层调用的模型就完全不一样了。
5.3 体验流式切换
http://localhost:8080/chat/stream?model=baichuan&msg=讲一个简短的笑话
使用 curl 观察打字机效果,和之前的流式体验完全一致。
六、常见问题与避坑提示
问题一:启动时提示多个 ChatClient Bean 冲突
如果你之前在别的地方直接用 @Autowired ChatClient 注入了 Bean,Spring 会因为找到多个候选 Bean 而报错。解决方案是:使用 @Qualifier 指定名称,或者在用到的地方注入我们手动创建的具名 Bean。本文的设计不会出现这个问题,因为所有 ChatClient 都有明确的 Bean 名称。
问题二:自动配置的 ChatModel Bean 名称不确定
DashScope 的自动配置类名为 DashScopeAutoConfiguration,它注册的 ChatModel Bean 名称通常为 dashScopeChatModel。Ollama 的为 ollamaChatModel。如果你不确定,可以在 @Bean 方法中使用 @Autowired Map<String, ChatModel> chatModels 打印所有 Bean 名称来确定。
问题三:百川 API Key 环境变量未设置导致启动失败
我们的 baichuanChatClient Bean 在创建时强制检查环境变量,如果未设置则抛异常阻止启动。这在生产中是合理的,但如果你暂时不想用百川,可以移除该 Bean 或者改为 Optional 注入。
问题四:Ollama 模型未下载导致调用失败
如果本地没有 llama3:8b 模型,调用会报错。请先执行 ollama pull llama3:8b。也可以更换为其他你已下载的模型,只需在配置文件中修改 model 名称。
问题五:多模型计费与监控
不同模型的计费标准不同,在生产环境中,建议在路由层加入调用次数和 Token 消耗的监控,方便成本分析。Spring AI 的 ChatResponse 中包含 getMetadata(),可以获取 Token 使用信息。
七、小结与下一步预告
本篇回顾
- 理解了多模型接入的场景价值:对比选型、任务分派、容灾降级。
- 掌握了在单个 Spring Boot 项目中同时管理多个模型的技巧:手动为每个模型创建具名
ChatClientBean。 - 实现了基于参数的路由切换,业务代码与具体模型完全解耦。
- 分别演示了通义千问、百川、本地 LLaMA 三种模型的无缝切换。
动手建议
在你的项目中,找出至少两个适用不同模型的任务(如内容生成和代码审查),用本文的路由模式接入对应的模型,体验“一个项目,多模协同”的开发效率。
下一步预告
多模型切换已经实现,但每个模型的能力边界不同,还有些原生高级功能(如百炼的函数调用、参数调优)我们还没深入挖掘。下一篇,我们将进入 Spring AI Alibaba 进阶,聚焦 DashScope 的原生能力与生产环境最佳实践,让你的百炼应用更稳定、更高效。
下一篇《Spring AI Alibaba 进阶:DashScope 原生能力与最佳实践》见。
本系列博客基于 Spring AI 1.1.6 和 Spring AI Alibaba 1.1.2.0 版本编写。各第三方模型的 API 地址和模型名称可能随平台更新而调整,请以官方文档为准。多模型共存时请注意依赖版本兼容,建议通过 BOM 统一管理。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)