本地RAG實戰:用Spring AI+Ollama+DeepSeek+ChromaDB增強文檔問答

本文手把手教你在本地部署RAG系統

  • Spring AI 整合 Ollama(運行DeepSeek中文模型)
  • ChromaDB 存儲本地文檔(PDF/TXT)向量
  • Java程序實現:文檔解析 → 語義檢索 → 增強生成
    最終效果:模型回答更準確,減少幻覺,全程離線運行!

檢索增強生成 (RAG)

RAG(Retrieval-Augmented Generation,檢索增強生成) 是一種將信息檢索大語言模型(LLM)生成能力相結合的技術,旨在提升模型回答的準確性、時效性和可靠性,尤其擅長處理需要專業知識或實時數據的任務。

好處:

  • 減少“幻覺”:強制模型基于提供的事實生成,避免編造不存在的信息。
  • 突破訓練數據限制:回答依賴最新或特定領域資料(如2025年政策、企業內部文檔)。
  • 提升可信度:答案可追溯來源(如引用文檔頁碼),便于驗證。
  • 降低微調成本:無需重新訓練模型,通過檢索動態擴展知識。

應用場景:

  • 企業知識庫問答:基于內部文檔(產品手冊/合同)回答專業問題。
  • 學術研究助手:根據論文庫生成文獻綜述。
  • 客服機器人:用最新產品信息回答用戶咨詢。
  • 代碼助手:結合項目文檔解釋代碼邏輯。

實現的核心原理:

  1. 檢索(Retrieve)

當用戶提問時,系統先從外部知識庫(如文檔、數據庫)中快速查找與問題相關的信息片段。

例如:從公司內部技術手冊中檢索“如何配置Spring AI連接Ollama”。

  1. 增強(Augment)

將檢索到的相關文本片段(如段落、表格)插入到給LLM的提示詞(Prompt)中,作為生成答案的參考依據。

例如:原本問題是“如何在Spring AI中調用Ollama的DeepSeek模型?”,那么接下來會把檢索到的內容 + 問題發送給大模型。

  1. 生成(Generate)

LLM 基于增強后的提示詞生成最終回答,確保答案緊扣提供的參考資料,而非僅依賴模型自身的訓練數據。

本博客代碼基于 上一篇博客 零基礎搭建Spring AI本地開發環境指南-CSDN博客 中的代碼繼續編寫,不知道怎么搭建Spring AI + ollama 的同學可以參照下

接下來我們來逐步完成一個基于RAG的問答接口,第一步我們需要一個存放文檔向量的向量數據庫,這里選擇使用Chroma

ChromaDB的安裝和使用

Chroma 是一個開源的向量數據庫,專為 AI 應用設計,特別是用于存儲和檢索嵌入向量

安裝,注意需要提前安裝python環境,打開命令行執行命令

pip install chromadb

啟動,這里Spring AI支持的是基于服務的處理,暫時沒找到基于本地存儲的ChromaDB處理,安裝完成后打開

chroma run --path "本地存儲路徑" --host 0.0.0.0 --port 8000

啟動后效果

更多詳細的內容可以參照這個博客

向量數據庫ChromaDB的使用-CSDN博客

Embedding模型

安裝好數據庫后,接下來需要安裝Embedding模型,用于把文檔轉換為可識別的內容, Embedding(嵌入) 是將離散的符號(如單詞、Token)映射為連續向量空間中的稠密向量的技術。其核心目標是讓機器理解語言語義

簡單點講,就是把文字轉換為數字格式,讓計算機更好的理解文字

例子: 張三 -> [0.1,1,3] ; 喜歡 -> [0.1,0.8]

這里的張三就是文檔中的內容,[0.1,1,3] 就是轉換后的向量,通過Embedding的轉換讓AI理解普通的話語,相當于現實世界和AI之間的橋梁

embedding有多種不同的方式,Spring AI也允許自定義處理,這里我們使用ollama中提供的模型Granite Embedding,

Granite Embedding,IBM 推出,支持 100+ 語言,Apache 2.0 許可,可商用免授權費,當然也可以去官網換其他的 Embedding models · Ollama Search

和大模型的處理差不多,打開命令行運行命令即可,和聊天模型不同的是下載完就好,不會打開聊天的處理

ollama pull granite-embedding

運行前需要安裝 ollama ,如果不知道怎么安裝的可以參照上一篇博客 零基礎搭建Spring AI本地開發環境指南-CSDN博客 , 后面的代碼也是基于上一篇博客中的項目為基礎做的

安裝完成后可以執行 ollama list 命令查看是否安裝完成

java 下操作 ChromaDB

代碼基于零基礎搭建Spring AI本地開發環境指南-CSDN博客 繼續編寫

1、在Springboot java項目的pom.xml添加RAG相關依賴

<!--RAG-->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-chroma-store</artifactId>
</dependency>

2、 demo 包下創建config包,在包下創建ChromaConfig類,在這類里面主要用于配置ChromaDB,chromaUrl配置ChromaDB服務的啟動地址

@Configuration
public class ChromaConfig {@Beanpublic RestClient.Builder builder() {return RestClient.builder().requestFactory(new SimpleClientHttpRequestFactory());}@Beanpublic ChromaApi chromaApi(RestClient.Builder restClientBuilder) {String chromaUrl = "http://localhost:8000";ChromaApi chromaApi = new ChromaApi(chromaUrl, restClientBuilder, null);return chromaApi;}@Beanpublic VectorStore chromaVectorStore(EmbeddingModel embeddingModel, ChromaApi chromaApi) {return ChromaVectorStore.builder(chromaApi, embeddingModel).collectionName("TestCollection").initializeSchema(true).build();}}

3、controller類中增加操作接口,主要的內容使用vectorStore API操作chromaDB數據庫,添加文檔使用add函數,查詢文檔使用query函數,這里只是展示下常用API,不是非要創建接口,也可以使用其他方式。

    @AutowiredVectorStore vectorStore;@GetMapping("/ai/vector/add")public String vectorAdd() {/*** Document 文檔類型*  text 文檔內容*  metadata 元數據,用于增強檢索能力,標注文檔額外數據,例如來源,時間等*/List<Document> documents = List.of(new Document("張三是一個java開發,性別男,愛好女", Map.of("meta1", "meta1")));vectorStore.add(documents);return "success";}@GetMapping("/ai/vector/query")public List<Document> vectorQuery(@RequestParam(value = "message") String message) {// similaritySearch 相似性查詢List<Document> results = vectorStore.similaritySearch(SearchRequest.builder().query(message).topK(5).build());return results;}

這種方式適合添加數據庫中存在的數據,你還可以使用讀取文檔的一些API來讀取文檔寫入,一樣的道理,后面也會描述。

4、添加完文檔后,接下來開始訪問,添加訪問接口,更方便展示效果

    @GetMapping("/ai/generateByRAG")public Map<String,String> generateByRAG(@RequestParam(value = "message") String message) {String result = ChatClient.builder(chatModel).build().prompt().advisors(new QuestionAnswerAdvisor(vectorStore)).user(message).call().content();return Map.of("generation", result);}

添加完成后,使用Apipost訪問generateByRAG接口,message參數數據“張三是誰”,發送后訪問結果如下

{"generation": "<think>\n好的,我現在需要幫助用戶回答關于“張三是誰”的問題。根據提供的上下文信息,張三是一位Java開發人員,性別是男性,并且喜歡女性。\n\n首先,我要仔細閱讀用戶的問題和提供的背景信息。用戶沒有提到任何其他限制或上下文,所以可以直接利用現有的信息來回答。\n\n接下來,我會考慮如何組織答案的結構。因為這是一個簡單的問答問題,我只需要明確地指出張三的身份、性別和他的興趣愛好即可。\n\n然后,我要確保我的回答準確無誤,完全基于提供的上下文內容,而不添加任何假設或推測。如果有不確定的地方,我應該禮貌地詢問用戶是否有更多信息。\n\n最后,我會將信息簡潔明了地呈現出來,讓用戶能夠快速理解并得到他們需要的答案。\n</think>\n\n根據提供的背景信息,張三是一位Java開發人員,性別為男性,并且喜歡女性。"
}

在原本情況下大模型并不知道張三是誰,但是基于RAG訪問后,可以明顯看出生成的結果是按照我們傳入的文檔數據生成。

基于文檔生成

除了直接添加后還可以讓程序讀取文檔內容,然后寫入,這里使用的是tika,當然也可以用其他的,這個無所謂

1、添加依賴

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-tika-document-reader</artifactId>
</dependency>

2、創建文檔 “測試文檔.docx”,這里注意文檔要放在resource文件夾下,文檔中添加內容

張三是個開發人員,喜歡玩游戲。
技能有java,python
平時最喜歡的游戲是星露谷,七日殺,永劫無間點個關注唄

3、添加完成后,開始寫代碼,代碼邏輯非常簡單,創建tikaReader對象,然后調用read函數,最后循環添加到vectorStore

    @GetMapping("/ai/vector/addDocument")public String addDocument() {String path = "測試文檔.docx";String label = "document";// 讀取文件TikaDocumentReader tikaReader = new TikaDocumentReader(path);List<Document> docbatch = tikaReader.read();// 文件發送給適量存儲docbatch = TokenTextSplitter.builder().withChunkSize(512).withMaxNumChunks(100).build().apply(docbatch);System.out.println("添加的文檔大小:" + docbatch.size());docbatch.forEach(doc -> {System.out.println("添加的文檔內容:"+doc.getText());doc.getMetadata().put("label",label);vectorStore.add(List.of(doc));});return "success";}

4、還是原來的generateByRAG接口, 使用Apipost訪問,message的值是“請介紹下張三”

生成結果如下,從結果中可以看出內容是基于“測試文檔.docx”生成的

{"generation": "<think>\n好的,我現在需要分析用戶的請求。用戶要求我介紹張三,并提供了上下文信息。首先,看看提供的上下文內容:張三是個開發人員,喜歡玩游戲,技能有Java和Python,最喜歡的游戲是星露谷、七日殺和永劫無間。\n\n然后,檢查是否有其他背景信息,比如性別或特定愛好。用戶提到李浩是一個Java開發者,男性,喜歡女性,但這是另一個用戶的信息,與張三無關。\n\n接下來,分析用戶的請求是否在提供的上下文中能找到答案。張三的個人介紹包括開發技能和游戲偏好,這些都是明確給出的,所以可以回答。此外,用戶提到關注的數量,這可能是在其他平臺上發布內容的方式,并不影響張三的介紹。\n\n最后,確保回復簡潔明了,不添加額外信息,只基于提供的上下文。因此,我應該直接列出張三的基本情況,包括開發技能和最喜歡的游戲,同時避免無關的信息。\n</think>\n\n張三是位開發人員,擅長Java和Python編程,并喜歡玩游戲。他的最愛游戲包括星露谷、七日殺和永劫無間。"
}

本次實戰清晰地印證了 Spring AI 作為 Java 開發生態接入 AI 能力的強大橋梁作用。通過整合 Ollama(本地模型運行)、DeepSeek(強大語義理解)和 ChromaDB(高效向量檢索),我們構建了一個完全本地化的 RAG 文檔問答系統 。

Spring AI 不僅簡化了集成,更開啟了 Java 應用智能化的新篇章,除了RAG功能外,還有聲明式 Prompt 工程一系列功能,在構建企業知識助手、智能文檔分析工具,還是個人研究方面提供一系列便利。

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

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

相關文章

Python 數據分析:DataFrame,生成,用字典創建 DataFrame ,鍵值對數量不一樣怎么辦?

目錄 1 示例代碼2 歡迎糾錯3 論文寫作/Python 學習智能體------以下關于 Markdown 編輯器新的改變功能快捷鍵合理的創建標題&#xff0c;有助于目錄的生成如何改變文本的樣式插入鏈接與圖片如何插入一段漂亮的代碼片生成一個適合你的列表創建一個表格設定內容居中、居左、居右S…

Java 并發編程的 CAS(Compare and Swap)是什么?

CAS&#xff08;Compare and Swap&#xff0c;比較并交換&#xff09; 并非 Java 語言特有的概念&#xff0c;而是現代計算機硬件提供的一條核心原子指令。在 Java 并發編程中&#xff0c;它扮演著“幕后英雄”的角色&#xff0c;是構建高性能、無鎖并發工具&#xff08;如原子…

【UnityAssetBundle】AssetBundle打包

AssetBundle生成AB包資源文件方式&#xff1a; Unity編輯器開發&#xff0c;自定義打包工具&#xff1b;官方提供好的打包工具&#xff0c;Asset Bundle Browser 打包 選擇一個資源&#xff0c;new一個壓縮包名稱或選擇一個壓縮包名稱 點擊Window->AssetBundle Browser&…

Hush Puppies大中華區鞋類業務移交品牌方繼續經營

據悉&#xff0c;隨著百麗集團運營的暇步士&#xff08;Hush Puppies&#xff09;大中華區鞋類授權的到期&#xff0c;暇步士&#xff08;Hush Puppies&#xff09;鞋類業務已開始運營權移交。其中線上渠道授權于2025年6月30日正式到期&#xff0c;線下渠道將于2025年12月31日前…

解釋LLM怎么預測下一個詞語的

解釋LLM怎么預測下一個詞語的 通過上文詞的向量進行映射 在Transformer架構的大語言模型(如GPT系列、BERT等)中,詞語會先被轉化為詞向量。在預測下一個詞時,模型會基于之前所有詞的向量表示(并非僅僅上一個詞,但上一個詞的向量是重要信息來源之一)進行計算。 以GPT-2…

DAY 49 CBAM注意力

目錄 DAY 49 CBAM注意力1.通道注意力模塊復習2.空間注意力模塊3.CBAM的定義作業&#xff1a;嘗試對今天的模型檢查參數數目&#xff0c;并用tensorboard查看訓練過程 DAY 49 CBAM注意力 1.通道注意力模塊復習 2.空間注意力模塊 3.CBAM的定義 import torch import torch.nn …

【網絡】Linux 內核優化實戰 - net.ipv4.conf.all.rp_filter

目錄 net.ipv4.conf.all.rp_filter 參數詳解一、參數基本概念二、參數取值及含義三、反向路徑過濾的工作原理四、配置示例與注意事項五、與其他參數的關聯六、總結 net.ipv4.conf.all.rp_filter 參數詳解 一、參數基本概念 net.ipv4.conf.all.rp_filter 是 Linux 內核中用于控…

ElementUI el-select多選下拉框,回顯數據后無法重新選擇和修改

問題 ElementUI el-select多選下拉框&#xff0c;回顯數據后無法重新選擇和修改&#xff0c;點擊選擇和刪除都沒有反應&#xff0c;頁面也沒有報錯 方案一 網上搜出來的基本上都是這個解決辦法&#xff0c;但是我設置后沒有生效&#xff0c;還是無法選擇和修改 原因 下拉框數…

計算機視覺的新浪潮:擴散模型(Diffusion Models)技術剖析與應用前景

近年來&#xff0c;擴散模型&#xff08;Diffusion Models, DMs&#xff09;迅速崛起&#xff0c;成為計算機視覺領域最令人矚目的生成模型之一。從生成高質量圖像到風格遷移、圖像修復&#xff0c;再到文本驅動圖像生成&#xff08;如 DALLE 2、Stable Diffusion、Midjourney&…

「Java流程控制」跳轉語句

今天來聊聊Java里的兩個重要跳轉語句——break和continue。它們就像馬路上的交通信號燈,能夠控制程序執行的流向。 break和continue break和continue在循環中的作用,特別像快遞分揀中心的工作場景: break:就像發現一個破損包裹,直接停止當前分揀流程,把它扔進異常品處理…

R1-Searcher使用強化學習增強語言模型解決問題的搜索能力

R1-Searcher&#xff1a;Incentivizing the Search Capability in LLMs via Reinforcement Learning 2025.3 https://github.com/RUCAIBox/R1-Searcher 針對的問題&#xff1a; 現有大型推理模型在時間敏感或知識密集型問題上通常僅使用模型內部知識&#xff0c;導致回答不準…

C++中的虛函數與純虛函數

文章目錄 虛函數 (Virtual Function)純虛函數 (Pure Virtual Function)主要區別實際應用示例 C中的虛函數和純虛函數是實現多態性的重要機制。 虛函數 (Virtual Function) 虛函數是在基類中用virtual關鍵字聲明的函數&#xff0c;它允許派生類重寫(override)該函數的實現。當…

(LeetCode 每日一題) 3330. 找到初始輸入字符串 I (字符串)

題目&#xff1a;3330. 找到初始輸入字符串 I 思路&#xff1a;字符串&#xff0c;時間復雜度0(n)。 默認沒有輸錯的情況ans1&#xff0c;而輸錯的情況&#xff0c;只會出現在連續相等字符串&#xff0c;假設這段字符串長度為ct&#xff0c;那么可能的情況為ct-1。累計這些和到…

Deep semi-supervised learning for medical image segmentation: A review

概述 醫學圖像分割的重要性&#xff1a;它是計算機輔助診斷&#xff08;CAD&#xff09;的關鍵部分&#xff0c;能幫助醫生定位病變、評估治療效果&#xff0c;減輕醫生工作量。 深度學習技術的應用&#xff1a;U-Net等網絡在醫學圖像分割中表現優異&#xff0c;近期大型視覺語…

[云上玩轉Qwen3系列之四]PAI-LangStudio x AI搜索開放平臺 x ElasticSearch: 構建AI Search RAG全棧應用

本文詳細介紹了如何使用 PAI-LangStudio 和 Qwen3 構建基于AI搜索開放平臺 x ElasticSearch 的 AI Search RAG 智能檢索應用。該應用通過使用 AI 搜索開放平臺、ElasticSearch 全文檢索向量檢索引擎的混合檢索技術配合阿里云最新發布的 Qwen3 推理模型編排在一個 Agentic Workf…

前端請求瀏覽器提示net::ERR_UNSAFE_PORT的解決方案

起因 項目中后端給到了6666端口的服務地址, 隨即前端項目訪問中瀏覽器報錯如下: 不安全端口在主流瀏覽器&#xff08;Chrome/Firefox/Edge/Safari&#xff09;中會被攔截&#xff0c;觸發瀏覽器Network的status列顯示 net::ERR_UNSAFE_PORT 錯誤, 以下是常見的不安全端口一覽…

【Bluedroid】藍牙設備管理器初始化全流程深度解析(BTA_dm_on_hw_on)

本文全面剖析Android藍牙設備管理器在硬件啟動時的初始化流程&#xff0c;涵蓋控制塊創建、服務發現啟動、設備類配置、安全密鑰加載、超時參數設置等核心環節。通過分析從底層硬件交互到上層服務注冊的全鏈路調用&#xff0c;揭示藍牙系統從硬件就緒到功能可用的完整啟動機制&…

大語言模型:是逐字生成還是一次多詞?

大語言模型(LLM)既可以按順序逐個生成單詞(token),也能實現一次生成多個 token 核心差異源于解碼策略與模型架構設計 一、常規“逐個生成”模式(基礎邏輯) 多數入門級演示或簡單文本生成中,LLM 會默認按 “生成一個 token → 拼接回輸入 → 再生成下一個” 的流程,…

通俗易懂的LangGraph圖定義解析

LangGraph 是一個基于狀態的工作流框架&#xff0c;它通過 節點&#xff08;Nodes&#xff09; 和 邊&#xff08;Edges&#xff09; 的組合&#xff0c;構建出復雜的工作流邏輯。這種設計特別適合處理需要動態決策、循環、多步驟交互的場景&#xff08;比如對話系統、智能代理…

K8s Pod調度基礎——2

目錄 一、Deployment ?一、Deployment 原理? ?二、核心特性? ?三、意義與場景? ?四、示例與逐行解釋? ?五、總結? StatefulSet ?一、StatefulSet 原理? ?二、核心特性? ?三、意義與場景? ?四、示例與逐行解釋? ?五、總結? 彼此的區別 一、本質…