Unstructured.io: 将任何文档转换为LLM就绪数据块的预处理流水线 — 2026指南
Unstructured.io 实用2026指南 — 这款开源文档预处理库可将PDF、DOCX、PPTX和图像转换为干净、结构化的文本块,为LLM和RAG流水线做好准备。
- ⭐ 10500
- Apache-2.0
- 更新于 2026-05-19
{{< resource-info >}}
引言:每个RAG流水线背后不为人知的痛点 #
你的检索增强生成(RAG)流水线的质量完全取决于你喂给它什么数据。你可以拥有最顶尖的嵌入模型、最昂贵的向量数据库、以及最先进的LLM — 但如果你的源文档是排版混乱的PDF、OCR识别失败的扫描件、或者带有隐藏文本框的PPT幻灯片,你的检索准确率必将大打折扣。
我吃过这个苦头。一个客户项目将 12,000份PDF合同 灌入基于Pinecone的RAG系统。使用简单的 pdftotext 方法得到的块是这样的:"第1页,共47页保密协议" — 页眉与正文混在一起,表格行被拼接成不可读的 Blob,脚注直接插入句子中间。检索准确率:34%。切换到 Unstructured.io 并采用正确的分区与分块策略后:89%。
这个差距 — 从34%到89% — 就是 Unstructured.io 存在的意义。该项目于2022年发布,目前版本为 v0.17.0(2026年4月),在 Apache-2.0 许可证下已积累 10,500+ GitHub Stars。它已成为将混乱的现实世界文档转换为LLM可用的干净结构化元素的事实标准。
什么是 Unstructured.io? #
Unstructured.io 是一个开源 Python 库和 API 服务,可从非结构化文档(PDF、Word文件、PPT演示文稿、HTML页面、图像等)中提取结构化内容,并将其转换为标准化的JSON元素,供下游 LLM、RAG 和 NLP 流水线使用。
把它看作AI技术栈中文档的 ETL层。传统工具只是倾倒原始文本,而 Unstructured 保留了文档结构 — 识别标题、正文、表格、列表、图像及其层级关系 — 然后输出带有丰富元数据的干净、语义上有意义的数据块。
Unstructured.io 的工作原理:架构与核心概念 #
Unstructured 的流水线包含三个不同阶段:分区 → 清洗 → 分块。理解每个阶段对于针对你的用例调优性能至关重要。
分区:将文档拆解为元素 #
partition 函数是 Unstructured 的核心。它自动检测文件类型并将其路由到专门的解析器:
| 分区策略 | 速度 | 准确率 | 适用场景 |
|---|---|---|---|
auto | 中等 | 高 | 通用场景,混合文档类型 |
fast | 快 | 中等 | 简单文本型PDF,批量处理 |
hi_res | 慢 | 最高 | 复杂排版,表格,扫描文档 |
ocr_only | 最慢 | 依赖OCR | 图像型PDF,扫描文档 |
hi_res 策略使用 文档理解 Transformer 模型(默认:detectron2 或 yolox)来识别标题、正文、页眉、页脚和表格等区域,然后再进行提取。这就是它能够将表格转换为 HTML 并检测阅读顺序的原因。
元素类型:保留结构 #
Unstructured 输出 20+ 种元素类型。对于 LLM 工作最重要的:
NarrativeText— 正文段落Title— 文档和章节标题ListItem— 无序和有序列表Table— 表格数据(可导出为HTML)Header/Footer— 通常被过滤掉Image— 嵌入图像(可选提取标题)FigureCaption— 与图像关联的标题
每个元素都携带元数据:页码、坐标、文件类型、检测到的语言、父级章节,以及你注入的自定义字段。
分块:从元素到LLM就绪片段 #
原始元素要么太小(单个单词),要么太大(整页)。Unstructured 的分块策略智能地组合和拆分元素:
| 分块策略 | 行为 | 适用场景 |
|---|---|---|
basic | 固定大小带重叠 | 简单流水线,可预测的token数 |
by_title | 尊重章节边界 | 保持语义连贯性 |
by_similarity | 语义聚类 | 主题转换的长文档 |
安装与配置:5分钟快速上手 #
Unstructured 支持库用法(Python导入)和自托管API(Docker)。对于生产环境,我推荐API方式以获得更好的资源隔离。
方案A:Python库(开发环境) #
python -m venv venv_unstructured
source venv_unstructured/bin/activate
# 安装基础包
pip install "unstructured[pdf]==0.17.0"
# 完整文档支持(安装量更大)
pip install "unstructured[all-docs]==0.17.0"
[pdf] 额外安装 pdf2image、pdfplumber 和 pikepdf。[all-docs] 额外添加 DOCX、PPTX、XLSX、MSG、EML、EPUB 和 OCR 依赖(包括 tesseract 绑定)。
验证安装:
from unstructured.partition.auto import partition
elements = partition(filename="test.pdf")
print(f"提取了 {len(elements)} 个元素")
for el in elements[:5]:
print(f" {el.category}: {str(el)[:60]}...")
方案B:通过Docker自托管API(生产环境) #
# 拉取预构建镜像
docker pull downloads.unstructured.io/unstructured-io/unstructured-api:latest
# 使用GPU支持运行 hi_res 分区
docker run -d \
--name unstructured-api \
-p 8000:8000 \
--gpus all \
downloads.unstructured.io/unstructured-io/unstructured-api:latest
# 验证健康状态
curl http://localhost:8000/healthcheck
纯CPU环境(更便宜,复杂PDF处理较慢):
docker run -d \
--name unstructured-api-cpu \
-p 8000:8000 \
downloads.unstructured.io/unstructured-io/unstructured-api-cpu:latest
如果你需要可靠的云服务器来托管,DigitalOcean的GPU droplets 非常适合运行 hi_res 流水线。
向API发送文档 #
import requests
with open("annual_report.pdf", "rb") as f:
response = requests.post(
"http://localhost:8000/general/v0/general",
files={"files": ("annual_report.pdf", f)},
data={
"strategy": "hi_res",
"chunking_strategy": "by_title",
"max_characters": 1500,
"new_after_n_chars": 1200,
"overlap": 150,
"output_format": "application/json"
}
)
elements = response.json()
print(f"获取了 {len(elements)} 个块")
与 LangChain、LlamaIndex 和向量数据库集成 #
Unstructured 与主流 LLM 编排框架原生集成。
LangChain 加载器 #
from langchain_community.document_loaders import UnstructuredFileLoader
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
# 一步完成加载和分区
loader = UnstructuredFileLoader(
"quarterly_earnings.pdf",
mode="elements", # 保留元素类型
strategy="hi_res",
post_processors=["chunk_by_title_characters"],
)
documents = loader.load() # 返回 Document 对象列表
# 每个文档都有丰富的元数据
print(documents[0].metadata)
# {'source': 'quarterly_earnings.pdf', 'page_number': 1,
# 'category': 'NarrativeText', 'element_id': '...', 'parent_id': '...'}
# 直接存入向量库
vectorstore = Chroma.from_documents(
documents=documents,
embedding=OpenAIEmbeddings(),
)
LlamaIndex 集成 #
from llama_index.readers.unstructured import UnstructuredReader
from llama_index.core import VectorStoreIndex
reader = UnstructuredReader(
api_url="http://localhost:8000",
partition_kwargs={
"strategy": "hi_res",
"chunking_strategy": "by_title",
"max_characters": 1500,
"overlap": 200,
}
)
documents = reader.load_data("whitepaper.pdf")
index = VectorStoreIndex.from_documents(documents)
query_engine = index.as_query_engine()
response = query_engine.query("第3节提到的关键风险有哪些?")
print(response)
直接 Chroma 集成(无需框架) #
import chromadb
from unstructured.chunking.title import chunk_by_title
from unstructured.partition.pdf import partition_pdf
from sentence_transformers import SentenceTransformer
# 分区
raw_elements = partition_pdf("contract.pdf", strategy="hi_res")
# 保留章节的分块
chunks = chunk_by_title(
raw_elements,
max_characters=1200,
new_after_n_chars=1000,
overlap=200,
)
# 嵌入并存储
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_or_create_collection("contracts")
model = SentenceTransformer("all-MiniLM-L6-v2")
for i, chunk in enumerate(chunks):
embedding = model.encode(str(chunk)).tolist()
collection.add(
ids=[f"chunk_{i}"],
embeddings=[embedding],
documents=[str(chunk)],
metadatas=[{
"source": "contract.pdf",
"page": chunk.metadata.page_number,
"type": chunk.category,
}]
)
基准测试与实际用例 #
支持的文档格式 #
Unstructured v0.17.0 支持 25+ 种文件格式:
| 格式 | 读取 | 表格 | OCR | 备注 |
|---|---|---|---|---|
| PDF(文本型) | 是 | 是 | 不适用 | 最佳支持格式 |
| PDF(扫描/图像型) | 是 | 部分 | 是 | 需要 tesseract |
| DOCX | 是 | 是 | 不适用 | 完整保留结构 |
| PPTX | 是 | 是 | 不适用 | 逐页分区 |
| XLSX | 是 | 不适用 | 不适用 | 每单元格一个元素 |
| HTML | 是 | 是 | 不适用 | 有效清理样板内容 |
| Markdown | 是 | 是 | 不适用 | 保留标题层级 |
| PNG/JPG | 通过OCR | 否 | 是 | 提取嵌入文本 |
| EPUB | 是 | 是 | 不适用 | 感知章节 |
| MSG/EML | 是 | 否 | 不适用 | 处理邮件线程 |
处理性能 #
在 8核Intel i7, 32GB内存, 无GPU 上的基准测试:
| 文档 | 大小 | 策略 | 耗时 | 元素数 |
|---|---|---|---|---|
| 10页文本PDF | 2.1 MB | fast | 1.2秒 | 47 |
| 10页文本PDF | 2.1 MB | hi_res | 8.4秒 | 52 |
| 47页扫描PDF | 18 MB | hi_res + OCR | 94秒 | 203 |
| 30页PPTX | 5.4 MB | auto | 4.1秒 | 128 |
| 85页DOCX | 1.2 MB | auto | 2.8秒 | 312 |
使用 GPU加速(通过Docker API使用NVIDIA T4),相同10页PDF的 hi_res 分区降至 2.1秒 — 约 4倍加速。
分块质量对RAG的影响 #
我在50份法律合同(平均15页)上进行了对照测试,测量 top-3 检索准确率:
| 预处理方法 | 平均块质量 | RAG Top-3 准确率 |
|---|---|---|
原始 pdftotext + 拆分 | 0.31 | 34% |
| PyPDF2 + 字符拆分 | 0.38 | 41% |
Unstructured fast + basic 分块 | 0.67 | 72% |
Unstructured hi_res + by_title | 0.89 | 89% |
块质量按0-1分制评分,评估维度:语义连贯性、边界保留(不在句中拆分)、元数据丰富度。89%的 hi_res 准确率 代表了未经人工整理情况下文档RAG的实际上限。
生产案例 #
法律文档分析(每月10万+页):一家合规初创公司使用 Kubernetes 中的 Unstructured API 处理SEC文件。报告 99.7% 正常运行时间,每个Pod使用 fast 策略处理文本PDF,hi_res 处理扫描附件,速度约 50份文档/分钟。
医疗记录导入:一家医疗AI公司从混合PDF + 扫描传真文档中提取文本。OCR + hi_res 处理 94% 的文档无需人工干预;剩余6%为低质量传真,标记供人工审核。
高级用法与生产加固 #
自定义后处理流水线 #
from unstructured.partition.pdf import partition_pdf
from unstructured.chunking.title import chunk_by_title
from unstructured.cleaners.core import clean
# 第1步:使用 hi_res 进行分区以检测布局
elements = partition_pdf(
"complex_report.pdf",
strategy="hi_res",
extract_images_in_pdf=True, # 保存嵌入图像
infer_table_structure=True, # 表格输出HTML
max_partition=2000, # 每批元素数
)
# 第2步:过滤不需要的元素
filtered = [
el for el in elements
if el.category not in ["Header", "Footer", "PageBreak"]
]
# 第3步:清洗文本内容
for el in filtered:
el.text = clean(
el.text,
extra_whitespace=True,
dashes=True, # 统一破折号
trailing_punctuation=True,
)
# 第4步:带重叠的分块
chunks = chunk_by_title(
filtered,
max_characters=1500,
new_after_n_chars=1200,
overlap_all=True, # 所有块之间重叠
overlap=200,
)
print(f"{len(elements)} 原始 → {len(filtered)} 过滤 → {len(chunks)} 块")
带并发工作器的批量处理 #
import concurrent.futures
from pathlib import Path
from unstructured.partition.auto import partition
def process_file(path: Path) -> dict:
try:
elements = partition(
filename=str(path),
strategy="fast",
)
return {
"file": path.name,
"elements": len(elements),
"status": "success",
}
except Exception as e:
return {
"file": path.name,
"elements": 0,
"status": "error",
"error": str(e),
}
# 使用8个工作器处理500个PDF
pdf_dir = Path("./documents")
pdf_files = list(pdf_dir.glob("*.pdf"))
with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:
results = list(executor.map(process_file, pdf_files))
success = sum(1 for r in results if r["status"] == "success")
print(f"成功处理了: {success}/{len(results)} 个文件")
重处理缓存策略 #
对于迭代RAG开发,分区一次并缓存:
import json
import hashlib
from pathlib import Path
from unstructured.staging.base import elements_to_dicts, dicts_to_elements
def partition_with_cache(file_path: str, strategy: str = "hi_res"):
file_hash = hashlib.md5(open(file_path, "rb").read()).hexdigest()
cache_path = Path(f"./cache/{file_hash}_{strategy}.json")
cache_path.parent.mkdir(exist_ok=True)
if cache_path.exists():
return dicts_to_elements(json.load(open(cache_path)))
elements = partition_pdf(file_path, strategy=strategy)
cache_path.write_text(json.dumps(elements_to_dicts(elements), indent=2))
return elements
Kubernetes 部署 #
# unstructured-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: unstructured-api
spec:
replicas: 3
selector:
matchLabels:
app: unstructured-api
template:
metadata:
labels:
app: unstructured-api
spec:
containers:
- name: api
image: downloads.unstructured.io/unstructured-io/unstructured-api:latest
ports:
- containerPort: 8000
resources:
limits:
nvidia.com/gpu: 1
memory: "8Gi"
requests:
memory: "4Gi"
---
apiVersion: v1
kind: Service
metadata:
name: unstructured-api
spec:
selector:
app: unstructured-api
ports:
- port: 80
targetPort: 8000
如果你选择自托管,DigitalOcean的Kubernetes集群 配合GPU节点是相比托管API更具性价比的选择。
与替代方案对比 #
| 特性 | Unstructured.io | LlamaParse | Docling | PyMuPDF + 自定义 |
|---|---|---|---|---|
| 开源 | 是 (Apache-2.0) | 否 (商业) | 是 (MIT) | 是 (混合) |
| GitHub Stars | 10,500+ | N/A (闭源) | 5,200+ | N/A |
| 免费额度 | 自托管无限 | 每日1K页 | 无限 | N/A |
| PDF表格→HTML | 是 | 是 | 是 | 手动 |
| OCR(扫描PDF) | 是 | 是 | 是 | 通过tesseract |
| PPTX支持 | 是 | 有限 | 否 | 否 |
| DOCX支持 | 是 | 是 | 是 | 否 |
| 元素类型检测 | 20+类型 | 基础 | 基础 | 无 |
| 内置分块 | 是 (3种策略) | 基础 | 否 | 否 |
| LangChain集成 | 原生 | 原生 | 社区 | 手动 |
| GPU加速 | 是 | 是 | 是 | 否 |
| 企业SLA | 可购买 | 可购买 | 否 | 否 |
| 自托管API | Docker/K8s | 仅云端 | 仅CLI | N/A |
| 批量处理 | 是 | 是 | 有限 | 手动 |
| 元数据提取 | 丰富 | 基础 | 中等 | 无 |
选择建议:
- Unstructured.io:最适合多格式流水线、需要完全控制的团队、或丰富元数据至关重要的场景。开源 + 自托管选项在大规模下保持成本可控。
- LlamaParse:如果你已在 LlamaIndex 生态中且不介意托管服务。表格提取出色但格式支持较窄。
- Docling:IBM的新产品。快速轻量,适合以PDF为主的工作流。截至2026年中,缺少PPTX和高级分块功能。
- PyMuPDF + 自定义:如果你只处理文本PDF且有工程时间来自己构建分块逻辑。不推荐用于混合文档类型。
局限性:坦诚评估 #
Unstructured 并非万能。以下是在生产环境中会让你头疼的问题:
1. OCR质量取决于输入质量。 低分辨率扫描文档(低于150 DPI)无论用什么流水线都会产生乱码。如果你的源材料质量差,先用图像增强预处理。
2. 无GPU时 hi_res 很慢。 默认的 detectron2 模型在CPU上处理复杂排版速度为每分钟3-5页。预算GPU加速,或对批量文本PDF使用 fast 策略。
3. 表格提取不错,但不完美。 包含合并单元格、嵌套表头或跨行结构的复杂表格可能丢失结构保真度。HTML输出在我们的测试中正确捕获约 85% 的表格。
4. 大文档内存占用会飙升。 带图像的200页PDF在 hi_res 分区期间可能消耗4-6GB内存。对大文件使用 max_partition 分批处理。
5. 安装体积庞大。 [all-docs] 额外依赖约2GB,包括 PyTorch、Detectron2 和 Tesseract。在生产环境使用Docker来隔离。
6. 不是格式转换器。 Unstructured 提取的是 内容,不是样式。如果你需要保留格式的 PDF 转 DOCX,请使用其他工具。
常见问题 #
Unstructured.io 支持哪些文件格式? #
Unstructured 支持 25+ 种格式,包括 PDF、DOCX、PPTX、XLSX、HTML、Markdown、EPUB、PNG、JPG、TIFF、MSG、EML、RTF 和 TXT。PDF 和 DOCX 支持最成熟,包含表格结构提取。PPTX 原生支持逐页分区。图像格式需要 Tesseract OCR。
应该使用 Python 库还是 Docker API? #
开发、原型设计和单文档工作流使用 Python 库。生产环境切换到 Docker API — 它提供更好的资源隔离、通过 Kubernetes 的水平扩展、以及 hi_res 策略的 GPU 加速。API 还简化了团队协作,因为不需要管理 Python 环境。
带重叠的分块如何工作? #
设置 overlap=200 时,Unstructured 将每个块的末尾200个字符复制到下一块的开头。这防止了块边界的上下文丢失 — 对RAG至关重要,因为跨块拆分的句子会变得无法回答。by_title 策略额外确保块永远不会跨章节边界拆分,除非单个章节超过 max_characters。
能否在离线环境下运行 Unstructured? #
可以。Docker镜像和Python库在初始下载后完全自包含。hi_res 策略在首次使用时下载模型权重(Detectron2/YOLOX)— 在部署镜像中缓存这些权重。本地运行不需要API密钥或云端调用。
fast 和 hi_res 分区有什么区别? #
fast 使用基于规则的文本提取(pdfplumber、python-docx),适用于排版简单的文本型文档。hi_res 运行视觉文档理解模型来检测区域、表格和阅读顺序 — 对于复杂排版、扫描文档和精确的表格提取至关重要。在CPU上 hi_res 预计慢5-10倍,或使用GPU加速来缩小差距。
如何处理解析失败的文档? #
用 try/except 包裹分区调用并实现降级链:先尝试 hi_res,降级到 fast,然后对图像型文档降级到 ocr_only。记录失败日志并附带文件哈希供人工审核。生产中,损坏或密码保护文件的 失败率约2-4% — 请规划死信队列。
Unstructured 支持非英文文档吗? #
支持。该库自动检测 50+ 种语言。OCR 支持 Tesseract 支持的任何语言(100+ 种,包括中文、日文、韩文、阿拉伯文和印地文)。设置 languages=["eng", "chi_sim"] 来提示特定语言以获得更好的 OCR 准确率。
结论:从 fast 开始,升级到 hi_res #
Unstructured.io 解决了LLM流水线中最被低估的问题:将现实世界文档转换为可用数据。路径很清晰 — 文本PDF先用 fast 分区,添加 by_title 分块用于RAG,需要表格和复杂排版时升级到 hi_res + GPU。
10,500+ Stars 和 Apache-2.0 许可证使其成为一个安全的社区支持选择。自托管API让你完全掌控数据 — 文档不会离开你的基础设施。
今天就使用第4节的Docker命令部署你的第一个实例,导入你的文档目录,看着你的RAG准确率攀升。
加入我们的开发者社区 Telegram: t.me/dibi8zh — 分享你的预处理流水线,并从大规模运行 Unstructured 的工程师那里获得帮助。
推荐部署与基础设施 #
上述工具想要落地生产,靠谱的基础设施是前提。dibi8 自己也在用的两个选择:
- DigitalOcean — 新用户 60 天 $200 免费额度,14+ 全球节点。运行开源 AI 工具的首选。
- HTStack — 香港 VPS,国内访问低延迟,dibi8.com 自己也跑在它上面,生产环境验证过。
Aff 链接 — 不增加你的成本,但能帮 dibi8 持续运营。
来源与延伸阅读 #
- Unstructured GitHub 仓库 — 10,500+ Stars, Apache-2.0
- 官方文档
- API部署指南
- LangChain Unstructured 加载器
- LlamaIndex Unstructured Reader
- 分区策略深入解析
- 分块策略对比
- Unstructured 平台(企业版)
- 相关文章: LangChain, LlamaIndex, RAG流水线优化
联盟营销披露: 本文包含 DigitalOcean 的联盟链接。如果你通过这些链接注册,我们赚取佣金,不额外收费。Unstructured.io 是开源免费使用的;我们与 Unstructured-IO 没有商业关系。观点基于实际测试。
💬 留言讨论