基于 SpringAI 整合 DeepSeek 模型實現 AI 聊天對話

目錄

1、Ollama 的下載配置 與 DeepSeek 的本地部署流程

1.1 下載安裝 Ollama

1.2 搜索模型并進行本地部署

2、基于 SpringAI 調用 Ollama 模型

2.1 基于OpenAI 的接口規范(其他模型基本遵循)

2.2 在 IDEA?中進行創建?SpringAI 項目并調用 DS 模型

3、基于 SpringAI 實現會話記憶功能

4、基于 SpringAI 實現會話歷史功能

需求一:需要進行展示歷史會話的列表信息

需求二:點擊會話列表,展示對應的歷史會話記錄信息


📜后端代碼地址:

MySpringAI: 基于 SpringAI + 大模型 實現基本的對話功能(只提供后端)https://gitee.com/MIMIDeK/my-spring-ai.git

1、Ollama 的下載配置 與 DeepSeek 的本地部署流程

很多云平臺都提供了一鍵部署大模型的功能,這里不再贅述(阿里云百煉平臺、火山方舟-火山引擎等)


官網地址如下:

Ollamahttps://ollama.com/

1.1 下載安裝 Ollama

首先,我們需要下載一個Ollama的客戶端,在官網提供了各種不同版本的Ollama,大家可以根據自己的需要下載

注意:

Ollama默認安裝目錄是C盤的用戶目錄,如果不希望安裝在C盤的話(其實C盤如果足夠大放C盤也沒事),就不能直接雙擊安裝了,需要通過命令行安裝

OllamaSetup.exe 所在目錄打開cmd命令行,然后命令如下:

OllamaSetup.exe /DIR=你要安裝的目錄位置

安裝完成后,需要進行環境變量的配置:

OLLAMA_MODELS=你想要保存模型的目錄

1.2 搜索模型并進行本地部署

Ollama 是一個模型管理工具和平臺,它提供了很多國內外常見的模型,我們可以在其官網上搜索自己需要的模型,這里我們部署的是 DeepSeek R1 模型(我選擇的是 7b,根據需求進行選擇):

其中,Ollama 的命令很像 Docker 的,選擇好對應的模型后,在控制臺中進行運行命令:

ollama run deepseek-r1:7b

首次下載的話會有些慢,耐性等待即可

以下是本地下載部署完成后,進行對話的場景,ctrl + d 進行退出與 DeepSeek 的對話:


2、基于 SpringAI 調用 Ollama 模型

2.1 基于OpenAI 的接口規范(其他模型基本遵循)

目前大多數大模型都遵循 OpenAI 的接口規范,是基于Http協議的接口;因此請求路徑、參數、返回值信息都是類似的,可能會有一些小的差別,具體需要查看大模型的官方API文檔

以下是基于 Python 的代碼示范:

# Please install OpenAI SDK first: `pip3 install openai`from openai import OpenAI# 1.初始化OpenAI客戶端,要指定兩個參數:api_key、base_url
client = OpenAI(api_key="<DeepSeek API Key>", base_url="https://api.deepseek.com")# 2.發送http請求到大模型,參數比較多
response = client.chat.completions.create(model="deepseek-chat", # 2.1.選擇要訪問的模型messages=[ # 2.2.發送給大模型的消息{"role": "system", "content": "You are a helpful assistant"},{"role": "user", "content": "Hello"},],stream=False # 2.3.是否以流式返回結果
)print(response.choices[0].message.content)

接口說明

  • 請求方式):通常是POST,因為要傳遞JSON風格的參數
  • 請求路徑):與平臺有關
    • DeepSeek官方平臺:https://api.deepseek.com
    • 阿里云百煉平臺:https://dashscope.aliyuncs.com/compatible-mode/v1
    • 本地ollama部署的模型:http://localhost:11434
  • 安全校驗):開放平臺?都需要提供 API_KEY 來校驗權限,本地 ollama 則不需要
  • 請求參數)(這里只列舉常用的):
    • model:要訪問的模型名稱
    • messages:發送給大模型的消息,是一個數組
    • stream:true,代表響應結果流式返回;false,代表響應結果一次性返回,但需要等待
    • temperature:取值范圍[0:2),代表大模型生成結果的隨機性,越小隨機性越低。DeepSeek-R1不支持
  • 這里請求參數中的 messages 是一個消息數組,其中包含兩個屬性):
    • role:消息對應的角色
    • content:消息內容

2.2 在 IDEA?中進行創建?SpringAI 項目并調用 DS 模型

以下是創建項目的基本依賴需求(基于SpringBoot3、JDK17):

.yaml 配置:

這里是基于 Ollama 的(默認端口是11434)

這里是基于 openAI 的,進行調用開放平臺的 API,需要輸入 API-KEY(后面就不具體寫明了,這里主要是基于 Ollama 的調用演示)

Config 配置類:(固定寫法)

@Configuration
public class CommonConfig {@Beanpublic ChatClient chatClient(OllamaChatModel model) {return ChatClient.builder(model).build();}
}

Controller 控制響應類:(這里是以流式的方式進行響應)

@RestController
@RequestMapping("/ai")
public class ChatController {@Resourceprivate ChatClient chatClient;// 由于以流式方式調用模型,展示的數據會出現亂碼,需要進行規定編碼格式@GetMapping(value = "/chat", produces = "text/html; charset=utf-8")public Flux<String> chat(String msg) {return chatClient.prompt().user(msg).stream().content();}
}

進行頁面的調用(若非流式訪問,則需要等待 DS 生成完畢,才會出現響應信息):

注意,進行接口的調用時,需要啟動 ollama 中的模型

🔖也可以加上日志的控制臺打印輸出,方便調試

.yml 中的配置:

然后在 Config 配置類中添加這一行代碼,即可開啟日志的打印:


3、基于 SpringAI 實現會話記憶功能

大致步驟:

定義會話存儲方式(默認基于Map集合) ?? 配置會話記憶(關聯上下文) ?? 添加會話ID(保證每個會話獨立)

這里使用默認方式,由源碼可知是基于 Map 直接存入內存中的;當然也可以重寫 ChatMemory,比如存入到 Redis 中做緩存之類的(根據業務需求)

然后將 "存儲方式" 配置到 "會話的上下文" 中,以處理會話的內容

運行結果:

之前的msg提問信息是:現在有15個蘋果,6個人應該怎么分才好

我現在直接問它x個人應該怎么分,很明顯它會進行關聯之前的會話,根據上下文,來進行作答

存在問題:

然而,以上會話的處理會比較混亂,不管是誰來進行提問,模型都會自動關聯所有的會話上下文來進行回答,這顯然是不符合需求的;這時就需要與前端進行交接,即傳遞對應的會話 ID 過來進行處理,以實現用戶的每個獨立會話內容互不干擾

由前端響應接口可知,不同的會話對應著不同的會話ID

這時需要在 Controller 接口中添加以下配置,來接收存儲不同會話下的ID


4、基于 SpringAI 實現會話歷史功能

存在問題:目前,只要頁面一刷新,之前的會話列表和對話記錄都會被清除,不會被保留展示

前言:以下的 type 參數可根據具體需求進行更換,chatId 建議作保留以記錄唯一會話

需求一:需要進行展示歷史會話的列表信息

以下是對應的 UI 頁面,以及對應的接口地址(模擬):

以下是 自定義 的 方法接口 與 實現類,主要用于 保存 和 獲取 會話信息

public interface ChatHistoryService {/*** 保存會話記錄(這里的 type 可根據需求進行更改,chatId 建議保留以作為會話的唯一ID)*/void save(String type, String chatId);/*** 獲取會話列表(這里的 type 可根據需求進行更改)*/List<String> getChatIds(String type);
}
@Service
public class ChatHistoryServiceImpl implements ChatHistoryService {// 使用 map 集合進行存儲private final Map<String, List<String>> chatHistoryMap = new HashMap<>();/*** 保存會話記錄(這里的 type 可根據需求進行更改,chatId 建議保留以作為會話的唯一ID)*/@Overridepublic void save(String type, String chatId) {// 1.判斷當前是否存在對應的 type 類型,若不存在則新增if (! chatHistoryMap.containsKey(type)) {chatHistoryMap.put(type, new ArrayList<>());}// 2.判斷當前的 type 對應的 會話集合ID 是否含有當前的會話IDList<String> chatIds = chatHistoryMap.get(type);if (chatIds.contains(chatId)) {return;}chatIds.add(chatId);}/*** 獲取會話列表信息(這里的 type 可根據需求進行更改)*/@Overridepublic List<String> getChatIds(String type) {List<String> chatIds = chatHistoryMap.get(type);return chatIds == null ? new ArrayList<>() : chatIds;}
}

每次用戶在進行模型對話的時候,都需要將會話ID做保存(這里的?key?根據自己的業務需求來定,比如使用?用戶ID?來進行拼接等,這里先寫死)

然后獲取當前對應?key 的會話 ID 集合,進行會話列表信息展示

@RestController
@RequestMapping("/ai/history")
public class ChatHistoryController {@Resourceprivate ChatHistoryService chatHistoryService;/*** 獲取歷史會話列表信息(這里的 type 可根據需求進行更改)*/@RequestMapping("/{type}")public List<String> getChatIds(@PathVariable("type") String type) {return chatHistoryService.getChatIds(type);}
}

需求二:點擊會話列表,展示對應的歷史會話記錄信息

像以下UI所示,隨便點擊其中一個會話列表,對應的歷史會話記錄依然存在,并進行全部展示

接口地址(模擬):

會話的存儲是在?ChatMemory 類中進行的,所以需要跟進源碼進行查看

主要還是這個 get 方法,來進行獲取對應會話的對話記錄

然后 返回值 Message 類型,內部有繼承以及實現的類

其中的 Content 代表著對話記錄的內容,MessageType 代表著當前對話記錄的類型

以上結論:由于需要滿足當前接口的返回值,所以需要創建一個?DTO?來進行滿足

@Data
@NoArgsConstructor
public class MessageDTO implements Serializable {/*** 角色類型*/private String role;/*** 對應的內容信息*/private String content;public MessageDTO(Message message) {// 判斷當前會話的類型switch (message.getMessageType()) {case USER:this.role = "user";break;case ASSISTANT:this.role = "assistant";break;case SYSTEM:this.role = "system";break;case TOOL:this.role = "tool";break;default:this.role = "";break;}this.content = message.getText();}@Serialprivate static final long serialVersionUID = 1L;
}

接下來實現 “查詢對話記錄” 接口,與前端交互,即可實現展現歷史對話記錄

    /*** 查詢會話記錄詳情(這里的 type 可根據需求進行更改,chatId 建議保留以作為會話的唯一ID)*/@GetMapping("/{type}/{chatId}")public List<MessageDTO> getChatHistory(@PathVariable("type") String type, @PathVariable("chatId") String chatId) {// 這里的展示記錄條數最大值規定,直接使用的 int 型最大值,具體自己根據需求規定List<Message> messages = chatMemory.get(chatId, Integer.MAX_VALUE);if (messages == null) {return List.of();}// 進行封裝返回類型return messages.stream().map(new Function<Message, MessageDTO>() {@Overridepublic MessageDTO apply(Message message) {return new MessageDTO(message);}}).toList();}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80048.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80048.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80048.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在線查看【免費】 dcm、drawio,dcm wps文件格式網站

可以免費在線查看 .docx/wps/Office/wmf/ psd/ psd/eml/epub/dwg, dxf/ txt/zip, rar/ jpg/mp3 m.gszh.xyz m.gszh.xyz 免費支持以下格式文件在線查看類型 支持 doc, docx, xls, xlsx, xlsm, ppt, pptx, csv, tsv, dotm, xlt, xltm, dot, dotx, xlam, xla, pages 等 Office 辦…

低光環境下雙目云臺攝像頭監控性能解析

雙目云臺攝像頭在低光環境下的監控效果主要取決于其硬件配置和軟件優化能力。以下是對雙目云臺攝像頭在低光環境下監控效果的詳細分析&#xff1a; 一、硬件配置對低光監控效果的影響 鏡頭與焦距 &#xff1a; 雙目云臺攝像頭通常配備超大廣角固定鏡頭和360視角的移動鏡頭&a…

繼承相關知識

概念 定義類時&#xff0c;代碼中有共性的成員&#xff0c;還有自己的屬性&#xff0c;使用繼承可以減少重復的代碼&#xff0c; 繼承的語法 class 子類&#xff1a;繼承方式 父類 繼承方式有&#xff1a;public&#xff0c;private&#xff0c;protected 公共繼承&#x…

【Python進階】數據可視化:Matplotlib從入門到實戰

Python數據可視化&#xff1a;Matplotlib完全指南 前言技術背景與價值當前技術痛點解決方案概述目標讀者說明 一、技術原理剖析核心概念圖解核心作用講解關鍵技術模塊說明技術選型對比 二、實戰演示環境配置要求核心代碼實現案例1&#xff1a;折線圖&#xff08;股票趨勢&#…

Java高效合并Excel報表實戰:GcExcel讓數據處理更簡單

前言&#xff1a;為什么需要自動化合并Excel&#xff1f; 在日常辦公場景中&#xff0c;Excel報表合并是數據分析的基礎操作。根據2023年企業辦公效率報告顯示&#xff1a; 財務人員平均每周花費6.2小時在Excel合并操作上人工合并的錯誤率高達15%90%的中大型企業已采用自動化…

Python 列表與元組深度解析:從基礎概念到函數實現全攻略

在 Python 編程的廣袤天地中&#xff0c;列表&#xff08;List&#xff09;和元組&#xff08;Tuple&#xff09;是兩種不可或缺的數據結構。它們如同程序員手中的瑞士軍刀&#xff0c;能高效地處理各類數據。從簡單的數值存儲到復雜的數據組織&#xff0c;列表和元組都發揮著關…

Java中的方法重寫(Override)與方法重載(Overload)詳解

一、基本概念對比 特性方法重寫(Override)方法重載(Overload)定義子類重新定義父類中已有的方法同一個類中多個同名方法&#xff0c;參數不同作用范圍繼承關系中&#xff08;父子類之間&#xff09;同一個類內方法簽名必須相同&#xff08;方法名參數列表&#xff09;必須不同…

發布一個npm包,更新包,刪除包

發布一個npm包&#xff0c;更新包&#xff0c;刪除包 如何將自己的項目 發布為一個 npm 包&#xff0c;并掌握 更新 和 刪除 的操作流程。 &#x1f680; 一、發布一個 npm 包的完整流程 ? 1. 注冊并登錄 npm 賬號 如果還沒有賬號&#xff0c;先注冊&#xff1a; 官網注冊&…

Linux系統之----進程的概念

1.進程 1.1基本概念 課本概念 &#xff1a;進程是程序的一個執行實例&#xff0c;是正在執行的程序。當程序被執行時&#xff0c;系統會為其創建一個進程&#xff0c;包含程序代碼、數據以及運行時所需的資源。 內核觀點 &#xff1a;進程是擔當分配系統資源&#xff08;CPU…

Shell腳本中的字符串截取和規則變化

文章目錄 前言if通配符判斷if判斷多個條件規則變化字符串的兩個示例改變中間段數字改變末尾段數字 總結 前言 科技的發展會帶來習慣的改變&#xff0c;特別是對于我們這批敲代碼的&#xff0c;之前還積累一些奇巧淫技&#xff0c;想著在必要的時候賣弄一下&#xff0c;自從生成…

c語言修煉秘籍 - - 禁(進)忌(階)秘(技)術(巧)【第七式】程序的編譯

c語言修煉秘籍 - - 禁(進)忌(階)秘(技)術(巧)【第七式】程序的編譯 【心法】 【第零章】c語言概述 【第一章】分支與循環語句 【第二章】函數 【第三章】數組 【第四章】操作符 【第五章】指針 【第六章】結構體 【第七章】const與c語言中一些錯誤代碼 【禁忌秘術】 【第一式】…

Feign 深度解析:Java 聲明式 HTTP 客戶端的終極指南

Feign 深度解析&#xff1a;Java 聲明式 HTTP 客戶端的終極指南 Feign 是由 Netflix 開源的 ?聲明式 HTTP 客戶端&#xff0c;后成為 Spring Cloud 生態的核心組件&#xff08;現由 OpenFeign 維護&#xff09;。它通過注解和接口定義簡化了服務間 RESTful 通信&#xff0c;并…

如何Ubuntu 22.04.5 LTS 64 位 操作系統部署運行SLAM3! 詳細流程

以下是在本地部署運行 ORB-SLAM3 的詳細步驟&#xff0c;基于官方 README.md 和最佳實踐整理&#xff0c;適用于 Ubuntu 16.04/18.04/20.04/22.04 系統&#xff1a; 一、系統要求與依賴項安裝 1. 基礎系統要求 操作系統&#xff1a;Ubuntu 16.04/18.04/20.04/22.04&#xff…

USB 共享神器 VirtualHere 局域網內遠程使用打印機與掃描儀

本文首發于只抄博客,歡迎點擊原文鏈接了解更多內容。 前言 很久之前,有分享過使用 CUPS 和路由器來實現局域網內共享打印機,但由于 SANE 支持的打印機較少以及掃描驅動的缺失,試了很多種方法都沒有辦法成功遠程使用打印機的掃描功能。 后面偶然發現 VirtualHere 可以曲線…

一洽智能硬件行業解決方案探索與實踐

一、智能硬件行業發展現狀剖析 在數字化浪潮推動下&#xff0c;智能硬件行業呈現蓬勃發展態勢。軟硬件一體化的深度融合&#xff0c;構建起智能化服務的核心架構&#xff0c;而移動應用作為連接用戶與設備的重要橋梁&#xff0c;其作用愈發關鍵。深入研究該行業&#xff0c;可…

【C++ 類和數據抽象】構造函數

目錄 一、構造函數的基本概念 1.1 構造函數核心特性 1.2 構造函數的作用 1.3 構造函數類型體系 二、構造函數的類型 2.1 默認構造函數 2.2 帶參數的構造函數 2.3 拷貝構造函數 2.4 移動構造函數&#xff08;C11 及以后&#xff09; 三、初始化關鍵技術 3.1 成員初始…

圖數據庫nebula測試指南

概述 Nebula是一個開源的分布式圖數據庫系統&#xff0c;專為處理超大規模關聯數據而設計。可以將復雜的關聯關系存在nebula圖數據庫中&#xff0c;提供可視化平臺用于案件關聯查詢及調查。測試的前提是了解nebula圖數據庫&#xff0c;會使用基本的插入語句和查詢語句&#xf…

dispaly: inline-flex 和 display: flex 的區別

display: inline-flex 和 display: flex 都是 CSS 中用于創建彈性盒子布局&#xff08;Flexbox&#xff09;的屬性值&#xff0c;但它們之間有一些關鍵的區別&#xff0c;主要體現在元素如何在頁面上被渲染和它們對周圍元素的影響。 主要區別 1&#xff0c;塊級 vs 行內塊級 d…

Sqlserver安全篇之_Sqlcmd命令使用windows域賬號認證sqlserver遇到問題如何處理的案例

sqlcmd https://learn.microsoft.com/zh-cn/sql/tools/sqlcmd/sqlcmd-connect-database-engine?viewsql-server-ver16 sqlcmd -S指定的數據庫連接字符串必須有對應的有效的SPN信息&#xff0c;否則會報錯SSPI Provider: Server not found in Kerberos database. 正常連接 1、…

電腦硬盤常見的幾種接口類型

一、傳統接口&#xff08;機械硬盤為主&#xff09; 1. SATA 接口&#xff08;Serial ATA&#xff09; 特點&#xff1a; 最主流的機械硬盤&#xff08;HDD&#xff09;接口&#xff0c;廣泛用于臺式機和筆記本電腦。傳輸速度較慢&#xff0c;理論最大帶寬為 6 Gbps&#xff…