引言
近期,在众多B端与G端的大模型落地实践中,检索增强生成(RAG)几乎已成为应用上线的标准起点。虽然开发者热情高涨,但实际操作时,数据预处理环节往往是第一个“深坑”。本文从RAG实施流程的数据预处理入手,重点分享文档分割环节的实操技巧与细节。

一、数据采集
数据采集是构建RAG系统的基石。在实际落地中,可将其拆解为“数据源识别”、“数据治理”与“数据清洗”三个关键步骤。
1. 数据源识别
该步骤需同时识别内部与外部数据源,并建立与RAG应用持续同步的更新机制。举例来说,假设某地产公司希望搭建RAG系统,用于市场洞察、智能客服及辅助决策三大场景,那么数据源识别大致涵盖以下内容:
- 内部数据:企业自有的资产数据库、销售数据库、在建项目管理系统、CRM系统、物业管理系统等。
- 外部数据:政府房产交易数据库、城市与土地规划信息库、城市交通规划数据库、宏观经济指标、社交媒体数据、竞品数据等。
- 内部系统集成:实现内部各系统的数据实时同步。
- 外部系统采集:例如对接政府开放数据平台的API接口;订阅专业地产数据服务;开发定制化数据爬虫程序等。
- 构建实时数据推送管道。
2. 数据治理
数据治理是另一不可忽视的环节,涉及数据质量管理、安全与隐私保护、合规性管理、数据生命周期管理、元数据管理等。数据治理本身是一个庞大的专题,此处不再展开论述。
3. 数据清洗
此处的“数据清洗”特指开发一套自动化数据清洗管线,能够按照数据治理阶段制定的规则,实时自动处理重复数据和错误数据,并与RAG系统及其他业务系统之间保持良好的数据更新协同机制。
二、文档数据转换
在LangChain的实现中,像PDF这类文档,每一页都会转化为一个Document对象。该对象包含两个核心属性:page_content和metadata。
page_content是从文档页面中提取出的文本内容;
metadata则记录页面的元数据,包括文档来源、页码、文件类型等信息。当大语言模型生成富有洞察力的答案时,会依赖这些元数据追溯到具体的出处。
三、文档分块
大语言模型在执行Embedding时,受到上下文窗口长度的制约——尽管当前一些长上下文模型的窗口已不断扩展。同时,为提升检索的准确性与效率,对文档进行分块是必不可少的环节。分块时需仔细权衡以下几个问题:
- 首先需考虑LLM输入上下文窗口的大小限制。
- 正如《高级RAG技术》中提到的,分块越小,生成时上下文信息越少,但搜索精度更高;分块越大(例如整页、多个段落甚至整个文档作为一个块),涵盖信息越丰富,能通过更完整的上下文提升生成效果。
- Top-K检索数量:举例来说,假设LLM输入上下文限制为10000 Tokens,为用户Query预留1000 Tokens,为指令提示和聊天记录预留2000 Tokens,那么留给检索文档信息的空间仅为7000 Tokens。若采用Top K=10,则每个分块大小约为700个token。
- 应在分块大小的可选范围内进行探索。选择时需考虑内容特性(如短消息还是长文档)、嵌入模型的特点及能力,目标是找到保留上下文与维持准确性之间的平衡点。可尝试多种分块尺寸:小至128或256个tokens,用于捕捉更细粒度的语义;大至512或1024个tokens,以保留更丰富的上下文。
- 性能限制:Transformer的自注意力机制决定了,上下文过长会导致计算时间和内存呈指数级增长。
- 从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中,若用户查询与此相关的内容,系统可能需要更多依赖视觉特征的向量进行检索与匹配,而非仅靠文本描述。
中间这张智能驾舱示意图,部分细节可用文字描述,例如驾舱内各设备的信息与位置。这种图像的检索可能需要结合文本与图像信息,利用文本描述增强对关键点的理解,同时借助图像特征捕捉整体视觉信息。
最右侧是小米SU7的话题趋势图。该图像的细节可完全用文字描述,检索与处理时可较多依赖文本向量,图像向量的作用相对较小。
构建多模态RAG主要有三种方法:
- 将所有模态嵌入同一个向量空间;
- 将所有模态归一化为同一种主要模态;
- 为不同模态设立独立的存储结构。
以下以图像与文本输入为例展开说明。
1. 将所有模态嵌入同一向量空间
该方法的思路是:将不同类型的数据(文本、图像)转换为具有相同维度与相似语义表示的向量。
- 所有模态的数据经处理后均转换为相同维度的向量。例如,图像与文本可能通过不同模型处理,但最终均转为相同长度的向量(如512维)。
- 相同或相似的语义信息(如图像中的“猫”与文本中的“猫”)在同一向量空间中应相互靠近。换言之,含义相同或相关的向量在空间中彼此接近。
若原有RAG模型仅支持文本,则需要将嵌入模型替换为支持多模态嵌入的模型(如CLIP,对比语言-图像预训练);生成阶段则需将仅能生成文本的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方法处理。
