all-in-rag第二章学习笔记
本文介绍了RAG(检索增强生成)流水线中的关键环节——数据加载与文本分块。在数据加载部分,详细对比了PyMuPDF4LLM、Unstructured等主流文档加载工具的特点和适用场景,重点讲解了Unstructured工具的多格式解析能力。文本分块部分阐述了固定大小分块、递归字符分块、语义分块等策略的原理及适用性,强调分块大小需适应模型限制并保持语义完整性。文章还分析了"块不是越大越好&
🔗教程链接all-in-rag
第一节、数据加载
-
垃圾进,垃圾出(Garbage in,Garbage out):高质量输入是高质量输出的前提
-
数据加载是RAG流水线的第一步,也是最基础最关键的环节
一、文档加载器
主要功能:文档格式解析、元数据提取、统一数据格式
当前主流RAG文档加载器
| 工具名称 | 特点 | 适用场景 | 性能表现 |
|---|---|---|---|
| PyMuPDF4LLM | PDF→Markdown转换,OCR+表格识别 | 科研文献、技术手册 | 开源免费,GPU加速 |
| TextLoader | 基础文本文件加载 | 纯文本处理 | 轻量高效 |
| DirectoryLoader | 批量目录文件处理 | 混合格式文档库 | 支持多格式扩展 |
| Unstructured | 多格式文档解析 | PDF、Word、HTML等 | 统一接口,智能解析 |
| FireCrawlLoader | 网页内容抓取 | 在线文档、新闻 | 实时内容获取 |
| LlamaParse | 深度PDF结构解析 | 法律合同、学术论文 | 解析精度高,商业API |
| Docling | 模块化企业级解析 | 企业合同、报告 | IBM生态兼容 |
| Marker | PDF→Markdown,GPU加速 | 科研文献、书籍 | 专注PDF转换 |
| MinerU | 多模态集成解析 | 学术文献、财务报表 | 集成LayoutLMv3+YOLOv8 |
二、Unstructured(重点工具)
- 格式支持广泛:PDF、Word、Excel、HTML、Markdown等
- 智能内容解析:自动识别文档结构元素,保留文档元数据信息
- 统一接口:无需为不同格式编写不同代码
重要文档元素类型
元素类型:
| 元素类型 | 说明 | 重要性 |
|---|---|---|
Title |
文档标题 | ★★★★★ |
NarrativeText |
正文文本 | ★★★★★ |
Table |
表格 | ★★★★☆ |
ListItem |
列表项 | ★★★★☆ |
CompositeElement |
分块产生的复合元素 | ★★★★☆ |
特别注意:CompositeElement是通过分块处理产生的特殊类型,理解它对于后续的文本分块很重要。
练习
window需要安装poppler,代码自动下载yolox_l0.05.onnx
from unstructured.partition.pdf import partition_pdf
# PDF文件路径
pdf_path = "../../data/C2/pdf/rag.pdf"
# 使用Unstructured加载并解析PDF文档
elements = partition_pdf(
filename=pdf_path,
content_type="application/pdf",
languages=["eng", "chi_sim"],
# hi_res_model_name="hi_res",
# hi_res_model_name="ocr_only"
# strategy="hi_res", # 会下载yolox_l0.05.onnx
strategy="ocr_only", #
)
strategy: 处理策略- “auto”:自动选择策略(默认)
- “fast”:快速策略,使用光学字符识别(OCR)以外的其他方法
- “ocr_only”:仅使用OCR来提取文本
- “hi_res”:高分辨率策略,使用OCR并且注重保持布局
pdf2image.exceptions.PDFInfoNotInstalledError: Unable to get page count. Is poppler installed and in PATH?
未成功
第二节、文本分块
一、 文本分块的本质
- 定义:将长篇文档切分成更小、更易处理的单元
- 地位:是后续向量检索和模型处理的基本单位
- 目标:在保持语义完整性与控制块大小之间找到平衡
二、为什么需要文本分块(关键原理)
2.1 适应模型限制(上下文限制)
| 模型类型 | 限制影响 | 解决方案 |
|---|---|---|
| 嵌入模型 | 严格输入长度上限(如512token) | 块大小必须≤模型窗口 |
| 大语言模型 | 上下文窗口限制 | 所有检索块+问题+提示词必须能放入窗口 |
2.2 为什么"块不是越大越好"(重要坑点)
信息损失问题
- 嵌入过程:token向量→池化→单一向量
- 向量稀释:块越长,语义信息越稀释,关键细节模糊化
"大海捞针"效应
- LLM倾向于记住开头和结尾信息
- 过大块会导致关键信息被淹没在噪音中
主题稀释导致检索失败
示例对比:
- 糟糕分块:"技能介绍+推荐出装+背景故事"在一个块
- 优秀分块:三个主题分别独立分块
- 结果:查询"出装"时,优秀分块能精准召回相关块
三、基础分块策略详解
3.1 固定大小分块(CharacterTextSplitter)
实际实现:并非严格固定大小,而是"段落感知的自适应分块"
工作流程:
- 按段落分割(默认
"\n\n") - 智能合并,优先保持段落完整性
- 处理超长段落(警告但保留)
适用场景:日志分析、数据预处理等简单场景
优势:实现简单、处理速度快且计算开销小。
3.2 递归字符分块(RecursiveCharacterTextSplitter)
核心算法:分层递归处理
优先级:段落→句子→单词→字符
关键特性:
- 从分隔符列表找第一个存在的分隔符;
- 切分后,短片段暂存,超长片段用剩余分隔符递归分割;
- 合并暂存片段为块
优势:相比固定大小分块,更能处理超长文本,减少语义割裂
代码语言特化:
splitter = RecursiveCharacterTextSplitter.from_language(
language=Language.PYTHON, # 自动使用代码结构分隔符
chunk_size=500,
chunk_overlap=50
)
3.3 语义分块(SemanticChunker)- 高级策略
核心思想:在语义主题显著变化处切分
工作流程:
- 句子分割 → 2. 上下文感知嵌入 → 3. 计算语义距离 → 4. 识别断点 → 5. 合并成块
断点识别方法:
percentile(默认):第95百分位作为阈值standard_deviation:平均值 + 3倍标准差interquartile:Q3 + 1.5倍IQRgradient:对梯度应用百分位法(适合法律、医疗文档)
优势:无需依赖固定分隔符,更贴合语义逻辑。
3.4 基于文档结构的分块
Markdown分块优势:
- 保留标题层级元数据
- 提供精确的"地址"信息
- 两阶段处理:先按标题分组,再按大小细分
四、其他框架分块策略
4.1 Unstructured:基于文档元素
核心优势:“先理解、后分割”
- 分区:解析为结构化元素(Title、NarrativeText等)
- 分块方法:
basic:连续组合元素直到达到大小限制by_title:在Title元素处强制分块,保持章节完整性
4.2 LlamaIndex:面向节点的体系
核心概念:文档→节点→转换
- 结构感知型:MarkdownNodeParser、JSONNodeParser
- 语义感知型:
- SemanticSplitterNodeParser:类似语义分块
- SentenceWindowNodeParser:单个句子+上下文窗口(检索精度高)
- 良好互操作性:可封装LangChain的TextSplitter
4.3 可视化工具
- ChunkViz:快速理解分块逻辑和重叠效果
总结
- 块大小并非越大越好,需平衡嵌入精度和 LLM 处理能力;
- 避免在语义边界(如句子、段落中间)切分,优先使用自然分隔符;
- 处理结构化文档时,忽略文档结构(如标题层级)会导致上下文丢失;
- 语义分块依赖嵌入模型质量,需选择适合的模型和断点识别方法。
更多推荐


所有评论(0)