JavaAI:LangChain4j学习(四)RAG 检索增强 - 向量数据库

前提:使用LangChain4j + SpringBoot + DashScope通义千问

前言:本文主要用于博主个人学习,内容80%来自于官方文档(英文),一切以官方文档为准

LangChain4j官方文档

系列文章

JavaAI:LangChain4j学习(一) 集成SpringBoot和阿里通义千问DashScope

JavaAI:LangChain4j学习(二)聊天,记忆存储,流式输出

JavaAI:LangChain4j学习(三)AI Service及与SpringBoot结合使用

一、概念

(文本图片来自官方文档)
RAG(Retrieval-Augmented Generation,检索增强生成)是一种在将数据发送到LLM大型语言模型之前,从数据中查找并注入相关信息的方法。这样,LLM将获得(希望获得的)相关信息,并能够利用这些信息进行回复,从而降低产生幻觉(即生成不准确或无关信息)的可能性。

可以使用各种信息检索方法来查找相关信息:

  • 全文(关键字)搜索。此方法利用TF-IDF和BM25等技术,通过匹配查询中的关键字来搜索文档数据库(例如,用户正在询问的内容)。它根据每个文档中这些关键字的频率和相关性对结果进行排名。
  • 向量搜索,也称为“语义搜索”。文本文档使用嵌入模型转换为数字向量。然后,根据余弦相似性或其他相似性/距离度量(如查询向量和文档向量之间的度量)来查找并排序文档,从而捕捉到更深层次的语义含义。
  • 混合搜索。组合多种搜索方法(例如,全文搜索 + 向量搜索)通常会提高搜索效率。

目前,全文搜索和混合搜索仅受Azure AI搜索集成支持,因此本文主要关注向量搜索。

RAG阶段

RAG 过程分两个阶段:索引和检索,LangChain4j 为这两个阶段提供了工具

索引

在索引阶段,对文档进行预处理的方式能够在检索阶段实现高效的搜索。

这一过程可能会因所采用的信息检索方法而有所不同,以向量搜索为例,通常包括清理文档、利用额外数据和元数据对文档进行丰富处理、将文档拆分成更小的段落(即分块)、对这些段落进行嵌入处理,最后将其存储到嵌入存储(即向量数据库)中。

索引阶段通常是在离线状态下进行的,无需最终用户等待其完成。这可以通过定时任务(如cron作业)来实现,例如,该任务可以在周末每周对公司内部文档进行一次重新索引。负责索引的代码也可以作为一个独立的应用程序,仅用于处理索引任务。

然而,在某些情况下,最终用户可能希望上传其自定义文档,以便让LLM能够访问这些文档。在这种情况下,索引操作应该在线执行,并成为主应用程序的一部分。

索引阶段的简化图:
在这里插入图片描述

检索

检索阶段通常是在线进行的,会利用已索引的文档来回答用户提交的问题。

这一过程可能会因所采用的信息检索方法而有所不同。以向量搜索为例,这通常涉及将用户的查询(即问题)进行嵌入处理,然后在嵌入存储中执行相似性搜索。之后将相关句段(即原始文档的片段)注入到提示信息中,并发送给LLM进行处理。

检索阶段的简化图:在这里插入图片描述

二、实践

LangChain4j 提供三种风格的 RAG

Easy RAG:使用 RAG 的最简单方法
自定义 RAG:向量搜索的 RAG 的基本实现
高级 RAG:模块化的 RAG 框架,允许执行 查询转换、多个源检索和重新排名 等

(一) Easy RAG 简易

Easy Rag 可以理解为 “ 快速启动 ” ,使用langchain提供的基础模型,执行简单的基础的功能

1. Document 文件/文档/文本

表示各种格式的文件/文档/文本,例如 PDF、DOC、TXT 、网页等。 未来的更新可能会支持图像和表格(目前不支持吧)。

常用方法
Document.text() 返回Document
Document.metadata() 返回 Metadata 部分
Document.toTextSegment() 将 Document 转为 TextSegment
Document.from(String, Metadata) 根据Text文本内容和Metadata元数据创建Document
Document.from(String) 根据Text文本内容和 空的Metadata 创建Document

2. Metadata 元数据

每个Document都存在Metadata元信息,例如Document的名称、来源、上次更新日期、所有者或其他细节。

存储为键值映射(k - v),其中 key 的类型为 值可以是以下类型之一:Metadata ,String , 其他基础数据类型

Metadata作用在于:

在 LLM 的提示中包含Document的内容时, 还可以包含元数据条目,为 LLM 提供需要考虑的其他信息。 例如,提供名称和来源有助于提高 LLM 对内容的理解。Document
搜索要包含在提示中的相关内容时, 可以按条目进行筛选。 例如,您可以将语义搜索范围缩小到仅 s 属于特定所有者。MetadataDocument
当 的源更新时(例如,文档的特定页面), 可以通过元数据条目(例如,“ID”、“Source”等)轻松找到相应的 并在 中更新它以使其保持同步。DocumentDocumentEmbeddingStore

3. DocumentLoader 文档加载器

根据路径加载文档,感觉跟File没什么区别

4. DocumentParser 文档解析器

用于解析Document

TextDocumentParser解析纯文本格式(e.g. TXT、HTML、MD 等)的文件
ApachePdfBoxDocumentParser解析 PDF 文件
ApachePoiDocumentParser解析 MS Office 文件格式 (DOC、DOCX、PPT、PPTX、XLS、XLSX 等)
ApacheTikaDocumentParser自动检测和解析几乎所有现有的文件格式

5. Embedding 嵌入

Embedding 在NLP语言处理中,可以将 “ 文本内容 ” 处理成为 向量 。

详情可以百度

6. Embedding Model 嵌入模型

接口,特殊类型的模型,将文本转换为Embedding

EmbeddingModel.embed(String) 嵌入给定的文本
EmbeddingModel.embed(TextSegment) 嵌入给定的TextSegment
EmbeddingModel.embedAll(List< TextSegment >) 嵌入所有给定的TextSegment
EmbeddingModel.dimension() 返回此模型生成的Embedding的维度

7. Embedding Store 嵌入数据库

EmbeddingStore可以单独存储 Embedding 或TextSegment

只能按 ID 存储Embedding ,原始嵌入数据可以存储在其他位置并使用 ID 进行关联。

它能够同时存储Embedding已嵌入的文本片段(TextSegment)及其原始数据。

* 个人记忆法

Embedding 记作动词 转换/嵌入,在NLP语言处理中,可以将 “ 文本内容 ” 处理成为 向量。
也记作名词 转换得到的产物 (向量) ,在这里 它一定被转换为向量。

Embedding Model 嵌入模型,记作 向量转换器,可以将 文本信息 转换为 Embedding向量
向量转换器将多个文本转为向量

Embedding Store 嵌入数据库,记作 向量数据库,储存向量的临时集合

流程:创建Embedding Model,将文本转为大量Embedding,将Embedding存入Embedding Store

8. Embedding Store Ingestor 嵌入数据库导入器

EmbeddingStoreIngestor负责将 Document 提取到 EmbeddingStore

示例

EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
        .embeddingModel(embeddingModel)
        .embeddingStore(embeddingStore)
        .build();

ingestor.ingest(document1);
ingestor.ingest(document2, document3);
IngestionResult ingestionResult = ingestor.ingest(List.of(document4, document5, document6));

9. 样例代码

  • 导入依赖项:langchain4j-easy-rag
	<dependency>
	    <groupId>dev.langchain4j</groupId>
	    <artifactId>langchain4j-easy-rag</artifactId>
	    <version>1.0.0-beta2</version>
	</dependency>
  • 加载文档(指定目录中所有文件或指定文件均可,也可以离线地将文本转换为嵌入内容):
    文档加载器 FileSystemDocumentLoader
	List<Document> documents = FileSystemDocumentLoader.loadDocuments("/home/langchain4j/documentation");

如果要加载 所有子目录 的文档,可以使用 loadDocumentsRecursively

	List<Document> documents = FileSystemDocumentLoader.loadDocumentsRecursively("/home/langchain4j/documentation");
  • 文档预处理并存储在向量数据库中,用于用户提出问题时快速找到相关信息
    本质上可以使用任何一个embedding store,这里使用的是Easy RAG 的默认嵌入模型bge-small-en-v1.5

    向量数据库 InMemoryEmbeddingStore
    攫取管道 EmbeddingStoreIngestor,用于将 Document 提取到 EmbeddingStore

	InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
	EmbeddingStoreIngestor.ingest(documents, embeddingStore);
  • 创建AI Service,用作 LLM 的 API
	interface Assistant {
   
   
	
	    String chat(String userMessage);
	}
	
	 ChatLanguageModel model = QwenChatModel.builder()
	           .apiKey(
### Java LangChain4J 0.35 RAG 检索实现 LangChain 是一种用于构建基于大模型的应用程序的框架,而 `langchain4j` 则是其针对 Java 的官方库。通过该库可以轻松集成向量数据库、文档加载器以及大型语言模型 (LLM),从而完成 Retrieval-Augmented Generation (RAG) 流程。 以下是关于如何在 Java 中使用 `langchain4j` 进行 RAG 检索的一个基本教程: #### 准备工作 为了运行此示例,需确保已安装以下依赖项: - Maven 或 Gradle 构建工具。 - 已配置好支持 LLM 和向量存储的服务提供商(如 OpenAI, Pinecone 等)。 #### 添加依赖 如果使用的是 Maven,则需要在项目的 `pom.xml` 文件中添加如下依赖关系[^2]: ```xml <dependency> <groupId>io.langchain</groupId> <artifactId>langchain4j-all</artifactId> <version>0.35.0</version> </dependency> ``` 对于 Gradle 用户,在 `build.gradle` 文件中加入以下内容[^2]: ```gradle implementation 'io.langchain:langchain4j-all:0.35.0' ``` #### 实现代码 下面是一个完整的例子展示如何利用 langchain4j 来执行简单的 RAG 查询操作: ```java import io.langchain4j.document.Document; import io.langchain4j.model.chat.ChatLanguageModel; import io.langchain4j.retriever.VectorStoreRetriever; import io.langchain4j.vectorstore.PineconeVectorStore; public class RagExample { public static void main(String[] args) { // 初始化 Chat Language Model ChatLanguageModel chatLlm = ...; // 替换为实际的语言模型实例 // 创建 Vector Store 并填充数据 PineconeVectorStore vectorStore = new PineconeVectorStore.Builder() .apiKey("your-pinecone-api-key") .environment("us-west1-gcp") .indexName("example-index") .build(); Document doc1 = new Document("This is the content of document one."); Document doc2 = new Document("Another piece of information stored here."); try { vectorStore.addDocuments(List.of(doc1, doc2)); } catch(Exception e){ System.out.println(e.getMessage()); } // 设置 Retriever 配置参数 int kValue = 2; // 返回最相似的结果数量 VectorStoreRetriever retriever = new VectorStoreRetriever(vectorStore); String queryText = "What can you tell me about the documents?"; List<Document> retrievedDocs = retriever.getRelevantDocuments(queryText, kValue); // 使用检索到的内容生成最终响应 StringBuilder contextBuilder = new StringBuilder(); for(Document d : retrievedDocs){ contextBuilder.append(d.getContent()).append("\n"); } String response = chatLlm.generateResponse( "Given this context:\n" + contextBuilder.toString() + "\nAnswer my question:" + queryText)[^3]; System.out.println(response); } } ``` 上述代码片段展示了几个重要部分的功能: 1. **初始化聊天型语言模型** (`ChatLanguageModel`) —— 此处省略具体实现细节,请替换为你所使用的 API 密钥和服务地址。 2. **创建并填充矢量存储** (`PineconeVectorStore`)—— 将两份测试文件存入松果云服务中的指定索引里。 3. **定义检索器对象** (`VectorStoreRetriever`) 及查询逻辑。 4. 调用 LLM 接口生成最终回复消息。 #### 注意事项 - 上述代码仅为演示目的编写;真实环境中应考虑异常处理机制、性能优化等问题。 - 如果计划部署至生产环境,建议仔细阅读官方文档以获取更多高级特性说明[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值