最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring?AI?+?ollama?本地搭建聊天?AI?功能

 更新時(shí)間:2024年11月14日 10:14:19   作者:抱糖果彡  
這篇文章主要介紹了Spring?AI?+?ollama?本地搭建聊天?AI?,本文通過實(shí)例圖文相結(jié)合給大家講解的非常詳細(xì),需要的朋友可以參考下

Spring AI + ollama 本地搭建聊天 AI

不知道怎么搭建 ollama 的可以查看上一篇Spring AI 初學(xué)

項(xiàng)目可以查看gitee

前期準(zhǔn)備

添加依賴

創(chuàng)建 SpringBoot 項(xiàng)目,添加主要相關(guān)依賴(spring-boot-starter-web、spring-ai-ollama-spring-boot-starter)

Spring AI supports Spring Boot 3.2.x and 3.3.x

Spring Boot 3.2.11 requires at least Java 17 and is compatible with versions up to and including Java 23

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
    <version>1.0.0-M3</version>
</dependency>

配置文件

application.properties、yml配置文件中添加,也可以在項(xiàng)目中指定模型等參數(shù),具體參數(shù)可以參考 OllamaChatProperties

# properties,模型 qwen2.5:14b 根據(jù)自己下載的模型而定
spring.ai.ollama.chat.options.model=qwen2.5:14b
#yml
spring:
  ai:
    ollama:
      chat:
        model: qwen2.5:14b

聊天實(shí)現(xiàn)

主要使用 org.springframework.ai.chat.memory.ChatMemory 接口保存對(duì)話信息。

一、采用 Java 緩存對(duì)話信息

支持功能:聊天對(duì)話、切換對(duì)話、刪除對(duì)話

controller

import com.yb.chatai.domain.ChatParam;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
/*
 *@title Controller
 *@description 使用內(nèi)存進(jìn)行對(duì)話
 *@author yb
 *@version 1.0
 *@create 2024/11/12 14:39
 */
@Controller
public class ChatController {
    //注入模型,配置文件中的模型,或者可以在方法中指定模型
    @Resource
    private OllamaChatModel model;
    //聊天 client
    private ChatClient chatClient;
    // 模擬數(shù)據(jù)庫存儲(chǔ)會(huì)話和消息
    private final ChatMemory chatMemory = new InMemoryChatMemory();
    //首頁
    @GetMapping("/index")
    public String index(){
        return "index";
    }
    //開始聊天,生成唯一 sessionId
    @GetMapping("/start")
    public String start(Model model){
        //新建聊天模型
//        OllamaOptions options = OllamaOptions.builder();
//        options.setModel("qwen2.5:14b");
//        OllamaChatModel chatModel = new OllamaChatModel(new OllamaApi(), options);
        //創(chuàng)建隨機(jī)會(huì)話 ID
        String sessionId = UUID.randomUUID().toString();
        model.addAttribute("sessionId", sessionId);
        //創(chuàng)建聊天client
        chatClient = ChatClient.builder(this.model).defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory, sessionId, 10)).build();
        return "chatPage";
    }
    //聊天
    @PostMapping("/chat")
    @ResponseBody
    public String chat(@RequestBody ChatParam param){
        //直接返回
        return chatClient.prompt(param.getUserMsg()).call().content();
    }
    //刪除聊天
    @DeleteMapping("/clear/{id}")
    @ResponseBody
    public void clear(@PathVariable("id") String sessionId){
        chatMemory.clear(sessionId);
    }
}

效果圖

二、采用數(shù)據(jù)庫保存對(duì)話信息

支持功能:聊天對(duì)話、切換對(duì)話、刪除對(duì)話、撤回消息

實(shí)體類

import lombok.Data;
import java.util.Date;
@Data
public class ChatEntity {
    private String id;
    /** 會(huì)話id */
    private String sessionId;
    /** 會(huì)話內(nèi)容 */
    private String content;
    /** AI、人 */
    private String type;
    /** 創(chuàng)建時(shí)間 */
    private Date time;
    /** 是否刪除,Y-是 */
    private String beDeleted;
    /** AI會(huì)話時(shí),獲取人對(duì)話ID */
    private String userChatId;
}

confiuration

import com.yb.chatai.domain.ChatEntity;
import com.yb.chatai.service.IChatService;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/*
 *@title DBMemory
 *@description 實(shí)現(xiàn) ChatMemory,注入 spring,方便采用 service 方法
 *@author yb
 *@version 1.0
 *@create 2024/11/12 16:15
 */
@Configuration
public class DBMemory implements ChatMemory {
    @Resource
    private IChatService chatService;
    @Override
    public void add(String conversationId, List<Message> messages) {
        for (Message message : messages) {
            chatService.saveMessage(conversationId, message.getContent(), message.getMessageType().getValue());
        }
    }
    @Override
    public List<Message> get(String conversationId, int lastN) {
        List<ChatEntity> list = chatService.getLastN(conversationId, lastN);
        if(list != null && !list.isEmpty()) {
            return list.stream().map(l -> {
                Message message = null;
                if (MessageType.ASSISTANT.getValue().equals(l.getType())) {
                    message = new AssistantMessage(l.getContent());
                } else if (MessageType.USER.getValue().equals(l.getType())) {
                    message = new UserMessage(l.getContent());
                }
                return message;
            }).collect(Collectors.<Message>toList());
        }else {
            return new ArrayList<>();
        }
    }
    @Override
    public void clear(String conversationId) {
        chatService.clear(conversationId);
    }
}

services實(shí)現(xiàn)類

import com.yb.chatai.domain.ChatEntity;
import com.yb.chatai.service.IChatService;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.stereotype.Service;
import java.util.*;
/*
 *@title ChatServiceImpl
 *@description 保存用戶會(huì)話 service 實(shí)現(xiàn)類
 *@author yb
 *@version 1.0
 *@create 2024/11/12 15:50
 */
@Service
public class ChatServiceImpl implements IChatService {
    Map<String, List<ChatEntity>> map = new HashMap<>();
    @Override
    public void saveMessage(String sessionId, String content, String type) {
        ChatEntity entity = new ChatEntity();
        entity.setId(UUID.randomUUID().toString());
        entity.setContent(content);
        entity.setSessionId(sessionId);
        entity.setType(type);
        entity.setTime(new Date());
        //改成常量
        entity.setBeDeleted("N");
        if(MessageType.ASSISTANT.getValue().equals(type)){
            entity.setUserChatId(getLastN(sessionId, 1).get(0).getId());
        }
        //todo 保存數(shù)據(jù)庫
        //模擬保存到數(shù)據(jù)庫
        List<ChatEntity> list = map.getOrDefault(sessionId, new ArrayList<>());
        list.add(entity);
        map.put(sessionId, list);
    }
    @Override
    public List<ChatEntity> getLastN(String sessionId, Integer lastN) {
        //todo 從數(shù)據(jù)庫獲取
        //模擬從數(shù)據(jù)庫獲取
        List<ChatEntity> list = map.get(sessionId);
        return list != null ? list.stream().skip(Math.max(0, list.size() - lastN)).toList() : List.of();
    }
    @Override
    public void clear(String sessionId) {
        //todo 數(shù)據(jù)庫更新 beDeleted 字段
        map.put(sessionId, new ArrayList<>());
    }
    @Override
    public void deleteById(String id) {
        //todo 數(shù)據(jù)庫直接將該 id 數(shù)據(jù) beDeleted 改成 Y
        for (Map.Entry<String, List<ChatEntity>> next : map.entrySet()) {
            List<ChatEntity> list = next.getValue();
            list.removeIf(chat -> id.equals(chat.getId()) || id.equals(chat.getUserChatId()));
        }
    }
}

controller

import com.yb.chatai.configuration.DBMemory;
import com.yb.chatai.domain.ChatEntity;
import com.yb.chatai.domain.ChatParam;
import com.yb.chatai.service.IChatService;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaApi;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.UUID;
/*
 *@title ChatController2
 *@description 使用數(shù)據(jù)庫(緩存)進(jìn)行對(duì)話
 *@author yb
 *@version 1.0
 *@create 2024/11/12 16:12
 */
@Controller
public class ChatController2 {
    //注入模型,配置文件中的模型,或者可以在方法中指定模型
    @Resource
    private OllamaChatModel model;
    //聊天 client
    private ChatClient chatClient;
    //操作聊天信息service
    @Resource
    private IChatService chatService;
    //會(huì)話存儲(chǔ)方式
    @Resource
    private DBMemory dbMemory;
    //開始聊天,生成唯一 sessionId
    @GetMapping("/start2")
    public String start(Model model){
        //新建聊天模型
//        OllamaOptions options = OllamaOptions.builder();
//        options.setModel("qwen2.5:14b");
//        OllamaChatModel chatModel = new OllamaChatModel(new OllamaApi(), options);
        //創(chuàng)建隨機(jī)會(huì)話 ID
        String sessionId = UUID.randomUUID().toString();
        model.addAttribute("sessionId", sessionId);
        //創(chuàng)建聊天 client
        chatClient = ChatClient.builder(this.model).defaultAdvisors(new MessageChatMemoryAdvisor(dbMemory, sessionId, 10)).build();
        return "chatPage2";
    }
    //切換會(huì)話,需要傳入 sessionId
    @GetMapping("/exchange2/{id}")
    public String exchange(@PathVariable("id")String sessionId){
        //切換聊天 client
        chatClient = ChatClient.builder(this.model).defaultAdvisors(new MessageChatMemoryAdvisor(dbMemory, sessionId, 10)).build();
        return "chatPage2";
    }
    //聊天
    @PostMapping("/chat2")
    @ResponseBody
    public List<ChatEntity> chat(@RequestBody ChatParam param){
        //todo 判斷 AI 是否返回會(huì)話,從而判斷用戶是否可以輸入
        chatClient.prompt(param.getUserMsg()).call().content();
        //獲取返回最新兩條,一條用戶問題(用戶獲取用戶發(fā)送ID),一條 AI 返回結(jié)果
        return chatService.getLastN(param.getSessionId(), 2);
    }
    //撤回消息
    @DeleteMapping("/revoke2/{id}")
    @ResponseBody
    public void revoke(@PathVariable("id") String id){
        chatService.deleteById(id);
    }
    //清空消息
    @DeleteMapping("/del2/{id}")
    @ResponseBody
    public void clear(@PathVariable("id") String sessionId){
        dbMemory.clear(sessionId);
    }
}

效果圖

總結(jié)

主要實(shí)現(xiàn) org.springframework.ai.chat.memory.ChatMemory 方法,實(shí)際項(xiàng)目過程需要實(shí)現(xiàn)該接口重寫方法。

到此這篇關(guān)于Spring AI + ollama 本地搭建聊天 AI 的文章就介紹到這了,更多相關(guān)Spring AI ollama聊天 AI 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Maven中怎么手動(dòng)添加jar包到本地倉庫詳解(repository)

    Maven中怎么手動(dòng)添加jar包到本地倉庫詳解(repository)

    這篇文章主要給大家介紹了關(guān)于Maven中怎么手動(dòng)添加jar包到本地倉庫的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-04-04
  • nohup運(yùn)行Java tail查看日志方式

    nohup運(yùn)行Java tail查看日志方式

    nohup命令允許程序在用戶退出賬戶或關(guān)閉終端后繼續(xù)運(yùn)行,常與"&"結(jié)合使用以實(shí)現(xiàn)程序的后臺(tái)執(zhí)行,配合重定向操作,nohup可以將程序輸出保存到日志文件中,如nohup java -jar XXX.jar &> myout.log &,此外,tail命令可用于實(shí)時(shí)監(jiān)控日志文件的變化
    2024-09-09
  • Java Idea TranslationPlugin翻譯插件使用解析

    Java Idea TranslationPlugin翻譯插件使用解析

    這篇文章主要介紹了Java Idea TranslationPlugin翻譯插件使用解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • 基于Maven的pom.xml文件詳解

    基于Maven的pom.xml文件詳解

    下面小編就為大家?guī)硪黄贛aven的pom.xml文件詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • Java 8 Lambda 表達(dá)式比較器使用示例代碼

    Java 8 Lambda 表達(dá)式比較器使用示例代碼

    這篇文章主要介紹了Java 8 Lambda 表達(dá)式比較器使用示例代碼,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • 使用spring+maven不同環(huán)境讀取配置方式

    使用spring+maven不同環(huán)境讀取配置方式

    這篇文章主要介紹了使用spring+maven不同環(huán)境讀取配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • mybatis?傳入null值的解決方案

    mybatis?傳入null值的解決方案

    這篇文章主要介紹了mybatis?傳入null值的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java反射獲取class對(duì)象方式解析

    Java反射獲取class對(duì)象方式解析

    這篇文章主要介紹了Java反射獲取class對(duì)象方式解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • 在SpringBoot中使用P6Spy攔截SQL語句的完整指南

    在SpringBoot中使用P6Spy攔截SQL語句的完整指南

    P6Spy 是一個(gè)用于攔截和記錄應(yīng)用程序和數(shù)據(jù)庫之間的所有 JDBC 操作的開源 Java 庫,本文先簡單介紹一下 P6Spy 的工作原理,然后以在 Spring Boot 中使用 P6Spy 攔截 SQL 語句為例來演示 P6Spy 的基本功能和使用方式,需要的朋友可以參考下
    2025-11-11
  • Java通過 Socket 實(shí)現(xiàn) TCP服務(wù)端

    Java通過 Socket 實(shí)現(xiàn) TCP服務(wù)端

    這篇文章主要介紹了Java通過 Socket 實(shí)現(xiàn) TCP服務(wù)端的相關(guān)資料,需要的朋友可以參考下
    2017-05-05

最新評(píng)論

华安县| 城步| 电白县| 松滋市| 鄢陵县| 平顶山市| 桂东县| 乐业县| 奎屯市| 巧家县| 南澳县| 盐亭县| 永城市| 沈丘县| 大港区| 江安县| 海宁市| 共和县| 辉县市| 观塘区| 南阳市| 尼勒克县| 昂仁县| 灵山县| 濮阳市| 彩票| 陆川县| 耿马| 莱芜市| 依安县| 谷城县| 乌鲁木齐县| 金门县| 邛崃市| 张掖市| 古丈县| 崇信县| 城步| 榆树市| 泰顺县| 吉水县|