0. 文档整体在讲什么
这份 Notebook 的主线是:RAG 系统里"文档切分(chunking)"怎么做得更好 。它强调切分不是"随便按长度分块",而是一个工程化的端到端流程:
- 先做数据清洗与预处理(高性价比,能显著降低噪声、成本与错误检索)
- 再理解切分在 RAG 中的作用与基本流程
- 以 LlamaIndex 为例解释:Document/Node/Metadata/Relationship 这些对象与机制
- 给出"切分核心原则"(语义完整、长度控制、重叠、特殊格式)
- 进入实战:各种切分器 / NodeParser(Token / Sentence / Code / Markdown / JSON / Semantic / SentenceWindow / Hierarchical)
- 最后讲:如何选型、如何混合策略、如何调参优化、如何评估效果与最佳实践
第一阶段:数据清洗与预处理
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 文档切分的基本流程
- 文档加载(loader)
- 清洗预处理
- 选择切分方法(按文档类型/场景)
- 执行切分生成 chunk / node
- 后处理(合并、过滤、补 metadata、建关系)
- 写入向量库 / 索引结构
2.4 切分效果评估指标(概览)
- 语义完整性
- 上下文覆盖度(是否能覆盖问答所需信息)
- 检索效果(召回率/精确率)
- 生成质量(回答是否基于证据、是否幻觉少)
- 计算效率(切分耗时、检索耗时、token 成本)
第三阶段:LlamaIndex 核心对象概念
3.1 Document vs Node
Notebook 用表格对比核心差异(总结成一句话):
- Document:原始文档容器(内容 + 元数据),是数据入口
- Node:切分后的语义单元(带文本、元数据、关系),是索引真正使用的基本颗粒
典型用途:
- Document:统一管理"来源、作者、分类、时间"等文档级信息
- Node:做 embedding、建立索引、做检索、做父子层级与窗口扩展
3.2 元数据传播机制(Metadata Inheritance)
遵循"继承 + 覆盖":
- Document 级元数据:默认传给所有子 Node
- Node 级元数据:可新增或覆盖
- 关系元数据:描述 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-Splitters → 5.2 文件型 Node Parsers → 5.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 把调优拆成几类:
- chunk_size
- 小(<300 tokens):召回精细,但更碎、索引量大
- 中(300--600 tokens):常见平衡区
- 大(>800 tokens):上下文强但主题混杂概率大、检索更粗
- chunk_overlap
- 10--20% 作为经验起点
- 观察检索碎片化/重复率,再增减
- Semantic 的阈值(breakpoint_percentile_threshold)
- 低:切得更碎
- 中(80--90):平衡
- 高(>90):块更大更连贯
- buffer_size / window_size(语义切分或句子窗口)
- 越大越稳定但可能糊在一起
- 越小越敏感但可能过度切分
第七阶段:切分效果评估
7.1 评估指标(更落地的分类)
Notebook 把评估分为三类:
- 检索指标
- Recall(召回率)
- Precision(精确率)
- Top-k 命中率(问题答案证据是否在 top-k 里)
- 生成质量指标
- 答案正确性/完整性
- 幻觉率(是否无中生有)
- 引用一致性(回答是否能对应检索证据)
- 效率指标
- 切分耗时
- 检索耗时
- 生成耗时
- 资源消耗(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 上按收益逐步叠加。