ollama的下载以及Spring AI Alibaba的ChatModel和ChatClient的流式输出和在idea的实现
本文介绍了ollama本地大模型部署与Spring AI集成方案。通过ollama可在本地运行大模型(如7B约8G),默认端口11434。文章详细讲解了Spring AI中ChatModel和ChatClient的配置与区别,展示了两者的API调用方式,并重点介绍了流式输出技术,通过Flux实现SSE推流,提升长文本响应体验。最后提供了多模型调用方案,演示了如何配置和使用不同大模型(如DeepSe
ollama
ollama相比对于docker,他就是可以下载大模型,使其能够在本地上面进行下载和使用,官方网址就是
ollama的使用也很简单和docker相差不大,ollama的默认端口号11434
我们如果想要在本地进行下载,我们也可以使用ollama的命令,在官网进行命令行的下载。选择一个合适的版本进行下载即可。(注意7b大约等于8G)
要想使用本地的大模型,首先需要增加ollama的依赖.
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-ollama</artifactId>
<version>1.0.0</version>
</dependency>
然后配置相对应的约束:
spring.ai.ollama.base-url=https://ollama.ai
spring.ai.ollama.chat.model=deepseek-r1:latest
当我们需要使用ChatModel的时候,我们在本地和阿里云都是存在的,所以在我们使用的时候需要指定一下,你所需要的是哪个。
@RestController
public class ChatHelloController {
@Resource(name = "ollamaChatModel")
private ChatModel chatModel;
/*通用的进行api调用
* */
@GetMapping("/hello/chat")
public String hello(@RequestParam(name = "message",defaultValue= "你是谁?")
String message) {
String result = chatModel.call(message);
System.out.println(result);
return result;
}
@GetMapping("/hello/stream")
public Flux<String> helloStream(@RequestParam(name = "message",defaultValue= "你是谁?")
String message) {
return chatModel.stream(message);
}
}
ChatClient和ChatModel
ChatClient和ChatModel其实相比较来说并不是有很大的区别,ChatClient事实上还是基于ChatModel实现的扩展,可以实现更多复杂的功能。
我们对比一下二者在处理用户提示词的时候样式,事实上在处理相同功能下的时候二者相差不大:
当我们想要注入ChatClient的时候就会发现,ChatClient不支持自动注入,仅支持手动注入。
当我们手动配置之后,我们就可以这样调用接口:
package com.kang.ai.controller;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatClientController {
private final ChatClient chatClient;
public ChatClientController(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
@GetMapping("ChatClient/doChat")
public String chat(@RequestParam(name = "msg",defaultValue = "你是谁") String msg) {
return this.chatClient.prompt()
.user(msg)
.call()
.content();
}
}
在于我们实际使用的过程当中,我们就需要两者都进行使用,我们可以将ChatClient的手动配置放入配置类里面进行简单设置。
@Bean
public ChatClient chatClient(ChatModel dashScopeChatModel) {
return ChatClient.builder(dashScopeChatModel).build();
}
在我们使用的时候ChatModel和ChatClient的时候,事实上我们是可以相互之间进行交替使用的,二者并不是对立存在。
package com.kang.ai.controller;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ChatClientControllerV2 {
@Resource
private ChatClient chatClient;
@Resource
private ChatModel chatModel;
@GetMapping("ChatClientV2/doChat")
public String chat(@RequestParam(name = "msg",defaultValue = "你是谁") String msg) {
return this.chatClient.prompt()
.user(msg)
.call()
.content();
}
@GetMapping("ChatModelV2/doChat")
public String chatModel(@RequestParam(name = "msg",defaultValue = "你是谁")String msg){
String result = chatModel.call(msg);
System.out.println( result);
return result;
}
}
SAA流式输出
流式输出(StreamingOutput) 是一种逐步返回大模型生成结果的技术,生成一点返回一点,允许服务器将响应内容分批次实时传输给客户端,而不是等待全部内容生成完毕后再一次性返回。 这种机制能显著提升用户体验,尤其适用于大模型响应较慢的场景(如生成长文本或复杂推理结果)。
在我们调用大模型的时候就可以使用流式输出,比方说stream
Server-Sent Events(SSE)是一种允许服务端可以持续推送数据片段(如逐词或逐句)到前端的 Web 技术。通过单向的HTTP长连接,使用一个长期存在的连接,让服务器可以主动将数据"推"给客户端,SSE是轻量级的单向通信协议,适合AI对话这类服务端主导的场景 核心概念:SSE 的核心思想是:客户端发起一个请求,服务器保持这个连接打开并在有新数据时,通过这个连接将数据发送给客户端。 这与传统的请求-响应模式(客户端请求一次,服务器响应一次,连接关闭)有本质区别。
为了解决多个大模型的使用的方案,我们可以进行以下的配置。
package ai.config;
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SAAConfig {
private final String DEEPSEEK_MODEL="deepseek-v3";
private final String QWEN_MODEL="qwen-max";
@Bean(name = "deepseek")
public ChatModel deepSeek() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder().apiKey("sk-*************************").build())
.defaultOptions(DashScopeChatOptions.builder().withModel(DEEPSEEK_MODEL).build())
.build();
}
@Bean(name = "qwen")
public ChatModel qwen() {
return DashScopeChatModel.builder()
.dashScopeApi(DashScopeApi.builder().apiKey("sk-*************************").build())
.defaultOptions(DashScopeChatOptions.builder().withModel(QWEN_MODEL).build())
.build();
}
}
我们自己定义一个ChatModel使得我们可以分别对qwen和deepseek进行调用,所以我们可以对此进行设置比方说api-key以及指定的大模型。
@RestController
public class StreamOutputController {
@Resource(name = "deepseek")
private ChatModel deepseekchatModel;
@Resource(name="qwen")
private ChatModel qwenChatModel;
@GetMapping("/stream/deepseek")
public Flux<String> deepseek(@RequestParam(name = "message",defaultValue = "你是谁?") String message) {
return deepseekchatModel.stream(message);
}
@GetMapping("/stream/qwen")
public Flux<String> qwen(@RequestParam(name = "message",defaultValue = "你是谁?") String message) {
return qwenChatModel.stream(message);
}
}
然后我们就可以对这大模型进行Controller层的书写,让我们可以正常的使用多模型的调用和流式输出。
SAA-ChatClient的构建
我们可以使用ChatModel进行大模型的配置,我们也可以使用ChatClient进行简单的调用,因为后者是依靠前者进行配置的,当然我们可以在Config类上面进行简单的使用。
@Bean(name = "deepseekChatClient")
public ChatClient deepseekChatClient(@Qualifier("deepseek") ChatModel deepseek) {
return ChatClient.builder(deepseek)
.defaultOptions(ChatOptions.builder().model(DEEPSEEK_MODEL).build())
.build();
}
@Bean(name = "qwenChatClient")
public ChatClient qwenChatClient(@Qualifier("qwen") ChatModel qwen) {
return ChatClient.builder(qwen)
.defaultOptions(ChatOptions.builder().model(QWEN_MODEL).build())
.build();
}
注意,我们事实上ChatClien进行演示的时候,因为我们是基于之前配置的,也就是ChatModel,所以是可以简化一部分实现的
而我们进行控制台的调用也是很简单的。
@Resource(name = "deepseekChatClient")
private ChatClient deepseekChatClient;
@Resource(name = "qwenChatClient")
private ChatClient qwenChatClient;
@GetMapping("/stream/deepseekChatClient")
public Flux<String> deepseekChatClient(@RequestParam(name = "message",defaultValue = "你是谁?") String message) {
return deepseekChatClient.prompt(message).stream().content();
}
@GetMapping("/stream/qwenChatClient")
public Flux<String> qwenChatClient(@RequestParam(name = "message",defaultValue = "你是谁?") String message) {
return qwenChatClient.prompt(message).stream().content();
}
扩展:
Flux是SpringWebFlux中的一个核心组件,属于响应式编程模型的一部分。它主要用于处理异步、非阻塞的流式数据,能够高效地处理高并发场景。Flux可以生成和处理一系列的事件或数据如流式输出等。 看类注释和类所在的iar包我们就明白:SAA中的流式输出是通过ReactorStreams技术实现的和SpringWebFlux的底层实现是一样的技术,。具体执行流程:ReactorStreams会订阅数据源,当有数据时,ReactorStreams以分块流的方式发送给客户端用户。
更多推荐
所有评论(0)