pdfmux — PDF extraction that actually works について
pdfmux は、ページごとに抽出結果を検証し、読み取れないページを黙って欠落させず明示する PDF 抽出 MCP サーバーです。RAG パイプラインや、信頼できる PDF テキストを必要とするAIエージェント向けで、verify コマンドによって他の抽出ツールの出力も検証できます。
主な機能
- 01ページごとの検証と失敗ページの自動再抽出
- 02ページ内容に応じた抽出バックエンドの選択
- 03RAG 向けチャンク分割と Markdown・JSON 出力
- 04他エンジンの出力における欠落ページの検出
- 05スキャン PDF の OCR と任意の LLM フォールバック
活用シーン
- 01RAG インデックス用に PDF テキストを準備し欠落ページを確認
- 02AIエージェントがセッション内で PDF を読み取り変換
- 03サードパーティ製PDF抽出ツールの出力完全性を一括確認
MCP 対応
pdfmux serve により stdio または HTTP モードの MCP サーバーとして動作します。PDF のメタデータ取得、変換、分析、一括変換、構造化抽出のツールと、他エンジンの出力を検証する verify_extraction ツールを MCP クライアントに提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx pdfmuxGEMINI_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 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
pdfmux
読み取れなかったページを削除せずに報告する、自己修復型 PDF 抽出ツールです。さらに、あらゆる抽出ツールの出力で、見落とされたページがないかを検証できます。 RAG パイプライン向けのオープンソース LlamaParse 代替ツールで、Claude Desktop 用 MCP サーバー、LangChain および LlamaIndex ローダーも提供します。
pdfmux は PDF を抽出して結果を自己検証します。さらに、あらゆる抽出ツールの出力を検証し、見落とされたページを知らせます。無料、MIT ライセンス。特許出願中の手法です。
pip install pdfmux。
1 つのツールで 2 つの役割を実現:
- 自己修復型の抽出。 出力を自己監査する唯一の PDF 抽出ツールです。空白ページ、列の乱れ、表の崩れを検出し、より強力なバックエンドで再抽出します。それでも読み取れないページは、黙って削除せずに報告します。これにより、LLM には見えないゴミデータではなく、クリーンなデータが渡されます。組み込みの 7 つの抽出バックエンドから各ページに最適なものを選択し、BYOK の LLM フォールバック(Gemini / Claude / GPT-4o / Ollama)も利用できます。CLI は 1 つ、API も 1 つ。設定は不要です。
- あらゆる出力を検証 — v1.8.1 の新機能。
pdfmux verifyは、元の PDF と照合して、あらゆる抽出エンジンの出力を監査します。Reducto、Mistral OCR、LlamaParse、Docling、自社製パーサーなどの出力から、見落とされたページを知らせます。無料、MIT ライセンスで、特許上の問題はありません。
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 に対応できます。実際の 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
一括処理には subprocess.run(['pdfmux', ...]) のループではなく、batch_extract() を使用してください。同じパイプラインを使いながら、ファイルごとのプロセス起動を避け、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
pdfmux を独自の pypdf/pdfplumber フォールバックでラップしないでください。 pdfmux はページごとに PyMuPDF → RapidOCR → vision LLM の順で処理を振り分けます。PyMuPDF は pypdf が拒否する不正な PDF("Stream has ended unexpectedly")にも対応できるため、後段に pypdf のフォールバックを追加すると、復旧可能な PDF がエラーになってしまいます。ルーターを信頼し、結果の信頼度スコアを確認してください。
あらゆる出力を検証
pdfmux verify は、元の PDF と照合してあらゆる抽出エンジンの出力を監査し、見落とされたページを知らせます。pdfmux 自身の抽出結果だけが対象ではありません。Reducto、Mistral OCR、LlamaParse、Docling、自社製パーサーなどの出力を指定すると、pdfmux 独自の監査処理で元のテキストを再導出して抽出結果と照合し、すべてのページを評価します。
検出する問題: 元の PDF には実際のテキストがあるのに、エンジンが何も返さず、それでも処理成功と報告するページです。この「サイレントドロップ」は、ログにエラーを一切残さず 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 ページが見落とされました」**という 1 行で表示します。これは、自社の PDF 100 件を対象に実行し、既存のパイプラインに潜む見えない失敗を見つけるためのレポートです。
あらゆるエンジンの出力に対応
--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 サーバーを参照)。これにより、エージェントは抽出と同じセッション内でエンジンの出力を検証できます。
無料、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 と競合しません。ページごとに最適なものを選択します。
- エージェントによるマルチパス処理。 抽出、信頼度の監査、失敗したページをより強力なバックエンドで再抽出します。品質の低いページは自動的に再試行されます。
- セグメントレベルの検出。 ルーティングの前に、各ページをコンテンツの種類(テキスト、表、画像、数式、ヘッダー)で分類します。
- 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 |
| スキーマ抽出 | 5 つの組み込みプリセット(請求書、レシート、契約書、履歴書、論文) | pdfmux convert file.pdf --schema invoice |
| プロファイル | 設定を保存して再利用できます。請求書/レシート/論文/契約書/一括 RAG 用の組み込みプロファイルもあります | pdfmux convert file.pdf --profile invoices |
| BYOK LLM | Gemini、Gemma 3、Claude、GPT-4o、Ollama、Mistral、OpenAI 互換 API | pdfmux convert file.pdf --llm-provider claude |
| コスト見積もり | 実行前にコストを予測します | pdfmux estimate file.pdf --llm-provider gemini |
| ストリーミング出力 | 長い文書向けに、ページごとに NDJSON イベントを出力します | pdfmux stream file.pdf |
| スマートキャッシュ | ハッシュキー方式の結果キャッシュ、TTL は 30 日、LRU は 1 GB | pdfmux convert file.pdf(自動)、バイパスするには --no-cache |
| 監視モード | フォルダーに追加された PDF を自動変換します | pdfmux watch ./inbox/ |
| 差分 | 2 つの抽出結果を比較します | pdfmux diff a.pdf b.pdf |
| ベンチマーク | インストール済みのすべての抽出器を正解データと照合して評価します | pdfmux benchmark |
| 診断 | インストール済みのバックエンド、未対応の範囲、推奨事項を表示します | pdfmux doctor |
| MCP サーバー | AI エージェントが stdio または HTTP 経由で PDF を読み取ります | pdfmux 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
AI エージェント連携用の MCP サーバーを起動します。
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']})")
スキーマに基づく抽出
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 エージェント)
mcpservers.org に掲載されています。1 行でセットアップできます。
{
"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
対応プロバイダー:
| プロバイダー | モデル | ローカル? | コスト |
|---|---|---|---|
| Gemini | 2.5 Flash、2.5 Pro | いいえ | 約 $0.01/ページ |
| Gemma 3 | 27B IT、12B IT(アラビア語に最適) | いいえ(Gemini キー経由) | 約 $0.0002/ページ |
| Claude | Sonnet、Opus | いいえ | 約 $0.015/ページ |
| GPT-4o | GPT-4o、GPT-4o-mini | いいえ | 約 $0.01/ページ |
| Mistral | mistral-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(または任意のビジョンプロバイダー)を設定すると、アラビア語のページを PyMuPDF ではなく Gemma に振り分けます。 - 積極的な正規化(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 件中 433 件を処理し、警告なしの失敗はゼロでした。**復旧できないページにはすべてフラグが付けられ、破棄されることはありません。
(小規模な内部信頼度キャリブレーション用セットも eval/ に含まれています。これは信頼度ゲートのリグレッションを防ぐためのもので、競合ベンチマークではありません。詳細は eval/README.md をご覧ください。)
ベンチマーク
opendataloader-bench — 実世界の PDF 200 件(財務報告書、学術論文、法的契約書、政府報告書)で、pdfmux は総合 0.903 を記録し、測定対象 8 エンジン中 2 位でした。1 位は opendataloader-hybrid(0.909)です。2026-07-16 に再実行しました(再現手順は以下を参照)。
| 順位 | エンジン | 総合 | 読み順 | 表(TEDS) | ライセンス | GPU |
|---|---|---|---|---|---|---|
| 1 | opendataloader-hybrid | 0.909 | 0.935 | 0.928 | Apache-2.0 | いいえ |
| 2 | pdfmux | 0.903 | 0.920 | 0.911 | MIT | いいえ |
| 3 | Docling | 0.877 | 0.900 | 0.887 | MIT | 任意 |
| 4 | marker | 0.861 | 0.890 | 0.808 | 無料 | GPU |
| 5 | mineru | 0.831 | 0.857 | 0.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 | ルールベースのバックエンドのみを使用します。LLM 呼び出しはありません。 | $0/ページ |
| balanced | ルールベースの抽出に失敗したページに限り、LLM を使用します。 | 平均 ~$0.002/ページ |
| premium | 最高品質を得るため、すべてのページで LLM を使用します。 | ~$0.01/ページ |
上限予算を設定できます。--budget 0.50 を指定すると、ドキュメントごとの支出が $0.50 に達した時点で LLM の呼び出しを停止します。
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 LLM フォールバックを使っても平均 ~$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/
コントリビューション
- リポジトリをフォークします
- ブランチを作成します(
git checkout -b feature/your-feature) - 新機能のテストを作成します
pytestとruff checkが成功することを確認します- PR を作成します
ライセンス
このリポジトリの pdfmux ライブラリと MCP サーバーは MIT ライセンスのもとで提供されており、あらゆる用途で無料で使用できます。また、リリースされたすべてのバージョンは MIT ライセンスのままです。
信頼度に基づいて予算を管理する decision-trace メソッド(却下した候補を保持する永続化されたページごとの意思決定トレースと、単調性を保つ修復ガード)は特許出願中(米国仮出願番号 64/106,302)であり、別途の商用ライセンスのもと、pdfmux Cloud/Pro 専用として留保されています。これは MIT ライセンスの許諾対象には含まれません。LICENSING.md と NOTICE をご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。