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 模型(默认:detectron2yolox)来识别标题、正文、页眉、页脚和表格等区域,然后再进行提取。这就是它能够将表格转换为 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] 额外安装 pdf2imagepdfplumberpikepdf[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页文本PDF2.1 MBfast1.2秒47
10页文本PDF2.1 MBhi_res8.4秒52
47页扫描PDF18 MBhi_res + OCR94秒203
30页PPTX5.4 MBauto4.1秒128
85页DOCX1.2 MBauto2.8秒312

使用 GPU加速(通过Docker API使用NVIDIA T4),相同10页PDF的 hi_res 分区降至 2.1秒 — 约 4倍加速

分块质量对RAG的影响 #

我在50份法律合同(平均15页)上进行了对照测试,测量 top-3 检索准确率:

预处理方法平均块质量RAG Top-3 准确率
原始 pdftotext + 拆分0.3134%
PyPDF2 + 字符拆分0.3841%
Unstructured fast + basic 分块0.6772%
Unstructured hi_res + by_title0.8989%

块质量按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.ioLlamaParseDoclingPyMuPDF + 自定义
开源是 (Apache-2.0)否 (商业)是 (MIT)是 (混合)
GitHub Stars10,500+N/A (闭源)5,200+N/A
免费额度自托管无限每日1K页无限N/A
PDF表格→HTML手动
OCR(扫描PDF)通过tesseract
PPTX支持有限
DOCX支持
元素类型检测20+类型基础基础
内置分块是 (3种策略)基础
LangChain集成原生原生社区手动
GPU加速
企业SLA可购买可购买
自托管APIDocker/K8s仅云端仅CLIN/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密钥或云端调用。

fasthi_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 持续运营。

来源与延伸阅读 #


联盟营销披露: 本文包含 DigitalOcean 的联盟链接。如果你通过这些链接注册,我们赚取佣金,不额外收费。Unstructured.io 是开源免费使用的;我们与 Unstructured-IO 没有商业关系。观点基于实际测试。

💬 留言讨论