现在已经收集了测试文档和查询,并在准备阶段进行了文档分析,下一阶段就是分块。 将文档分解成大小合适的区块集合,其中每项都包含语义相关的内容,是成功实施检索增强生成 (RAG) 的关键因素。 传递整个文档或超大区块的成本高昂,可能会使模型的令牌限制不堪重负,并且不会产生最佳结果。 将信息传递给与查询无关的语言模型可能会导致幻觉。 你需要优化传递相关信息和删除不相关的信息的过程。 你可以使用有效的分块和搜索策略来进行此优化,以最大限度地减少假正和假负,并最大限度地增加真正和真负。
如果传递的区块太小并且未包含足够的上下文来处理查询,也会导致结果不佳。 可能无法捕获到存在于多个区块中的相关上下文。 技巧在于针对特定文档类型及其结构和内容实施有效的分块方法。 有多种分块方法可供考虑,而每种方法都有各自的成本影响和效果,具体取决于所应用的文件类型和结构。
本文介绍了各种分块方法,并探讨了文档结构如何影响分块方法的选择。
本文是一系列文章的其中一篇。 阅读简介。
分块经济效益
在确定总体分块策略时,必须考虑预算以及文档语料库的质量和吞吐量要求。 设计和实施每种独特的分块方法都需要耗费工程成本,而每份文档的处理成本也因方法而异。 如果文档已嵌入或链接媒体,则必须考虑处理这些元素的经济性。 对于分块,此处理通常使用语言模型来生成媒体的说明,然后对这些说明进行分块。 某些媒体的替代方法是在推理时按原样将它们传递给多模式模型,但这种方法不会影响分块经济学。
本部分介绍分块图像和整体解决方案的经济性。
图像分块经济效益
使用语言模型生成图像的说明然后进行分块会产生成本。 例如,Azure OpenAI 等基于云的服务可以按每笔交易基本收费,也可以按预付费配置收费。 较大的图像会产生更大的成本。 通过文档分析,你应该确定哪些图像对分块有价值以及哪些图像应该忽略。 从那里,你需要了解解决方案中图像的数量和大小,并且应该权衡分块图像描述的价值与生成这些描述的成本。
确定要处理的图像的一种方法是使用 Azure AI 视觉等服务对图像、标记图像或执行徽标检测进行分类。 然后,可以使用结果和置信度指示器来确定图像是否添加了有意义的上下文值,并应进行处理。 对 Azure AI 视觉的调用可能比对语言模型调用的成本更低,因此这种方法可能会节省成本。 你需要进行试验以确定哪些置信度以及哪些分类或标记为数据提供最佳结果。 另一种选择是生成自己的分类器模型。 你需要考虑到生成、托管和维护自己的分类器模型的成本。
另一种成本优化是使用缓存端模式进行缓存。 你可以根据图像的哈希生成密钥。 第一步,可以查看之前运行或以前处理的文档是否有缓存结果。 如果执行此操作,可以使用该结果。 这种方法可以避免调用分类器或语言模型的成本。 如果没有缓存,当你调用分类器或语言模型时,你将缓存结果。 将来对该图像的调用将会使用缓存。
集成所有这些成本优化流程的简单工作流程如下:
- 检查图像处理是否已缓存。 如果已缓存,请使用缓存的结果。
- 运行分类器以确定你是否应处理映像。 缓存分类结果。 仅当分类逻辑告知你执行此操作时,才继续。
- 生成映像的说明。 缓存结果。
整体解决方案的经济性
在考虑整体解决方案的成本时,需要着眼以下因素:
- 独特的分块实施数量 - 每种独特的实施都会产生工程和维护成本。 你需要考虑语料库中独特文档类型的数量,以及每种类型独特实现的成本与质量的权衡。
- 每个实现的每个文档成本 - 某些分块方法可能会产生质量更好的分块,但生成这些分块的经济和时间成本较高。 例如,在 Azure AI 文档智能中使用预生成模型的单个文档成本可能高于纯文本解析实现,但可能带来质量更好的区块。
- 初始文档数 - 启动解决方案时需要处理的初始文档数。
- 增量文档数 - 为持续维护系统而必须处理的新文档的数量和速率。
加载和分块
从逻辑上讲,在分块期间,必须先以某种格式将文档加载到内存中。 然后,分块代码针对文档的内存中表示形式进行操作。 你可以选择将加载代码与分块合并,也可以将加载分离到其自己的阶段。 你选择的方法在很大程度上应基于体系结构约束和偏好。 本节简要探讨这两种选择,然后为你提供一些一般性建议。
单独加载和分块
你可能出于多种原因选择分离加载阶段和分块阶段。 你可能需要在加载代码中封装逻辑。 你可能希望在分块之前保留加载代码的结果,尤其是在尝试各种分块排列以节省处理时间或成本时。 最后,出于体系结构原因(例如进程批量处理或涉及删除 PII 的安全分段),你可能希望在单独的进程中运行加载和分块代码。
在加载代码中封装逻辑
你可以选择在加载阶段封装预处理逻辑。 这简化了分块代码,因为它不需要进行任何预处理。 预处理可以像删除或注释文档中确定要在文档分析中忽略的部分一样简单,例如水印、页眉和页脚或重新格式化文档的复杂部分。 以下是你可能选择在加载阶段封装的一些预处理示例:
- 删除或注释要忽略的项。
- 将图像引用替换为图像说明。 在此阶段,你将使用 LLM 为图像生成说明,并使用该说明更新文档。 如果在文档分析中确定周围的文本为图像提供了有价值的背景信息,请将其连同图像一起传递给 LLM。
- 将图像下载或复制到 Azure Data Lake 等文件存储,以便与文档文本分开处理。 如果你在文档分析中确定周围的文本为图像提供了有价值的背景信息,则需要将该文本与图像一起存储在文件存储中。
- 重新格式化表,使其更易于处理。
保留加载代码的结果
有多种原因可以选择保留加载代码的结果。 其中一个原因是你希望在文档加载和预处理之后、但在分块逻辑运行之前检查文档。 另一个原因是你可能希望在开发或生产过程中针对相同的预处理代码运行不同的分块逻辑。 持久化加载的代码可以加速这一过程。
在单独的进程中运行加载和分块代码
将加载和分块代码分成不同的进程有助于针对相同的预处理代码运行多个分块实现。 这种分离还允许你在不同的计算环境和不同的硬件上运行加载和分块代码。 此外,此设计允许你独立缩放用于加载和分块的计算。
合并加载和分块
在大多数情况下,合并加载和分块代码是更简单的实现。 你可能考虑在单独的加载阶段的预处理中执行的许多操作都可以在分块阶段完成。 例如,分块逻辑可以调用 LLM 来获取文本描述并对描述进行分块,而不是在加载阶段用描述替换图像 URL。
当你拥有像 HTML 这样的包含图像引用的标签的文档格式时,你需要确保分块代码使用的读取器或解析器不会删除标签。 分块代码需要能够识别图像引用。
建议
在确定是合并还是分离分块逻辑时,需要考虑以下一些建议。
- 首先结合加载和分块逻辑。 解决方案需要时将它们分开。
- 如果选择分隔进程,请避免将文档转换为中间格式。 诸如此类的操作可能会导致损失。
分块方法
本部分概述了一些常见的分块方法。 此列表并非详尽无遗,而是一些常见的代表性方法。 可以在实现中使用多种方法,例如结合使用语言模型来获取图像的文本表示形式和列出的许多方法。
每种方法都附有一个汇总的决策矩阵,其中突出显示了工具、相关成本等。 工程工作量和处理成本较为主观,列入其中是为了进行相对比较。
基于句子的解析
这种直截了当的方法将文本文档分解成由完整句子组成的区块。 这种方法的优点包括实现成本低、处理成本低,而且可以应用于任何以文本或完整句子编写的基于文本的文档。 这种方法面临的一个挑战是,每个区块可能无法捕获到思想或含义的完整上下文。 通常情况下,必须将多个句子放在一起才能捕获到语义含义。
工具:SpaCy 句子标记器、LangChain 递归文本拆分器、NLTK 句子标记器
工程工作量:低
处理成本:低
用例:以文本或完整句子编写的非结构化文档,而文档语料库包含的不同文档类型数量过多,无法为其生成单独的分块策略
示例:用户生成的内容,如来自调查、论坛帖子、评论、电子邮件、小说或论文的开放式反馈
固定大小解析(有重叠)
这种方法会根据固定数量的字符或标记将文档分成若干区块,并允许各区块之间的字符存在部分重叠。 这种方法与基于句子的解析有许多相同的优缺点。 与基于句子的解析相比,这种方法的优势在于可以获得语义跨越多个句子的区块。
必须选择区块的固定大小和重叠量。 由于不同文档类型的结果不同,因此最好使用 HuggingFace 区块可视化工具等工具来进行探索性分析。 通过此类工具,就可以根据自己的决策来直观显示文档的分块方式。 在使用固定大小的解析时,最好使用 BERT 标记而不是字符数。 BERT 标记基于有意义的语言单位,因此比字符数保留了更多语义信息。
工具:LangChain 递归文本拆分器、Hugging Face 区块可视化工具
工程工作量:低
处理成本:低
用例:以文本或非文本形式编写的非结构化文档,句子完整或不完整。 文档语料库中包含大量不同类型的文档,要为它们建立单独的分块策略,难度令人望而却步
示例:用户生成的内容,如来自调查、论坛帖子、评论、电子邮件、个人或研究笔记或列表的开放式反馈
自定义代码
这种方法使用自定义代码来解析文档,从而创建文档区块。 这种方法最适用于已知结构或可推断结构的文本文档,而且需要对区块的创建加以高度控制。 可以使用正则表达式等文本解析技术,根据文档结构中的模式来创建区块。 目标是创建长度相似的区块,以及具有不同内容的区块。 许多编程语言都支持正则表达式,有些语言的库或包还提供更完美的字符串操作功能。
工具:Python(re、regex、BeautifulSoup、lxml、html5lib、marko)、R(stringr、xml2)、Julia (Gumbo.jl)
工程工作量:中
处理成本:低
用例:可推断结构的半结构化文件
示例:专利申请、研究论文、保险单、脚本和剧本
语言模型扩充
语言模型可用于创建区块。 常见的用例是使用大型语言模型(如 GPT-4)来生成图像的文本表述或表格摘要,而这些表述或摘要可用作区块。 语言模型扩充与其他分块方法(如自定义代码)一起使用。
如果在文档分析部分的 图像部分确定, 图像前后的文本需要回答一些问题,则需要将此附加上下文传递给语言模型。 请务必进行试验,以确定此附加上下文是否能够提高解决方案的性能。
如果分块逻辑将映像说明拆分为多个区块,请确保在每个区块中都包含映像 URL。 在每个区块中包含图像 URL 可确保为图像提供的所有查询返回元数据,尤其是对于最终用户需要能够通过该 URL 访问源图像或在推断时间使用原始图像的情况。
工具:Azure OpenAI、OpenAI
工程工作量:中
处理成本:高
用例:图像、表格
示例:生成表格和图像的文本表示形式,总结会议、演讲、访谈或播客的记录内容
文档布局分析
文档布局分析库和服务将光学字符识别 (OCR) 功能与深度学习模型相结合,以提取文档的结构和文本。 结构元素包括页眉、页脚、标题、章节标题、表格和图片。 其目标是为文档中包含的内容提供更好的语义含义。
文档布局分析库和服务提供了一个代表文档内容(包括结构和文本)的模型。 仍然需要编写与模型交互的代码。
注意
Azure AI 文档智能是一项基于云的服务,需要将文档上传到服务中。 需要确保安全性和合规性法规允许将文档上传到此类服务。
工具:Azure AI 文档智能文档分析模型、圆环图、布局解析器
工程工作量:中
处理成本:中
用例:半结构化文档
示例:新闻文章、网页、简历
预生成模型
诸如 Azure AI 文档智能等服务提供预生成模型,可以利用这些模型来处理各种文档类型。 一些模型针对特定的文档类型(如美国税务 W-2 表单)进行训练,而另一些模型则针对更广泛的文档类型(如发票)。
工具:Azure AI 文档智能预生成模型、Power Automate 智能文档处理、LayoutLMv3
工程工作量:低
处理成本:中/高
用例:存在预生成模型的结构化文档
具体示例:发票、收据、医疗保险卡、W-2 表单
自定义模型
对于不存在预生成模型的高度结构化文档,可能需要生成一个自定义模型。 这种方法对于高度结构化的图像或文档很有效,因为它们很难使用文本解析技术。
工具:Azure AI 文档智能自定义模型、Tesseract
工程工作量:高
处理成本:中/高
用例:不存在预生成模型的结构化文档
示例:汽车维修和保养时间表、成绩单和记录、技术手册、操作程序、保养指南
文档结构
文档的结构数量各不相同。 有些文档(如政府表格)的结构复杂且众所周知,如 W-2 美国税务文件。 另一类是非结构化文档,如自由形式的笔记。 文档类型的结构程度是确定有效分块方法的良好起点。 虽然没有硬性规定和快速规则,但本部分提供了一些可遵循的准则。
图 1. 分块方法适合文档结构
结构化文档
结构化文档(有时也被称为固定格式文档)具有确定的布局。 这些文档中的数据位于固定位置。 例如,日期或客户姓氏在格式固定的每份文档中都位于相同的位置。 固定格式文档的示例包括 W-2 美国税务文档。
固定格式文件可能是原始文件的扫描图像,它们要么是手工填写的,要么具有复杂的布局结构,因此难以用基本的文本解析方法进行处理。 处理复杂文档结构的一种常见方法是使用机器学习模型来提取数据,并在可能的情况下对这些数据应用语义含义。
示例:W-2 表单、保险卡
常见方法:预生成模型、自定义模型
半结构化文档
半结构化文档没有固定格式或架构,如 W-2 表单,但在格式或模式方面具有一致性。 例如,所有发票的布局都不尽相同,但总的来说,它们的架构是一致的。 除其他数据外,可以预期发票上会有 invoice number
和某种形式的 bill to
和 ship to
名称和地址。 网页可能并不具有架构一致性,但它们具有类似的结构或布局元素,如 body
、title
、H1
和 p
,它们可用于为周围的文本添加语义含义。
与结构化文档一样,具有复杂布局结构的半结构化文档也很难用文本解析法进行处理。 对于这些文档类型,机器学习模型是一种很好的方法。 某些域具有一致架构(如发票、合同或医疗保险)的预生成模型。 对于没有预生成模型的复杂结构,可考虑建立自定义模型。
示例:发票、收据、网页、Markdown 文件
常见方法:文档分析模型
推断的结构
某些文档具有结构,但并非是用标记编写的。 对于这些文档,必须推断其结构。 以下欧盟法规文件就是一个很好的例子。
图 2. 显示推断结构的欧盟法规
由于可以清楚地了解文档的结构,而且没有已知的模型,因此可以确定允许编写自定义代码。 像这样的文档格式可能不需要创建自定义模型,具体取决于要处理的此类不同文档的数量。 例如,如果语料库全部是欧盟法规或美国各州法律,那么自定义模型可能是一种不错的方法。 如果要处理的是单一文件,如示例中的欧盟法规,则自定义代码可能更经济高效。
示例:法律文档、脚本、制造规范
常见方法:自定义代码、自定义模型
非结构化文档
对于几乎没有结构的文档而言,基于句子或固定大小与重叠的方法是一种很好的方法。
示例:用户生成的内容,如来自调查、论坛帖子或评论、电子邮件以及个人或研究笔记或开放式反馈
常见方法:基于句子或基于边界的重叠
试验
虽然列出了每种分块方法的最佳适用范围,但在具体实践中,任何一种方法都可能适用于任何文档类型。 例如,基于句子的解析可能适合高度结构化的文档,而自定义模型可能适合非结构化文档。 优化 RAG 解决方案的部分工作是尝试各种分块方法,同时考虑到自身所拥有的资源数量、资源的技术技能以及需要处理的文档数量。 为了实现最佳的分块策略,需要观察每种测试方法的优势和权衡,以确保为用例选择合适的方法。