Part3 RAG文档切分


0. 文档整体在讲什么

这份 Notebook 的主线是:RAG 系统里"文档切分(chunking)"怎么做得更好 。它强调切分不是"随便按长度分块",而是一个工程化的端到端流程

  1. 先做数据清洗与预处理(高性价比,能显著降低噪声、成本与错误检索)
  2. 再理解切分在 RAG 中的作用与基本流程
  3. 以 LlamaIndex 为例解释:Document/Node/Metadata/Relationship 这些对象与机制
  4. 给出"切分核心原则"(语义完整、长度控制、重叠、特殊格式)
  5. 进入实战:各种切分器 / NodeParser(Token / Sentence / Code / Markdown / JSON / Semantic / SentenceWindow / Hierarchical)
  6. 最后讲:如何选型、如何混合策略、如何调参优化、如何评估效果与最佳实践

第一阶段:数据清洗与预处理

1.1 总体目标与原则

核心目标:在切分前把噪声降到最低,让后续 chunk 更"干净"、更可检索。主要收益:

  • 降低向量库存储成本(少存垃圾)
  • 提高检索速度(更少无效 chunk)
  • 提升回答质量(减少"检索到噪声→LLM胡说"的概率)
  • 更容易识别合理切分边界(段落/句子/标题)

清洗的典型处理点(Notebook 强调的方向):

  • 去除无关内容:HTML/XML 标签、脚注、导航栏、页眉页脚、无意义重复段
  • 统一空白:多空格/制表符/换行异常
  • 修复断行/断词:例如 PDF 抽取导致的 "word- \n next" 断裂
  • 标点/引号标准化(避免下游分句、tokenizer 异常)
  • 特殊字符处理与转义(避免解析器误判)

1.2 不同类型数据的清洗步骤

1.2.1 纯文本文档清洗(Notebook 有示例代码)

主要做:

  • 空白归一化:\s+ -> 单空格
  • 断词修复:(\w+)-\s+(\w+) -> \1\2
  • HTML 标签去除:<.*?> -> ''
  • Markdown 简化:去掉 **bold** 等标记但保留文字;把 [text](url) 变成 text

Notebook 用 re 写了 clean_text / clean_html / clean_markdown 这类函数,并给了简单 demo。

1.2.2 表格数据清洗(Notebook 有 pandas 示例)

表格清洗重点是结构完整性字段一致性,典型操作:

  • 去重、处理缺失值(填充/删除/统一空值表示)
  • 统一列名:去空格、规范命名
  • 类型纠正:数值列/日期列转换
  • 去掉单元格多余空白、异常字符
  • (如果来源是 OCR/抽取)还要处理错列、合并单元格造成的错位

Notebook 有 clean_table(df) 示例:对 DataFrame 做去重、缺失处理、列名 strip 等,并演示"处理前/处理后"。

1.2.3 图像文档清洗(扫描 PDF 等)

这类通常要先 OCR。Notebook 给的思路:

  • 图像预处理:二值化、降噪、倾斜校正
  • 再 OCR 得到文本后,回到"纯文本清洗"的流程
  • 提醒:图像处理需要专门库(示例提到了 cv2 / matplotlib
1.2.4 代码块清洗

代码的清洗原则和自然语言相反:要尽量保持格式

常见处理:

  • 去除行尾空白(不破坏缩进结构)
  • 合并连续空行(适度)
  • 清理首尾空行
  • 不随便改缩进、不乱折行(否则语义变了)
1.2.5 混合文档清洗

混合文档(正文 + 表格 + 代码 + 图片)建议:

  • 先分类再分别清洗
  • 对企业级 RAG:清洗往往比"换一个更复杂的切分器"更划算
  • 图片表格:先 OCR 再结构化(否则表格清洗是假设数据已结构化)

1.3 数据清洗最佳实践

Notebook 给的工程建议(归纳):

  • 建立可复用的清洗 pipeline(不同源数据可插拔)
  • 保留原始副本,做好版本控制与回滚
  • 把清洗规则与异常案例沉淀成可测试的规则集
  • 优先处理"高频噪声源"(页眉页脚、目录、重复免责声明等),ROI 最高

第二阶段:RAG 文档切分概述

2.1 切分的重要性

切分直接决定:

  • 检索准确性:检索到的 chunk 是否包含完整答案证据
  • 生成质量:检索上下文是否足够支撑 LLM 不胡编
  • 计算效率:chunk 太大→embedding/检索慢;太小→索引量爆炸 & 召回碎片化

2.2 切分粒度对效果的影响("第一性变量")

Notebook 强调两个极端的风险:

  • 块过大

    • 向量表示"混杂主题",相似度不稳定
    • 检索召回内容冗余,浪费上下文窗口
    • 可能把不相关内容一起喂给模型导致跑偏
  • 块过小/切分不当

    • 语义被切碎,一个知识点分散在多个 chunk
    • 检索时只命中碎片,答案不完整
    • 需要更高 overlap 或更复杂的重组策略来补救

2.3 文档切分的基本流程

  1. 文档加载(loader)
  2. 清洗预处理
  3. 选择切分方法(按文档类型/场景)
  4. 执行切分生成 chunk / node
  5. 后处理(合并、过滤、补 metadata、建关系)
  6. 写入向量库 / 索引结构

2.4 切分效果评估指标(概览)

  • 语义完整性
  • 上下文覆盖度(是否能覆盖问答所需信息)
  • 检索效果(召回率/精确率)
  • 生成质量(回答是否基于证据、是否幻觉少)
  • 计算效率(切分耗时、检索耗时、token 成本)

第三阶段:LlamaIndex 核心对象概念

3.1 Document vs Node

Notebook 用表格对比核心差异(总结成一句话):

  • Document:原始文档容器(内容 + 元数据),是数据入口
  • Node:切分后的语义单元(带文本、元数据、关系),是索引真正使用的基本颗粒

典型用途:

  • Document:统一管理"来源、作者、分类、时间"等文档级信息
  • Node:做 embedding、建立索引、做检索、做父子层级与窗口扩展

3.2 元数据传播机制(Metadata Inheritance)

遵循"继承 + 覆盖":

  1. Document 级元数据:默认传给所有子 Node
  2. Node 级元数据:可新增或覆盖
  3. 关系元数据:描述 Node 之间父子、前后等关系(用于高级检索与上下文拼接)

3.3 Node 结构

Notebook 罗列了 Node 常见字段(你可以理解为):

  • id_:唯一标识
  • text/content:节点文本
  • metadata:元数据
  • relationships:关系(父子/前后/来源等)
  • 其他:可能包含 embedding、score、start/end 等信息(视实现)

3.4 关系结构(Relationships)

重点两类:

  • 前后关系:保持原文顺序,支持"扩展上下文窗口"
  • 父子层级关系:保持章节结构,支持 hierarchical retrieval(先检索父,再下钻子)

第四阶段:文档切分核心原则

4.1 语义完整性原则

尽量不要把句子、段落、列表项、代码块从中间切断。

Notebook 用例强调:错误切分会让"因果/指代/定义"断开。

4.2 长度控制原则

目标:让 chunk 既能被 embedding 表达好,也能在 LLM 上下文窗口里高效使用。

Notebook 给了经验区间(大意):

  • 通用文档:约 300--500 tokens
  • 技术文档:约 400--600 tokens
  • 对话记录:约 200--400 tokens
    (实际要结合你的模型、向量库、检索 top-k、prompt 模板一起调)

4.3 重叠率原则(Overlap)

重叠用于避免边界信息丢失,常见经验:

  • overlap 通常设为 chunk_size 的 10%--20%
  • overlap 过高会导致索引冗余、向量库膨胀、检索重复
  • overlap 过低容易漏掉跨边界信息(定义+结论分裂)

4.4 特殊格式策略原则

不同内容要"特殊对待":

  • 代码:保持函数/类完整,别随便按句子切
  • 表格:尽量保持表格整体或按行/块切但保留结构信息
  • 列表:保持列表项完整,避免拆半条

第五阶段:切分工具选型与实战(Notebook 最核心的一段)

这一阶段分三块:
5.1 文本分割器 Text-Splitters5.2 文件型 Node Parsers5.3 混合策略


5.1 Text-Splitters(文本分割器)

5.1.1 TokenTextSplitter(按 token 切)

适用:

  • 你需要严格控制 token 数(模型上下文限制强、embedding 有 token 限制)
  • 文本结构弱(没有明显标题/段落)

关键参数(Notebook 代码里出现):

  • chunk_size:目标 token 数(例:512)
  • chunk_overlap:重叠 token 数(例:64)
  • separator:分隔符(一般空格)

优缺点:

  • ✅ 精准控长、实现简单
  • ❌ 容易破坏语义边界(可能在句中间断)
5.1.2 SentenceSplitter(按句子切 + 再控长)

适用:

  • 普通文本、博客、新闻、说明文
  • 想要比纯 token 切更好的语义连续性

Notebook 的要点:

  • "句子边界"优先于"固定长度"
  • 仍然会配 chunk_size/overlap 去拼接成合适大小

风险提醒:

  • 如果句子分割不准(尤其中文),会造成段落断裂
  • 对标题、列表等结构化信息不敏感(不如 Markdown/Hierarchical)
5.1.3 CodeSplitter(代码切分器)

适用:

  • 代码库、API 文档、Notebook 输出代码片段
    核心原则:
  • 以函数/类/代码块结构为边界
  • 保持缩进与语法结构完整

5.2 File-Based Node Parsers(文件型节点切分器)

5.2.1 MarkdownNodeParser

适用:

  • Markdown 文档(天然结构化:标题、段落、列表、代码块)
    核心:
  • 以标题层级/块结构切分,比 SentenceSplitter 更结构友好
5.2.2 JSONNodeParser

适用:

  • JSON 配置、日志、结构化数据导出
    核心:
  • 按 key-path/对象粒度拆分(避免打平导致语义丢失)
5.2.3 SemanticSplitterNodeParser(语义切分器,Notebook 很强调)

适用:

  • 主题跳跃明显的长文
  • 你希望切分点由"语义相似度变化"决定,而不是长度/句子

实现原理(Notebook 描述的核心逻辑):

  • 先得到一系列候选片段(通常是句子或小段)
  • 用 embedding 计算相邻片段语义相似度/距离
  • 在"语义断裂"处插入切分点(breakpoint)

关键可调参数(Notebook 在"调优建议"里反复提):

  • buffer_size:用于比较的上下文窗口大小(越大越平滑,越小越敏感)

  • breakpoint_percentile_threshold(或类似阈值概念):

    • 低阈值:更容易切 → chunk 更碎
    • 中阈值(80--90):常用平衡点
    • 高阈值(>90):更不容易切 → chunk 更大更连贯

调优方向(Notebook 给的经验):

  • 你如果发现 chunk 太碎:提高 threshold / 增大 buffer
  • 你如果发现主题混杂:降低 threshold / 减小 buffer
5.2.4 SentenceWindowNodeParser(句子窗口切分器)

核心思想:

  • 以"句子"为索引单元,但在检索/组装时带上窗口邻居句子 (前后扩展)
    适用:
  • 问答需要上下文,但你又不想把索引块做得很大
  • 对"局部上下文依赖"强的文本(定义在前一句,结论在后一句)

Notebook 还专门给了:

  • 英文文本实践
  • 中文文本实践
  • 使用注意事项(通常是:窗口太大=冗余;太小=上下文不足;中文分句要稳)
5.2.5 HierarchicalNodeParser(结构切分器)

核心:

  • 按层级切(章节→小节→段落),建立父子关系
    适用:
  • 教材、论文、规范、技术手册(结构强、标题层级清晰)
    优势:
  • 检索可以先命中父节点(章节),再下钻子节点(段落/细节)
  • 便于做"多粒度检索"和"上下文拼装"

Notebook 强调的策略理念:

  • 默认设置优先:先用默认跑通 + 看评估,再针对业务场景调参
  • 场景适配:结构强文档优先 Hierarchical;主题跳跃优先 Semantic;普通文本优先 Sentence

5.3 混合策略(工程里最常用)

5.3.1 Unstructured 的 chunk_by_title

适用:

  • 你希望"按标题分块"优先,兼顾结构
  • 文档来源复杂(PDF/HTML/Word)但能抽出标题结构
5.3.2 HierarchicalNodeParser + SemanticSplitterNodeParser

思路:

  • 第一层按结构切(章节/小节)
  • 第二层在每个小节内部再做语义切分(避免一个小节里主题仍然过长或跳跃)
5.3.3 Metadata 增强的自定义切分

核心思想:

  • chunk 不只是 text,还要"可检索的标签"
  • 通过规则或模型抽取 metadata(标题、章节号、主题、时间、实体、来源链接等)
  • 让检索阶段能用 metadata 做过滤、加权、分组
使用 Metadata Extractor 进一步增强

Notebook 的方向是:

  • 在 Node 生成后跑一遍 metadata extractor(实体/关键词/摘要等)

  • 用于:

    • 提高检索精度(过滤、rerank 特征)
    • 提高答案可解释性(引用来源更清晰)

第六阶段:切分策略选择与优化

6.1 切分工具选择(按场景表格)

Notebook 的选型逻辑可以总结为:

  • 普通文本/报告/网页:SentenceSplitter(简单、稳)
  • 代码:CodeSplitter
  • Markdown:MarkdownNodeParser
  • JSON:JSONNodeParser
  • 教材/论文/强结构文档:HierarchicalNodeParser
  • 主题跳跃/需要语义边界:SemanticSplitterNodeParser

6.2 切分策略选择(按文档类型→策略→关键参数)

Notebook 给的总体建议:

  • 通用场景:SentenceSplitter 起步
  • 高精度场景(合同、法规、技术规范):更倾向结构/层级/语义切分 + 更严谨评估
  • 多格式混合:优先混合策略(标题/结构优先,再做语义微调)

6.3 切分策略优化方法(重点:参数调优)

Notebook 把调优拆成几类:

  1. chunk_size
  • 小(<300 tokens):召回精细,但更碎、索引量大
  • 中(300--600 tokens):常见平衡区
  • 大(>800 tokens):上下文强但主题混杂概率大、检索更粗
  1. chunk_overlap
  • 10--20% 作为经验起点
  • 观察检索碎片化/重复率,再增减
  1. Semantic 的阈值(breakpoint_percentile_threshold)
  • 低:切得更碎
  • 中(80--90):平衡
  • 高(>90):块更大更连贯
  1. buffer_size / window_size(语义切分或句子窗口)
  • 越大越稳定但可能糊在一起
  • 越小越敏感但可能过度切分

第七阶段:切分效果评估

7.1 评估指标(更落地的分类)

Notebook 把评估分为三类:

  1. 检索指标
  • Recall(召回率)
  • Precision(精确率)
  • Top-k 命中率(问题答案证据是否在 top-k 里)
  1. 生成质量指标
  • 答案正确性/完整性
  • 幻觉率(是否无中生有)
  • 引用一致性(回答是否能对应检索证据)
  1. 效率指标
  • 切分耗时
  • 检索耗时
  • 生成耗时
  • 资源消耗(CPU/GPU/内存)与 token 成本

第八阶段:总结(通用最佳实践 + 参考资料)

8.1 通用最佳实践(Notebook 的"落地清单"风格)

可归纳为一组工程 checklist:

  • 先理解数据:结构强不强?主题跳跃多不多?是否多格式混合?
  • 清洗优先:先降噪再切分(性价比最高)
  • 从简单策略起步:SentenceSplitter/MarkdownNodeParser 跑 baseline
  • 用评估驱动调参:不要凭感觉"越复杂越好"
  • 必要时混合:结构切 + 语义切 + metadata 增强
  • 让 chunk 可解释:保留来源、章节、标题、页码/段落号等元数据,方便引用与排错

8.2 参考文献/资料(Notebook 里出现的链接方向)

  • LlamaIndex Node Parsers API
  • LlamaIndex Evaluation API
  • 一篇 chunking strategies 的文章(5 种切分策略)
  • 以及图像预处理/OCR 相关参考链接

你如果想把它用到项目里:这份 Notebook 的"最重要结论"(一句话版)

清洗先行 + 语义完整 + 合理长度/重叠 + 针对文档类型选对 parser + 用评估闭环调参,才是 RAG 切分的正确打开方式;复杂策略(Semantic/Hierarchical/Window/Metadata)应当在 baseline 上按收益逐步叠加。


相关推荐
Hgfdsaqwr18 小时前
Django全栈开发入门:构建一个博客系统
jvm·数据库·python
开发者小天19 小时前
python中For Loop的用法
java·服务器·python
老百姓懂点AI19 小时前
[RAG实战] 向量数据库选型与优化:智能体来了(西南总部)AI agent指挥官的长短期记忆架构设计
python
奥特曼_ it20 小时前
【数据分析+机器学习】基于机器学习的招聘数据分析可视化预测推荐系统(完整系统源码+数据库+开发笔记+详细部署教程)✅
笔记·数据挖掘·数据分析
四维碎片21 小时前
QSettings + INI 笔记
笔记·qt·算法
喵手21 小时前
Python爬虫零基础入门【第九章:实战项目教学·第15节】搜索页采集:关键词队列 + 结果去重 + 反爬友好策略!
爬虫·python·爬虫实战·python爬虫工程化实战·零基础python爬虫教学·搜索页采集·关键词队列
Suchadar21 小时前
if判断语句——Python
开发语言·python
ʚB҉L҉A҉C҉K҉.҉基҉德҉^҉大21 小时前
自动化机器学习(AutoML)库TPOT使用指南
jvm·数据库·python
喵手1 天前
Python爬虫零基础入门【第九章:实战项目教学·第14节】表格型页面采集:多列、多行、跨页(通用表格解析)!
爬虫·python·python爬虫实战·python爬虫工程化实战·python爬虫零基础入门·表格型页面采集·通用表格解析
zzcufo1 天前
多邻国第5阶段17-18学习笔记
笔记·学习