一、LangChain4j实现RAG知识库
Gitee同步(可以加载图片):https://gitee.com/rickkkFang/my-notes/blob/master/72.AI/Learning.md 文章参考:https://javaai.pig4cloud.com/docs/
RAG:Retrieval Augmented Generation(检索增强生成)
1、RAG基础
1.1 什么是 RAG?
检索增强生成(Retrieval-Augmented Generation,简称RAG)是一种结合大型语言模型(LLM)和外部知识库的技术,旨在提高生成文本的准确性和相关性。以下是对RAG的通俗介绍: RAG的基本概念 RAG的核心思想是通过引入外部知识源来增强LLM的输出能力。传统的LLM通常基于其训练数据生成响应,但这些数据可能过时或不够全面。RAG允许模型在生成答案之前,从特定的知识库中检索相关信息,从而提供更准确和上下文相关的回答
1.2 RAG 流程
RAG 过程分为两个阶段:索引(indexing)和检索(retrieval)。LangChain4j 提供了这两个阶段的工具。
索引阶段
在索引阶段,文档经过预处理以便在检索阶段进行高效搜索。对于向量搜索,通常包括清理文档、添加额外数据和元数据、将文档分割为小段(分块),将这些段落嵌入为向量,并存储在嵌入存储(向量数据库)中。
索引通常是离线进行的,可以通过定期任务(如每周重建索引)完成。
用户上传文档 → 文本分割为段落
嵌入模型生成段落向量 → 存入Milvus等向量数据库
搜索时,查询文本被转为向量 → Milvus返回最相似段落
检索阶段
检索阶段通常是在线进行的,当用户提交问题时,从索引的文档中寻找相关信息。对于向量搜索来说,这通常包括将用户的查询嵌入为向量,并在嵌入存储中执行相似性搜索,找到相关的段落并将它们注入提示中,再发送给 LLM。
1.3 Easy RAG
LangChain4j 提供了”Easy RAG”功能,旨在让你快速上手 RAG,无需学习嵌入、选择向量存储或如何解析和分割文档等复杂步骤。只需指向你的文档,LangChain4j 将为你处理大部分细节。
1.导入依赖:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-easy-rag</artifactId>
</dependency>
2.配置存储和Ai service
/**
* 嵌入存储 (简易内存存储)
*
* @return {@link InMemoryEmbeddingStore }<{@link TextSegment }>
*/
@Bean
public InMemoryEmbeddingStore<TextSegment> embeddingStore() {
return new InMemoryEmbeddingStore<>();
}
@Bean
public ChatAssistant assistant(ChatLanguageModel chatLanguageModel, EmbeddingStore<TextSegment> embeddingStore) {
return AiServices.builder(ChatAssistant.class)
.chatLanguageModel(chatLanguageModel)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.contentRetriever(EmbeddingStoreContentRetriever.from(embeddingStore))
.build();
}
3. 向量存储文档
Document document = FileSystemDocumentLoader.loadDocument("/Users/lengleng/Downloads/test.docx");
EmbeddingStoreIngestor.ingest(document,embeddingStore);
4. 测提提问
String result = assistant.chat("合同总金额");
进阶配置
/**
* 这个类负责将文档摄入嵌入存储。
* 它使用各种组件来转换、分割和嵌入文档,然后存储它们。
*/
public class EmbeddingStoreIngestor {
// 将输入文档转换为适合处理的格式
private final DocumentTransformer documentTransformer;
// 将文档分割成更小的段落
private final DocumentSplitter documentSplitter;
// 转换单个文本段落(例如,用于标准化或清理)
private final TextSegmentTransformer textSegmentTransformer;
// 为文本段落生成嵌入向量
private final EmbeddingModel embeddingModel;
// 存储生成的嵌入向量及其对应的文本段落
private final EmbeddingStore<TextSegment> embeddingStore;
}
// 使用构建器模式的示例
EmbeddingStoreIngestor
.builder()
.documentTransformer() // 设置文档转换器
.documentSplitter() // 设置文档分割器
.embeddingModel() // 设置嵌入模型
.embeddingStore() // 设置嵌入存储
.build() // 构建EmbeddingStoreIngestor实例
.ingest(document); // 将文档摄入嵌入存储
1.4 RAG API基础
LangChain4j 是一个强大的 Java 库,提供了丰富的 API 来简化构建自定义 RAG(检索增强生成)管道的过程。本指南将详细介绍 LangChain4j 的主要组件和 API,从简单到复杂的多种管道实现。
1)核心概念
1.Document (文档):Document
类表示一个完整的文档,例如单个 PDF 文件或网页。
主要方法:
Document.text()
: 返回文档的文本内容Document.metadata()
: 返回文档的元数据Document.toTextSegment()
: 将Document
转换为TextSegment
Document.from(String, Metadata)
: 从文本和元数据创建Document
Document.from(String)
: 从文本创建不带元数据的Document
2.Metadata (元数据):Metadata
存储文档的额外信息,如名称、来源、最后更新时间等。
主要方法:
Metadata.from(Map)
: 从Map
创建Metadata
Metadata.put(String key, String value)
: 添加元数据条目Metadata.getString(String key)
/getInteger(String key)
: 获取指定类型的元数据值Metadata.containsKey(String key)
: 检查是否包含指定键Metadata.remove(String key)
: 移除指定键的元数据条目Metadata.copy()
: 复制元数据Metadata.toMap()
: 将元数据转换为Map
3.TextSegment (文本片段):TextSegment
表示文档的一个片段,专用于文本信息。
主要方法:
TextSegment.text()
: 返回文本片段的内容TextSegment.metadata()
: 返回文本片段的元数据TextSegment.from(String, Metadata)
: 从文本和元数据创建TextSegment
TextSegment.from(String)
: 从文本创建不带元数据的TextSegment
4.Embedding (嵌入):Embedding
类封装了一个数值向量,表示嵌入内容的语义含义。
主要方法:
Embedding.dimension()
: 返回嵌入向量的维度CosineSimilarity.between(Embedding, Embedding)
: 计算两个嵌入向量的余弦相似度Embedding.normalize()
: 对嵌入向量进行归一化
2)文档处理
1.Document Loader (文档加载器)
LangChain4j 提供了多种文档加载器:
FileSystemDocumentLoader
: 从文件系统加载文档UrlDocumentLoader
: 从 URL 加载文档AmazonS3DocumentLoader
: 从 Amazon S3 加载文档AzureBlobStorageDocumentLoader
: 从 Azure Blob 存储加载文档GitHubDocumentLoader
: 从 GitHub 仓库加载文档TencentCosDocumentLoader
: 从腾讯云 COS 加载文档
2.Document Parser (文档解析器)
用于解析不同格式的文档:
TextDocumentParser
: 解析纯文本文件ApachePdfBoxDocumentParser
: 解析 PDF 文件ApachePoiDocumentParser
: 解析 MS Office 文件格式ApacheTikaDocumentParser
: 自动检测并解析几乎所有文件格式
示例:
// 加载单个文档
Document document = FileSystemDocumentLoader.loadDocument("/path/to/file.txt", new TextDocumentParser());
// 加载目录下的所有文档
List<Document> documents = FileSystemDocumentLoader.loadDocuments("/path/to/directory", new TextDocumentParser());
3.Document Transformer (文档转换器)
DocumentTransformer
用于对文档执行各种转换,如清理、过滤、增强或总结。
目前提供的转换器:
HtmlToTextDocumentTransformer
: 从 HTML 中提取文本内容和元数据
4.Document Splitter (文档拆分器)
用于将文档拆分成更小的片段,拆分结果为TextSegment
DocumentByParagraphSplitter
: 按段落拆分DocumentBySentenceSplitter
: 按句子拆分DocumentByWordSplitter
: 按单词拆分DocumentByCharacterSplitter
: 按字符拆分DocumentByRegexSplitter
: 按正则表达式拆分
使用步骤:
实例化
DocumentSplitter
并指定TextSegment
的大小和重叠字符数调用
split(Document)
或splitAll(List<Document>)
方法DocumentSplitter
将文档拆分成小片段,并组合为TextSegment
3)嵌入处理
1.Embedding Model (嵌入模型)
EmbeddingModel
接口表示一种将文本转换为 Embedding
的模型。
主要方法:
EmbeddingModel.embed(String)
: 嵌入指定文本EmbeddingModel.embed(TextSegment)
: 嵌入指定TextSegment
EmbeddingModel.embedAll(List<TextSegment>)
: 嵌入多个TextSegment
EmbeddingModel.dimension()
: 返回嵌入向量的维度
2.Embedding Store (嵌入存储)
EmbeddingStore
接口表示一个嵌入存储库(向量数据库),用于存储和高效搜索相似的嵌入。
主要方法:
EmbeddingStore.add(Embedding)
: 添加嵌入并返回随机 IDEmbeddingStore.addAll(List<Embedding>)
: 添加多个嵌入并返回随机 ID 列表EmbeddingStore.search(EmbeddingSearchRequest)
: 搜索最相似的嵌入EmbeddingStore.remove(String id)
: 删除指定 ID 的嵌入
3.Embedding Store Ingestor (嵌入存储摄取器)
EmbeddingStoreIngestor
负责将文档嵌入并存储到 EmbeddingStore
中。
示例:
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(document1);
可以通过指定 DocumentTransformer
和 DocumentSplitter
,在嵌入前对文档进行转换和拆分。
4)构建RAG管道
使用 LangChain4j 构建 RAG 管道的一般步骤:
加载文档: 使用适当的
DocumentLoader
和DocumentParser
加载文档转换文档: 使用
DocumentTransformer
清理或增强文档(可选)拆分文档: 使用
DocumentSplitter
将文档拆分为更小的片段嵌入文档: 使用
EmbeddingModel
将文档片段转换为嵌入向量存储嵌入: 使用
EmbeddingStore
存储嵌入向量检索相关内容: 根据用户查询,从
EmbeddingStore
检索最相关的文档片段生成响应: 将检索到的相关内容与用户查询一起提供给语言模型,生成最终响应
5)最佳实践
根据具体需求选择合适的文档拆分策略
使用自定义的
DocumentTransformer
来清理和增强文档选择合适的嵌入模型和嵌入存储以平衡性能和准确性
定期更新和维护嵌入存储,以确保信息的时效性
对检索结果进行后处理,如重新排序或过滤,以提高相关性
LangChain4j 提供了构建高效 RAG 系统所需的全套工具。通过灵活组合这些组件,可以创建适合特定用例的自定义 RAG 管道。随着项目的发展,不断优化和调整各个组件,以提高系统的整体性能和准确性。