PDF解析、表格提取与多模态文档理解
前言
在企业级 LLM 应用中,大部分知识存储在 PDF、Word 或扫描件中。如何准确地从这些非结构化文档中提取文本、表格和布局信息,是 RAG 系统成功的关键。本文将介绍现代文档智能处理的工具与策略。
文档处理的挑战
- 布局复杂性:多栏排版、页眉页脚、侧边栏干扰。
- 表格提取:跨行跨列、无框线表格、嵌套表格。
- 非文本元素:公式、流程图、印章、手写签名。
- 扫描件:需要高质量 OCR 和倾斜校正。
深度解析工具链:Marker vs Docling
在 2024 年,Marker 和 IBM 的 Docling 是开源界处理 PDF 的双雄。
1. 使用 Docling 进行工业级解析
Docling 采用了更轻量级的模型,解析速度比 Marker 快 10 倍,且对复杂表格的支持极佳。
from docling.datamodel.base_models import InputFormat
from docling.document_converter import DocumentConverter
def convert_with_docling(file_path: str):
converter = DocumentConverter()
result = converter.convert(file_path)
# 导出为 Markdown
markdown_content = result.document.export_to_markdown()
# 导出为 JSON (包含完整的布局信息)
json_content = result.document.export_to_dict()
return markdown_content, json_content
# 示例
md, _ = convert_with_docling("complex_report.pdf")
2. 结构化切片 (Structural Chunking)
解析出 Markdown 后,我们需要根据文档的层级结构(H1, H2, H3)进行切片,而不是简单的字符数切片。
from langchain_text_splitters import MarkdownHeaderTextSplitter
def hierarchical_chunking(markdown_text: str):
headers_to_split_on = [
("#", "Header 1"),
("##", "Header 2"),
("###", "Header 3"),
]
splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
chunks = splitter.split_text(markdown_text)
# 每个 chunk 都会自动带上其所属的层级元数据
# 例如: metadata={'Header 1': '第一章', 'Header 2': '1.1 节'}
return chunks
核心进阶:多模态表格解析 (VLM-based)
对于扫描件中的复杂表格,传统的 OCR 往往会错行。使用 GPT-4o 或 Claude 3.5 Sonnet 直接解析图片是目前的 SOTA 方案。
import base64
def parse_table_with_vlm(image_path: str):
with open(image_path, "rb") as f:
base64_image = base64.b64encode(f.read()).decode('utf-8')
prompt = """
请分析图片中的表格,并将其转换为结构化的 JSON 格式。
要求:
1. 识别合并单元格。
2. 保持数值的精确性。
3. 输出格式为: {"tables": [{"headers": [], "rows": []}]}
"""
# 调用 GPT-4o API...
pass
---
#### 行业革命:ColPali (OCR-Free 检索)
传统的文档 RAG 流程是:`PDF -> OCR -> 文本 -> 向量化 -> 检索`。
**ColPali** 彻底颠覆了这一流程:`PDF -> 图像块 -> 多模态向量化 -> 检索`。
#### 为什么 ColPali 更好?
1. **零丢失**:不再受 OCR 识别错误的影响。
2. **视觉感知**:模型能“看到”加粗的字体、红色的警告、复杂的流程图和表格排版。
3. **极速索引**:直接对 PDF 页面截图进行编码,省去了复杂的解析步骤。
#### 架构
它基于 **PaliGemma** 多模态模型,将图像块映射到与文本查询相同的向量空间。检索时,它能直接定位到 PDF 页面中包含答案的那个“视觉区域”。
---
#### 布局分析 (Layout Analysis)
在处理长文档时,识别出哪些是“正文”,哪些是“图表说明”,哪些是“页码”至关重要。
- **工具**:使用 **LayoutParser** 或 **Unstructured.io**。
- **逻辑**:
- 移除页眉页脚(防止检索到重复的干扰信息)。
- 将图片和表格与其最近的标题关联起来。
- 识别出多栏排版的阅读顺序。
---
#### 公式与学术文档处理 (Nougat)
对于包含大量数学公式的论文或技术手册,普通的解析器会把公式变成乱码。
- **方案**:使用 Meta 开源的 **Nougat** 模型。
- **特点**:它是一个“图像到序列”的模型,能直接将 PDF 页面图像翻译成高质量的 LaTeX 源码。
---
#### 总结:文档处理的“金字塔”策略
1. **底层:纯文本 PDF** -> 使用 `PyMuPDF` 或 `pypdf` 快速提取。
2. **中层:复杂排版/表格** -> 使用 **Docling** 或 **Marker** 转换为 Markdown。
3. **高层:扫描件/学术文档** -> 使用 **Nougat** 或 **GPT-4o (VLM)**。
4. **顶层:极致体验** -> 引入 **ColPali** 实现视觉增强检索。
文档处理不再是简单的“读字”,而是一场结合了计算机视觉(CV)和自然语言处理(NLP)的综合战役。
"""
# 调用多模态 LLM
# response = llm.invoke([HumanMessage(content=[{"type": "text", "text": prompt}, {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}}])])
# return response.content
表格提取策略
表格是文档中最难处理的部分。
1. 视觉解析法 (Vision-based)
将表格区域截图,发送给多模态模型(如 GPT-4o)。
def extract_table_with_vision(image_path: str):
"""使用多模态模型提取表格"""
prompt = "请将图片中的表格转换为 Markdown 格式。确保保留所有行和列,不要遗漏数据。"
# 调用 GPT-4o-mini 或 Claude 3.5 Sonnet
response = vision_model.invoke(prompt, image_path)
return response.content
2. 结构化解析法
使用 Table Transformer 或 DeepSearch 识别表格边界和单元格。
多模态文档理解
对于极其复杂的文档,直接使用多模态 LLM 往往比先解析再处理效果更好。
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
def analyze_complex_document(image_paths: list[str]):
"""多模态文档分析"""
llm = ChatOpenAI(model="gpt-4o")
content = [
{"type": "text", "text": "请分析这些文档页面,总结核心财务指标,并以表格形式输出。"}
]
for img in image_paths:
content.append({
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{img}"}
})
message = HumanMessage(content=content)
return llm.invoke([message]).content
布局分析 (Layout Analysis)
在切片(Chunking)之前,识别文档的逻辑结构(标题、段落、列表)。
from unstructured.partition.pdf import partition_pdf
def smart_partitioning(pdf_path: str):
"""使用 Unstructured 进行布局感知分区"""
elements = partition_pdf(
filename=pdf_path,
strategy="hi_res", # 使用模型进行高精度解析
infer_table_structure=True,
chunking_strategy="by_title", # 按标题切片
max_characters=1000,
combine_text_under_n_chars=200
)
return elements
# 遍历元素
for el in elements:
if el.category == "Title":
print(f"Heading: {el.text}")
elif el.category == "Table":
print(f"Table Data: {el.metadata.text_as_html}")
文档处理流水线 (Pipeline)
一个完整的企业级文档处理流程:
[上传 PDF]
│
▼
[预处理] (去噪、纠偏、转图片)
│
▼
[布局分析] (识别标题、正文、表格区域)
│ │
│ └─→ [表格处理] (OCR + 结构化提取)
│
▼
[文本提取] (Markdown 转换)
│
▼
[语义切片] (基于布局信息的智能切片)
│
▼
[向量化与存储] (写入向量数据库)
最佳实践
| 场景 | 推荐方案 |
|---|---|
| 标准论文/报告 | Marker (Markdown 转换) |
| 复杂报表/发票 | 多模态 LLM (GPT-4o/Claude) |
| 海量历史文档 | Unstructured + PaddleOCR |
| 法律合同 | 布局分析 + 层次化切片 |
总结
文档智能处理是 RAG 系统的“脏活累活”,但也是决定系统上限的关键。通过组合使用传统的规则解析、现代的深度学习模型(如 Marker)以及强大的多模态 LLM,我们可以攻克绝大多数文档解析难题。
参考资源
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:《 LLM应用开发——文档智能处理实战 》
本文链接:http://localhost:3015/ai/%E6%96%87%E6%A1%A3%E6%99%BA%E8%83%BD%E5%A4%84%E7%90%86.html
本文最后一次更新为 天前,文章中的某些内容可能已过时!