ollama

ollama相比对于docker,他就是可以下载大模型,使其能够在本地上面进行下载和使用,官方网址就是

Download Ollama on Windows

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以分块流的方式发送给客户端用户。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐