LangChain4j学习(四)RAG 检索增强 - 向量数据库
前提:使用LangChain4j + SpringBoot + DashScope通义千问
前言:本文主要用于博主个人学习,内容80%来自于官方文档(英文),一切以官方文档为准
系列文章
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(

最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



