第五章 RAG的工艺流程管道
5.1 工艺流程
我们将汇编 RAG 流程的所有步骤和构建块
RAG 工艺流程示意图
- 文档加载:初始步骤涉及从数据存储加载文档、文本提取、解析、格式化和清理,作为文档拆分的数据准备的一部分。
- 文档分割:接下来,将文档分解为可管理的小片段或块。策略可能包括固定大小的分块和内容感知分块,后者可以理解内容的结构并进行相应的分割。
- 文本嵌入:接下来,使用 Word2Vec、GloVe、BERT、RoBERTa 和 ELECTRA 等技术将这些块转换为向量表示或嵌入。此步骤对于文档块的语义理解至关重要。
- 向量存储:生成的向量(每个向量都与一个唯一的文档块 ID 相关联)存储在向量存储中。在这里,存储的向量被编入索引,以便高效检索。根据所使用的向量存储,这可能涉及创建搜索树或哈希表,或将向量映射到多维空间中的箱体。
- 查询处理:当收到查询时,它也会使用与第三个“文本嵌入”步骤相同的技术将其转换为向量表示。
- 文档检索:检索器使用查询的向量表示,定位并获取语义上与查询最相似的文档块。此检索使用相似性搜索技术执行。
- 文档块获取:然后使用其唯一 ID 从原始存储中检索相关文档块。
- LLM 提示创建:检索到的文档块和查询组合在一起形成 LLM 的上下文和提示。
- 答案生成:在最后一步,LLM 根据提示生成答案,从而结束 RAG 过程。
5.2 文档加载
文本数据是 LLM 的原始材料,其形式多种多样,包括非结构化的纯文本文件 (.txt)、富文档(如 PDF (.pdf) 或 Microsoft Word (.doc、.docx))、以数据为中心的格式(如逗号分隔值 (.csv) 或 JavaScript 对象表示法 (.json))、超文本标记语言 (.html、.htm) 中的 Web 内容、Markdown (.md) 中的文档,甚至用不同语言编写的编程代码(.py、.js、.java、.cpp 等)等等。
准备和加载这些用于 LLM 的各种源的过程通常涉及文本提取、解析、清理、格式化和转换为纯文本等任务。
在协助此过程的工具中,LangChain脱颖而出。这个流行的框架在 LLM 应用程序开发领域得到广泛认可。
它与众不同之处在于其处理 80 多种不同类型文档的出色能力,使其成为一种用途极为广泛的数据加载工具。
LangChain 的数据加载器非常全面,包括用于将不同文档格式转换为 LLM 可以轻松处理的统一格式的转换加载器。此外,它还支持公共数据集加载器(可访问流行且广泛使用的数据集)以及专有数据集或服务加载器(可与私有的(通常是公司特定的)数据源或 API 集成)。
5.3 文件拆分
一旦文档成功加载、解析并转换为文本,文档拆分过程就开始了。此阶段的核心活动是将这些文本分割成可管理的块,这个过程也称为文本拆分或分块。
在处理大量文档时,这一点至关重要。
考虑到许多 LLM 施加的标记限制(例如 GPT-3 的标记限制约为 2048 个),并考虑到文档的潜在大小,文本拆分变得不可或缺。所选的文本拆分方法主要取决于数据的独特性质和要求。
固定大小文本分割的示例,它导致句子作为一个整体阅读时所承载的丰富上下文含义的丢失。在查尔斯·狄更斯的《双城记》著名的开场白中,狄更斯巧妙建立的自然流畅和对比被打乱了。例如,如果没有块 2 中的“时代”,块 1 中的“这是最好的”就会失去其上下文。
同样,如果没有块 5 中的“愚蠢的时代”,块 4 中的“智慧的时代”就不完整。
尽管将这些文档划分为更小、更易于管理的部分的过程看似简单,但这个过程充满了复杂性,可能会对后续步骤产生重大影响。
一种简单的方法是使用固定的块大小,但如果我们这样做,我们最终可能会将一个句子的一部分放在一个块中,而将另一个句子的一部分放在另一个块中,当我们进行问答时,由于两个块被分开,我们将无法从这两个块中获得正确的信息。
因此,在将文档划分为块时,考虑语义至关重要。大多数文档分割算法都基于块大小和重叠的原理。
下面的 是描述此原理的简化图。块大小可以通过字符数、单词数或标记数来衡量,指的是每个段的长度。重叠允许两个相邻块之间共享一部分文本,就像滑动窗口一样。
此策略促进了连续性,并允许一段上下文出现在一个块的末尾和下一个块的开头,从而确保保留语义上下文。
块之间的重叠确保了语义上下文不会在块之间丢失。
固定大小重叠分块是一种简单的方法,由于其简单性和计算效率而受到青睐。除了固定大小分块外,还有更复杂的“内容感知”分块技术:
- 句子分割:句子分块的方法有很多种,包括简单分割(按句号和换行符分割)、使用自然语言工具包 ( NLTK ) 或使用 Python 库spaCy。NLTK和 spaCy 都是强大的自然语言处理 (NLP) 库,可提供将文本分割成句子的有效方法。 一些高级工具使用较小的模型来预测句子结尾,并使用这些点进行句段划分。
- 递归分块:此方法以分层和迭代的方式将输入文本划分为较小的块。它使用不同的分隔符或标准,直到达到所需的块大小或结构。
- 专门的分块技术:对于 Markdown 和 LaTeX 等结构化和格式化的内容,专门的分块技术可以根据内容的结构和层次结构智能地划分内容,从而生成语义连贯的块。
在确定块大小时,如果常见的分块方法不适合您的用例,则以下几点可以指导您选择最佳块大小:
- 预处理数据:在确定应用程序的最佳块大小之前,确保数据质量。例如,如果您的数据是从 Web 检索的,则可能需要删除只会增加噪音的 HTML 标签或特定元素。
- 选择一系列块大小:预处理完数据后,选择一系列潜在的块大小进行测试。此选择应考虑内容的性质、要使用的嵌入模型及其功能(例如令牌限制)。目标是在保留上下文和保持准确性之间找到平衡。
- 评估每个块大小的性能:使用代表性数据集,为要测试的块大小创建嵌入。运行一系列查询,评估质量,并比较各种块大小的性能。此过程很可能是迭代的。
总之,文档拆分没有一刀切的解决方案,适用于一个用例的方法可能不适用于另一个用例。本节应该有助于直观地了解如何针对特定应用程序进行文档分块。
5.4 文本嵌入
在文档拆分过程之后,文本块会转换为矢量表示,以便轻松比较语义相似性。这种“嵌入”对每个块进行编码,使相似的块在矢量空间中聚集在一起。
将文本块转换为矢量表示
向量嵌入是现代机器学习 (ML) 模型不可或缺的一部分。它们涉及将数据从复杂的非结构化形式(如文本或图像)映射到数学空间(通常维度较低)中的点。
这个数学空间或向量空间可以实现高效计算,而且至关重要的是,这个空间中的空间关系可以捕捉原始数据的有意义特征。例如,在文本数据的情况下,嵌入可以捕捉语义信息。即使措辞不同,传达相似含义的文本也会映射到嵌入空间中的近点。
举例来说,“猫追老鼠”和“猫科动物追赶啮齿动物”这两个句子可能具有不同的表面形式,但它们的语义内容非常相似。
训练有素的文本嵌入模型会将这些句子映射到嵌入空间中的近似点。
文本嵌入的可视化可以直观地了解其工作原理。在嵌入空间的二维或三维表示中,相似的单词或句子聚集在一起,表明它们的语义接近性。例如,“狗”、“猫”、“宠物”的嵌入可能比“汽车”的嵌入更接近彼此,如下图所示。
向量空间中分组的相似词
生成这些嵌入需要复杂的 ML 模型。最初,Word2Vec和GloVe等模型通过学习捕捉许多有用语义关系的单词级嵌入取得了长足进步。这些模型本质上是孤立地处理单词,从大型文本语料库中的共现统计数据中学习。
目前最先进的技术已经转向基于 Transformer 的模型,例如 BERT、RoBERTa、ELECTRA、T5、GPT 及其变体,这些模型可以生成上下文感知的嵌入。与之前的模型不同,这些 Transformer 在为单词或句子生成嵌入时会考虑整个句子的上下文。
这种上下文感知可以更丰富地捕获语义信息和解决歧义问题。
例如,“我坐在河岸边”和“我把钱存入银行”中的“银行”一词具有不同的含义,这些含义可以通过基于 Transformer 的模型中的不同嵌入来捕获。
这种基于 Transformer 的模型是 NLP 最新进展的核心,包括 RAG。在 RAG 中,基于 Transformer 的模型用于从大量文档中检索相关信息(“检索”部分),并使用它来生成详细的响应(“生成”部分)。
Transformer 模型生成的高质量嵌入对于此过程至关重要,既可以检索语义相关的文档,也可以生成连贯且适合上下文的响应。
5.5 向量存储
将文档分割成语义上有意义的块并随后转换为向量空间后,生成的嵌入将存储在向量存储中。
向量存储是唯一的搜索数据库,旨在实现向量搜索并处理存储和向量管理的某些方面。
本质上,向量存储是一个允许直接查找相似向量的数据库。RAG 模型的有效执行需要有效的向量存储或索引来容纳转换后的文档块及其关联的 ID。
向量存储的选择取决于许多变量,例如数据规模和计算资源。一些值得注意的向量存储是:
- FAISS:由 Facebook AI 开发的 FAISS 库以高效管理大量高维向量以及在高维环境中执行相似性搜索和聚类而闻名。它采用了旨在优化内存使用和查询持续时间的高级方法,即使在处理数十亿个向量时也能熟练地存储和检索向量。
- SPTAG:SPTAG是微软的产品,是专门为高维数据量身定制的库,提供多种索引和搜索算法类型,可根据具体需求在精度和速度之间取得平衡。
- Milvus:Milvus 是一个开源向量数据库,在数据科学和机器学习领域享有盛誉。它通过尖端算法实现了强大的向量索引和查询功能,即使在大量数据集的情况下,也可以快速检索可比较的向量。Milvus 广受好评的一个因素是它与 PyTorch 和 TensorFlow 等成熟框架兼容,从而能够顺利过渡到现有的机器学习工作流程。
- Chroma:Chroma 是一个开源轻量级内存向量数据库,专门为帮助各种规模的开发人员和组织创建 LLM 应用程序而量身定制。它为高维向量的存储、搜索和检索提供了一个高效、可扩展的平台。Chroma 广受欢迎的一个关键因素是其多功能性。它提供云端和本地部署选项,可满足不同的基础设施需求。此外,它对各种数据类型和格式的支持增强了其在各种应用程序中的实用性。
- Weaviate:Weaviate 是一个强大的开源矢量数据库,专为自托管或全托管服务而设计。这个多功能平台为组织提供了一种管理和处理数据的高级解决方案,重点是高性能、可扩展性和可访问性。无论选择哪种部署策略,Weaviate 都具有全面的功能和灵活性,可适应各种数据类型和应用程序。Weaviate 的一个重要特性是它能够存储矢量和对象,这使其有利于需要融合不同搜索技术的应用程序,例如基于矢量和基于关键字的搜索。
- Elasticsearch:这是一个分布式、RESTful 搜索和分析引擎,可高效存储和搜索高维向量。它的可扩展性和处理海量数据的能力使其适合大规模应用程序。
- Pinecone:Pinecone 于 2021 年初推出,是一款基于云的托管矢量数据库,专门用于简化企业和组织大规模 ML 应用程序的开发和部署。与许多流行的矢量数据库不同,Pinecone 使用专有的闭源代码。它对高维矢量数据库的强大支持使 Pinecone 适用于各种应用,包括相似性搜索、推荐系统、个性化和语义搜索。它还拥有单级过滤功能。此外,它执行实时数据分析的能力使其成为网络安全领域威胁检测和网络攻击监控的最佳选择。Pinecone 还促进了与各种系统和应用程序的集成,包括但不限于 Google Cloud Platform、Amazon Web Services (AWS)、OpenAI、GPT-3、GPT-3.5、GPT-4、ChatGPT Plus、Elasticsearch、Haystack 等。
通过选择正确的文本嵌入技术和向量存储,可以建立一个高效且有效的文档块索引系统。这样的系统可以快速检索任何查询的最相关块,这是 RAG 中至关重要的一步。
5.6 文档检索
检索过程是任何信息检索系统(例如用于文档搜索或问答的系统)不可或缺的一部分。检索过程从收到查询开始,并使用与文档索引相同的嵌入模型将其转换为向量表示。
这会产生用户问题的语义上有意义的表示,随后可以将其与索引中存储的文档的块向量(也称为向量存储)进行比较。
检索的主要目的是返回与收到的查询相对应的相关文档块。相关性的具体定义取决于所使用的检索器类型。
检索器不需要存储文档;其唯一目的是检索相关文档块的 ID,从而通过识别可能包含相关信息的块来帮助缩小搜索空间。
检索相关文档块
检索器可以采用不同类型的搜索机制。
例如,“相似性搜索”基于余弦相似性识别与查询相似的文档。如果向量存储支持,另一种搜索类型,即最大边际相关性 (MMR),将非常有用。
这种搜索方法可确保检索到不仅与查询相关而且多样化的文档,从而消除冗余并增强检索结果的多样性。相比之下,“相似性搜索”机制仅考虑语义相似性。
RAG 还采用了相似度得分阈值检索方法。此方法设置相似度得分阈值,仅返回得分超过该阈值的文档。在搜索相似文档时,通常使用“k”参数指定要检索的前“k”个文档。
还有另一种类型的检索,称为自查询或 LLM 辅助检索。这种类型的检索在处理不仅涉及我们想要在语义上查找的内容,而且还包括一些用于过滤的元数据的问题时特别有用。
LLM 可以有效地将查询拆分为搜索和过滤词。大多数向量存储都可以促进元数据过滤器,以帮助根据特定元数据过滤记录。本质上,LLM 辅助检索将预训练语言模型的功能与传统检索方法相结合,提高了文档检索的准确性和相关性。
另一个重要的检索方法是压缩,旨在减小索引文档或嵌入的大小,从而提高存储效率和检索速度。此过程涉及压缩 LLM 检查所有文档并提取与最终 LLM 最相关的文档。
虽然这种技术涉及进行更多 LLM 调用,但它也有助于将最终答案集中在最重要的方面。这是一个需要考虑的必要权衡。在处理大型文档集时,检索中的压缩尤其重要。压缩方法的选择取决于多种因素,包括特定的检索系统、文档集的大小、可用的存储资源以及存储效率和检索速度之间的首选平衡。
使用压缩 LLM 提取最相关的块
还值得注意的是,存在其他不涉及向量数据库的检索方法,而是使用更传统的 NLP 技术,例如支持向量机 ( SVM ) 和词频-逆文档频率 ( TF-IDF )。但是,这些方法并不常用于 RAG。
5.7 答案生成
在最后阶段,将确定为相关的文档块与用户查询一起使用,为 LLM 生成上下文和提示。此提示(图 15)本质上是一个精心构建的问题或陈述,可指导 LLM 生成既相关又有见地的答案。
包含相关上下文文档和问题的提示示例
默认情况下,我们会在单个 LLM 调用中将所有块集中到同一个上下文窗口中。在 LangChain 中,这种方法称为“Stuff”方法,它是问答的最简单形式。
它遵循一种简单的方法,即处理提示,并根据 LLM 理解立即返回答案。“Stuff”方法不涉及任何中间步骤或复杂算法,非常适合需要直接答案的简单问题。
然而,在处理大量文档时会出现限制,因为在上下文窗口中容纳所有文档可能不切实际,这可能会导致在面对复杂查询时缺乏深度。
尽管如此,还是有几种不同的方法可以解决上下文窗口短的问题,例如:“Map-reduce”、“Refine”和“Map-rerank”。
Map-reduce 方法的灵感来自广受欢迎的并行处理范式,其工作原理是首先将每个文档单独发送到语言模型以获得单独的答案。
然后通过对 LLM 的最终调用将这些单独的响应组合成最终响应。虽然这种方法需要与语言模型进行更多交互,但它具有处理任意数量文档块的明显优势。
这种方法对于复杂查询特别有效,因为它能够同时处理问题的不同方面,从而生成更全面的响应。然而,这种方法并非没有缺点。
它往往较慢,在某些情况下可能会产生次优结果。例如,由于响应基于单个文档块,因此可能没有基于给定文档块的明确答案。
因此,如果相关信息分散在两个或多个文档块中,则可能缺乏必要的上下文,从而导致最终答案可能不一致。
问答系统的 Map-Reduce 链类型
优化方法采用迭代方法。它通过迭代更新提示中的相关信息来优化答案。它在动态和不断发展的环境中特别有用,因为第一个答案可能不是最好的或最准确的。
优化问答链类型
Map-rerank 方法是一种复杂的方法,它根据检索到的文档与查询的相关性对其进行排序。这种方法非常适合存在多个合理答案的情况,并且需要根据其相关性或质量对它们进行优先排序。
问答系统的 Map-rerank 链式结构
5.8 总结:
上述每种方法都有各自的优势,可以根据问答所需的抽象程度进行选择。总之,不同类型的问答为从文档中检索和提取答案提供了灵活性和定制选项。它们可用于提高语言模型提供的答案的准确性和相关性。
RAG 流程中所有这些步骤的成功相互作用可以产生一个高效的系统,用于自动化文档处理并对各种查询生成有见地的响应。
RA/SD 衍生者AI训练营。发布者:chris,转载请注明出处:https://www.shxcj.com/archives/6909