Back to Blog

数据清洗与切片

数据清洗与切片位于 RAG 的入口。它把 PDF、Word、Markdown、图片等原始文件,转换为可以建立索引的结构化文本单元。该阶段需要同时解决解析质量、噪声过滤、语义边界、块长度、重叠区和元数据传播问题。 | 边界 | 数据 | 关键字段或要求 | | --- | --- | --- | | 输入 | 原始...

01 数据清洗与切片

这一阶段做什么

数据清洗与切片位于 RAG 的入口。它把 PDF、Word、Markdown、图片等原始文件,转换为可以建立索引的结构化文本单元。该阶段需要同时解决解析质量、噪声过滤、语义边界、块长度、重叠区和元数据传播问题。

输入与输出

边界数据关键字段或要求
输入原始文档文件路径、文件类型、语言、是否扫描件、是否包含表格/公式/图片
解析输出Element[]textcategorymetadata;常见类型有 TitleNarrativeTextTableImage
框架输出Document[]text 和文档级 metadata
切片输出Node[]id_textmetadatarelationships,后续可写入 embedding
下游输入可索引节点每个 Node 应能追溯到文件、页码或章节,并满足 Embedding 模型长度限制

UnstructuredReader.load_data(...) 返回 Document 列表;直接调用 unstructured.partition 返回 Element 列表;NodeParser.get_nodes_from_documents(...) 返回 Node 列表。三者不能混为同一种返回值。

主流程

flowchart LR
    A[原始文件] --> B{识别文档类型与质量}
    B -->|电子 PDF / 规则文本| C[fast / PyMuPDF]
    B -->|复杂布局 / 表格| D[hi_res / MinerU / Marker]
    B -->|扫描件| E[OCR / ocr_only]
    B -->|极复杂图文| F[VLM]
    C --> G[Element 或 Document]
    D --> G
    E --> G
    F --> G
    G --> H[过滤页眉页脚与重复噪声]
    H --> I[保留标题、页码、坐标等元数据]
    I --> J[按标题 / 句子 / Token / 语义切片]
    J --> K[Node 列表]
    K --> L{质量检查}
    L -->|合格| M[进入向量化与入库]
    L -->|超长或语义断裂| J

使用顺序

  1. 先判断文档是否有文本层、是否为扫描件、是否含复杂表格和多栏布局。
  2. 根据文档类型选择解析器和 strategy,不要直接对所有 PDF 使用同一方案。
  3. 从解析结果中清除页眉、页脚、乱码、重复段和无效图片说明,同时保留来源元数据。
  4. 选择 NodeParser 或 TextSplitter,并设置 chunk_sizechunk_overlap 或语义断点阈值。
  5. 用召回率、精确率、语义完整性、平均块长和超长块数量检查结果。

完成标准

  • 每个切片都能追溯到原文件,复杂文档还应保留页码、标题或坐标。
  • 表格、代码、列表、公式等结构没有被无意义截断。
  • chunk_size 不超过 Embedding 模型限制,重叠区没有造成大量重复召回。
  • 页眉、页脚和 OCR 噪声不会进入主要索引文本。

完整技术说明

以下内容保留源文档的全部正文、表格、代码、参数、链接和原有流程图,仅调整标题级别,使其纳入当前文档结构。 向量数据库:

  • chromadb
  • Milvus

切片

第一种:

切分依据(语义优先+上限兜底):以 512 个 Token 为硬上限,但落刀点优先选择自然语言的物理边界(如段落换行符 \n\n、句号等),以此来保证每一块内容的语句完整。

切分方式(递归动态切分):不采用死板的固定字数一刀切,而是用递归算法。先尝试按大段落拆,如果超长,再降级找单换行符或标点符号继续拆。切片最终的实际大小是动态浮动的。

切片关系(冗余衔接):相邻的前后切片之间会强制保留 51 个 Token 的重叠内容。这就像铺瓦片一样,通过几十个字的上下文冗余,防止核心概念被生硬切断,确保大模型检索时能读到连贯的上下文。

PDF解析困难

  • 布局解析困难:PDF文件的布局可能会因为不同的作者、工具或用途而有所不同,通常具有多列文本,对于图像或表格来说,这些文本可能会突然中断,因此解析其布局是一个具有挑战性的任务。
  • 格式错综复杂:PDF文件中可能包含各种格式的内容,包括文字、图像、表格等,因此解析其内容需要考虑到这种多样性和复杂性。
  • 复合表格:纵向/横向合并的复杂表格,在PDF中进行抽象还原是最难处理的问题之一
  • 文本、图片、表格顺序提取:提取PDF文件中的文本、图片和表格,并确保它们的顺序正确性,是一个需要解决的重要问题。
  • 文档结构还原:还原PDF文件的文档结构,包括标题、目录等信息,是实现自动化文档处理和理解的关键步骤之一。
  • 元数据提取:在PDF中隐藏的元数据信息是RAG产品的关键数据,比如链接、目录、字体等等
  • 扫描件:PDF中如果是扫描件,就需要依靠OCR模型来进行有效的提取,这里面还会包含清晰度、模型的稳定性等问题
  • Latex公式提取:在一些特殊领域,PDF文本中包含了Latex等数学公式。通过完整的提取和转换是对RAG问答的有效补充
1. 主流工具对比与选择

技术选型决策

  • 数字原生PDF:优先选择PyMuPDF,利用其渲染效率优势处理纯文本/简单表格批量任务
  • 扫描PDF:必须启用OCR流程,可搭配Unstructured的”ocr_only”策略
  • 复杂学术文档:推荐Marker(代码/公式支持)或MinerU(数学公式识别),但需容忍GPU加速需求
工具性能对比表
工具核心优势适用场景
unstructured.io支持50+格式,生态完善多源数据ETL入口
PyMuPDF解析速度>200页/分钟纯文本/简单PDF批量处理
Marker代码/公式支持优秀技术白皮书/学术文献
MinerU数学公式识别精准科技/专利类文档
DoclingAI表格提取精度98%+金融财报/科研报告
DeepDoc中文优化+端到端方案中文RAG系统建设
Unstructured.io的集成优势

Unstructured.io作为集成框架,通过strategy参数实现后端自适应切换:

  • “fast”策略:调用PyMuPDF等轻量引擎处理规则文档
  • “hi_res”策略:激活YOLOX目标检测模型进行布局分析,配合detectron2实现表格与图像的精准提取
  • “ocr_only”策略:使用OCR模型进行图文识别
  • “vlm”策略:针对极端复杂场景调用GPT-4o等多模态模型,通过视觉语义理解突破传统解析局限

这种混合架构使其在金融财报(表格提取精度98%+)和科研报告等场景中表现突出。

Unstructured的核心优势
  • 可以和Agent框架集成(LangChain、LlamaIndex)
  • 也可以解析多种不同的文档形式(比较通用)
  • 主流应用的比较多、适用性比较广
  • 生态协同核心地位:Unstructured库通过与LangChain主流框架的深度集成(如UnstructuredLoader组件),与LlamaIndex的深度集成(如UnstructuredReader组件)已成为检索增强生成(RAG)pipeline中的关键预处理节点。其能够将非结构化数据转化为向量数据库可索引的结构化格式,解决了RAG系统中”数据输入异构性”这一核心痛点,为下游的知识检索与生成任务提供了标准化数据基础

Unstructured (StructKit) 数据解析与 RAG 预处理核心指南

基于你提供的关键信息,这份文档系统性地梳理了用于检索增强生成(RAG)的文档解析模块(以 unstructured 库架构为核心)。在整理截图信息的基础上,补充了部分在 RAG 实际工程中的应用逻辑和最佳实践。


1. 核心底层依赖与跨平台组件

在处理非结构化文档时,底层的系统级依赖是确保各种复杂文件格式(尤其是扫描件、富文本格式)能够被正确读取的基础。

  • (1) Tesseract OCR (图像文本识别)
    • 定位:处理扫描版 PDF 和图片文件的核心组件,提供底层的图像转文本能力。
    • 扩展支持:原生支持多语言,但在处理中文或混合排版时,需额外安装 tesseract-lang 多语言扩展包。
    • 安装参考:提供多种平台的安装方式(如 Windows 的 Github 安装包及开发者文档)。
  • (2) Poppler (PDF 内容提取底层引擎)
    • 定位:主要通过 pdf2image 库将 PDF 转换为图像格式,为后续的 Tesseract OCR 处理提供标准化的图像输入。
  • (3) Pandoc (富文本格式转换)
    • 定位:专门处理 EPUB、RTF 等富文本格式的转换工具。
    • 避坑指南必须使用 2.14.2 及以上版本,否则在解析 RTF 文件时会出现底层兼容性报错。
  • (4) libmagic (跨平台文件类型检测)
    • 定位:用于精准识别文件 MIME 类型的底层 C 库。
    • 环境差异:Linux 和 macOS 必须手动配置安装,而 Windows 环境自带替代方案,可忽略此依赖。
  • (5) 常见依赖问题解决方案
    • 问题:本地完整安装解析引擎时,极易触发依赖链报错(例如 "Could not build wheels for pikepdf")。
    • 对策:需要预先安装图像处理的底层 C 库依赖,如 qpdflibheifpillow

2. API 与客户端接入

在企业级 RAG 系统中,本地部署庞大的解析模型(如布局检测模型)会导致极高的冷启动延迟和资源占用。

  • Serverless API 安装: pip install unstructured-client
  • 工程价值:通过优化处理流程,将庞大的文档处理模型启动时间从 30分钟剧减至 3秒以内。同时支持多区域的横向扩展,有效突破了高并发场景下的吞吐量瓶颈。

3. 核心解析策略 (strategy) 与进阶参数

在调用解析器时,参数的配置直接决定了速度与质量的平衡

解析策略选择 (strategy)
  • fast(默认):适用于纯数字版 PDF(包含标准文本层),解析速度极快,不加载视觉模型。
  • hi_res(高精度):核心特性。会调用复杂的视觉布局检测模型(如 Detectron2, YOLOX, 或自研的 Chipper 等)来提取文档的物理结构信息(段落边界、表格、图片)。
  • ocr_only:专为扫描件或纯图像版 PDF 设计,仅执行 OCR 提取。
  • vlm:前沿方案,直接调用多模态视觉语言模型(如 OpenAI/Anthropic 的 Vision 模型)进行页面理解。
图像与表格提取控制
  • 图像提取(仅在 hi_res 下生效):
    • extract_images_in_pdf (布尔值):是否提取嵌入的图像块。
    • extract_image_block_types (列表):指定提取类型,例如精确提取 ["Image", "Table"]
    • extract_image_block_output_dir (字符串) / extract_image_block_to_payload (布尔):决定提取的图片是落盘保存到指定目录,还是直接转为 base64 payload 存入内存。
  • 表格推断
    • infer_table_structure:设为 True 尝试还原复杂的表格行列结构。
    • skip_infer_table_types:在不需要表格结构的场景中,跳过表格推断以大幅提升解析速度。
其他关键参数
  • max_partition:在使用 ocr_only 时,限制单个文本块的最大字符长度(默认 1500),这是防止单块输入超出 LLM Token 限制的初步手段。
  • split_pdf_page (True):大文件分块处理机制,提升超大文档的解析效率。
  • languages / ocr_languages:显式指定 OCR 使用的语言包列表,提高识别准确率。

4. 数据结构:解析后的 Element 对象详解

解析引擎完成工作后,会将文档结构化为一个个 Element 对象的集合。理解这些对象是构建高质量 RAG 索引的关键。

核心字段
  1. text: 元素的纯文本内容。(重点:对于表格类型,这里的文本会自动呈现为 Markdown 表格格式,这对 LLM 非常友好)
  2. category: 元素类型标识。
  3. metadata: 丰富的上下文元数据。
Category 元素类型详解

精确的分类能让 RAG 切块不再盲目按字数截断。

  • Title (标题):文档的各级标题和副标题。
  • NarrativeText (叙事文本):标准正文段落。
  • Table (表格):包含结构化数据的表格。
  • Text (段落):普通无明显特征的文本。
  • Image (图像):文档中的所有插图。
  • Formula (数学公式):提取出的公式文本,例如 y = Wx + b
  • Header/Footer (页眉/页脚):(重要:在 RAG 中通常直接过滤掉这些元素,防止注入无意义的噪声)
Metadata 元数据详解

丰富的元数据为检索后的召回排序和文档溯源提供了依据。

  • page_number:该文本块所在的页码(从 1 开始计)。
  • coordinates (坐标信息):
    • points:文本块在页面上的四个角坐标(格式:[左上, 左下, 右下, 右上],单位为像素)。
    • system:坐标系统类型(通常为 PixelSpace 像素坐标系)。
    • layout_width / layout_height:该页面的总宽度和高度。
  • languages:检测到的文档语言(如 ["zho"] 代表中文,遵循 ISO 639-3 标准)。
  • filename / last_modified (ISO 8601格式) / filetype (如 application/pdf):文件基本溯源信息。

5. RAG 场景应用与性能优化(工程经验)

在实际业务落地时,如何根据文档特点动态调整策略是拉开差距的关键。

下游 RAG 系统应用优化
  1. 噪声过滤:利用 category 字段直接过滤掉不需要的内容,如 ImageHeaderFooter,保证输入给向量数据库的文本纯净度。
  2. 结构化切块 (Semantic Chunking):这是 RAG 优化的核心。优先使用 Title 元素构建文档的层次树(Hierarchy)。与其按死板的 500 字切块,不如按照“标题 -> 下属子段落”的逻辑打包(如 Parent-Child 切块策略),这能极大提升检索召回的准确性和语义完整性。
疑难杂症与性能调优
  • 混合中英文本方向 / 版式混乱
    • 解法:绝对不能用 fast。必须优先使用 strategy="hi_res" 先做强大的版面分析(Layout Detection),将页面准确切割后,再对图片区域分别进行 OCR。
    • 低质量扫描件:在此基础上,需在传入前进行图像预处理流程(deskew 倾斜校正、denoise 去噪、binarize 二值化)。
  • 工业级性能优化策略
    • 场景 A(海量标准电子 PDF):文档自带良好文本层,此时使用 fast + PyMuPDF/pdftotext 管线通常是最快且足够准确的方案。
    • 场景 B(需要高质量表格边界/复杂多栏布局):必须用 hi_res,它能显著提高表格/标题/图片的检测率。但由于视觉模型开销巨大(时间和依赖),如果对系统吞吐量有严格要求,应考虑将 hi_res 推理外包给独立的 GPU 处理服务,并对任务进行异步/队列的批量调度

LlamaIndex框架介绍

1. 大模型开发框架(SDK)是什么?

SDK: Software Development Kit,它是一组软件工具和资源的集合,旨在帮助开发者创建、测试、部署和维护应用程序或软件。 所有开发框架(SDK)的核心价值,都是降低开发、维护成本。大语言模型开发框架的价值,是让开发者可以更方便地开发基于大语言模型的应用。

主要提供两类帮助:

  • 第三方能力抽象。比如LLM、向量数据库、搜索接口等
  • 常用工具、方案封装
  • 底层实现封装。比如流式接口、超时重连、异步与并行等

好的开发框架,需要具备以下特点:

  • 可靠性、鲁棒性高
  • 可维护性高
  • 可扩展性高
  • 学习成本低

2. LlamaIndex介绍

LlamaIndex 是一个为开发「上下文增强」的大语言模型应用的框架(也就是 SDK)。上下文增强,泛指任何在私有或特定领域数据基础上应用大语言模型的情况。例如:

graph TD
    User((User))

    subgraph Your_data [Your data]
        DB[(Database)]
        Doc[Document]
        API[API]
    end

    Index[Index]
    LLM[LLM]

    User -- query --> Index
    DB -- structured --> Index
    Doc -- unstructured --> Index
    API -- programmatic --> Index

    Index -- prompt + query +<br>relevant data --> LLM
    LLM -- response --> User

LlamaIndex 有 Python 和 Typescript 两个版本,Python 版的文档相对更完善。

1. LlamaIndex环境准备

核心库安装

LlamaIndex版本0.14.x

pip install llama-index-core llama-index

解析库安装

pip install llama-parse unstructured nest-asyncio python-multipart llama-index-readers-file
pip install pytest
pip install "unstructured[md]"

2. LlamaIndex常用组件

常用组件:


3. LlamaIndex集成unstructured

LlamaIndex与Unstructured的关系

  • LlamaIndex本身并不专注于文件解析(Parsing),而专注于:
    • “结构化地管理与大模型交互的外部知识(即索引、检索、问答)。”
  • 而Unstructured.io是一个独立的”文档解析引擎”,核心职责是:
    • “将各种复杂格式(PDF、DOCX、HTML、Excel、图片等)解析成统一的文本元素(elements)。”

因此:

  • LlamaIndex是知识管理层(Knowledge Layer)
  • Unstructured是文档提取层(Extraction Layer)

3. LlamaIndex 的核心模块
flowchart LR
    subgraph Data ["Data (数据源: 各种文件格式与数据源)"]
        direction TB
        sub1["Document\n(pdf, docx, image, audio, csv, markdown...)"]
        sub2["Arxiv, Github, Database, Gmail,\nGraphDB, Jira ... (180+种)"]
    end

    subgraph Loading ["Loading (将各种数据统一加载为 Doc, Node, Metadata)"]
        direction TB
        L1["Documents\nNodes\nMetadata"]
        L2["DirectoryReader"]
        L3["Data Connectors"]
    end

    subgraph Chunking ["Chunking (文本结构解析 / 文本切割)"]
        direction TB
        C1["Node Parsers"]
        C2["Text Splitters"]
    end

    subgraph Indexing ["Indexing (建索引 (并灌库))"]
        direction TB
        I1["Keyword\nVector\nProperty Graph"]
        I2[/"Storing"/]
    end

    subgraph Querying ["Querying (检索+预处理、后处理)"]
        direction TB
        Q1["Retrieval"]
        Q2["Postprocessors"]
        Q3["Query Pipelines"]
        Q4["Routing"]
    end

    subgraph Responding ["Responding (生成回复)"]
        direction TB
        R1["QA"]
        R2["Chat (multi-turn)"]
        R3["Structured"]
        R4["Agents"]
    end

    Data --> Loading
    Loading --> Chunking
    Chunking --> Indexing
    Indexing --> Querying
    Querying --> Responding

    subgraph Models ["Models"]
        direction LR
        M1["Embedding Models"]
        M2["LLMs"]
    end

    Models -.-> Indexing
    Models -.-> Querying
    Models -.-> Responding

方式三:最佳混合方案(推荐实践)

结合两者优势:

这种做法在实际RAG框架开发中非常常见:

  • 90%文件走LlamaIndex内置Reader
  • 特殊格式(扫描件、混合HTML、表格)回退到底层 unstructured

总结一句话

  • LlamaIndex的 UnstructuredReader = 快速封装,适合上层应用
  • unstructured.partition = 底层引擎,适合复杂数据管线
  • 在原型阶段用 UnstructuredReader,在生产阶段直接集成 unstructured。

方式一:直接使用UnstructuredReader

推荐场景:快速测试/教学/单格式文件读取

优点

  • 写法极简
  • 自动生成Document对象
  • 无需显式调用 partition

缺点

  • 无法细调OCR、chunk_size、文本清洗
  • 对图片、HTML、公式等复杂结构支持有限
  • Document对象只保留了文本和元数据,没有数据类型
from llama_index.readers.file.unstructured import UnstructuredReader
from pathlib import Path

reader = UnstructuredReader()
documents = reader.load_data(file=Path("甬兴证券-AI行业点评报告:海外科技巨头持续发力AI,龙头公司中报业绩亮眼.pdf"))

print("打印列表长度: " + str(len(documents)))
print("=====================================")
print("打印解析的文本内容: " + documents[0].text[:100])
print("=====================================")
print("打印元数据信息: " + str(documents[0].metadata))

方式二:独立使用unstructured.partition + 自定义逻辑

推荐场景:生产级RAG应用/多格式数据管线/高可控性需求

优点

  • 可自由控制解析策略(OCR、chunk、去噪、正则)
  • 可在加载前后插入清洗逻辑(例如表格转结构化文本)
  • 易于扩展(批量处理/并行任务/自定义metadata)

场景推荐方式特点/说明
初学者/快速DemoUnstructuredReader()封装好,一行代码
RAG系统UnstructuredReader()输出直接是Document对象
生产系统/多文件管线partition()可完全控制OCR/分块策略
精细元数据追踪(页码/坐标/字体)partition()元数据更丰富

LlamaIndex 的更多功能

切片前的处理

数据清洗与预处理

在文档切分之前,针对文本内容需要进行适当的数据清洗和预处理,这一步骤可以显著提高切分质量和后续检索效果。数据清洗和预处理就是在源头把关,确保流入RAG系统的每一滴水都是干净的,这样最终输出的答案才能清澈见底。这个环节投入1小时的工作,可能在后续每个环节都为你节省10小时的调试和优化时间,并且将噪声内容清洗掉以后,会降低后期向量存储成本,提升检索的速度和回答的答案质量。对于企业级项目来说,这是性价比最高的投入之一。


1.1 总体目标与原则

数据清洗的核心目标是:

  • 去除无关内容和噪声
    • HTML/XML标签:div, span, p 等
    • Markdown符号:粗体, [链接], #标题 等
    • 代码片段:无意义的程序代码块
  • 标准化文本格式
    • 修复断行问题:PDF转换经常把一句话拆成多行
    • 统一换行符:Windows(\r\n), Unix(\n), Mac(\r)
    • 合并短行:把被错误分割的短行重新合并
    • 标准化空格:多个连续空格→单个空格
  • 提高切分边界识别的准确性

1.3 数据清洗的最佳实践

数据清洗是文档切分的基础工作,良好的清洗能够显著提高后续切分质量和检索效果。

  1. 保持原始结构:清洗过程中尽量保留文档的原始结构和层次关系
  2. 最小化信息损失:只去除明确的噪声,避免删除可能有用的内容
  3. 标准化格式:统一标点符号、引号、连字符等格式元素
  4. 处理特殊字符:转义或替换可能影响后续处理的特殊字符
  5. 版本控制:保留原始文档副本,以便需要时回滚

RAG文档切分概述

RAG (Retrieval-Augmented Generation) 系统中的文档切分是构建高效检索系统的关键步骤。文档切分,也称为分块(Chunking),是将长文档分割成更小、更易于管理的片段的过程,防止长文档有大部分的噪音数据进入上下文中,这些片段随后被转换为向量并存储在向量数据库中,以便在查询时进行快速检索。


2.1 文档切分的重要性

文档切分直接影响RAG系统的性能表现:

  • 检索准确性:合理的切分能确保检索到的片段包含完整的相关信息,避免语义割裂
  • 上下文完整性:适当的块大小保持足够的上下文信息,使LLM能够生成准确的回答
  • 计算效率:合理的块大小平衡了检索精度和计算成本
  • 召回率与精确度:切分策略直接影响检索系统的召回率和精确度

2.2 切分粒度对RAG效果的影响

粒度是RAG性能的”第一性变量”。不同粒度级别对系统性能有显著影响:

粒度级别检索准确性生成质量计算成本典型策略
细粒度(句子级)低(上下文不足)SentenceWindowNodeParser
中等粒度(段落级)中高中高SentenceSplitter
粗粒度(文档级)低(噪声多)高(上下文完整)直接使用Document

分块过大:可能导致检索到的单个块包含过多无关信息(噪音),增加了 LLM 理解上下文的难度,降低了答案的精确性,甚至可能超出 LLM 的上下文窗口限制。

分块过小或切分不当:可能破坏原文的语义连贯性,导致一个完整的知识点被拆散到多个块中。检索时可能只召回了部分信息,使得 LLM 无法获得完整的背景,难以生成全面、准确的答案。

未能适应文档结构:不同的文档类型(如论文、手册、报告、网页)具有不同的结构特点。死板的分块方式可能无法有效利用标题、列表、表格等结构信息,影响信息提取的完整性。

一般工程上,层次化切分与句子窗口相结合,通过”粗检索——细生成”的两阶段路径,有效平衡召回率与上下文完整性。


2.3 文档切分的基本流程

文档切分通常包括以下基本步骤:

  1. 文档加载:使用适当的文档加载器加载文档内容(unstructured, Reader等)
  2. 预处理:根据文档类型进行必要的清洗和格式化
  3. 切分策略选择:根据文档特点和需求选择合适的切分方法
  4. 执行切分:应用选定的切分策略将文档分割成块
  5. 后处理:对切分结果进行必要的调整和优化
2.4 切分效果评估指标

评估文档切分效果的常用指标包括:

  • 语义完整性:切分后的块是否保持完整的语义信息,能够表达完整的含义
  • 上下文连贯性:相邻块之间的内容是否连贯,重叠部分保证思路不中断
  • 检索相关性:切分后的块是否能有效支持相关查询
  • 生成质量:基于切分块生成的回答质量
  • 计算效率:切分和检索过程的计算成本

LlamaIndex核心对象概念

LlamaIndex提供了灵活的文档处理框架,理解其核心概念是有效使用文档切分功能的基础。它们是将大文档首先会读取为document对象,然后拆解为适宜检索的语义片段(节点Node)。选择合适的切分器对于提升 RAG 系统的检索精度和回答质量至关重要。


graph LR
    subgraph Data_Sources [Data Sources]
        direction TB
        DB[Databases]
        Doc[Documents]
        API[APIs]
    end

    DC[Data Connectors]

    subgraph Documents_Group [Documents]
        Nodes[Nodes]
        %% Representing multiple documents visually
        Doc1[ ]
        Doc2[ ]
        Doc3[ ]
    end

    KB[(Knowledge Base)]

    Data_Sources --> DC
    DC --> Documents_Group
    Documents_Group --> KB

(此处原图展示了 Data Sources (Databases, Documents, APIs) 通过 Data Connectors 转换为 Documents (包含多个 Nodes),最终存入 Knowledge Base 的流程)


维度Document (文档)Node (节点)
概念层级顶层数据容器,代表一个完整的数据源(如一个PDF文件、一个API响应)基础数据单元,由Document解析/分块而成,代表其中一段文本
核心职责数据的统一与标准化:将不同来源、格式的数据封装成统一对象,便于系统处理数据的精细化组织与关联:通过分块、元数据和关系,构建细粒度的数据网络以支持高效检索
内容与关系包含原始、完整的数据内容;Document之间通常独立包含数据片段;Node之间可通过关系(如父子、先后)构建复杂的图结构
典型使用场景数据加载与初始化,统一元数据管理(如为整个文档设置来源、作者)构建各类索引(向量、关键词等)的基础,实现精确的语义检索,构建复杂的关系知识图谱

关于Document

  • 数据的起点:在LlamaIndex中,任何外部数据(PDF、数据库、网页等)首先需要通过数据连接器被加载成一个或多个 Document 对象。它充当了原始数据的统一接口,随后,通过称为 NodeParser(节点解析器)的组件,将Document解析为多个Node。
  • 元数据承载Document 级别非常适合存储文档整体的元数据,例如 file_name(文件名)、author(作者)、category(分类)等。这些元数据可以被其下的所有 Node 继承,也可用于高级检索策略。

关于Node

  • 索引的基石Node 是LlamaIndex构建索引的真正原材料。将 Document 解析成 Node 的过程(常称为”分块”或”切分”)对检索性能至关重要。
  • 灵活的关系定义:Node不仅是文本块,每个 Node 可以与其他 Node 建立关系,例如 Next(下一个)、Previous(上一个)、Parent(父级)、Child(子级)等。这使得LlamaIndex不仅能处理线性文本,还能构建树状或图状的复杂知识结构,这对于理解长文档的逻辑或回答需要多步推理的问题非常关键。

Document和Node在LlamaIndex中分别扮演着数据容器和语义单元的角色。理解它们的分工与协作,是有效使用LlamaIndex构建高效检索系统的关键。 Document负责承载原始数据,而Node则作为构建索引、进行语义检索和生成回答的真正基石。


3.2 元数据传播机制

LlamaIndex中的元数据传播遵循继承原则:

  1. Document级元数据:自动传播到所有由该Document生成的Node
  2. Node级元数据:可以覆盖或补充Document级元数据
  3. 关系元数据:存储Node之间的关系信息,如父子、前后关系

3.3 Node结构
属性名类型说明
id_ (node_id)str节点的唯一标识符,可自动生成或手动指定
textstr节点包含的文本内容 (chunk)
metadataDict[str, Any]存储文档的元数据信息(如文件名、页码等)
embeddingList[float]节点的向量嵌入表示
relationshipsDict[NodeRelationship, RelatedNodeInfo]节点间关系映射
hashstr内容的哈希值,用于去重和变更检测
excluded_embed_metadata_keysList[str]embedding 时排除的元数据键
excluded_llm_metadata_keysList[str]LLM 处理时排除的元数据键
start_char_idxOptional[int]在原始文档中的起始字符位置
end_char_idxOptional[int]在原始文档中的结束字符位置
text_templatestr文本格式化模板
metadata_templatestr元数据格式化模板

3.4 关系结构

切分后的Node之间可以建立多种关系:

  1. 前后关系:表示Node在原文档中的顺序
  2. 父子关系:表示层次化切分中的层级关系
  3. 相似关系:表示语义相似的Node

文档切分核心原则

有效的文档切分应遵循以下核心原则,以确保切分结果既保持语义完整性又满足检索需求。

4.1 语义完整性原则

核心思想:切分应尽量不破坏语义单元的完整性,避免在句子或段落中间进行不合理的分割。

  • 句子边界优先:优先在自然语言句子结束处(如句号、问号、感叹号)进行分割

  • 段落边界考虑:在段落分隔符处进行分割,保持段落的完整性

  • 主题连贯性:切分点应选择在主题转换处,避免将不同主题的内容混合在一个块中

  • 例如

    • 块1:“人工智能的核心技术包括机器学习和深度学习。”
    • 块2:“这两者都属于监督学习的范畴。“

4.2 长度控制原则

核心思想:控制每个文本块的长度,使其适应模型的上下文限制和检索需求。

  • 模型上下文限制:确保块大小不超过模型的输入限制
    • DeepSeek-R1: 128K tokens
  • 检索效率考虑:过大的块会增加检索噪声,过小的块会丢失上下文
    • 对于一般文档:300-800 tokens
    • 技术文档:400-600 tokens
    • 对话记录:200-400 tokens

4.3 重叠率原则
[Artificial intelligence is] [transforming technology] [and shaping the future.]
|--------- Chunk 1 ------------------|
                             |--------- Chunk 2 -----------------------|
                             |<----- Overlap ------->|

核心思想:在相邻文本块之间设置适当的重叠区域,避免重要信息在边界处丢失。

  • 上下文连续性:重叠区域确保跨边界的语义连续性
  • 信息完整性:防止关键信息因切分而被分割到不同块中
  • 重叠大小优化:通常设置为块大小的10-20%,根据具体应用场景调整

4.4 特殊格式策略原则

核心思想:针对特殊格式的文档(如代码、表格、列表)采用专门的切分策略。

  • 代码块完整性:保持函数、类等代码单元的完整性
  • 表格结构保持:尽量保持表格的完整性,避免将表格内容分割
  • 列表项处理:保持列表项的完整性,避免将单个列表项分割

切分工具选型与实战

LlamaIndex提供了多种切分工具,适应不同的文档类型和应用场景。了解这些工具的特点和适用场景是选择合适切分策略的关键。

维度TextSplitterNodeParser
核心定位基础的文本分割工具高级的文档解析与节点生成框架
处理逻辑通常基于固定规则,如长度、标点或字符递归分割除基础分割外,可集成语义分割、代码解析等复杂策略
输出结果文本块(字符串列表)Node对象列表,包含文本、元数据及节点间关系信息
语义感知通常不具备部分解析器(如SemanticSplitterNodeParser)具备语义感知能力
性能特点轻量快速,计算开销小功能更强的解析器(如语义分割)可能速度较慢,计算成本高
适用场景基于语义相似度进行文本切分,保持语义连贯性
处理主题转换自然、结构复杂的文档
对切分质量要求较高的生产环境
构建生产级RAG系统
处理复杂文档(如代码、学术论文)
需要利用节点间关系(如父节点…)进行复杂查询

5.1 Text-Splitters (文本分割器) 类型

Text-Splitters专注于将任意文本字符串拆分成多个片段,按字符/句子/token/自定义分隔规则切分,通常只关心文本长度与重叠上下文,不会理解文件格式。

5.1.1 TokenTextSplitter Token切分器

TokenTextSplitter按照token长度进行切分,适用于需要精确控制token数量的场景,特别是在有严格token限制的嵌入模型或语言模型中使用。

核心特性:

  • 基于token而非字符进行切分,更准确地反映模型处理能力
  • 支持不同的token计算方法(如tiktoken、huggingface tokenizer)
  • 适用于多语言场景,不同语言的token密度不同

5.1.2 SentenceSplitter 句子切分器

SentenceSplitter是一种基于自然语言句子和段落边界进行分割的解析器,类似于LangChain的RecursiveCharacterTextSplitter。它优先在句子结束处或段落分隔符处进行分割,尽量避免在句子中间切断,以保持语义单元的完整性。

核心特性与工作原理:

  • 保持句子完整性:首先尝试按句子边界(如中文的”。” ”!” ”?” 或英文的”.” ”!” ”?”)进行分割
  • 递归分割策略:如果单个句子长度超过chunk_size,则递归地使用更小的分隔符进行分割
  • 重叠控制:通过chunk_overlap参数,允许相邻文本块之间有少量重叠的token
  • 多语言支持:通过separator参数可以自定义分隔符

关键参数:

参数名类型说明默认值
chunk_sizeint每个文本块的目标最大token数1024
chunk_overlapint相邻文本块之间重叠的token数200
separatorstr用于分割的主要分隔符” ” (空格)
paragraph_separatorstr用于识别段落的分隔符”\n\n\n”

适用场景:SentenceSplitter非常适用于自然语言文本,如新闻文章、博客文章、书籍章节等结构清晰的散文体内容。


5.1.3 CodeSplitter 代码切分器

CodeSplitter专为编程语言源代码设计,利用编程语言的抽象语法树(AST)来理解代码结构,确保将代码按功能单元进行分割。

核心特性:

  • 基于抽象语法树(AST)的结构化解析
  • 语言特定,需要指定编程语言
  • 保持代码块的功能完整性

5.2.2 JSONNodeParser Json切分器

JSONNodeParser用于处理JSON文件,能够根据JSON结构进行切分,保持数据的层次关系。


5.2.3 SemanticSplitterNodeParser 语义切分器

SemanticSplitterNodeParser通过嵌入模型计算文本块间的语义相似度,实现自适应断点识别,核心解决固定分块的语义割裂问题。其检索准确率较固定分块提升20%左右,适合对上下文连贯性要求高的场景(如学术论文、长文档理解)。

实现原理

  1. 句子分割:将文档拆分为独立句子单元
  2. 嵌入计算:通过嵌入模型(如OpenAIEmbedding、BAAI/bge-m3)生成句子向量,计算成本较高
  3. 相似度判断:计算相邻句子向量的余弦相似度
  4. 断点识别:当相似度低于设定阈值(如breakpoint_percentile_threshold=90)时执行切分
  5. 块生成:合并语义相近的句子为完整分块,适用于对语义连贯性要求高的场景

简单来说,它的工作流程是:先将文本拆分成句子,然后通过滑动窗口计算句子群的综合语义,最后在语义发生显著变化的地方(即相似度低于阈值时)进行分割,它的分割点是动态的、由语义决定的,因此无法像固定大小的分割器那样,简单地在前一个块的末尾和后一个块的开头插入一段重叠的文本;这种基于语义的分割方式,其设计目标之一就是让每个分割出的文本块在语义上尽可能独立和完整。buffer_size参数在某种程度上扮演了维持上下文连贯性的角色,因为它确保了在判断是否分割时,已经考虑了当前句子周围一定范围内的语义上下文。

调优建议

  • 尝试不同buffer_size:
    • 1 对局部句子差异敏感
    • 2~3 会以更宽的窗口判断相似度(可能得到更长但更连贯的chunk)
  • 断点阈值 (breakpoint_percentile_threshold):
    • 降低阈值会更容易切断(产生更多小块)
    • 提高阈值会合并更多句子
  • 中文句子拆分要牢靠:务必先用可靠的拆句器;对复杂文本(引号、括号、列表)需要更细致的预处理。
  • 超长chunk的”安全裁剪”:在极端结构化文本中可能产生超长chunk(导致embedding报错),可以在 SemanticSplitterNodeParser 之后接一个 SentenceSplitterNodeParserTokenTextSplitter 作”后备分割”。

5.2.4 SentenceWindowNodeParser 句子窗口切分器

SentenceWindowNodeParser的工作流程核心在于检索单元和上下文窗口的分离:

  1. 精细索引:在索引构建阶段,它会将文档拆分成单个句子作为基础节点(Node)。这种细粒度拆分有助于向量模型更好地表征句子语义,从而在检索时能更精准地找到相关句子。
  2. 窗口上下文:每个句子节点都会在元数据(metadata)中存储其周围句子构成的窗口文本。检索时,系统首先找到最相关的句子节点,然后将其替换为对应的上下文窗口,再将这个更大的文本块传递给LLM生成答案。

这种方法有效缓解了RAG系统中”检索精度”与”生成答案所需上下文完整性”之间的矛盾。

特性维度具体说明
核心原理将文档按句子拆分并建立索引,检索时返回匹配句子及其周围句子(滑动窗口)。
主要优势检索与上下文解耦:检索用小粒度句子提升精度,提供给LLM的是包含更完整上下文的窗口文本。
关键参数windowsize:控制窗口大小;windowmetadata_key:存储窗口文本的元数据键名。
典型应用场景处理文档结构清晰、句子间逻辑连贯的文档,如技术文档、学术论文、法律合同等。

使用注意事项

  • 处理长文档:
    • 对于多页PDF,有时需要先将所有页面的文本内容合并为一个文档,以确保句子窗口能跨页面边界正确划分。
  • 窗口大小的选择:
    • 太小:可能无法提供足够的上下文,影响LLM的理解。
    • 太大:会增加传递给LLM的token数量,可能导致成本上升和处理延迟,甚至可能触及模型上下文长度限制。
    • 通常建议从3开始尝试,并根据效果调整。
  • 适用场景:
    • 处理结构清晰的文档:对于技术文档、学术论文、法律合同等逻辑性强、句子间关联紧密的文档,能有效避免固定分块可能导致的答案被割裂的问题。
    • 对答案准确性要求高的应用:当需要LLM生成的答案严格基于文档上下文,减少”幻觉”时,提供更完整的窗口上下文有助于提升答案的准确性和可靠性。

5.2.5 HierarchicalNodeParser 结构切分器

HierarchicalNodeParser结合文档结构(标题、章节、段落)和语义边界进行多层次切分,适合处理Markdown、PDF、Word等结构化文档,尤其适用于说明书、规约、设计文档等场景。其核心优势在于保留文档原生逻辑层级,支持父节点(章节标题+简介)与子节点(具体段落)的嵌套组织。

5.3 混合策略

结合多种切分策略,发挥各自优势:

5.3.1 Unstructured的chunk_by_title

核心思想:利用Title元素作为分段标志,将Title与其后的内容组合成语义完整的chunk

  • 优势:
    • 保留文档结构边界
    • 自动合并小段落
    • 保留元数据层级信息
    • 避免噪音被混入
5.3.2 HierarchicalNodeParser 结合 SemanticSplitterNodeParser语义切分 ¶

核心思想:创建多层级的chunk结构,对长文本再进一步使用SemanticSplitterNodeParser或其他切分器进行

  • 优势:
    • 提供多粒度检索
    • 自动保留父子关系
    • 适合长文档
5.3.3 Metadata增强的自定义切分
  • 适用场景:需要精确控制metadata传播和Title信息保留
  • 核心思想:将Title信息注入到后续chunks的metadata中
# ==================== 步骤4: 使用Metadata Extractor进一步增强 ====================
"""
可选: 使用LLM自动提取更多metadata
"""

# 导入metadata提取器
from llama_index.core.extractors import (
    TitleExtractor,
    SummaryExtractor,
    KeywordExtractor,
    QuestionsAnsweredExtractor,
)

# 导入IngestionPipeline管道
from llama_index.core.ingestion import IngestionPipeline


# 定义metadata提取器
extractors = [
    TitleExtractor(nodes=5),      # 从前5个节点提取标题
    KeywordExtractor(keywords=10),    # 提取10个关键词
    SummaryExtractor(summaries=["self"]),   # 生成摘要
    QuestionsAnsweredExtractor(questions=3),    # 生成3个问题
]

切分策略选择与优化

选择合适的切分策略并对其进行优化是构建高效RAG系统的关键步骤。本节将介绍如何根据不同的应用场景选择合适的切分策略,并提供优化建议。

6.1 切分工具选择
场景推荐工具原因
普通文本/报告/网页SentenceSplitter简单快速,保持句子完整性
长文本/Embedding限制场景TokenTextSplitter精确控制token数量
精确语义块/摘要场景SemanticSplitterNodeParser基于语义的智能切分
技术文档、NotebookCodeSplitter保持代码结构完整性
教程、技术博客MarkdownNodeParser识别Markdown层级结构
教材、论文类文档HierarchicalNodeParser
6.2 切分策略选择
文档类型推荐策略关键参数
结构化文档 (Markdown、PDF、Word)HierarchicalNodeParserchunk_sizes=[2048, 512, 128]
纯文本 (小说、新闻、邮件)SentenceSplitterchunksize=500, chunkoverlap=50
代码文件CodeSplitterlanguage=“python”, max_chars=1000
混合文档 (文本+表格+图像)Unstructured + SentenceSplitterchunksize=500, chunkoverlap=50
长文档 (书籍、报告)SemanticSplitterbuffersize=1, breakpointpercentile_threshold=90
  • 通用场景(如博客、新闻):优先使用SentenceSplitter,兼顾速度与可用性
  • 高精度需求(如法律合同、医疗报告):使用SemanticSplitterNodeParser,牺牲部分效率换取检索的准确率提升
  • 结构化文档(如技术手册、学术论文):强制指定HierarchicalNodeParser,利用文档自身层级优化分块
6.3 切分策略优化方法
6.3.1 参数调优
  1. 块大小 (chunk_size) 优化:
  • 小块 (< 300 tokens):高精度,低上下文,适用于精确匹配
  • 中等块 (300-800 tokens):平衡精度与上下文,适用于大多数场景
  • 大块 (> 800 tokens):高上下文,低精度,适用于长文档理解
  1. 重叠区域 (chunk_overlap) 优化:
  • 小重叠 (< 50 tokens):减少冗余,提高检索效率
  • 中等重叠 (50-150 tokens):平衡上下文连续性与效率
  • 大重叠 (> 150 tokens):确保上下文连续性,增加冗余
  1. 语义断点阈值 (breakpoint_percentile_threshold) 优化:
  • 低阈值 (< 80):产生更多小块,提高检索精度
  • 中等阈值 (80-90):平衡块大小与语义连贯性
  • 高阈值 (> 90):产生更大块,保持语义连贯性

切分效果评估

7.1 评估指标
  1. 检索指标:
  • 召回率 (Recall):检索到的相关文档占所有相关文档的比例
  • 精确率 (Precision):检索到的文档中相关文档的比例
  • F1分数:召回率和精确率的调和平均
  1. 生成质量指标:
  • 相关性:生成内容与查询的相关程度
  • 完整性:生成内容是否包含完整信息
  • 准确性:生成内容是否准确无误
  1. 效率指标:
  • 检索时间:从查询到返回结果的时间
  • 生成时间:从检索结果到生成答案的时间
  • 资源消耗:计算资源(CPU、GPU、内存)使用情况

总结

8.1 通用最佳实践
  1. 了解你的数据:在切分之前,充分了解文档的结构、内容和特点
  2. 选择合适的策略:根据文档类型和应用场景选择最适合的切分策略
  3. 调整参数:根据实际效果调整切分参数,如块大小、重叠区域等
  4. 评估效果:建立评估体系,定期评估切分效果并优化策略
  5. 混合使用:结合多种切分策略,发挥各自优势
8.2 参考文献
  1. LlamaIndex官方文档. Node Parsers. https://developers.llamaindex.ai/python/framework-api-reference/node_parsers/
  2. LlamaIndex官方文档. Evaluating. https://developers.llamaindex.ai/python/framework-api-reference/evaluation/
  3. 图片参考出处:https://blog.dailydoseofds.com/p/5-chunking-strategies-for-rag
商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。本文采用 CC BY-NC-SA 4.0 - 非商业性使用 - 相同方式共享 4.0 国际 进行许可。

Comments

Notes, questions, and follow-ups are welcome here.

Comments are temporarily unavailable because WALINE_SERVER_URL or PUBLIC_WALINE_SERVER_URL is not configured.