首页 > 教程攻略 > ai资讯 >RAG 详解-数据预处理

RAG 详解-数据预处理

来源:互联网 时间:2026-08-26 14:13:14

引言

最近在不少B端和G端的大模型项目里,RAG几乎成了应用落地的标配起点。大家热情很高,但真正动手时,数据预处理这一步往往是第一个“坑”。这篇文章就从RAG实施流程的数据预处理开始聊,重点聊聊文档分割这个环节的一些实操细节。

RAG 详解-数据预处理

一、数据采集

数据采集是整个RAG系统的地基。具体落地时,可以拆解成“数据源识别”、“数据治理”、“数据清洗”三个步骤。

1. 数据源识别

这一步既要识别内部数据源,也要识别外部数据源,并且要跟RAG应用建立持续更新的机制。举个例子,假设某地产公司想搭建一个RAG系统,用于市场洞察、智能客服和辅助决策这三类场景,那么数据源的识别大概会涉及这些内容:

  • 内部数据:公司自有的资产数据库、销售数据库、在建项目管理、CRM系统、物业管理系统等。
  • 外部数据:政府的房产交易数据库、城市与土地规划信息库、城市交通规划数据库、经济指标、社交媒体数据、竞争对手数据等。
  • 内部系统集成:实现内部系统的数据同步。
  • 外部系统采集:比如建立与政府开发数据平台的API连接;订阅专业的地产数据服务;开发数据爬虫程序等。
  • 建立实时的数据推送系统。

2. 数据治理

另一个绕不开的环节是数据治理。这里面包括数据质量管理、安全与隐私保护、合规性管理、数据周期管理、元数据管理等等。数据治理本身是一个很大的主题,这里就不展开了。

3. 数据清洗

这里的“数据清洗”指的是开发一套自动化的数据清洗管道,能够按照数据治理过程中制定好的规则,实时、自动地处理重复数据和错误数据,并且与RAG系统及其他业务系统之间建立良好的数据更新机制。

二、文档数据转换

在Langchain的实现里,像PDF这样的文档,每一页都会转化成一个Document对象。这个对象包含两个属性:page_contentmetadata
page_content就是从文档页面中提取到的文本内容;
metadata是页面的元数据,包括文档来源、页码、文件类型等信息。当LLM生成有洞察力的答案时,会依赖这些元数据追溯到具体的来源。

三、文档分块

大语言模型在做Embedding时,有上下文窗口长度的限制——尽管现在一些长上下文模型的窗口越来越大。同时,为了提高检索的准确性和效率,对文档进行分块是必须的。分块时,有几个问题需要仔细掂量:

  1. 首先要考虑的是

    LLM对输入上下文窗口大小的限制

  2. 正如之前在《高级RAG技术》中提到过的,Chunk越小,生成时上下文信息越少,但搜索精度更高;Chunk越大(比如整页、多个段落,甚至整个文档作为一个Chunk),涵盖的信息越多,能通过更丰富的上下文来提升生成效果。
  3. Top-K检索大小

    :举个例子,假设LLM对输入上下文的限制是10000 Tokens,给用户的Query预留1000 Tokens,给指令提示和聊天记录再预留2000 Tokens,那么留给检索文档信息的就只有7000 Tokens。如果采用Top K=10,每个块的大小大约是700个token。
  4. 尝试在分块大小的可选范围里做探索。选择时要考虑内容的性质(比如短消息还是长文档)、嵌入模型的特性及其能力,目标是找到保留上下文与保持准确性之间的平衡点。可以试试多种块大小:小到128或256个tokens,用来捕捉更细粒度的语义;大到512或1024个tokens,用来保留更多上下文。
  5. 性能限制

    :Transformer的自注意力机制决定了,上下文太长会带来计算时间和内存的指数级增长。
  6. 从LlamaIndex发布的示例来看,随着分块大小增加,平均响应时间会略有上升。有趣的是,平均忠实度在分块大小为1024时达到顶峰,而平均相关性则随着分块大小的增大持续提升,同样在1024时达到峰值。这个数据说明,1024这个大小可能在响应时间和响应质量之间找到了一个不错的平衡点。

四、分块方法

1. 固定大小分块

那固定大小的分块法怎么回事呢?简单说,就是在每个块里固定token数量,再设置一定数量的重叠部分,确保上下文的丰富语义在各块之间能完整保留。

这种方法的优势很明显:逻辑简单,容易实现,不需要复杂的算法或条件判断,直接按字数、词数或字符数来切就行。块的大小固定,处理速度和效率高,尤其是在并行处理或批量操作时,每个块的处理时间差不多,方便系统优化和资源分配。此外,固定分块有助于在后续处理(如检索或编码)时保持一致的输入格式,减少复杂性。

但问题也同样突出:语义完整性不足。如果切在不恰当的位置(比如句子中间、段落中间),就会导致语义不完整或断档,这直接影响检索准确性和生成结果的质量。对于内容密度高或语义复杂的文本,固定分块可能并不适用,容易造成信息丢失或分块数量过多。

2. 上下文感知分块

相比固定分块,“上下文感知分块”是一种更智能的方式,在传统NLP任务和RAG中应用很广。跟固定分块不同的是,它在分块时会把文本的语义和上下文信息考虑进去,保证每个块都保持语义完整性和连贯性。常见的上下文感知分块方法有这几种:

a. 基于句子的分块

比如Naive splitting,通过标点符号(句号、问号、感叹号等)来分割。这个方法快速且简单,但可能会在错误的位置分割——比如缩写或数字里的句号(像“Dr. Smith”或“3.14”)也会被当作句子终止符,造成误判。

NLTK这个Python自然语言处理库,提供了基于规则的句子分割器,比如PunktSentenceTokenizer。它使用训练好的模型(如Punkt模型)结合上下文来识别句子边界,比Naive splitting更智能,能处理常见的标点符号误分割问题,比如识别缩写中的句号不作为句子终止符。不过,在复杂语境下,它依然可能出错。

spaCy是另一个强大的自然语言处理库,它的句子分割器利用了依存句法分析和预训练的统计模型来准确识别句子边界。因为结合了依存句法分析,spaCy能更准确地处理复杂句子结构,尤其在处理嵌套从句或其他复杂句法结构时效果更好。它特别适合需要高准确度的句子分割任务,尤其是处理复杂或非标准文本时表现出色。当然,缺点也很明显:计算开销较大,某些语言或特定领域的文本可能需要额外微调。

总结一下:

  • Naive splitting最简单,但容易出错。
  • NLTK更智能,能处理常见问题。
  • spaCy用了更复杂的语言模型和句法分析,通常分割结果最准。

b. 递归分块

递归分块算是一种更高级的方法。它通过递归的方式,把文本逐步分割成更小的块。跟普通固定分块不同,递归分块能更好地捕捉文本的层次结构和语义关联,而且能灵活处理各种类型的文本,尤其是那些语义层次复杂的长文档。由于它能捕捉到文本的多层次结构,这对于需要细粒度理解和处理的任务特别有用。

它的工作原理是这样的:

  • 初始分块

    :文本先按照某个策略(比如段落、句子)做初步分块,得到第一层次的分块。
  • 递归分块

    :对每个初始块,如果长度或复杂性超过了预设的阈值,就进一步分割成更小的子块。这一步可以基于语义、主题或其他上下文信息来进行。这个过程是递归的,可以重复多次,直到每个块都满足预设的条件(比如长度合适、语义完整)。
  • 终止条件

    :递归分块会根据设定的条件(比如最大块长度、最小语义单位)终止。条件满足后,分块过程停止,得到的块就用于后续处理或模型输入。

LangChain中的RecursiveCharacterTextSplitter类就能实现递归分块。

c. 专业化分块

对于Markdown和LaTeX这类结构化文本,可以使用专门的分块方法,这样能在拆分过程中保留内容的原始结构。

五、多模态RAG数据处理

B端或G端客户的数据通常以多种形态存在,比如PDF里包含图像、表格和文本内容,还有一些文件夹里混着各种常见格式。每种模态都有它独特的挑战和细微差别。构建多模态RAG流程时,必须捕捉并处理这些细微差别。举个例子:

多模态RAG示例

先看这三张图。最左侧的丹霞地貌,很难用文字完全捕捉它的信息——虽然能用文字描述,但整体的“视觉效果”很难完整表达。在多模态RAG中,如果用户查询的是跟这相关的内容,系统可能需要更多地依赖视觉特征的向量来做检索和匹配,而不仅仅是靠文本描述。

中间这张智能驾舱的图示,一部分细节可以用文字描述,比如驾舱里每个设备的信息和位置。这种图像的检索,可能需要结合文本和图像信息,用文本描述来增强对关键点的理解,同时利用图像特征来捕捉整体的视觉信息。

最右侧是小米SU7的话题趋势图。这种图像的细节可以完全用文字来描述,检索和处理时可以较多地依赖文本向量,图像向量的作用可能相对小一些。

构建多模态RAG主要有三种方法:

  1. 将所有模态嵌入同一个向量空间;
  2. 将所有模态归结为一种主要模态;
  3. 为不同模态设立独立的存储结构。

下面以图像和文本输入为例展开聊聊。

1. 将所有模态嵌入同一向量空间

这种方法的思路是:把不同类型的数据(文本、图像)转换成具有相同维度和相似语义表示的向量。

  • 所有模态的数据在处理后都被转换成相同维度的向量。比如,图像和文本可能通过不同的模型处理,但最终都被转为相同长度的向量(比如512维)。
  • 相同或相似的语义信息(如图像中的“猫”和文本中的“猫”)在同一向量空间中应该相互接近。也就是说,具有相同含义或相关含义的向量在空间里彼此靠近。

如果原来只有针对文本的RAG模型,那需要把嵌入模型换成支持多模态嵌入的模型(比如CLIP,Contrastive Language-Image Pre-training);生成阶段则要把只能生成文本的LLM换成多模态LLM(比如GPT-4V、LLaVA、FUYU-8b)。

2. 将所有模态归一化为同一种模态

根据应用的需求,选一种主要模态,然后把其他模态基于这种模态来构建。比如,如果最终目标是根据PDF做基于文本的问答,那就按常规方法处理文本数据;对于图像,在数据预处理阶段就创建文本描述和元数据存储起来,后续再用。

推理过程中,检索主要依据图像的文本描述和元数据来进行。答案生成时,可以结合LLMs和MLLMs,具体取决于检索到的图像类型。

这种方法的优点是:从图像中生成的元数据在回答客观问题时非常有用;而且绕开了“需要为图像嵌入更换嵌入模型”的问题;也不需要专门设计排序器来对跨模态结果重新排序。

缺点也很明显:数据预处理的成本不低,而且原始图像中包含的细节可能会丢失。

3. 设置独立的存储结构

为不同的模态设置独立的数据存储,然后使用Rank-rerank方法来处理。具体流程是:在初次排序(Ranking)中,系统先把查询提交给多个模态的独立存储库,每个存储库根据自身模态特性返回与查询最相关的前N个结果(chunks)。文本存储库返回文本片段,图像存储库返回语义相关的图像。

当从各个模态的存储库拿到初步结果后,一个多模态重排序器(multimodal re-ranker)会介入,把这些来自不同模态的top-N结果整合起来,根据它们与查询的整体相关性重新排序,最终交给用户最相关的结果。

总结

这篇文章初步梳理了RAG系统中的数据处理方法,重点讲了文档分割的方法和多模态数据的处理。

  • 数据采集

    :包括数据源识别、数据治理和数据清洗,关键是要建立持续更新机制和自动化数据清洗管道。
  • 文档数据转换

    :把文档(如PDF)转换成包含页面内容和元数据的对象。
  • 文档分块

    :考虑LLM的上下文窗口限制、块大小对检索精确度的影响以及Top-K检索大小,建议探索不同的块大小,在上下文保留和准确性之间找到平衡。
  • 分块方法

    :固定大小分块简单但可能导致语义不完整;上下文感知分块考虑了语义和上下文信息;递归分块适合复杂结构的长文档;专业化分块针对Markdown、LaTeX等特定格式。
  • 多模态RAG数据处理

    :面对文本、图像、表格等多种形态的数据,主要方法有三种——将所有模态嵌入同一向量空间、将所有模态归一化为一种主要模态、为不同模态设立独立存储并用Rank-rerank方法处理。