Advertisement

第8章:LangChain检索增强生成RAG--2.1Easy RAG实现

阅读量:

该库提供了名为“Easy RAG”的功能模块,在最大限度地降低了RAG的门槛的同时帮助用户快速上手


Easy RAG

注意 :Easy RAG 的质量当然会低于定制化的 RAG 设置。然而,这是开始学习 RAG 或构建概念验证(Proof of Concept)的最简单方式。之后,你可以平滑地从 Easy RAG 过渡到更高级的 RAG,逐步调整和定制更多方面。

步骤 1:导入依赖

复制代码
    <dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-easy-rag</artifactId>
    <version>1.0.0-beta1</version>
    </dependency>

步骤 2:加载文档

复制代码
    List<Document> documents = 
    FileSystemDocumentLoader.loadDocuments("/home/langchain4j/documentation");

这将加载指定目录中的所有文件。

1. 幕后发生了什么?

支持多种文件格式的 Apache Tika 库可被用来识别文件类型并解析其内容。

未明确指定文档解析器时,默认选择 DocumentParser

会使用 FileSystemDocumentLoader 加载 ApacheTikaDocumentParser 解析器。

通过 SPI 接口由 langchain4j-easy-rag 提供支持。

2. 如何自定义加载文档?

如果想要从指定目录中获取所有子目录下的文件,请使用loadDocumentsRecursively方法

复制代码
    List<Document> documents = 
    FileSystemDocumentLoader.loadDocumentsRecursively("/home/langchain4j/documentation");

此外,你还可以使用全局符号或正则表达式检索文档

复制代码
    PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:*.pdf");
    List<Document> documents = FileSystemDocumentLoader
                .loadDocuments("/home/langchain4j/documentation", pathMatcher);

注意 :使用加载文档递归方法时,可能需要在glob: glob:**.pdf中使用双星号(而不是单号)。

步骤 3:预处理并存储文档

目前而言,在一个专门的嵌入存储中进行文档预处理并将其存储起来是一项必要操作。当用户向系统提出查询时,在快速检索相关信息方面具备高效能力是系统设计的基本需求之一。我们可以从支持该功能的各种嵌入索引方案中选择其中一种方案更为灵活;出于简化系统架构的目的,在本项目中我们决定采用内存中的数据缓存方案。

复制代码
    InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
    EmbeddingStoreIngestor.ingest(documents, embeddingStore);

这一步将文档分割成小片段,嵌入为向量,并存储在内存中的嵌入存储中。

幕后发生了什么?

The EmbeddingStoreIngestor utilizes the SPI (Service Provider Interface) from the langchain4j-easy-rag dependency to acquire a splitter, which is responsible for breaking down documents into smaller segments known as **TextSegments». Each document is divided into portions, with each segment containing a maximum of 300 tokens and overlapping with adjacent segments by up to thirty tokens.

EmbeddingStoreIngestor 还借助 SPI 从 langchain4j-easy-rag 依赖项中引入了一个 EmbeddingModel。每个 TextSegment 都被 EmbeddingModel 转换成一个嵌入(Embedding)。

注意: 我们为 Easy RAG 选择了 bge-small-en-v1.5 作为默认的嵌入模型。这个模型在 MTEB 排行榜上取得了令人印象深刻的分数,其量化版本仅占用 24MB 的空间。因此,我们可以轻松地将其加载到内存中,并使用 ONNX Runtime在同一进程中运行。

你可以在完全离线状态下,在同一 JVM 环境中实现文本到嵌入的转换,并不需要任何外部服务的支持。LangChain4j 包含了五种经典的嵌入模型,并且方便直接调用这些模型。所有的 TextSegment-Embedding 实例都被存储在 EmbeddingStore 中。


对此进行详细阐述如下:该系统如何在易用性检索增强模式中对文件进行处理并实现其编码?以下将重点阐述其核心环节与技术实现细节。

文档分割(Document Splitting)

以下是按照要求对原文进行同义改写的文本

输出结束

嵌入模型(Embedding Model)

  • EmbeddingModel :该模型通过将文本片段生成向量表示来进行处理。其默认采用的是 bge-small-en-v1.5 模型,在性能与资源消耗方面实现了良好的平衡。

模型特点

  1. 基于 MTEB(Multilingual Text Embedding Benchmark)评估标准表现出色。
  2. 该量化版本仅需 24MB 内存空间即可完美适应内存环境。
  3. ONNX Runtime 并行于同一 JVM 进程运行可完全独立于第三方服务。

离线嵌入(Offline Embedding)

  • 全盘离线处理:LangChain4j 能在本地 JVM 进程内实现文本到嵌入的转换,并且不需要依赖外部服务的支持。这种做法不仅增强了安全性,还降低了对外部网络资源的依赖.
    • 预先配置好的模型:LangChain4j 提供了五种常见的嵌入模型,用户可以直接使用这些现成的模型,无需额外训练或配置设置.

嵌入存储(EmbeddingStore)

改写说明


步骤 4:创建 AI Service

复制代码
    interface Assistant {
    String chat(String userMessage);
    }
    
    ChatLanguageModel chatModel = OpenAiChatModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName(GPT_4_O_MINI)
    .build();
    
    Assistant assistant = AiServices.builder(Assistant.class)
    .chatLanguageModel(chatModel)
    .chatMemory(MessageWindowChatMemory.withMaxMessages(10))
    .contentRetriever(EmbeddingStoreContentRetriever.from(embeddingStore))
    .build();

步骤 5:开始对话

复制代码
    String answer = assistant.chat("How to do Easy RAG with LangChain4j?");

总结

根据前面提到的步骤,能够实现一个基础的RAG模型,并考虑升级其高级功能,请保持关注后续文章更新

导读说明:
这是LangChain开发智能体的系列文档,欢迎连读

全部评论 (0)

还没有任何评论哟~