Java大模型開發入門 (9/15):連接外部世界(中) - 向量嵌入與向量數據庫

前言

在上一篇文章中,我們成功地將一篇長文檔加載并分割成了一系列小的文本片段(TextSegment)。我們現在有了一堆“知識碎片”,但面臨一個新問題:計算機如何理解這些碎片的內容,并找出與用戶問題最相關的片段呢?

如果用戶問“X-Wing的設置要求是什么?”,我們不能只用簡單的關鍵詞匹配(比如搜索“setup”或“requirements”),因為用戶可能會用不同的詞語提問(“我該如何安裝X-Wing?”)。我們需要一種能夠理解**語義(Semantic Meaning)**的搜索方式。

這就是文本嵌入(Text Embedding)向量數據庫(Vector Database) 發揮作用的地方。今天,我們將深入RAG技術的心臟地帶,學習如何將文本轉化為向量,并將其存儲起來以便進行高效的語義搜索。

第一部分:什么是文本嵌入(Embedding)?語義的“指紋”

想象一下圖書館里的書。圖書管理員不會記住每本書的每一個字,但他們知道哪些書是關于“歷史”的,哪些是關于“科幻”的,哪些是關于“烹飪”的。他們將書的內容“映射”到了一個類別體系中。

文本嵌入模型(Embedding Model)做的是類似但更精細的事情。它是一個專門的AI模型,它的唯一工作就是讀取一段文本,然后輸出一個由幾百上千個數字組成的列表——向量(Vector)

這個向量,就是這段文本在多維語義空間中的“坐標”或“指紋”。

這個語義空間非常神奇。在其中,意思相近的文本,它們的向量在空間中的距離也相近。經典的例子是:
vector("King") - vector("Man") + vector("Woman") ≈ vector("Queen")

通過將所有文檔片段都轉換成向量,我們就可以通過計算向量之間的“距離”來判斷文本之間的語義相似度,從而實現比關鍵詞搜索高級得多的語義搜索。

在LangChain4j中,這個功能由EmbeddingModel接口來抽象。

第二部分:什么是向量數據庫(Vector Store)?向量的“家”

現在我們有能力將所有文本片段都轉換成向量了,但我們該把這些向量存放在哪里,又如何高效地搜索它們呢?

這就是向量數據庫(或稱為向量存儲,EmbeddingStore)的作用。

如果說嵌入模型是“翻譯官”,把文本翻譯成向量;那么向量數據庫就是專門為這些向量建立的“高維空間索引系統”。

它允許我們:

  1. 存儲大量的向量及其關聯的原始文本。
  2. 當給定一個新的查詢向量時,能以極高的效率找出數據庫中與它最相似的N個向量(這個過程通常被稱為“最近鄰搜索”)。

LangChain4j通過EmbeddingStore接口支持多種向量數據庫,從簡單的內存存儲到專業的分布式數據庫:

  • InMemoryEmbeddingStore: 完全在內存中運行,非常適合快速原型開發和測試,無需任何外部依賴。
  • Chroma, Milvus, Pinecone, Weaviate: 生產級的、可獨立部署的向量數據庫,支持海量數據和高并發查詢。

在今天的教程中,我們將從最簡單的InMemoryEmbeddingStore開始。

第三部分:實戰 - 將文檔片段嵌入并存儲

我們將繼續完善上一篇的DocumentService,為其增加嵌入和存儲的功能。

  1. 確認依賴和配置
    好消息是,我們之前添加的langchain4j-open-ai-spring-boot-starter已經包含了嵌入模型的功能。現在還需要修改application.prroperties增加embedding模型配置
langchain4j.open-ai.chat-model.api-key=${OPENAI_API_KEY:your-api-key-here}
langchain4j.open-ai.chat-model.base-url=https://yibuapi.com/v1/
langchain4j.open-ai.chat-model.model-name=gpt-4o-mini
langchain4j.open-ai.chat-model.temperature=0.7
langchain4j.open-ai.chat-model.max-tokens=1024langchain4j.open-ai.embedding-model.model-name=text-embedding-ada-002
  1. 修改DocumentService
    我們將注入EmbeddingModelEmbeddingStoreIngestor,并創建一個InMemoryEmbeddingStore的Bean。

    第一步:在config/LangChain4jConfig.java中創建EmbeddingModel Bean

    package com.example.aidemoapp.config;
    // ... other imports
    import dev.langchain4j.store.embedding.EmbeddingStore;
    import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;@Configuration
    public class LangChain4jConfig {// ... chatLanguageModel 和 chatMemoryProvider Beans ...@Beanpublic EmbeddingModel embeddingModel() {// 通常嵌入模型也使用相同的api-key和base-url// 注意:OpenAI有專門的嵌入模型名稱,// 比如 "text-embedding-ada-002" 。// 如果不指定,LangChain4j可能會使用一個默認值。// 為清晰起見,最好在properties中也定義它。return OpenAiEmbeddingModel.builder().apiKey(apiKey).baseUrl(baseUrl)// 推薦在application.properties中添加:// langchain4j.open-ai.embedding-model.model-name=text-embedding-ada-002.modelName(embeddingModelName).build();}
    }
    

    第二步:改造DocumentService.java

    package com.example.aidemoapp.service;import dev.langchain4j.data.document.Document;
    import dev.langchain4j.data.document.DocumentSplitter;
    import dev.langchain4j.data.document.loader.FileSystemDocumentLoader;
    import dev.langchain4j.data.document.parser.TextDocumentParser;
    import dev.langchain4j.data.document.splitter.DocumentSplitters;
    import dev.langchain4j.data.segment.TextSegment;
    import dev.langchain4j.model.embedding.EmbeddingModel;
    import dev.langchain4j.store.embedding.EmbeddingStore;
    import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Service;import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.List;@Service
    @RequiredArgsConstructor
    public class DocumentService {// 注入由Starter自動創建的EmbeddingModelprivate final EmbeddingModel embeddingModel;// 注入我們自己創建的EmbeddingStore Beanprivate final EmbeddingStore embeddingStore;public void loadSplitAndEmbed() {Path documentPath = Paths.get("src/main/resources/documents/product-info.txt");Document document = FileSystemDocumentLoader.loadDocument(documentPath, new TextDocumentParser());// 2. 將文檔分割成片段DocumentSplitter splitter = DocumentSplitters.recursive(300, 10);List<TextSegment> segments = splitter.split(document);System.out.println("Document split into " + segments.size() + " segments.");// 3. 將片段嵌入并存儲到向量數據庫中// LangChain4j提供了一個方便的EmbeddingStoreIngestor來處理這個流程EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder().documentSplitter(splitter) // 可以在這里也指定分割器.embeddingModel(embeddingModel).embeddingStore(embeddingStore).build();// 開始攝入文檔ingestor.ingest(document);System.out.println("Document ingested and stored in the embedding store.");}
    }
    

    代碼解析

    • 我們注入了EmbeddingModelEmbeddingStore
    • 我們使用了EmbeddingStoreIngestor,這是一個高級工具,它將分割、嵌入和存儲這三個步驟打包成了一個簡單的.ingest()方法調用,非常方便。
    • 運行loadSplitAndEmbed()方法后,我們的InMemoryEmbeddingStore中就包含了文檔所有片段的向量信息。
第四部分:進行第一次語義搜索

光存儲還不夠,我們需要驗證一下檢索效果。讓我們添加一個搜索方法。

// 在 DocumentService.java 中繼續添加
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.store.embedding.EmbeddingMatch;// ...public List<String> search(String query) {System.out.println("\n--- Performing search for query: '" + query + "' ---");// 1. 將用戶問題也進行嵌入,得到查詢向量Response<Embedding> queryEmbedding = embeddingModel.embed(query);// 2. 在向量存儲中查找最相關的N個匹配項// 參數1: 查詢向量// 參數2: 返回的最大結果數EmbeddingSearchRequest request = EmbeddingSearchRequest.builder().queryEmbedding(queryEmbedding.content()).build();List<EmbeddingMatch<TextSegment>> relevant = embeddingStore.search(request).matches();// 3. 打印結果System.out.println("Found " + relevant.size() + " relevant segments:");relevant.forEach(match -> {System.out.println("--------------------");System.out.println("Score: " + match.score()); // 相似度得分System.out.println("Text: " + match.embedded().text()); // 原始文本});return relevant.stream().map(match -> match.embedded().text()).collect(Collectors.toList());}

現在,你可以創建一個測試端點來調用loadSplitAndEmbed(),然后再調用search("What are the setup requirements for X-Wing?")。你會看到,即使你的問題中沒有“RAM”或“CPU”這些詞,返回的最相關的片段也正是包含“16GB RAM and a 4-core CPU”的那一段!這就是語義搜索的威力。

總結

今天,我們深入了RAG技術的核心腹地。我們學習了:

  • **文本嵌入(Embedding)**如何將文字轉換成代表其語義的數學向量。
  • **向量數據庫(Vector Store)**如何存儲這些向量并進行高效的相似度搜索。
  • 如何使用LangChain4j的EmbeddingModelEmbeddingStoreIngestor將文檔片段向量化并存入內存向量庫。
  • 如何執行一次真正的語義搜索,并找到了與問題最相關的文檔片段。

我們已經成功地“開卷”并“找到了答案所在的頁面”。現在,我們離終點只差最后一步:將找到的這些“參考資料”連同原始問題一起,交給大語言模型,讓它用自然、流暢的語言“總結”出最終的答案。


下一篇預告:
Java大模型開發入門 (10/15):連接外部世界(下) - 端到端構建完整的RAG問答系統》—— 我們將整合所有學過的知識,打通RAG的“最后一公里”。我們將把檢索到的文本片段與用戶問題組合起來,發送給ChatLanguageModel,最終構建一個可以針對我們私有文檔進行智能問答的完整端到端應用!

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

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

相關文章

Windows下MySQL安裝全流程圖文教程及客戶端使用指南(付整合安裝包)

本教程是基于5.7版本安裝&#xff0c;5.7和8.0的安裝過程大差不差 安裝包「windows上mysql中安裝包資源」 鏈接&#xff1a;https://pan.quark.cn/s/de275899936d 一、安裝前的準備 1.1 獲取 MySQL 安裝程序 官網 前往 MySQL 官方下載頁面&#xff0c;下載適用于 Windows 系…

筆記 軟件工程復習

第一章 軟件工程學概述 1.1 軟件危機&#xff08;Software Crisis&#xff09; 概念 定義&#xff1a;軟件危機指在計算機軟件開發與維護過程中遇到的一系列嚴重問題&#xff0c;源于1960年代軟件復雜度激增與傳統開發方法失效的矛盾。 本質&#xff1a;軟件規模擴大 → 開…

GaussDB創建數據庫存儲

示例一&#xff1a; 下面是一個簡單的GaussDB存儲過程示例&#xff1a; –創建一個存儲過程。 CREATE OR REPLACE PROCEDURE prc_add (param1 IN INTEGER,param2 IN OUT INTEGER ) AS BEGINparam2: param1 param2;dbe_output.print_line(result is: ||to_char(param…

基于51單片機的校園打鈴及燈控制系統

目錄 具體實現功能 設計介紹 資料內容 全部內容 資料獲取 具體實現功能 具體功能&#xff1a; &#xff08;1&#xff09;實時顯示當前時間&#xff08;年月日時分秒星期&#xff09;&#xff0c;LED模式指示燈亮。 &#xff08;2&#xff09;按下“打鈴”和“打鈴-”按鍵…

PHP+mysql雪里開輕量級報修系統 V1.0Beta

# PHP雪里開輕量級報修系統 V1.0Beta ## 簡介 這是一個基于PHP7和MySQL5.6的簡易報修系統&#xff0c;適用于學校、企業等機構的設備報修管理。 系統支持學生提交報修、后勤處理報修以及系統管理員管理用戶和報修記錄。 初代版本V1.0&#xff0c;尚未實際業務驗證&#xff0c;…

XCTF-misc-base64÷4

拿到一串字符串 666C61677B45333342374644384133423834314341393639394544444241323442363041417D轉換為字符串得到flag

Mini DeepSeek-v3訓練腳本學習

Mini DeepSeek-v3 訓練腳本詳細技術說明(腳本在文章最后) &#x1f4cb; 概述 這是一個實現了Mini DeepSeek-v3大語言模型的訓練腳本&#xff0c;集成了多項先進的深度學習技術。該腳本支持自動GPU選擇和分布式訓練&#xff0c;適合在多GPU環境下訓練Transformer模型。 &…

FPGA 的硬件結構

FPGA 的基本結構分為5 部分&#xff1a;可編程邏輯塊&#xff08;CLB&#xff09;、輸入/輸出塊&#xff08;IOB&#xff09;、邏輯塊之間的布線資源、內嵌RAM 和內嵌的功能單元。 &#xff08;1&#xff09;可編程邏輯塊&#xff08;CLB&#xff09; 一個基本的可編程邏輯塊由…

算法專題八: 鏈表

1.兩數相加 題目鏈接&#xff1a;2. 兩數相加 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode…

5G+邊緣計算推動下的商品詳情API低延遲高效率新方案

在電商行業&#xff0c;商品詳情API的性能直接關系到用戶體驗與平臺競爭力。傳統云計算模式在處理高并發請求時&#xff0c;常面臨網絡延遲高、帶寬成本大等問題。而5G與邊緣計算的結合&#xff0c;為商品詳情API的低延遲高效率提供了新方案。本文將深入探討這一新方案&#xf…

【Python教程】CentOS系統下Miniconda3安裝與Python項目后臺運行全攻略

一、引言 為了在CentOS系統上高效地開發和運行Python項目&#xff0c;我們常常需要借助Miniconda3來管理Python環境。本文將詳細介紹如何在CentOS系統上安裝Miniconda3&#xff0c;并將Python項目部署到后臺運行。 二、Miniconda3和CentOS系統介紹 Miniconda3介紹 Minicond…

【讀點論文】A Survey on Open-Set Image Recognition

A Survey on Open-Set Image Recognition Abstract 開集圖像識別(Open-set image recognition&#xff0c;OSR)旨在對測試集中已知類別的樣本進行分類&#xff0c;并識別未知類別的樣本&#xff0c;在許多實際應用中支持魯棒的分類器&#xff0c;如自動駕駛、醫療診斷、安全監…

使用DuckDB查詢DeepSeek歷史對話

DeepSeek網頁版在左下角個人信息/系統設置的賬號管理頁簽中有個“導出所有歷史對話”功能&#xff0c;點擊“導出”&#xff0c;片刻就能生成一個deepseek_data-2025-06-14.zip的文件&#xff0c;里面有2個json文件&#xff0c;直接用文本編輯器查看不太方便。 而用DuckDB查詢卻…

多線程下 到底是事務內部開啟鎖 還是先加鎖再開啟事務?

前言 不知大家是否有觀察到一個最常見的錯誤&#xff1a; 先開啟事務&#xff0c;然后針對資源加鎖&#xff0c;操作資源&#xff0c;然后釋放鎖&#xff0c;最后提交事務 你是否發現了在這樣的場景下會出現并發安全的問題&#xff1f; &#xff08;提示&#xff1a;一個線程A…

Javascript解耦,以及Javascript學習網站推薦

一、學習網站推薦 解構 - JavaScript | MDN 界面如下&#xff0c;既有知識點&#xff0c;也有在線編譯器執行代碼。初學者可以看看 二、Javascript什么是解構 解構語法是一種 Javascript 語法。可以將數組中的值或對象的屬性取出&#xff0c;賦值給其他變量。它可以在接收數…

Java大模型開發入門 (11/15):讓AI自主行動 - 初探LangChain4j中的智能體(Agents)

前言 在過去的十篇文章里&#xff0c;我們已經打造出了一個相當強大的AI應用。它有記憶&#xff0c;能進行多輪對話&#xff1b;它有知識&#xff0c;能通過RAG回答關于我們私有文檔的問題。它就像一個博學的“學者”&#xff0c;你可以向它請教任何在其知識范圍內的問題。 但…

Qt KDReports詳解與使用

Qt KDReports詳解與使用 一、KD Reports 簡介二、安裝與配置三、核心功能與使用1、創建基礎報表2、添加表格數據3、導出為 PDF4、XML報表定義 四、高級功能1、動態數據綁定2、自定義圖表3、模板化設計4、頁眉頁腳設置 五、常見問題六、總結七、實際應用示例&#xff1a;發票生成…

Spring Cloud 原生中間件

&#x1f4dd; 代碼記錄 Consul&#xff08;服務注冊與發現 分布式配置管理&#xff09; 擁有服務治理功能&#xff0c;實現微服務之間的動態注冊與發現 ?不在使用Eureka&#xff1a;1. 停更進維 2. 注冊中心獨立且和微服務功能解耦 Consul官網 Spring官方介紹 三個注冊中…

CMake實踐: 以開源庫QSimpleUpdater為例,詳細講解編譯、查找依賴等全過程

目錄 1.環境和工具 2.CMake編譯 3.查找依賴文件 3.1.windeployqt 3.2.dumpbin 4.總結 相關鏈接 QSimpleUpdater&#xff1a;解鎖 Qt 應用自動更新的全新姿勢-CSDN博客 1.環境和工具 windows 11, x64 Qt5.12.12或Qt5.15.2 CMake 4.0.2 干凈的windows 7&#xff0c;最好是…

WordToCard制作高考志愿填報攻略小卡片【豆包版】

一、什么是WordToCard WordToCard是一個免費的工具&#xff0c;能夠將Word文檔自動轉換為美觀的知識卡片或圖文海報。以下是它的主要特點&#xff1a; 功能優勢 格式支持&#xff1a;支持標題、列表、表格、LaTeX公式等多種格式。模板豐富&#xff1a;提供多種風格的模板&am…