Spring Boot集成LangChain來(lái)實(shí)現(xiàn)Rag應(yīng)用的問(wèn)題小結(jié)
1.什么是rag?
檢索增強(qiáng)生成(RAG)是指對(duì)大型語(yǔ)言模型輸出進(jìn)行優(yōu)化,使其能夠在生成響應(yīng)之前引用訓(xùn)練數(shù)據(jù)來(lái)源之外的權(quán)威知識(shí)庫(kù)。大型語(yǔ)言模型(LLM)用海量數(shù)據(jù)進(jìn)行訓(xùn)練,使用數(shù)十億個(gè)參數(shù)為回答問(wèn)題、翻譯語(yǔ)言和完成句子等任務(wù)生成原始輸出。在 LLM 本就強(qiáng)大的功能基礎(chǔ)上,RAG 將其擴(kuò)展為能訪問(wèn)特定領(lǐng)域或組織的內(nèi)部知識(shí)庫(kù),所有這些都無(wú)需重新訓(xùn)練模型。這是一種經(jīng)濟(jì)高效地改進(jìn) LLM 輸出的方法,讓它在各種情境下都能保持相關(guān)性、準(zhǔn)確性和實(shí)用性。
為什么檢索增強(qiáng)生成很重要?
LLM 是一項(xiàng)關(guān)鍵的人工智能(AI)技術(shù),為智能聊天機(jī)器人和其他自然語(yǔ)言處理(NLP)應(yīng)用程序提供支持。目標(biāo)是通過(guò)交叉引用權(quán)威知識(shí)來(lái)源,創(chuàng)建能夠在各種環(huán)境中回答用戶問(wèn)題的機(jī)器人。不幸的是,LLM 技術(shù)的本質(zhì)在 LLM 響應(yīng)中引入了不可預(yù)測(cè)性。此外,LLM 訓(xùn)練數(shù)據(jù)是靜態(tài)的,并引入了其所掌握知識(shí)的截止日期。 LLM 面臨的已知挑戰(zhàn)包括:
- 在沒(méi)有答案的情況下提供虛假信息。
- 當(dāng)用戶需要特定的當(dāng)前響應(yīng)時(shí),提供過(guò)時(shí)或通用的信息。
- 從非權(quán)威來(lái)源創(chuàng)建響應(yīng)。
- 由于術(shù)語(yǔ)混淆,不同的培訓(xùn)來(lái)源使用相同的術(shù)語(yǔ)來(lái)談?wù)摬煌氖虑椋虼藭?huì)產(chǎn)生不準(zhǔn)確的響應(yīng)。
您可以將大型語(yǔ)言模型看作是一個(gè)過(guò)于熱情的新員工,他拒絕隨時(shí)了解時(shí)事,但總是會(huì)絕對(duì)自信地回答每一個(gè)問(wèn)題。不幸的是,這種態(tài)度會(huì)對(duì)用戶的信任產(chǎn)生負(fù)面影響,這是您不希望聊天機(jī)器人效仿的! RAG 是解決其中一些挑戰(zhàn)的一種方法。它會(huì)重定向 LLM,從權(quán)威的、預(yù)先確定的知識(shí)來(lái)源中檢索相關(guān)信息。組織可以更好地控制生成的文本輸出,并且用戶可以深入了解 LLM 如何生成響應(yīng)。
檢索增強(qiáng)生成的工作原理是什么?
如果沒(méi)有 RAG,LLM 會(huì)接受用戶輸入,并根據(jù)它所接受訓(xùn)練的信息或它已經(jīng)知道的信息創(chuàng)建響應(yīng)。RAG 引入了一個(gè)信息檢索組件,該組件利用用戶輸入首先從新數(shù)據(jù)源提取信息。用戶查詢和相關(guān)信息都提供給 LLM。LLM 使用新知識(shí)及其訓(xùn)練數(shù)據(jù)來(lái)創(chuàng)建更好的響應(yīng)。以下各部分概述了該過(guò)程。
創(chuàng)建外部數(shù)據(jù)
LLM 原始訓(xùn)練數(shù)據(jù)集之外的新數(shù)據(jù)稱為外部數(shù)據(jù)。它可以來(lái)自多個(gè)數(shù)據(jù)來(lái)源,例如 API、數(shù)據(jù)庫(kù)或文檔存儲(chǔ)庫(kù)。數(shù)據(jù)可能以各種格式存在,例如文件、數(shù)據(jù)庫(kù)記錄或長(zhǎng)篇文本。另一種稱為嵌入語(yǔ)言模型的 AI 技術(shù)將數(shù)據(jù)轉(zhuǎn)換為數(shù)字表示形式并將其存儲(chǔ)在向量數(shù)據(jù)庫(kù)中。這個(gè)過(guò)程會(huì)創(chuàng)建一個(gè)生成式人工智能模型可以理解的知識(shí)庫(kù)。
檢索相關(guān)信息
下一步是執(zhí)行相關(guān)性搜索。用戶查詢將轉(zhuǎn)換為向量表示形式,并與向量數(shù)據(jù)庫(kù)匹配。例如,考慮一個(gè)可以回答組織的人力資源問(wèn)題的智能聊天機(jī)器人。如果員工搜索:“我有多少年假?”,系統(tǒng)將檢索年假政策文件以及員工個(gè)人過(guò)去的休假記錄。這些特定文件將被退回,因?yàn)樗鼈兣c員工輸入的內(nèi)容高度相關(guān)。相關(guān)性是使用數(shù)學(xué)向量計(jì)算和表示法計(jì)算和建立的。
增強(qiáng) LLM 提示
接下來(lái),RAG 模型通過(guò)在上下文中添加檢索到的相關(guān)數(shù)據(jù)來(lái)增強(qiáng)用戶輸入(或提示)。此步驟使用提示工程技術(shù)與 LLM 進(jìn)行有效溝通。增強(qiáng)提示允許大型語(yǔ)言模型為用戶查詢生成準(zhǔn)確的答案。
更新外部數(shù)據(jù)
下一個(gè)問(wèn)題可能是——如果外部數(shù)據(jù)過(guò)時(shí)了怎么辦? 要維護(hù)當(dāng)前信息以供檢索,請(qǐng)異步更新文檔并更新文檔的嵌入表示形式。您可以通過(guò)自動(dòng)化實(shí)時(shí)流程或定期批處理來(lái)執(zhí)行此操作。這是數(shù)據(jù)分析中常見(jiàn)的挑戰(zhàn)——可以使用不同的數(shù)據(jù)科學(xué)方法進(jìn)行變更管理。 下圖顯示了將 RAG 與 LLM 配合使用的概念流程。
2.什么是LangChain?
LangChain 是一個(gè)用于開(kāi)發(fā)由語(yǔ)言模型驅(qū)動(dòng)的應(yīng)用程序的框架。他主要擁有 2 個(gè)能力:
- 可以將 LLM 模型與外部數(shù)據(jù)源進(jìn)行連接
- 允許與 LLM 模型進(jìn)行交互
LLM 模型:Large Language Model,大型語(yǔ)言模型
3.代碼工程
實(shí)驗(yàn)?zāi)康?/h3>
利用LangChain實(shí)現(xiàn)rag應(yīng)用
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>rag</artifactId> <properties> <java.version>17</java.version> <langchain4j.version>0.23.0</langchain4j.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>${langchain4j.version}</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>${langchain4j.version}</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-embeddings</artifactId> <version>${langchain4j.version}</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-embeddings-all-minilm-l6-v2</artifactId> <version>${langchain4j.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
controller
package com.et.rag.controller; import com.et.rag.service.SBotService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @Controller @RequiredArgsConstructor public class SBotController { private final SBotService sBotService; @GetMapping public String home() { return "index"; } @PostMapping("/ask") public ResponseEntity<String> ask(@RequestBody String question) { try { return ResponseEntity.ok(sBotService.askQuestion(question)); } catch (Exception e) { return ResponseEntity.badRequest().body("Sorry, I can't process your question right now."); } } }
service
package com.et.rag.service; import dev.langchain4j.chain.ConversationalRetrievalChain; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor @Slf4j public class SBotService { private final ConversationalRetrievalChain chain; public String askQuestion(String question) { log.debug("======================================================"); log.debug("Question: " + question); String answer = chain.execute(question); log.debug("Answer: " + answer); log.debug("======================================================"); return answer; } }
EmbeddingStoreLoggingRetriever
package com.et.rag.retriever; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.retriever.EmbeddingStoreRetriever; import dev.langchain4j.retriever.Retriever; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.util.List; /** * EmbeddingStoreLoggingRetriever is a logging-enhanced for an EmbeddingStoreRetriever. * <p> * This class logs the relevant TextSegments discovered by the supplied * EmbeddingStoreRetriever for improved transparency and debugging. * <p> * Logging happens at INFO level, printing each relevant TextSegment found * for a given input text once the findRelevant method is called. */ @RequiredArgsConstructor @Slf4j public class EmbeddingStoreLoggingRetriever implements Retriever<TextSegment> { private final EmbeddingStoreRetriever retriever; @Override public List<TextSegment> findRelevant(String text) { List<TextSegment> relevant = retriever.findRelevant(text); relevant.forEach(segment -> { log.debug("======================================================="); log.debug("Found relevant text segment: {}", segment); }); return relevant; } }
components
初始化documents
package com.et.rag.configuration; import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.UrlDocumentLoader; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; import static com.et.rag.constant.Constants.SPRING_BOOT_RESOURCES_LIST; @Configuration public class DocumentConfiguration { @Bean public List<Document> documents() { return SPRING_BOOT_RESOURCES_LIST.stream() .map(url -> { try { return UrlDocumentLoader.load(url); } catch (Exception e) { throw new RuntimeException("Failed to load document from " + url, e); } }) .toList(); } }
初始化langchain
package com.et.rag.configuration; import com.et.rag.retriever.EmbeddingStoreLoggingRetriever; import dev.langchain4j.chain.ConversationalRetrievalChain; import dev.langchain4j.data.document.Document; import dev.langchain4j.data.document.splitter.DocumentSplitters; import dev.langchain4j.data.segment.TextSegment; import dev.langchain4j.model.embedding.AllMiniLmL6V2EmbeddingModel; import dev.langchain4j.model.embedding.EmbeddingModel; import dev.langchain4j.model.input.PromptTemplate; import dev.langchain4j.model.openai.OpenAiChatModel; import dev.langchain4j.retriever.EmbeddingStoreRetriever; import dev.langchain4j.store.embedding.EmbeddingStore; import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.time.Duration; import java.util.List; import static com.et.rag.constant.Constants.PROMPT_TEMPLATE_2; @Configuration @RequiredArgsConstructor @Slf4j public class LangChainConfiguration { @Value("${langchain.api.key}") private String apiKey; @Value("${langchain.timeout}") private Long timeout; private final List<Document> documents; @Bean public ConversationalRetrievalChain chain() { EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel(); EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>(); EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder() .documentSplitter(DocumentSplitters.recursive(500, 0)) .embeddingModel(embeddingModel) .embeddingStore(embeddingStore) .build(); log.info("Ingesting Spring Boot Resources ..."); ingestor.ingest(documents); log.info("Ingested {} documents", documents.size()); EmbeddingStoreRetriever retriever = EmbeddingStoreRetriever.from(embeddingStore, embeddingModel); EmbeddingStoreLoggingRetriever loggingRetriever = new EmbeddingStoreLoggingRetriever(retriever); /*MessageWindowChatMemory chatMemory = MessageWindowChatMemory.builder() .maxMessages(10) .build();*/ log.info("Building ConversationalRetrievalChain ..."); ConversationalRetrievalChain chain = ConversationalRetrievalChain.builder() .chatLanguageModel(OpenAiChatModel.builder() .apiKey(apiKey) .timeout(Duration.ofSeconds(timeout)) .build() ) .promptTemplate(PromptTemplate.from(PROMPT_TEMPLATE_2)) //.chatMemory(chatMemory) .retriever(loggingRetriever) .build(); log.info("Spring Boot knowledge base is ready!"); return chain; } }
application.yaml
langchain: api: # "demo" is a free API key for testing purposes only. Please replace it with your own API key. key: demo # key: OPEN_API_KEY # API call to complete before it is timed out. timeout: 30
index.html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Spring Boot Doc Bot</title> <link rel="external nofollow" rel="stylesheet"> <link rel="stylesheet" rel="external nofollow" > </head> <body> <nav class="bg-dark text-white py-3"> <div class="text-center d-flex justify-content-center align-items-center"> <img src="/logo.png" alt="Logo" style="width:60px; margin-right: 10px;"> <h2 style="margin: 0;">Welcome to Spring Boot Documentation Bot</h2> </div> </nav> <div class="container mt-5"> <div class="row"> <div class="col-md-8 offset-2"> <h3 class="text-center mb-3">Ask your Spring related queries here!</h3> <form> <div class="mb-3"> <label for="questionInput" class="form-label">Question</label> <input type="text" class="form-control" id="questionInput" name="question" placeholder="Enter your question" required> </div> <div class="mb-3 text-center"> <button id="submitBtn" type="button" class="btn btn-primary">Ask!</button> <button id="clearBtn" type="button" class="btn btn-secondary">Clear</button> </div> </form> </div> </div> <div class="row my-5"> <div class="col-md-8 offset-md-2"> <label for="answerBox" class="form-label"><h5>Answer</h5></label> <div class="position-relative my-3"> <textarea class="form-control" rows="10" id="answerBox" disabled></textarea> <a href="#" rel="external nofollow" class="position-absolute top-0 end-0 m-2" id="copyBtn"> <i class="far fa-copy"></i> </a> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <script> $(document).ready(function () { $("#submitBtn").click(function () { let questionValue = $("#questionInput").val(); if (!questionValue) { alert('Please enter your question'); return; } $("#answerBox").val('Please wait... fetching answer...'); $.ajax({ type: "POST", url: "/ask", data: JSON.stringify({ question: $("#questionInput").val() }), //contentType: "application/json; charset=utf-8", dataType: "text", success: function (data) { //console.log(typeof data); //console.log(data); $("#answerBox").val(data); }, error: function (errMsg) { alert(errMsg); } }); }); $("#clearBtn").click(function () { $("#questionInput").val(''); $("#answerBox").val(''); }); document.getElementById("copyBtn").addEventListener("click", function() { var copyText = document.getElementById("answerBox"); copyText.select(); copyText.setSelectionRange(0, 99999); document.execCommand("copy"); alert("Copied: " + copyText.value); }); }); </script> </body> </html>
只是一些關(guān)鍵代碼,所有代碼請(qǐng)參見(jiàn)下面代碼倉(cāng)庫(kù)
代碼倉(cāng)庫(kù)
4.測(cè)試
啟動(dòng)Spring Boot應(yīng)用,訪問(wèn)http://127.0.0.1:8080/
5.引用
什么是 RAG?— 檢索增強(qiáng)生成 AI 詳解 — AWS
GitHub - liaokongVFX/LangChain-Chinese-Getting-Started-Guide: LangChain 的中文入門(mén)教程
Spring Boot集成LangChain來(lái)實(shí)現(xiàn)Rag應(yīng)用 | Harries Blog™
到此這篇關(guān)于Spring Boot集成LangChain來(lái)實(shí)現(xiàn)Rag應(yīng)用的文章就介紹到這了,更多相關(guān)Spring Boot集成LangChain Rag應(yīng)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot+websocket實(shí)現(xiàn)并發(fā)搶紅包功能
本文主要介紹了springboot+websocket實(shí)現(xiàn)并發(fā)搶紅包功能,主要包含了4種步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12SpringBoot整合Spring?Boot?Admin實(shí)現(xiàn)服務(wù)監(jiān)控的方法
這篇文章主要介紹了SpringBoot整合Spring?Boot?Admin實(shí)現(xiàn)服務(wù)監(jiān)控,內(nèi)容包括Server端服務(wù)開(kāi)發(fā),Client端服務(wù)開(kāi)發(fā)其中Spring Boot Admin還可以對(duì)其監(jiān)控的服務(wù)提供告警功能,如服務(wù)宕機(jī)時(shí),可以及時(shí)以郵件方式通知運(yùn)維人員,感興趣的朋友跟隨小編一起看看吧2022-03-03Maven項(xiàng)目引用第三方j(luò)ar包找不到類ClassNotFoundException
這篇文章主要為大家介紹了Maven項(xiàng)目引用第三方j(luò)ar包找不到類ClassNotFoundException解決及原因分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07SpringBoot事件機(jī)制相關(guān)知識(shí)點(diǎn)匯總
這篇文章主要介紹了SpringBoot事件機(jī)制相關(guān)知識(shí)點(diǎn)匯總,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09淺談MyBatisPlus中LocalDateTime引發(fā)的一些問(wèn)題和解決辦法
MyBatisPlus進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),我們經(jīng)常會(huì)遇到處理日期時(shí)間類型的需求,本文主要介紹了淺談MyBatisPlus中LocalDateTime引發(fā)的一些問(wèn)題和解決辦法,具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07一文詳解SpringBoot使用Kafka如何保證消息不丟失
這篇文章主要為大家詳細(xì)介紹了SpringBoot使用Kafka如何保證消息不丟失的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考一下2025-01-01java.imageIo給圖片添加水印的實(shí)現(xiàn)代碼
最近項(xiàng)目在做一個(gè)商城項(xiàng)目, 項(xiàng)目上的圖片要添加水?、?添加圖片水印;②:添加文字水印;一下提供下個(gè)方法,希望大家可以用得著2013-07-07