本文手把手教你在本地部署RAG系統:
- 用 Spring AI 整合 Ollama(運行DeepSeek中文模型)
- ChromaDB 存儲本地文檔(PDF/TXT)向量
- Java程序實現:文檔解析 → 語義檢索 → 增強生成
最終效果:模型回答更準確,減少幻覺,全程離線運行!
檢索增強生成 (RAG)
RAG(Retrieval-Augmented Generation,檢索增強生成) 是一種將信息檢索與大語言模型(LLM)生成能力相結合的技術,旨在提升模型回答的準確性、時效性和可靠性,尤其擅長處理需要專業知識或實時數據的任務。
好處:
- 減少“幻覺”:強制模型基于提供的事實生成,避免編造不存在的信息。
- 突破訓練數據限制:回答依賴最新或特定領域資料(如2025年政策、企業內部文檔)。
- 提升可信度:答案可追溯來源(如引用文檔頁碼),便于驗證。
- 降低微調成本:無需重新訓練模型,通過檢索動態擴展知識。
應用場景:
- 企業知識庫問答:基于內部文檔(產品手冊/合同)回答專業問題。
- 學術研究助手:根據論文庫生成文獻綜述。
- 客服機器人:用最新產品信息回答用戶咨詢。
- 代碼助手:結合項目文檔解釋代碼邏輯。
實現的核心原理:
- 檢索(Retrieve)
當用戶提問時,系統先從外部知識庫(如文檔、數據庫)中快速查找與問題相關的信息片段。
例如:從公司內部技術手冊中檢索“如何配置Spring AI連接Ollama”。
- 增強(Augment)
將檢索到的相關文本片段(如段落、表格)插入到給LLM的提示詞(Prompt)中,作為生成答案的參考依據。
例如:原本問題是“如何在Spring AI中調用Ollama的DeepSeek模型?”,那么接下來會把檢索到的內容 + 問題發送給大模型。
- 生成(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 工程一系列功能,在構建企業知識助手、智能文檔分析工具,還是個人研究方面提供一系列便利。