乘风破浪:使用数据湖构建生产级RAG应用

Navigating the Waters: Building Production-Grade RAG Applications with Data Lakes

在2024年中期,创建一个令人印象深刻和兴奋的 AI 演示非常容易。只需要一个优秀的开发者、一些巧妙的提示实验,以及对强大基础模型的一些 API 调用,通常就可以在一个下午内构建一个定制的 AI 机器人。添加像 langchainllamaindex 这样的库来使用 RAG 使用一些自定义数据增强你的 LLM - 一个下午的工作可能会变成一个周末项目。

然而,要投入生产则是另一回事。您将需要一个可靠的、可观察的、可调整的以及在规模上具有高性能的系统。必须超越人为设计的演示场景,并考虑您的应用程序对更广泛的提示范围的响应,这些提示代表了实际客户行为的全部范围。LLM 可能需要访问其预训练数据集通常缺乏的丰富的领域特定知识语料库。最后,如果您将 AI 应用于准确性至关重要的用例,则必须检测、监控和减轻幻觉。

虽然解决所有这些问题似乎令人生畏,但可以通过将基于 RAG 的应用程序分解成其各自的概念部分,然后根据需要采用有针对性和迭代的方法来改进每个部分,从而使其变得更容易管理。这篇文章将帮助您做到这一点。在本文中,我们将专门关注用于创建 RAG 文档处理管道的技术,而不是在检索时发生的那些技术。这样做,我们的目标是帮助生成式 AI 应用程序开发者更好地为从原型到生产的旅程做好准备。

现代数据湖:AI 基础设施的重心

人们常说,在 AI 时代,数据就是你的护城河。为此,构建一个生产级的 RAG 应用程序需要一个合适的数据基础设施来存储、版本化、处理、评估和查询构成您的专有语料库的数据块。由于 MinIO 采用数据优先的方法来处理 AI,因此我们对于此类项目的默认初始基础设施建议是建立一个现代数据湖和一个向量数据库。虽然可能需要沿途插入其他辅助工具,但这两个基础设施单元是基础。它们将成为在将您的 RAG 应用程序投入生产过程中随后遇到的几乎所有任务的重心。

可以在 此处 找到基于 MinIO 构建的现代数据湖参考架构。一篇配套论文展示了这种架构如何支持所有 AI/ML 工作负载,请参阅 此处

一个 RAG 文档处理管道,分阶段更新您的自定义语料库并将其加载到向量数据库中以进行下游检索(未显示检索步骤)。

RAG:文档管道步骤

评估

构建生产级 RAG 应用程序的一个关键早期步骤是建立一个评估框架 - 通常简称为评估。如果没有评估,您将无法可靠地了解您的系统运行情况,不知道哪些组件需要调整,或者无法确定您是否取得了真正的进展。此外,评估充当了澄清您试图解决的问题的强制函数。以下是一些最常见的评估技术

  • 启发式代码评估 - 使用各种指标(如输出标记计数、关键字存在/不存在、JSON 有效性等)以编程方式对输出进行评分。这些通常可以使用正则表达式和断言库进行确定性评估,以进行传统的单元测试。
  • 算法代码评估 - 使用各种知名的数据科学指标对输出进行评分。例如,通过将提示重新表述为排名问题,您可以使用推荐系统中的流行评分函数,例如归一化折损累计增益 (NDCG) 或平均倒数排名 (MRR)。相反,如果可以将提示表述为分类问题,则精度、召回率和 F1 分数可能适用。最后,您可以使用 BLEU、ROUGE 和语义答案相似性 (SAS) 等指标将语义输出与已知的真实情况进行比较。
  • 模型评估 - 使用一个模型对另一个模型的输出进行评分,如 Judging LLM-as-a-Judge 论文中所述。这种技术越来越受欢迎,并且比人工扩展要便宜得多。但是,在项目从原型到生产的初始阶段,可靠地实施它可能很棘手,因为在这种情况下,评估器是一个 LLM,它通常与底层系统本身存在类似的限制和偏差。密切关注该领域的最新研究、工具和最佳实践,因为它们正在迅速发展。
  • 人工评估 - 请人类领域专家提供他们最好的答案通常是黄金标准。尽管此方法缓慢且昂贵,但也不应忽视它,因为它对于获得见解和构建初始评估数据集至关重要。如果您想从执行的工作中获得更多收益,您可以使用 AutoEval Done Right 论文中详细介绍的技术,以合成变体来补充您的人工专家生成的评估。
评估金字塔显示了各种评估类型的推荐分布。越靠近顶部的评估方法在工作量和复杂度方面更高,因此更能反映与真实情况的一致性。越靠近底部的评估方法可以更快、更频繁地运行 - 但只能将其解释为事实准确性的近似值。

除了您关于使用哪些评估技术的决定之外,请考虑创建一个自定义基准评估数据集 - 通常用于 Hugging Face 排行榜上的通用数据集(如 MMLU 数据集)不适用。您的自定义评估数据集将包含各种提示及其理想的响应,这些响应是特定于领域的,并且代表了您的实际客户将输入到您的应用程序中的提示类型。理想情况下,人类专家可以帮助创建评估数据集,但如果不是,请考虑自己动手。如果您对可能出现的提示不确定,只需形成一个操作假设并继续前进,就好像它已经得到验证一样。随着更多数据的可用,您可以稍后不断修改您的假设。

考虑对评估数据集中每一行的输入提示应用约束,以便 LLM 以具体的判断类型进行回答:二元、分类、排名、数值或文本。各种判断类型的组合将使您的评估保持合理的差异性,并减少输出偏差。在其他条件相同的情况下,更多的评估测试用例更好;但是,在此阶段建议关注质量而不是数量。最近关于 LLM 微调的研究(在 LIMA: Less is More For Alignment 论文中)表明,即使只有 1000 行的小型评估数据集也可以显着提高输出质量,前提是它们是真实更广泛人群的代表性样本。对于 RAG 应用程序,我们观察到使用包含几十到数百行的评估数据集可以提高性能。

虽然您可以开始手动和临时运行评估,但不要等到太晚才实现 CI/CD 管道来自动执行评估评分过程。通常认为,每天运行评估或触发与源代码存储库和可观察性工具相关的评估是 ML-ops 的最佳实践。考虑使用像 ragasDeepEval 这样的开源 RAG 评估框架来帮助您快速启动和运行。使用您的数据湖作为包含版本化评估数据集和每次执行评估时生成的各种输出指标的表的真相来源。这些数据将提供有价值的见解,以便您在项目后期使用这些见解进行战略性和高度有针对性的改进。

数据提取器

您最初开始使用原型设计的 RAG 语料库很少足以让您投入生产。您可能需要持续地使用其他数据来增强您的语料库,以帮助 LLM 减少幻觉、遗漏和有问题的偏差类型。这通常是通过构建提取器和加载器逐案进行的,这些提取器和加载器将上游数据转换为可以在下游文档管道中进一步处理的格式。

虽然尝试收集超出所需的数据存在“试图煮沸海洋”的小风险,但至关重要的一点是,要富有创造力,跳出固有思维,思考公司可以访问的优质信息来源。显而易见的可能性包括从公司OLTP和数据仓库中存储的结构化数据中提取见解。公司博客文章、白皮书、已发表的研究和客户支持查询等来源也应予以考虑,前提是它们可以被适当地匿名化并去除敏感信息。很难过分强调将少量高质量的领域内数据添加到语料库中带来的积极性能影响,因此不要害怕花时间探索、实验和迭代。以下是用于引导高质量领域内语料库的一些常用技术。

  • 文档提取 - 专有的PDF、办公文档、演示文稿和Markdown文件可以成为丰富的资讯来源。一个庞大的开源和SaaS工具生态系统存在于提取这些数据。通常,数据提取器是特定于文件类型的(JSON、CSV、docx等)、基于OCR的,或由机器学习和计算机视觉算法驱动。从简单开始,仅在需要时添加复杂性。
  • API提取 - 公共和私有API可以成为丰富的领域内知识来源。此外,设计良好的基于JSON和XML的Web API已经具有一些内置结构,这使得更容易在有效负载中执行相关属性的目标提取,同时丢弃任何被认为无关紧要的内容。一个庞大的经济实惠的低代码和无代码API连接器生态系统存在于帮助你避免为每个你希望使用的API编写自定义ETL,这种方法在没有专门的数据工程师团队的情况下难以维护和扩展。
  • 网页抓取 - 网页被认为是具有树状DOM结构的半结构化数据。如果你知道你要查找的信息是什么、它在哪里以及它所在的页面布局,即使没有完善的API文档,你也可以快速构建一个抓取工具来获取这些数据。许多脚本库和低代码工具存在于为网页抓取提供有价值的抽象。
  • 网页爬虫 - 网页爬虫可以遍历网页并构建递归URL列表。此方法可以与抓取相结合,根据你的标准扫描、总结和过滤信息。在更大的规模上,此技术可用于创建自己的知识图谱。

无论你使用什么数据收集技术,都要抵制构建临时拼凑脚本的冲动。相反,应用数据工程最佳实践将提取器部署为可重复且容错的ETL管道,并将数据存储到数据湖中的表中。确保每次运行这些管道时,关键元数据元素(如源URL和提取时间)都与每段内容一起捕获和标记。元数据捕获对于后续的数据清理、过滤、重复数据删除、调试和归因将证明是无价的。

分块

分块将大型文本样本分解成更小的离散片段,这些片段可以放入LLM的上下文窗口中。虽然上下文窗口越来越大,允许在推理过程中填充更多内容块,但分块仍然是平衡准确性、召回率和计算效率的关键策略。

有效的分块需要选择合适的块大小。较大的块大小倾向于保留文本片段的上下文和语义含义,但代价是允许上下文窗口中存在的总块数更少。相反,较小的块大小将允许更多离散的内容块填充到LLM的上下文窗口中。但是,如果没有额外的防护措施,每个内容片段在从其周围上下文中移除时都存在质量降低的风险。

针对提示“告诉我碧昂斯的职业成就”的不同块大小配置的示例检索结果。

除了块大小之外,你还需要评估各种分块策略和方法。以下是一些需要考虑的标准分块方法。

  • 固定大小策略 - 在此方法中,我们只需为内容块选择固定数量的标记,并相应地将内容分解成更小的块。通常,在使用此策略时建议相邻块之间有一些重叠,以避免丢失太多上下文。这是最直接的分块策略,通常是在进一步冒险到更复杂的策略之前的一个良好起点。
  • 动态大小策略 - 此方法使用各种内容特征来确定块的起始和结束位置。一个简单的例子是标点符号分块器,它根据句点和换行符等特定字符的存在来分割句子。虽然标点符号分块器可能对简单的短内容(例如,推文、字符限制的产品描述等)效果相当好,但如果用于更长和更复杂的内容,它将存在明显的缺点。
  • 内容感知策略 - 内容感知分块器针对正在提取的内容类型和元数据进行调整,并使用这些特征来确定每个块的起始和结束位置。一个例子可能是用于HTML博客的分块器,它使用标题标签来描绘块边界。另一个例子可能是语义分块器,它比较每个句子的成对余弦相似度得分与其前面的邻居,以确定上下文何时发生重大变化,从而保证新块的描绘。

RAG应用程序的最佳分块策略需要针对LLM的上下文窗口长度、底层文本结构、文本长度和语料库中内容的复杂性进行调整。随意尝试各种分块策略,并在每次更改后运行评估,以更好地了解给定策略的应用程序性能。在你的数据湖表中对分块内容进行版本控制,并确保每个块都具有谱系信息,以便将其追溯到原始内容及其来自上游数据提取步骤的相应元数据。

增强

在许多情况下,在RAG期间被索引以供检索的内容块在上下文中与应用程序在生产环境中遇到的实际提示不同。例如,如果你正在构建一个AI问答机器人,你可能拥有一个包含大量针对客户查询的正确答案的专有信息的大型语料库。然而,在其原始形式中,你的语料库不太可能预先组织成问答对的格式,这对于基于相似性的嵌入检索来说是理想的。在此示例中,如果在检索时,我们简单地搜索语料库中与传入客户问题在语义上相似的原始内容块,我们可能会遇到检索结果集的相关性不佳。这是因为我们比较的是上下文不同的项目的相似性,即问题与答案。幸运的是,解决方案相对简单:我们可以利用LLM的功能来丰富我们可能的答案,即原始内容块,方法是将它们重新上下文化为假设问题。然后,我们将这些假设问题索引到我们的向量数据库中,以便后续检索。这种称为假设文档嵌入(HyDE)的技术,说明了使用LLM在文档处理管道中丰富数据的强大功能。以下是如何在来自知名squad_v2数据集的一些内容上使用此技术的示例。

System Prompt: Given the provided snippet of text, generate three hypothetical questions that could be asked about it. Each question must be able to be answered using the information within the referenced snippet of text and only that information. Be concise.

User Prompt: “At the 52nd Annual Grammy Awards, Beyoncé received ten nominations, including Album of the Year for I Am... Sasha Fierce, Record of the Year for "Halo", and Song of the Year for "Single Ladies (Put a Ring on It)", among others. She tied with Lauryn Hill for most Grammy nominations in a single year by a female artist. In 2010, Beyoncé was featured on Lady Gaga's single "Telephone" and its music video. The song topped the US Pop Songs chart, becoming the sixth number-one for both Beyoncé and Gaga, tying them with Mariah Carey for most number-ones since the Nielsen Top 40 airplay chart launched in 1992. "Telephone" received a Grammy Award nomination for Best Pop Collaboration with Vocals.”

Response:  Here are some questions that could be asked based on the provided text:
* How many nominations did Beyoncé receive at the 52nd Annual Grammy Awards?
* For which album was Beyoncé nominated for Album of the Year at the 52nd Annual Grammy Awards?
* Which song earned Beyoncé a nomination for Record of the Year at the 52nd Annual Grammy Awards?

如果使用由长篇和/或主题复杂的内容组成的语料库,请考虑进行额外的预处理以预先总结内容块,从而降低其语义维度。在检索时,你可以查询块摘要的嵌入,然后将非摘要文本替换为上下文窗口插入。此方法在对大型、复杂和/或频繁更改的语料库进行RAG时可以提高相关性。

标记化

2024年的大型语言模型通常是基于Transformer的神经网络,它们本身并不理解书面文字。传入的原始文本会被转换为标记,然后转换为针对矩阵乘法运算优化的高维嵌入向量。此传入过程通常称为编码。反向的输出过程称为解码。许多LLM仅适用于使用其训练时使用的相同标记化方案进行推理。因此,了解所选标记化策略的基础知识至关重要,因为它可能具有许多细微的性能影响。

虽然存在简单的字符和词级标记化方案,但在撰写本文时,几乎所有最先进的LLM都使用子词标记器。因此,我们将只关注此类标记器。

子词标记器将单词递归地分解成更小的单元。这使它们能够理解超出词汇表的单词,而不会过多地增加词汇量,这是训练性能和LLM泛化到未见文本的能力的关键考虑因素。

当今使用的一种流行的子词标记化方法是字节对编码(BPE)。在高层次上,BPE算法的工作原理如下:

  • 将单词拆分为子词单元的标记,并将这些标记添加到词汇表中。每个标记代表一个子词,该子词受训练语料库中常见相邻字符模式的相对频率控制。
  • 用代表该对的单个标记替换上述步骤中的常见标记对,并将其添加到词汇表中。
  • 递归重复上述步骤。

BPE标记化通常是RAG应用程序的绝佳起点,因为它适用于许多用例。但是,假设你拥有大量高度专业化的领域语言,这些语言在所选模型使用的预训练语料库的词汇表中没有得到很好的体现。在这种情况下,请考虑研究替代的标记化方法,或探索微调和低秩自适应,这些方法超出了本文的范围。上述受限词汇表问题可能会表现为针对医学、法律或晦涩编程语言等专业领域构建的应用程序的性能低下。更具体地说,它将普遍存在于包含高度专业化语言/术语的提示中。根据需要,使用存储在数据湖中的评估数据集来试验不同的标记化方案及其与各种模型的相应性能。请记住,标记器、嵌入和语言模型通常是紧密耦合的,因此更改其中一个可能需要更改其他。

结论

构建在MinIO对象存储之上的现代数据湖,为自信地将基于RAG的应用程序投入生产提供了基础设施。有了它,你可以创建评估和特定领域的评估数据集,这些数据集可以存储和版本化到你的数据湖表中。使用这些评估,反复评估并逐步改进RAG应用程序文档管道的每个组件,例如提取器、分块器、增强器和标记器,尽可能多地构建生产级的文档处理管道。

如有任何疑问,请务必在Slack上与我们联系!