mcpField
P
pdfmux — PDF extraction that actually works

pdfmux — PDF extraction that actually works

本地服务
pdfmux.com文件与存储862 周前更新

关于 pdfmux — PDF extraction that actually works

pdfmux 是一个 PDF 提取 MCP 服务,可按页审核输出结果,并标记无法读取的页面而非静默丢弃。它面向 RAG 流水线和需要可靠 PDF 文本的 AI Agent,并可用 pdfmux verify 校验其他提取工具的输出。

主要功能

  1. 01按页审核提取结果并自动重新提取失败页面
  2. 02按页面内容路由到最合适的提取后端
  3. 03支持 RAG 分块与 Markdown、JSON 输出
  4. 04通过 verify 检测其他引擎输出中的静默丢失页面
  5. 05扫描件 OCR 与可选的 LLM 回退

适用场景

  1. 01为 RAG 索引准备 PDF 文本并排查缺失页面
  2. 02让 AI Agent 在会话中读取和转换 PDF 文件
  3. 03批量校验第三方 PDF 提取工具的输出完整性

MCP 相关

该项目作为 MCP 服务运行,通过 pdfmux serve 提供 stdio 或 HTTP 模式,向 MCP 客户端暴露 PDF 元数据读取、转换、分析、批量转换和结构化提取等工具,以及 verify_extraction 校验工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"pdfmux": {
"command": "uvx",
"args": [
"pdfmux"
],
"env": {
"GEMINI_API_KEY": "<GEMINI_API_KEY>"
}
}
}
}
启动命令uvx pdfmux
需要配置的环境变量
GEMINI_API_KEY密钥Optional Google AI API key. Enables the paid Gemini Flash fallback for pages where all local backends report low confidence. pdfmux runs 100% locally without this.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypipdfmux1.8.7

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

pdfmux

CI PyPI Python 3.11+ License: MIT Downloads

具有自我修复能力的 PDF 提取工具:标记无法读取的页面,而不是将其丢弃;现在还能验证任何提取器的输出,找出静默丢页。 开源的 LlamaParse 替代方案,适用于 RAG 工作流;可用作 Claude Desktop 的 MCP 服务,以及 LangChain + LlamaIndex 加载器。

pdfmux 能提取 PDF 并检查自己的工作;现在还能验证任何提取器的输出,告诉你哪些页面被静默丢弃。免费,采用 MIT 许可证。方法正在申请专利。pip install pdfmux。

两项功能,一个工具:

  • 自我修复式提取。 唯一能审核自身输出的 PDF 提取器。它能发现空白页面、错乱的分栏和损坏的表格,并使用更强大的后端重新提取;对于仍无法读取的内容,会进行标记,而不是静默丢弃。这样,大模型获取的是干净数据,而不是无声的垃圾数据。它会将每个页面路由到 7 个内置提取后端中的最佳选项,并支持 BYOK 大模型回退方案(Gemini / Claude / GPT-4o / Ollama)。一个 CLI,一个 API,零配置。
  • 验证任何提取结果 — v1.8.1 新增。 pdfmux verify 会根据源 PDF 审核任何提取引擎的输出,包括 Reducto、Mistral OCR、LlamaParse、Docling 和你自研的解析器,并告诉你哪些页面被静默丢弃。免费,采用 MIT 许可证,专利方面无风险。

pdfmux 终端演示

PDF ──> pdfmux router ──> best extractor per page ──> audit ──> re-extract failures ──> Markdown / JSON / chunks
            |
            ├─ PyMuPDF         (digital text, 0.01s/page)
            ├─ OpenDataLoader  (complex layouts, 0.05s/page)
            ├─ RapidOCR        (scanned pages, CPU-only)
            ├─ Docling         (tables, 97.9% TEDS)
            ├─ Surya           (heavy OCR fallback)
            ├─ Marker          (academic papers, neural)
            ├─ Mistral OCR     ($0.002/page, 96.6% tables)
            └─ YOUR LLM        (Gemini / Gemma 3 / Claude / GPT-4o / Ollama / Mistral — BYOK via YAML)

安装

pip install pdfmux

这适用于数字 PDF。对于任何真实场景中的批量处理,也请安装 pdfmux[ocr]——几乎每个 PDF 文件夹里都有至少一份扫描件;没有 OCR,这些页面就会返回空文本:

pip install "pdfmux[ocr]"             # ⭐ recommended — RapidOCR for scanned pages (~200MB, CPU)

按文档类型选择其他后端:

pip install "pdfmux[tables]"          # Docling — table-heavy docs (~500MB)
pip install "pdfmux[opendataloader]"  # OpenDataLoader — complex layouts (Java 11+)
pip install "pdfmux[marker]"          # Marker — neural extraction for academic papers
pip install "pdfmux[llm]"             # Gemini fallback (default LLM)
pip install "pdfmux[llm-claude]"      # Claude (Sonnet / Opus)
pip install "pdfmux[llm-openai]"      # GPT-4o family
pip install "pdfmux[llm-ollama]"      # Ollama (any local model)
pip install "pdfmux[llm-mistral]"     # Mistral OCR API ($0.002/page)
pip install "pdfmux[llm-all]"         # all LLM providers (incl. Gemma via Gemini key)
pip install "pdfmux[watch]"           # `pdfmux watch <dir>` auto-convert on change
pip install "pdfmux[all]"             # everything

需要 Python 3.11+。

快速开始

CLI
# zero config — just works
pdfmux convert invoice.pdf
# invoice.pdf -> invoice.md (2 pages, 95% confidence, via pymupdf4llm)

# RAG-ready chunks with token limits
pdfmux convert report.pdf --chunk --max-tokens 500

# cost-aware extraction with budget cap
pdfmux convert report.pdf --mode economy --budget 0.50

# schema-guided structured extraction (5 built-in presets)
pdfmux convert invoice.pdf --schema invoice

# BYOK any LLM for hardest pages
pdfmux convert scan.pdf --llm-provider claude

# use a built-in or saved profile (invoices, receipts, papers, contracts, bulk-rag)
pdfmux convert invoice.pdf --profile invoices

# predict cost before running anything
pdfmux estimate big-report.pdf --llm-provider gemini

# stream pages as NDJSON as they finish (great for long documents)
pdfmux stream report.pdf --quality high

# auto-convert any new PDFs that land in a folder
pdfmux watch ./inbox/ -o ./output/

# diff two extractions side-by-side
pdfmux diff old.pdf new.pdf

# batch a directory — writes manifest.json with per-doc confidence
pdfmux convert ./docs/ -o ./output/

# CI mode: fail the run if any document is below 0.20 confidence
pdfmux convert ./docs/ -o ./output/ --strict --min-confidence 0.20

# pre-flight a directory: which extras do you actually need for THIS batch?
pdfmux doctor --check ./docs/

# results are cached by file hash — re-runs are instant; bypass with --no-cache
pdfmux convert report.pdf --no-cache
pdfmux convert report.pdf --clear-cache
Python

批量处理时,请使用 batch_extract(),不要循环调用 subprocess.run(['pdfmux', ...])。两者使用相同的流水线,但前者不会为每个文件单独启动进程,还能处理非 ASCII 文件名:

import pdfmux
from pathlib import Path

# Batch extract — yields (path, result) tuples as each PDF completes.
pdfs = list(Path("./inbox").glob("*.pdf"))
for path, result in pdfmux.batch_extract(pdfs, quality="standard"):
    if isinstance(result, Exception):
        print(f"FAILED {path.name}: {result}")
        continue
    if result.confidence < 0.50:
        print(f"REVIEW {path.name} ({result.confidence:.2f})")
    else:
        print(f"OK     {path.name} ({result.confidence:.2f})")

# Single-file helpers.
text   = pdfmux.extract_text("report.pdf")             # markdown string
data   = pdfmux.extract_json("report.pdf")             # locked schema dict
chunks = pdfmux.chunk("report.pdf", max_tokens=500)    # RAG-ready chunks

不要自行用 pypdf/pdfplumber 为 pdfmux 添加回退方案。 pdfmux 已经会逐页通过 PyMuPDF → RapidOCR → 视觉大模型进行路由。PyMuPDF 能处理 pypdf 会拒绝的格式错误 PDF(“Stream has ended unexpectedly”),因此下游的 pypdf 回退会让原本可恢复的 PDF 变成失败。请信任路由器,并检查结果中的置信度分数。

验证任何提取结果

pdfmux verify 会根据源 PDF 审核任何提取引擎的输出,并告诉你哪些页面被静默丢弃——不仅限于 pdfmux 自身的提取结果。将 Reducto、Mistral OCR、LlamaParse、Docling 或自研解析器的输出交给它,它就会使用 pdfmux 自身的审核流程重新推导源文本,将提取结果与之对齐,并为每个页面评分。

它能捕获的故障: 源文件中某个页面包含真实文本,但引擎却未返回任何内容,同时还报告成功。这种“静默丢弃”正是会污染 RAG 索引、却不会在日志中产生任何错误的故障。

# Certify pdfmux's own extraction of a document
pdfmux verify --source report.pdf --engine pdfmux

# Certify ANOTHER engine's output (JSON / Markdown / text)
pdfmux verify --source report.pdf --extracted reducto.json --engine-name reducto

# Batch a whole directory — the "M pages silently dropped across N docs" report
pdfmux verify --source ./pdfs/ --extracted ./engine-outputs/ -o certification.json

# CI gate: exit non-zero unless the overall verdict is PASS
pdfmux verify --source report.pdf --extracted out.json --strict

每次运行都会输出 PASS / REVIEW / FAIL 判定、整体置信度和覆盖率;发现静默丢弃的页面时,还会列出页码:

pdfmux verify — report.pdf · engine: reducto
  FAIL   confidence 71% · coverage 68%
  reducto: FAIL; 3 page(s) SILENTLY DROPPED (pages 7, 12, 31); overall
  confidence 71%, coverage 68% across 40 page(s).

❌ 3 page(s) SILENTLY DROPPED: 7, 12, 31

每个页面都会提供判定(pass / review / fail)、置信度、覆盖率、对齐度、幻觉风险以及表格和标题完整性。批处理模式会将结果汇总为一行:“M 份文档中有 N 个页面被静默丢弃”——你可以用这份报告检查自有的 100 份 PDF,找出流水线中已经存在的静默故障。

适用于任何引擎的输出

--extracted 接受 JSON、Markdown 或纯文本(--extracted-format auto | json | markdown | text)。如果提取结果呈现真实的逐页结构,pdfmux 会逐页比较;如果结果是一个整体内容块,则会回退到内容存在性检查,因此绝不会因分页不匹配而虚构“静默丢失”。

Python API
from pdfmux import verify_extraction, verify_batch

# Single document → a CertificationManifest
manifest = verify_extraction("report.pdf", "reducto.json", engine="reducto")
print(manifest.verdict)        # "PASS" | "REVIEW" | "FAIL"
print(manifest.silent_drops)   # e.g. (7, 12, 31)  — 1-indexed page numbers
print(manifest.coverage)       # 0.0–1.0

# Many documents → a BatchCertification ("M pages dropped across N docs")
batch = verify_batch([("a.pdf", "a.json"), ("b.pdf", "b.json")], engine="llamaparse")
print(batch.total_silent_drops, "pages dropped across", batch.doc_count, "docs")

每份清单都包含一个防篡改的 SHA-256 内容签名,该签名基于其规范化正文生成;同时还嵌入了一份如实列出的局限性说明:该认证器基于词法,而非语言学——它能检测缺失和乱码内容,但无法判断释义或翻译是否忠实。

MCP

verify_extraction 作为 MCP 工具公开(第 7 个工具——参见 MCP 服务),因此 Agent 可以在提取内容的同一会话中认证引擎的输出。

免费、MIT、专利无争议

Certify Anything 仅复用 pdfmux 随附的 MIT 审计层。它不包含也不需要申请中的专利决策追踪方法——该方法仍仅适用于 pdfmux Cloud/Pro。pip install pdfmux 可免费提供完整的 verify 命令。

完整参考:docs/CERTIFY-ANYTHING.md。

需要向他人证明时

本地安装可以审计提取结果,但无法对其进行证明——任何人都可以伪造本地签署的内容。pdfmux Cloud 会返回一份针对提取结果的 Ed25519 签名清单:审计人员无需账号,也无需信任 pdfmux,即可根据公开发布的公钥离线验证。

pdfmux verify-manifest manifest.json      # free, MIT, offline — no account

验证永久免费且保持开源;只有生成需要付费(每月 $49)。这种不对称是有意为之——你永远不该需要我们的许可才能核查我们的工作。

免费工具,无需注册:app.pdfmux.com/audit——上传 PDF,查看当前提取器静默漏掉了哪些页面。实测准确率(及其盲点)已发布在 pdfmux-bench。

架构

                           ┌─────────────────────────────┐
                           │     Segment Detector         │
                           │  text / tables / images /    │
                           │  formulas / headers per page │
                           └─────────────┬───────────────┘
                                         │
                    ┌────────────────────────────────────────┐
                    │            Router Engine                │
                    │                                        │
                    │   economy ── balanced ── premium        │
                    │   (minimize $)  (default)  (max quality)│
                    │   budget caps: --budget 0.50            │
                    └────────────────────┬───────────────────┘
                                         │
          ┌──────────┬──────────┬────────┴────────┬──────────┐
          │          │          │                  │          │
     PyMuPDF   OpenData    RapidOCR           Docling     LLM
     digital   Loader      scanned            tables    (BYOK)
     0.01s/pg  complex     CPU-only           97.9%    any provider
               layouts                        TEDS
          │          │          │                  │          │
          └──────────┴──────────┴────────┬────────┴──────────┘
                                         │
                    ┌────────────────────────────────────────┐
                    │           Quality Auditor               │
                    │                                        │
                    │   4-signal dynamic confidence scoring   │
                    │   per-page: good / bad / empty          │
                    │   if bad -> re-extract with next backend│
                    └────────────────────┬───────────────────┘
                                         │
                    ┌────────────────────────────────────────┐
                    │           Output Pipeline               │
                    │                                        │
                    │   heading injection (font-size analysis)│
                    │   table extraction + normalization      │
                    │   text cleanup + merge                  │
                    │   confidence score (honest, not inflated)│
                    └────────────────────────────────────────┘
关键设计决策
  • 路由器,而非提取器。 pdfmux 不与 PyMuPDF 或 Docling 竞争,而是为每一页挑选最佳工具。
  • Agent 多轮处理。 提取内容、审计置信度,再用更强的后端重新提取失败内容。较差的页面会自动重试。
  • 片段级检测。 路由之前,先按内容类型(文本、表格、图像、公式、页眉)对每一页进行分类。
  • 4 信号置信度。 根据字符密度、OCR 噪声比例、表格完整性和标题结构动态评估质量,而非使用硬编码阈值。
  • 文档缓存。 每份 PDF 只打开一次,而不是每个提取器打开一次。整个处理流水线共享缓存。
  • 数据飞轮。 本地遥测会追踪不同文档类型中表现最佳的提取器。路由效果会随着使用不断提升。

功能

功能作用命令
零配置提取自动路由到最佳后端pdfmux convert file.pdf
RAG 分块按章节切分,并估算令牌数pdfmux convert file.pdf --chunk --max-tokens 500
成本模式economy / balanced / premium,支持预算上限pdfmux convert file.pdf --mode economy --budget 0.50
Schema 提取内置 5 种预设(invoice、receipt、contract、resume、paper)pdfmux convert file.pdf --schema invoice
配置方案保存并重用配置;内置 invoices/receipts/papers/contracts/bulk-rag 配置pdfmux convert file.pdf --profile invoices
自带密钥的 LLMGemini、Gemma 3、Claude、GPT-4o、Ollama、Mistral,以及任何兼容 OpenAI 的 APIpdfmux convert file.pdf --llm-provider claude
成本估算运行前预测开销pdfmux estimate file.pdf --llm-provider gemini
流式输出长文档按页输出 NDJSON 事件pdfmux stream file.pdf
智能缓存基于哈希键的结果缓存,TTL 为 30 天,LRU 容量为 1 GBpdfmux convert file.pdf(自动),使用 --no-cache 跳过
监视模式自动转换添加到文件夹中的任何 PDFpdfmux watch ./inbox/
差异对比比较两次提取结果pdfmux diff a.pdf b.pdf
基准测试根据基准数据评估所有已安装的提取器pdfmux benchmark
诊断显示已安装的后端、覆盖缺口和建议pdfmux doctor
MCP 服务AI Agent 通过 stdio 或 HTTP 读取 PDFpdfmux serve
批量处理转换整个目录pdfmux convert ./docs/
页面级流式 API以有界内存逐页处理大型文件for page in ext.extract("500pg.pdf")
带退避的重试每个 LLM 提供商都会自动进行指数退避重试,并遵循 Retry-After(内置)

CLI 参考

pdfmux convert
pdfmux convert <file-or-dir> [options]

Options:
  -o, --output PATH          Output file or directory
  -f, --format FORMAT        markdown | json | csv | llm (default: markdown)
  -q, --quality QUALITY      fast | standard | high (default: standard)
  -s, --schema SCHEMA        JSON schema file or preset (invoice, receipt, contract, resume, paper)
  --chunk                    Output RAG-ready chunks
  --max-tokens N             Max tokens per chunk (default: 500)
  --mode MODE                economy | balanced | premium (default: balanced)
  --budget AMOUNT            Max spend per document in USD
  --llm-provider PROVIDER    LLM backend: gemini | claude | openai | ollama
  --confidence               Include confidence score in output
  --stdout                   Print to stdout instead of file
pdfmux serve

启动 MCP 服务,以便与 AI Agent 集成。

pdfmux serve              # stdio mode (Claude Desktop, Cursor)
pdfmux serve --http 8080  # HTTP mode
pdfmux doctor
pdfmux doctor
# ┌──────────────────┬─────────────┬─────────┬──────────────────────────────────┐
# │ Extractor        │ Status      │ Version │ Install                          │
# ├──────────────────┼─────────────┼─────────┼──────────────────────────────────┤
# │ PyMuPDF          │ installed   │ 1.25.3  │                                  │
# │ OpenDataLoader   │ installed   │ 0.3.1   │                                  │
# │ RapidOCR         │ installed   │ 3.0.6   │                                  │
# │ Docling          │ missing     │ --      │ pip install pdfmux[tables]       │
# │ Surya            │ missing     │ --      │ pip install pdfmux[ocr-heavy]    │
# │ LLM (Gemini)     │ configured  │ --      │ GEMINI_API_KEY set               │
# └──────────────────┴─────────────┴─────────┴──────────────────────────────────┘
pdfmux benchmark
pdfmux benchmark report.pdf
# ┌──────────────────┬────────┬────────────┬─────────────┬──────────────────────┐
# │ Extractor        │   Time │ Confidence │      Output │ Status               │
# ├──────────────────┼────────┼────────────┼─────────────┼──────────────────────┤
# │ PyMuPDF          │  0.02s │        95% │ 3,241 chars │ all pages good       │
# │ Multi-pass       │  0.03s │        95% │ 3,241 chars │ all pages good       │
# │ RapidOCR         │  4.20s │        88% │ 2,891 chars │ ok                   │
# │ OpenDataLoader   │  0.12s │        97% │ 3,310 chars │ best                 │
# └──────────────────┴────────┴────────────┴─────────────┴──────────────────────┘
pdfmux estimate

在处理前预测开销(以及将运行哪些后端)。

pdfmux estimate report.pdf --quality high --llm-provider gemini
# Pages       : 47
# Extractors  : pymupdf4llm + gemini-2.5-flash on 9 pages
# Estimated   : $0.0234
# Cache hit?  : no  (first run for this file)
pdfmux stream

页面处理完成后输出 NDJSON 事件,适用于超长 PDF 和实时 UI。

pdfmux stream long.pdf --quality high
# {"event":"classified","page_count":312,"plan":"pymupdf+gemini-fallback"}
# {"event":"page","page_num":0,"confidence":0.97,"chars":1842}
# {"event":"page","page_num":1,"confidence":0.92,"chars":1611,"ocr":true}
# ...
# {"event":"complete","confidence":0.94,"cost_usd":0.0712}
pdfmux watch

自动转换放入目录中的任何 PDF。持续运行,直到按下 Ctrl+C。

pdfmux watch ./inbox/ -o ./output/ --profile bulk-rag
pdfmux diff

并排比较提取结果(质量、内容、成本)。

pdfmux diff a.pdf b.pdf --quality standard
pdfmux profiles

已保存的配置位于 ~/.config/pdfmux/profiles.yaml。内置常见类型的配置;也可为项目默认设置保存自定义配置。

pdfmux profiles list
# invoices    quality=standard, schema=invoice, format=json
# receipts    quality=fast,     schema=receipt, format=json
# papers      quality=high,     chunk=true, max_tokens=500
# contracts   quality=high,     schema=contract
# bulk-rag    quality=standard, format=llm, chunk=true

pdfmux profiles show invoices
pdfmux profiles save my-default --quality high --format llm --chunk
pdfmux profiles delete my-default

# use a profile when converting
pdfmux convert file.pdf --profile invoices

Python API

文本提取
import pdfmux

text = pdfmux.extract_text("report.pdf")                    # -> str (markdown)
text = pdfmux.extract_text("report.pdf", quality="fast")    # PyMuPDF only, instant
text = pdfmux.extract_text("report.pdf", quality="high")    # LLM-assisted
结构化提取
data = pdfmux.extract_json("report.pdf")
# data["page_count"]   -> 12
# data["confidence"]   -> 0.91
# data["ocr_pages"]    -> [2, 5, 8]
# data["pages"][0]["key_values"]  -> [{"key": "Date", "value": "2026-02-28"}]
# data["pages"][0]["tables"]      -> [{"headers": [...], "rows": [...]}]
RAG 分块
chunks = pdfmux.chunk("report.pdf", max_tokens=500)
for c in chunks:
    print(f"{c['title']}: {c['tokens']} tokens (pages {c['page_start']}-{c['page_end']})")
Schema 引导的提取
data = pdfmux.extract_json("invoice.pdf", schema="invoice")
# Uses built-in invoice preset: extracts date, vendor, line items, totals
# Also accepts a path to a custom JSON Schema file
流式处理(有界内存)
from pdfmux.extractors import get_extractor

ext = get_extractor("fast")
for page in ext.extract("large-500-pages.pdf"):  # Iterator[PageResult]
    process(page.text)  # constant memory, even on 500-page PDFs
类型和错误
from pdfmux import (
    # Enums
    Quality,              # FAST, STANDARD, HIGH
    OutputFormat,         # MARKDOWN, JSON, CSV, LLM
    PageQuality,          # GOOD, BAD, EMPTY

    # Data objects (frozen dataclasses)
    PageResult,           # page: text, page_num, confidence, quality, extractor
    DocumentResult,       # document: pages, source, confidence, extractor_used
    Chunk,                # chunk: title, text, page_start, page_end, tokens

    # Errors
    PdfmuxError,          # base -- catch this for all pdfmux errors
    FileError,            # file not found, unreadable, not a PDF
    ExtractionError,      # extraction failed
    ExtractorNotAvailable,# requested backend not installed
    FormatError,          # invalid output format
    AuditError,           # audit could not complete
)

框架集成

LangChain
pip install langchain-pdfmux
from langchain_pdfmux import PDFMuxLoader

loader = PDFMuxLoader("report.pdf", quality="standard")
docs = loader.load()  # -> list[Document] with confidence metadata
LlamaIndex
pip install llama-index-readers-pdfmux
from llama_index.readers.pdfmux import PDFMuxReader

reader = PDFMuxReader(quality="standard")
docs = reader.load_data("report.pdf")  # -> list[Document]
MCP 服务(AI Agent)

已收录于 mcpservers.org。一行即可完成设置:

{
  "mcpServers": {
    "pdfmux": {
      "command": "npx",
      "args": ["-y", "pdfmux-mcp"]
    }
  }
}

也可通过 Claude Code 设置:

claude mcp add pdfmux -- npx -y pdfmux-mcp

提供的工具:convert_pdf、analyze_pdf、extract_structured、 extract_streaming、get_pdf_metadata、batch_convert。

BYOK LLM 配置

pdfmux 只需 5 行 YAML 即可支持任意 LLM。使用你自己的密钥——除非你进行配置,否则任何数据都不会离开你的设备。

# ~/.pdfmux/llm.yaml
provider: claude          # gemini | claude | openai | ollama | any OpenAI-compatible
model: claude-sonnet-4-20250514
api_key: ${ANTHROPIC_API_KEY}
base_url: https://api.anthropic.com  # optional, for custom endpoints
max_cost_per_page: 0.02   # budget cap

支持的提供商:

提供商模型本地?费用
Gemini2.5 Flash、2.5 Pro否约 $0.01/页
Gemma 327B IT、12B IT(非常适合阿拉伯语)否(通过 Gemini 密钥)约 $0.0002/页
ClaudeSonnet、Opus否约 $0.015/页
GPT-4oGPT-4o、GPT-4o-mini否约 $0.01/页
Mistralmistral-ocr-latest否$0.002/页
Ollama任意本地模型是免费
自定义任意兼容 OpenAI 的 API可配置不等

每个提供商的 extract_page() 都由 @with_retry(max_attempts=3, backoff_base=2.0) 包装,会遵循 429 响应中的 Retry-After 标头,并跳过认证失败后的重试,确保密钥无效时能快速失败。

阿拉伯语和 RTL 支持

pdfmux 原生支持阿拉伯语、波斯语、乌尔都语和希伯来语。 默认情况下,系统会对每个 PDF 执行 RTL 检测,并对 PyMuPDF 提取的页面应用 Unicode 双向算法,确保以从左到右顺序存储的字形按正确的阅读顺序显示。

# Default install — already includes python-bidi for RTL reordering
pip install pdfmux

# Recommended for Arabic-heavy docs — adds Gemma vision OCR
# (Gemma speaks the OpenAI protocol, so it needs the openai SDK)
pip install "pdfmux[llm-openai]"

# One credential covers Gemma + Gemini (same Google endpoint)
export GEMINI_API_KEY=...

自动执行的操作:

  • pdfmux convert 会检测阿拉伯语内容,并将阿拉伯字符占比 >5% 的页面交由支持阿拉伯语的提取器链处理。
  • PyMuPDF、RapidOCR 和 Docling 的输出会经过 Bidi 算法后处理——Markdown 标题(#)和管道符表格行会保留结构,仅调整内部文本的顺序。
  • 只要任意页面包含阿拉伯文字,DocumentResult.has_arabic 就会设为 True。

需要选择启用的功能:

  • 视觉 LLM 提取。设置 --llm-provider gemma(或任意视觉提供商),即可将阿拉伯语页面交由 Gemma 而非 PyMuPDF 处理。
  • 激进规范化(移除 Tatweel、统一 Alef/Yeh、去除 Tashkeel)——如果你需要用于搜索或嵌入的规范化输出,请对提取的字符串调用 pdfmux.arabic.normalize_arabic(text)。
from pdfmux.arabic import (
    is_arabic_text,
    is_rtl_dominant,
    fix_bidi_order,
    normalize_arabic,
)

text = "مرحبا بالعالم"
assert is_arabic_text(text)
assert is_rtl_dominant(text)

# Fix glyph order from PyMuPDF / OCR engines
visual = fix_bidi_order(text)

# Canonicalize for indexing — strip Tatweel, unify Alef variants, drop diacritics
indexable = normalize_arabic("أَحْمَدْ")  # → "احمد"

实证:真实客户批次

我们在 433 份真实客户文档上测试了 pdfmux——包括技术数据表和安全数据表,既有数字文档,也有扫描件,其中一些存在编码损坏。先用朴素方式运行(早期版本的 pdfmux CLI 在子进程中运行,使用 pypdf 作为回退方案,不进行 OCR),结果处理流程 悄无声息地丢弃了 16 份文档——其中 11 份连一条日志都没有。 我们自己的工具在它承诺解决的关键问题上失效了。

使用逐页审计和预算控制的 OCR 级联重建后:433 份全部处理成功,没有任何静默失败。 每个无法恢复的页面都会被标记,而非丢弃。

(eval/ 中还附带了一小组内部置信度校准数据——它用于防止置信度门控出现回归,并非竞争性基准;请参阅 eval/README.md。)

基准测试

在 opendataloader-bench 上——涵盖 200 份真实 PDF(财务申报文件、学术论文、法律合同、政府报告)——pdfmux 的总分为 0.903,在测评的 8 个引擎中排名第 2,仅次于 opendataloader-hybrid(0.909)。于 2026-07-16 重新运行(复现方法见下文)。

排名引擎总分阅读顺序表格(TEDS)许可证GPU
1opendataloader-hybrid0.9090.9350.928Apache-2.0否
2pdfmux0.9030.9200.911MIT否
3Docling0.8770.9000.887MIT可选
4marker0.8610.8900.808免费GPU
5mineru0.8310.8570.873免费GPU

完整的逐文档得分: 200 份 PDF 正面对比 · 方法说明:最佳 PDF 提取库:基准测试。

智能结果缓存

重新运行相同的提取任务可即时完成。pdfmux 会对每个输入 PDF 计算哈希值(SHA-256),并根据 (file_hash, quality, format, schema) 为结果建立键。缓存文件保存在 ~/.cache/pdfmux/results/ 下,30 天后过期,并会在达到 1 GB 时按 LRU 策略淘汰。

pdfmux convert big-report.pdf            # first run: 14.2s
pdfmux convert big-report.pdf            # cache hit: 0.05s
pdfmux convert big-report.pdf --no-cache # bypass cache (still writes back)
pdfmux convert big-report.pdf --clear-cache  # purge and re-run

缓存还可以加快切换 --profile、--schema 和 --format 的速度——每种组合都会单独建立键,因此对同一文档首次提取后,便可免费在 Markdown 和 JSON 之间切换。

置信度评分

每个结果都包含一个基于 4 项信号的置信度评分:

  • 95-100% —— 数字文本清晰,可完整提取
  • 80-95% —— 提取效果良好,部分页面存在少量 OCR 噪声
  • 50-80% —— 提取不完整,部分页面无法恢复
  • <50% —— 大量内容缺失,并附有警告

当置信度低于 80% 时,pdfmux 会准确告知出错原因以及修复方法:

Page 4: 32% confidence. 0 chars extracted from image-heavy page.
  -> Install pdfmux[ocr] for RapidOCR support on 6 image-heavy pages.

成本模式

模式行为典型成本
economy仅使用基于规则的后端。不调用大模型。$0/页
balanced仅对基于规则的提取失败的页面调用大模型。平均约 $0.002/页
premium对每一页都调用大模型,以获得最高质量。$0.01/页

设置硬性预算上限:--budget 0.50 会在单个文档的支出达到 $0.50 时停止调用大模型。

为什么选择 pdfmux?

pdfmux 不只是另一个 PDF 提取器。它是一个编排层,会为每页选择合适的提取器、验证结果,并在失败时重试。

工具擅长处理局限
PyMuPDF快速提取数字文本无法处理扫描件或图像布局
Docling表格(准确率 97.9%)处理非表格文档时速度较慢
Marker学术论文的神经网络提取需要 GPU 才能获得较快速度;用于数字 PDF 时大材小用
Mistral OCR表格(TEDS 96.6%),$0.002/页仅提供云端 API
Unstructured企业平台设置复杂,并提供付费层级
LlamaParse原生云端需要 API 密钥,无法本地运行
Reducto高准确率$0.015/页,闭源
pdfmux编排以上所有工具按页路由、审计并重新提取

开源的 Reducto 替代方案:在其他地方每页收费 $0.015 的功能,使用 pdfmux 的基于规则的后端即可免费实现;或通过 BYOK 大模型回退方案,平均每页约 $0.002。

开发

git clone https://github.com/NameetP/pdfmux.git
cd pdfmux
python3.12 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

pytest              # 659 tests
ruff check src/ tests/
ruff format src/ tests/

贡献

  1. Fork 此代码库
  2. 创建分支(git checkout -b feature/your-feature)
  3. 为新功能编写测试
  4. 确保 pytest 和 ruff check 均通过
  5. 提交 PR

许可证

本代码库中的 pdfmux 库和 MCP 服务采用 MIT 许可证——可免费用于任何用途,且每个发布版本均继续采用 MIT 许可证。

按置信度预算的 decision-trace 方法(持久化的逐页决策跟踪,保留被拒绝的候选项,并采用单调修复保护机制)正在申请专利(美国临时专利申请号 64/106,302),并根据单独的商业许可证保留给 pdfmux Cloud/Pro 使用——它不属于 MIT 许可授权范围。请参阅 LICENSING.md 和 NOTICE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。