📖 目录
- [一、RAG 为什么需要文档解析?](#一、RAG 为什么需要文档解析?)
- [二、PyMuPDF 和 Unstructured 的定位区别](#二、PyMuPDF 和 Unstructured 的定位区别)
- [三、PyMuPDF 简介](#三、PyMuPDF 简介)
- [四、PyMuPDF 基础用法](#四、PyMuPDF 基础用法)
- [1. 提取 PDF 文本](#1. 提取 PDF 文本)
- [2. 提取文本块](#2. 提取文本块)
- [3. 提取字典结构](#3. 提取字典结构)
- [4. 把 PDF 页面渲染成图片](#4. 把 PDF 页面渲染成图片)
- [5. 提取 PDF 中的图片](#5. 提取 PDF 中的图片)
- [6. 表格提取](#6. 表格提取)
- [五、PyMuPDF 在 RAG 中的推荐用法](#五、PyMuPDF 在 RAG 中的推荐用法)
- [1. 普通 PDF 文本知识库](#1. 普通 PDF 文本知识库)
- [2. 扫描件 PDF](#2. 扫描件 PDF)
- [3. 图片较多的 PDF](#3. 图片较多的 PDF)
- [4. 表格较多的 PDF](#4. 表格较多的 PDF)
- [六、Unstructured 简介](#六、Unstructured 简介)
- [七、Unstructured 基础用法](#七、Unstructured 基础用法)
- [1. 自动解析文档](#1. 自动解析文档)
- [2. 解析 PDF](#2. 解析 PDF)
- [3. 解析图片](#3. 解析图片)
- [八、Unstructured 的 Title 是怎么来的?](#八、Unstructured 的 Title 是怎么来的?)
- [九、Unstructured Chunking 用法](#九、Unstructured Chunking 用法)
- [1. 按标题切 Chunk](#1. 按标题切 Chunk)
- [2. 为什么 Unstructured 的 chunking 和普通文本切分不同?](#2. 为什么 Unstructured 的 chunking 和普通文本切分不同?)
- [十、QA 格式文档怎么处理?](#十、QA 格式文档怎么处理?)
- [QA 数据向量化问题还是答案?](#QA 数据向量化问题还是答案?)
- [十一、QA 里有图片怎么办?](#十一、QA 里有图片怎么办?)
- [十二、QA 里有表格怎么办?](#十二、QA 里有表格怎么办?)
- [十三、PyMuPDF 与 Unstructured 的组合方案](#十三、PyMuPDF 与 Unstructured 的组合方案)
- [方案 1:Unstructured 主导](#方案 1:Unstructured 主导)
- [方案 2:PyMuPDF 主导](#方案 2:PyMuPDF 主导)
- [方案 3:混合方案](#方案 3:混合方案)
- [十四、RAG 入库数据结构推荐](#十四、RAG 入库数据结构推荐)
- 十五、总结
一、RAG 为什么需要文档解析?
RAG 的完整流程通常是:
text
原始文档
-> 文档解析
-> 文本清洗
-> Chunk 切分
-> 向量化
-> 写入向量库
-> 检索
-> LLM 生成回答
在这个流程里,文档解析非常关键。如果 PDF、Word、图片、表格在解析阶段就被处理坏了,后面的向量检索和问答效果都会下降。
常见问题包括:
- PDF 提取出来文字顺序错乱;
- 扫描件 PDF 没有可复制文本;
- 表格被拆成一堆无意义的行;
- 图片里的文字没有 OCR;
- 标题和正文没有结构;
- Chunk 切得太碎或太长;
- 检索结果没有页码、来源、章节信息。
PyMuPDF 和 Unstructured 都是 RAG 文档处理里常见的工具,但它们定位不同。
二、PyMuPDF 和 Unstructured 的定位区别
| 工具 | 核心定位 | 更适合做什么 |
|---|---|---|
| PyMuPDF | PDF 底层解析与页面处理库 | 提取文本、图片、坐标、页面渲染、表格检测 |
| Unstructured | 多格式文档解析与结构化预处理框架 | 把 PDF、Word、HTML、图片等解析成结构化 Element,并支持 chunk |
可以简单理解:
text
PyMuPDF 更像 PDF 手术刀。
Unstructured 更像 RAG 文档预处理流水线。
如果你只处理 PDF,并且想要更细粒度控制页面、坐标、图片、表格,PyMuPDF 很合适。
如果你要处理多种格式,例如 PDF、DOCX、HTML、PPTX、图片,并希望直接拿到 Title、NarrativeText、Table 等结构化元素,Unstructured 更方便。
三、PyMuPDF 简介
PyMuPDF 是一个高性能 Python 文档处理库,底层基于 MuPDF。它可以处理 PDF、XPS、EPUB 等格式。RAG 中最常用的是 PDF 解析。
安装:
bash
pip install pymupdf
导入方式:
python
import fitz
注意:PyMuPDF 的导入名是 fitz。
四、PyMuPDF 基础用法
1. 提取 PDF 文本
python
import fitz
doc = fitz.open("demo.pdf")
for page_index, page in enumerate(doc):
text = page.get_text()
print(f"第 {page_index + 1} 页")
print(text)
page.get_text() 默认提取纯文本,适合普通可复制文本 PDF。
如果是扫描件 PDF,可能提取不到文字,需要先 OCR。
2. 提取文本块
python
import fitz
doc = fitz.open("demo.pdf")
page = doc[0]
blocks = page.get_text("blocks")
for block in blocks:
print(block)
blocks 会返回带坐标的文本块,常用于:
- 分析页面布局;
- 判断标题和正文;
- 按区域抽取内容;
- 保留页码和坐标 metadata。
3. 提取字典结构
python
import fitz
doc = fitz.open("demo.pdf")
page = doc[0]
data = page.get_text("dict")
for block in data["blocks"]:
if block["type"] == 0:
for line in block["lines"]:
line_text = "".join(span["text"] for span in line["spans"])
print(line_text)
dict 结构里有更详细的字体、字号、坐标信息。你可以根据字号、加粗、位置来粗略判断标题。
4. 把 PDF 页面渲染成图片
python
import fitz
doc = fitz.open("demo.pdf")
for i, page in enumerate(doc):
pix = page.get_pixmap()
pix.save(f"page_{i + 1}.png")
如果想提高图片分辨率:
python
import fitz
doc = fitz.open("demo.pdf")
page = doc[0]
matrix = fitz.Matrix(2, 2)
pix = page.get_pixmap(matrix=matrix)
pix.save("page_1_2x.png")
这在 OCR、视觉模型理解、图片问答中很常用。
5. 提取 PDF 中的图片
python
import fitz
doc = fitz.open("demo.pdf")
for page_index, page in enumerate(doc):
images = page.get_images(full=True)
for image_index, img in enumerate(images):
xref = img[0]
base_image = doc.extract_image(xref)
image_bytes = base_image["image"]
image_ext = base_image["ext"]
image_path = f"page_{page_index + 1}_image_{image_index + 1}.{image_ext}"
with open(image_path, "wb") as f:
f.write(image_bytes)
RAG 中图片一般不要直接向量化原图,而是:
text
图片 -> OCR / caption -> 文本描述参与向量化
原图路径 -> metadata 保存,用于回答时引用或展示
6. 表格提取
PyMuPDF 新版本支持页面表格检测。典型用法类似:
python
import fitz
doc = fitz.open("demo.pdf")
page = doc[0]
tables = page.find_tables()
for table in tables:
df = table.to_pandas()
print(df)
注意:
- 表格检测依赖 PDF 版面质量;
- 复杂跨页表格、无线框表格可能识别不稳定;
- 如果表格很重要,建议结合
pdfplumber、Camelot、Tabula 或 Unstructured 的表格能力做对比。
五、PyMuPDF 在 RAG 中的推荐用法
1. 普通 PDF 文本知识库
text
PyMuPDF 提取文本
-> 按页保存 page metadata
-> 清洗页眉页脚
-> 按标题或段落切 chunk
-> 向量化
示例数据结构:
json
{
"content": "这里是第 3 页中的一段正文...",
"metadata": {
"source": "manual.pdf",
"page": 3,
"type": "text"
}
}
2. 扫描件 PDF
text
PyMuPDF 渲染页面图片
-> OCR
-> 得到文本
-> 切 chunk
-> 向量化
3. 图片较多的 PDF
text
PyMuPDF 提取图片
-> OCR / caption
-> 图片说明进入 embedding_text
-> 原图路径进入 metadata
示例:
json
{
"embedding_text": "登录页面截图,包含用户名、密码、验证码、登录按钮。",
"metadata": {
"source": "manual.pdf",
"page": 5,
"image_path": "/assets/page_5_image_1.png",
"type": "image"
}
}
4. 表格较多的 PDF
表格不要只当普通文本处理,建议保存三份:
text
Markdown 表格:给 LLM 阅读
CSV / JSON:用于精确查询和计算
表格摘要:参与向量检索
六、Unstructured 简介
Unstructured 是一个面向 LLM / RAG 的文档预处理库。它可以把 PDF、HTML、Word、PPT、图片等文件解析成结构化元素。
安装:
bash
pip install unstructured
如果处理 PDF、图片和 OCR,通常需要额外依赖。实际项目中可以按官方文档安装对应 extras,例如 PDF、OCR、local inference 相关依赖。
Unstructured 的核心思想是:
text
先 partition 成 Elements
再基于 Elements 做 chunking
常见 Element 类型:
| Element 类型 | 含义 |
|---|---|
Title |
标题 |
NarrativeText |
正文段落 |
ListItem |
列表项 |
Table |
表格 |
Image |
图片 |
Header |
页眉 |
Footer |
页脚 |
七、Unstructured 基础用法
1. 自动解析文档
python
from unstructured.partition.auto import partition
elements = partition(filename="demo.pdf")
for e in elements:
print(type(e).__name__, e.text[:80] if hasattr(e, "text") else "")
这会自动根据文件类型选择解析方式。
2. 解析 PDF
python
from unstructured.partition.pdf import partition_pdf
elements = partition_pdf(
filename="demo.pdf",
strategy="hi_res",
infer_table_structure=True,
)
for e in elements:
print(type(e).__name__, e.text[:100])
常见参数:
| 参数 | 说明 |
|---|---|
strategy="fast" |
速度快,适合可复制文本 PDF |
strategy="hi_res" |
使用版面分析,适合复杂 PDF、扫描件、表格、标题识别 |
infer_table_structure=True |
尝试识别表格结构 |
3. 解析图片
python
from unstructured.partition.image import partition_image
elements = partition_image(
filename="page.png",
strategy="hi_res",
)
for e in elements:
print(type(e).__name__, e.text)
图片解析一般依赖 OCR 和布局识别。
八、Unstructured 的 Title 是怎么来的?
Unstructured 不是在 chunk 阶段凭空判断标题,而是在 partition 阶段把文档解析成 Elements。
如果某段内容被识别为:
python
Title
那么 chunk_by_title 才能把它当作章节边界。
流程如下:
text
原始文档
-> partition
-> Title / NarrativeText / ListItem / Table 等 Elements
-> chunk_by_title
-> 按 Title 边界切 chunk
九、Unstructured Chunking 用法
1. 按标题切 Chunk
python
from unstructured.partition.pdf import partition_pdf
from unstructured.chunking.title import chunk_by_title
elements = partition_pdf(
filename="demo.pdf",
strategy="hi_res",
infer_table_structure=True,
)
chunks = chunk_by_title(
elements,
max_characters=1200,
new_after_n_chars=1000,
combine_text_under_n_chars=200,
)
for chunk in chunks:
print(type(chunk).__name__)
print(chunk.text[:300])
参数说明:
| 参数 | 作用 |
|---|---|
max_characters |
单个 chunk 最大字符数 |
new_after_n_chars |
超过这个长度后倾向开启新 chunk |
combine_text_under_n_chars |
太短的 section 尽量合并 |
2. 为什么 Unstructured 的 chunking 和普通文本切分不同?
普通 splitter 往往是:
text
纯文本 -> 按字符数 / token 数硬切
Unstructured 更像:
text
文档 -> Element 结构 -> 根据标题、段落、表格等结构切
优势是能保留文档结构,尤其适合说明书、政策文档、FAQ、操作手册。
十、QA 格式文档怎么处理?
推荐结构:
json
{
"question": "访问中心站需要哪些条件?",
"answer": "中心站部署...",
"embedding_text": "问题:访问中心号。",
"metadata": {
"source": "中心站说明文档.pdf",
"page": 1,
"section": "1"
}
}
QA 数据向量化问题还是答案?
推荐:
text
用于检索:问题 + 同义问题 + 答案摘要 + 关键词
用于回答:完整答案
不要只向量化答案,也不要只保存问题。
更稳的 embedding_text:
text
问题:如何登录中心站?
同义问题:中心站怎么登录?登录中心站需要什么?
答案摘要:通过浏览器访问中心站网址,输入用户名、密码和手机验证码登录。
关键词:登录、网址、用户名、密码、手机验证码、验证码。
十一、QA 里有图片怎么办?
图片不要直接塞进向量库。推荐流程:
text
图片
-> OCR
-> caption
-> OCR 文本和 caption 参与向量化
-> 原图路径保存到 metadata
示例:
json
{
"type": "image",
"path": "/assets/page_2_image_1.png",
"caption": "登录页面截图,包含用户名输入框、密码输入框、发送手机验证码按钮和登录按钮。",
"ocr_text": "用户名 密码 发送手机验证码 验证码 登录"
}
然后把这些信息加入 embedding_text:
text
图片说明:登录页面截图,包含用户名、密码、验证码和登录按钮。
图片 OCR:用户名、密码、发送手机验证码、验证码、登录。
这样用户问:
text
登录页面验证码按钮在哪里?
也有机会检索到正确 QA。
十二、QA 里有表格怎么办?
表格建议不要只做 caption,也不要只把表格原文混进一大段文本。
推荐保存三种形态:
text
Markdown 表格:给 LLM 看。
CSV / JSON:用于精确查询和计算。
表格摘要:参与向量检索。
例如:
markdown
| 项目 | 最低配置 | 推荐配置 |
| --- | --- | --- |
| CPU | i5 | i7 / Ryzen 7 |
| 内存 | 8GB | 16GB |
| 显卡 | 集成显卡 | GTX 1660 |
表格摘要:
text
表格说明访问中心站的硬件配置要求。最低配置为 i5、8GB 内存、集成显卡;推荐配置为 i7 或 Ryzen 7、16GB 内存、GTX 1660。
向量化文本可以写成:
text
问题:访问中心?
答案摘要:需要电脑,最低配置 i5、8GB 内存、集成显卡;推荐 i7/Ryzen 7、16GB 内存、GTX 1660。
表格关键词:CPU、内存、显卡、最低配置、推荐配置。
如果用户问计算类问题:
text
推荐内存比最低内存多多少?
更好的做法是:
text
检索到表格
-> 读取 CSV / JSON
-> 用程序计算
-> LLM 解释结果
不要完全依赖模型从自然语言表格里猜。
十三、PyMuPDF 与 Unstructured 的组合方案
实际项目中,两者可以组合使用。
方案 1:Unstructured 主导
适合多格式文档:
text
Unstructured partition
-> Elements
-> chunk_by_title
-> 表格摘要 / 图片 OCR
-> 向量化
优点:
- 多格式统一;
- Title、Table、ListItem 等结构清晰;
- chunking 更贴近文档结构。
缺点:
- 依赖较多;
- 复杂 PDF 的效果和环境配置有关;
- 需要检查 Title、Table 是否识别正确。
方案 2:PyMuPDF 主导
适合 PDF 控制更细的场景:
text
PyMuPDF 按页解析
-> 提取文本 / 图片 / 坐标 / 表格
-> 自定义规则切 chunk
-> 向量化
优点:
- 速度快;
- PDF 级控制强;
- 方便保留页码、坐标、图片路径。
缺点:
- 标题、段落、表格结构需要自己处理;
- 多格式支持不如 Unstructured 统一。
方案 3:混合方案
推荐给生产项目:
text
先用 Unstructured 获取结构化 Elements
如果表格 / 图片 / 页码不满足要求
再用 PyMuPDF 做补充提取
例如:
text
Unstructured 负责标题、正文、表格初步解析。
PyMuPDF 负责页面截图、图片抽取、坐标和页码补充。
十四、RAG 入库数据结构推荐
无论使用 PyMuPDF 还是 Unstructured,最终建议统一成类似结构:
json
{
"id": "manual_pdf_page_1_qa_1",
"embedding_text": "问题:访问中心答案摘要:需要硬件、软件、网络、账号条件。关键词:Windows10、Chrome、固定出口 IP、白名单、账号。",
"content": "完整答案正文...",
"metadata": {
"source": "manual.pdf",
"page": 1,
"section": "1",
"type": "qa",
"question": "访问中心站",
"images": [
{
"path": "/assets/page_1_image_1.png",
"caption": "硬件条件示意图"
}
],
"tables": [
{
"path": "/tables/page_1_table_1.csv",
"summary": "硬件配置要求表"
}
]
}
}
向量库里主要存:
text
embedding_text
metadata
回答时再根据 metadata 取:
text
完整答案
Markdown 表格
图片说明
原始文件路径
页码来源
十五、总结
| 场景 | 推荐工具 | 推荐处理方式 |
|---|---|---|
| 普通可复制 PDF | PyMuPDF / Unstructured | 提取文本,按页和标题切 chunk |
| 扫描件 PDF | PyMuPDF + OCR / Unstructured hi_res | 页面渲染或 OCR 解析 |
| 多格式文档 | Unstructured | partition 成 Elements,再 chunk |
| 标题结构明显的文档 | Unstructured | chunk_by_title |
| QA / FAQ 文档 | 自定义规则 + Unstructured | 按 QA 单元入库 |
| 图片多的文档 | PyMuPDF + OCR/caption | 图片说明参与向量化,原图保存路径 |
| 表格多的文档 | Unstructured / PyMuPDF / pdfplumber | Markdown + CSV/JSON + 表格摘要 |
| 需要精确页码和坐标 | PyMuPDF | 保存 page、bbox metadata |
PyMuPDF 和 Unstructured 在 RAG 中不是互相替代,而是互补关系:
text
PyMuPDF 适合精细控制 PDF:文本、图片、坐标、页面渲染、表格检测。
Unstructured 适合统一处理多格式文档:Title、NarrativeText、ListItem、Table 等结构化 Elements。