【Task03】:数据准备(第二章)

一、文档加载器

在RAG系统中,数据加载是整个流水线的第一步,也是至关重要的一步。

通过文档加载器,将 PDF、Word、Markdown、HTML 等非结构化文档,转换为程序可处理的结构化数据

数据加载的质量会直接影响后续的索引构建、检索效果和最终的生成质量。

1.1 主要功能

1.2 当前主流RAG文档加载器

工具名称特点适用场景性能表现
PyMuPDF4LLMPDF→Markdown转换,OCR+表格识别科研文献、技术手册开源免费,GPU加速
TextLoader基础文本文件加载纯文本处理轻量高效
DirectoryLoader批量目录文件处理混合格式文档库支持多格式扩展
Unstructured多格式文档解析PDF、Word、HTML等统一接口,智能解析
FireCrawlLoader网页内容抓取在线文档、新闻实时内容获取
LlamaParse深度PDF结构解析法律合同、学术论文解析精度高,商业API
Docling模块化企业级解析企业合同、报告IBM生态兼容
MarkerPDF→Markdown,GPU加速科研文献、书籍专注PDF转换
MinerU多模态集成解析学术文献、财务报表集成LayoutLMv3+YOLOv8

二、Unstructured文档处理库

Unstructured 是一个专业的文档处理库,专门设计用于RAG和AI微调场景的非结构化数据预处理。提供了统一的接口来处理多种文档格式,是目前最受欢迎的文档加载解决方案之一。

三、从LangChain封装到原始Unstructured

直接使用Unstructured库

三、从LangChain封装到原始Unstructured

创建一个简单的示例,尝试使用Unstructured库加载并解析一个PDF文件:

from unstructured.partition.auto import partition

# PDF文件路径
pdf_path = "../../data/C2/pdf/rag.pdf"

# 使用Unstructured加载并解析PDF文档
elements = partition(
    filename=pdf_path,
    content_type="application/pdf"
)

# 打印解析结果
print(f"解析完成: {len(elements)} 个元素, {sum(len(str(e)) for e in elements)} 字符")

# 统计元素类型
from collections import Counter
types = Counter(e.category for e in elements)
print(f"元素类型: {dict(types)}")

# 显示所有元素
print("\n所有元素:")
for i, element in enumerate(elements, 1):
    print(f"Element {i} ({element.category}):")
    print(element)
    print("=" * 60)

练习

  • 使用partition_pdf替换当前partition函数并分别尝试用hi_resocr_only进行解析,观察输出结果有何变化。
使用hi_res模式解析(高精度模式,保留布局信息):

使用ocr_only模式解析(纯OCR模式,适合扫描件):

  1. hi_res 模式(高精度模式)

    • 工作原理:结合 PDF 的文本层和布局分析,保留原始排版结构
    • 适用场景:包含可复制文本的 PDF(非扫描件)
    • 预期结果:
      • 元素类型更丰富(可能包含 Title、Header、Footer、Table 等)
      • 文本提取更准确,保留原始格式和布局信息
      • 解析速度相对较慢,但质量更高
      • 对于有表格的 PDF,能更好地识别表格结构
  2. ocr_only 模式(纯 OCR 模式)

    • 工作原理:将 PDF 视为图片,通过 OCR 技术识别文本
    • 适用场景:扫描件 PDF(没有文本层,只有图片内容)
    • 预期结果:
      • 元素类型相对简单(多为 Text、NarrativeText 等)
      • 可能出现识别错误(尤其是特殊符号、复杂排版)
      • 不保留原始布局信息,文本可能按阅读顺序排列
      • 对于纯文本 PDF,识别效果可能不如 hi_res 模式
      • 解析速度取决于 PDF 页数和图片复杂度

遇到问题:

Xet Storage is enabled for this repo, but the 'hf_xet' package is not installed. Falling back to regular HTTP download. For better performance, install the package with: `pip install huggingface_hub[hf_xet]` or `pip install hf_xet` Traceback (most recent call last): File "D:\Virtualenv\all-in-rag\lib\site-packages\pdf2image\pdf2image.py", line 581, in pdfinfo_from_path proc = Popen(command, env=env, stdout=PIPE, stderr=PIPE) File "D:\SoftInstall\StudySoft\python\lib\subprocess.py", line 969, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "D:\SoftInstall\StudySoft\python\lib\subprocess.py", line 1438, in _execute_child hp, ht, pid, tid = _winapi.CreateProcess(executable, args, FileNotFoundError: [WinError 2] 系统找不到指定的文件。 During handling of the above exception, another exception occurred: Traceback (most recent call last): File "D:\Code\pyCharm\all-in-rag\code\C2\01_unstructured_example.py", line 12, in <module> elements = partition_pdf( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\common\metadata.py", line 162, in wrapper elements = func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\chunking\dispatch.py", line 74, in wrapper elements = func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf.py", line 225, in partition_pdf return partition_pdf_or_image( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf.py", line 340, in partition_pdf_or_image elements = _partition_pdf_or_image_local( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\utils.py", line 216, in wrapper return func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf.py", line 647, in _partition_pdf_or_image_local inferred_document_layout = process_file_with_model( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured_inference\inference\layout.py", line 388, in process_file_with_model else DocumentLayout.from_file( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured_inference\inference\layout.py", line 62, in from_file _image_paths = convert_pdf_to_image( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured_inference\inference\layout.py", line 414, in convert_pdf_to_image images = pdf2image.convert_from_path( File "D:\Virtualenv\all-in-rag\lib\site-packages\pdf2image\pdf2image.py", line 127, in convert_from_path page_count = pdfinfo_from_path( File "D:\Virtualenv\all-in-rag\lib\site-packages\pdf2image\pdf2image.py", line 607, in pdfinfo_from_path raise PDFInfoNotInstalledError( pdf2image.exceptions.PDFInfoNotInstalledError: Unable to get page count. Is poppler installed and in PATH?

原因:

缺少 poppler 工具,这是 pdf2image 库(unstructured 解析 PDF 时会用到)依赖的 PDF 处理工具。以下是详细的解决步骤:

1. 安装 poppler 工具

这是解决问题的核心,需要根据你的操作系统安装:

Windows 系统:
  1. 下载 poppler 安装包:

    • 访问 poppler for Windows
    • 选择最新版本的 poppler-xx.x.x.zip 下载(如 poppler-23.11.0.zip
  2. 解压并配置环境变量:

    • 将下载的压缩包解压到一个路径(如 C:\Program Files\poppler-23.11.0
    • 找到解压目录下的 bin 文件夹(如 C:\Program Files\poppler-23.11.0\Library\bin
    • 将这个 bin 路径添加到系统环境变量 PATH 中
  3. 验证安装:

    • 重启命令提示符或 PyCharm
    • 运行 pdfinfo -v,如果能显示版本信息则安装成功

问题2:

Traceback (most recent call last): File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured_pytesseract\pytesseract.py", line 275, in run_tesseract proc = subprocess.Popen(cmd_args, **subprocess_args()) File "D:\SoftInstall\StudySoft\python\lib\subprocess.py", line 969, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File "D:\SoftInstall\StudySoft\python\lib\subprocess.py", line 1438, in _execute_child hp, ht, pid, tid = _winapi.CreateProcess(executable, args, FileNotFoundError: [WinError 2] 系统找不到指定的文件。 During handling of the above exception, another exception occurred: Traceback (most recent call last): File "D:\Code\pyCharm\all-in-rag\code\C2\01_unstructured_example.py", line 12, in <module> elements = partition_pdf( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\common\metadata.py", line 162, in wrapper elements = func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\chunking\dispatch.py", line 74, in wrapper elements = func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf.py", line 225, in partition_pdf return partition_pdf_or_image( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf.py", line 340, in partition_pdf_or_image elements = _partition_pdf_or_image_local( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\utils.py", line 216, in wrapper return func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf.py", line 691, in _partition_pdf_or_image_local final_document_layout = process_file_with_ocr( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\utils.py", line 216, in wrapper return func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf_image\ocr.py", line 201, in process_file_with_ocr raise e File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf_image\ocr.py", line 186, in process_file_with_ocr merged_page_layout = supplement_page_layout_with_ocr( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\utils.py", line 216, in wrapper return func(*args, **kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\pdf_image\ocr.py", line 231, in supplement_page_layout_with_ocr ocr_layout = _ocr_agent.get_layout_from_image(image) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\utils\ocr_models\tesseract_ocr.py", line 53, in get_layout_from_image ocr_df: pd.DataFrame = self.image_to_data_with_character_confidence_filter( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured\partition\utils\ocr_models\tesseract_ocr.py", line 99, in image_to_data_with_character_confidence_filter hocr: str = unstructured_pytesseract.image_to_pdf_or_hocr( File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured_pytesseract\pytesseract.py", line 514, in image_to_pdf_or_hocr return run_and_get_output(*args) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured_pytesseract\pytesseract.py", line 353, in run_and_get_output run_tesseract(**kwargs) File "D:\Virtualenv\all-in-rag\lib\site-packages\unstructured_pytesseract\pytesseract.py", line 280, in run_tesseract raise TesseractNotFoundError() unstructured_pytesseract.pytesseract.TesseractNotFoundError: tesseract is not installed or it's not in your PATH. See README file for more information.

原因:

1. 安装 Tesseract OCR 工具

Windows 系统:
  1. 下载安装包:

    • 访问 UB-Mannheim/tesseract 下载最新的 Windows 安装程序(如 tesseract-ocr-w64-setup-5.3.3.20231005.exe
    • 运行安装程序,特别注意:在安装过程中勾选 "Add tesseract to system PATH" 选项(将 Tesseract 添加到系统环境变量)
  2. 验证安装:

    • 重启命令提示符或 PyCharm
    • 运行 tesseract --version,如果显示版本信息则安装成功

第二节 文本分块

一、文本分块基础认知

  • 定义:文本分块(Text Chunking)是 RAG 流程的关键步骤,核心是将加载后的长篇文档切分为更小、可处理的单元,这些单元是后续向量检索和模型处理的基本单位
  • 核心目标:平衡 “模型上下文限制” 与 “检索生成性能”,确保文本能被有效处理且语义完整。

二、文本分块的重要性(两大核心考量)

1. 满足模型上下文硬限制

文本分块首要目的是适配 RAG 中两个核心组件的长度上限:

  • 嵌入模型(Embedding Model):如bge-base-zh-v1.5上下文窗口为 512 Token,超量文本会被截断,导致信息丢失、向量语义不完整,因此文本块需≤其 Token 上限。
  • 大语言模型(LLM):虽上下文窗口更大(几千至百万 Token),但检索到的文本块 + 问题 + 提示词需整体适配窗口;若单块过大,会导致可容纳的相关块数量减少,限制信息广度。

2. 为何 “块不是越大越好”

即使未超模型上限,过大的块会严重损害 RAG 性能:

  • 嵌入信息损失:嵌入模型通过 “分词→向量化→池化” 生成单向量,块越长语义点越多,向量承载的信息越稀释,关键细节模糊,检索精度下降。
  • 生成 “大海捞针”(Lost in the Middle):LLM 对长上下文的开头 / 结尾记忆更清晰,中间信息易被忽略;大块含大量无关噪音时,模型难提取关键信息,易产生幻觉。
  • 主题稀释导致检索失败:大块若包含多个无关主题(如 “鲁班技能 + 出装 + 背景” 混为一块),语义被稀释,查询 “出装” 时因相关性得分低无法召回;聚焦单主题的小块(如单独 “出装” 块)检索精度更高。

三、LangChain 核心文本分块策略

1. 固定大小分块(CharacterTextSplitter)

  • 核心逻辑:“段落感知的自适应分块”,非严格按字符数切割:
    1. 先按默认分隔符\n\n(段落)分割文本;
    2. _merge_splits合并段落,超chunk_size时终止当前块,通过chunk_overlap保持上下文连续;
    3. 单个段落超限时发出警告但保留完整块,优先保语义完整性。
  • 优劣势:实现简单、速度快;但可能在语义边界切割,影响连贯性。
  • 代码示例核心参数
    text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=10)  # 目标200字符/块,重叠10字符
    

2. 递归字符分块(RecursiveCharacterTextSplitter)

  • 核心逻辑:按分隔符层级递归切割,解决超长文本问题:
    1. 按优先级遍历分隔符(如\n\n\n),找到首个存在的分隔符;
    2. 切割后,合格片段(≤chunk_size)暂存,超长片段用更细粒度分隔符递归切割;
    3. 分隔符用尽时停止递归,保留超长块。
  • 关键差异:相比固定大小分块,能对超长片段进一步细分(如段落→句子→单词)。
  • 分隔符配置
    • 中文适配:["\n\n", "\n", "。", ",", " ", ""]
    • 代码适配:用from_language(Language.PYTHON)调用编程语言专属分隔符。

3. 语义分块(SemanticChunker)

  • 核心逻辑:基于语义主题切分,每个块语义高度一致,不依赖固定分隔符 / 字符数:
    1. 句子分割:按标点将文本拆为句子列表;
    2. 上下文感知嵌入:用buffer_size(默认 1)将句子与前后句组合后嵌入,向量含上下文语义;
    3. 计算语义距离:算相邻句子向量的余弦距离(距离越大语义关联越弱);
    4. 识别断点:用统计方法(如百分位法)设动态阈值,超阈值处为语义断点;
    5. 合并成块:按断点合并句子为语义连贯的块。
  • 断点识别方法
    • percentile(默认):取第 N 百分位(如 95)为阈值,超阈值为断点;
    • standard_deviation:超 “均值 + N 倍标准差”(如 3 倍)为断点;
    • 其他:interquartile(四分位距)、gradient(梯度法,适配法律 / 医疗文档)。

4. 基于文档结构的分块(如 MarkdownHeaderTextSplitter)

  • 核心逻辑:利用文档结构标记(如 Markdown 标题、HTML 标签)切分,保留宏观逻辑:
    1. 定义规则:映射标题层级(如[("#", "Header 1"), ("##", "Header 2")]);
    2. 内容聚合:将标题下所有内容(至下一个同级 / 高级标题)聚合,赋予 “标题路径” 元数据(如{"Header 1": "第三章", "Header 2": "3.2节"});
    3. 组合使用:先按标题分大逻辑块,再用RecursiveCharacterTextSplitter切分至符合chunk_size,最终小块继承标题元数据。
  • 优势:元数据提供精确 “信息地址”,增强 LLM 对上下文来源的理解,是结构化文档(Markdown/HTML)的理想方案。

四、其他开源框架分块策略

框架核心分块特点
Unstructured1. 先 “分区”:将文档解析为带语义标签的元素(如 Title、ListItem);
2. 再 “分块”:
basic:组合元素至超max_characters
by_title:按 Title 元素分割,避免跨章节。
LlamaIndex1. 以 “节点(Node)” 为核心,文档先解析为节点,分块是节点转换的一环;
2. 节点解析器类型:
- 结构感知型(MarkdownNodeParser);
- 语义感知型(SemanticSplitterNodeParser);
3. 支持灵活流水线(如标题分块→句子分块)。
ChunkViz文本分块可视化工具,输入文档和分块配置,用颜色标记块边界与重叠,辅助理解分块逻辑。

【项目地址】https://github.com/datawhalechina/all-in-rags

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值