社内の PDF を RAG(検索で見つけた文書を生成 AI に渡す仕組み)に入れる前に、PDF を文字にする変換の道具を選ぶ必要があります。本文は読めても、表の行見出しと値がずれたり、漢字が見た目の同じ別の文字に変わったりすると、検索や回答が不正確になります。AIコンパスを運営する ALLFORCES の編集部は、日本語の PDF を変換する無料の道具8つ(10設定)を、正解つきの PDF で測りました。
同じ PDF を変換すると、pypdf は「文」を部首の文字「⽂」に変え、pdfminer.six は行見出しと値を離して並べ、Docling は行見出しを右端の列に配置した
- 例1:本文の文(正解)
- COEIROINK と VOICEVOX の読みが全文で一致しています。
- pypdf の出力(Chromium の PDF)
- COEIROINK と VOICEVOX の読みが全⽂で⼀致しています。
- PyMuPDF の出力
- COEIROINK と VOICEVOX の読みが全文で一致しています。(変更なし)
- 例2:表の見出し行(正解)
- ソフト 日付・時刻 (16文) 難読語・地名 (20文)
- pypdf の出力
- ソフト ⽇付‧時刻 (16⽂) 難読語‧地名 (20⽂)
- 例3:表のデータ行の最初の 2 行(正解)
- VOICEVOX 16 18
AivisSpeech 15 18 - pypdf の出力
- VOICEVOX 16 18
AivisSpeech 15 18 - pdfminer.six の出力(行ごとに改行して示した。実物は各行の間に空行が入る。表の直前の「実測表」の行は省いた)
- ソフト
VOICEVOX
AivisSpeech
COEIROINK
Style-Bert-VITS2
pyopenjtalk-plus
⽇付‧時刻 (16⽂)
難読語‧地名 (20⽂)
16
15
16
16
16
18
18
18
19
19 - Docling の出力(Markdown の表のデータ行の最初の 2 行)
- | 16 | 18 | VOICEVOX |
| 15 | 18 | AivisSpeech |
測った道具は、MarkItDown、Docling、PyMuPDF、PyMuPDF4LLM、pypdf、pdfminer.six、pdfplumber、unstructured です。引数やモードを変えた物は別の「設定」と数えます。PyMuPDF4LLM は layout あり・なし(レイアウト解析機能の有無)、unstructured は fast(PDF の文字データを読む)と hi_res(レイアウト認識と OCR を使う)の2設定ずつで、合わせて10設定です。
PDF の元データ(以下「原稿」)は44本で、AIコンパスの公開済みの記事(40本)と、青空文庫の作品(縦書きの4本)から作りました。同じ原稿を Chromium の印刷・Typst・ReportLab・LibreOffice の4つの方法(以下「作り方」)で PDF にし、フォントを変えた PDF も追加して、合計188本の PDF を変換しました。測ったのは、文字の層がある PDF(文字を選択してコピーできる PDF)だけです。Word や Excel から書き出した PDF と、スキャンした PDF は測っていません(OCR の実測表)。
測り方は3段です。段1は、変換した出力を正解の原稿と照合して採点しました(本文・表・読む順序など)。段2は、変換した文字を意味検索(ruri-v3-310m)とキーワード検索(BM25)で検索し(条件はRAG の実測表と同じ)、答えを含む区切り(チャンク)が上位5件に入るかを見ました。段3は、変換した文書を LLM(Qwen3 14B)に1本丸ごと渡して問いに答えさせ、正答率を測りました。問いは201問(本文132〔横書き120・縦書き12〕・表69)です。
横書きの本文は、どの設定でも LLM が正しく答えられました。表は設定で分かれました。 2段組みと縦書きでは、本文でも設定の差が出ます。結論は4つです。
- 本文:変換した文書を LLM に読ませた時の、横書きの本文の問い(120問)の正答率は、10設定とも94.8〜97.4%で、最良と差があるとは言えませんでした(上限は96.7%)。縦書きの3設定は正答率が0〜16.7%、2段組みでは本文の再現が67.0〜81.7%に下がる設定がありました。
- 表:表の問い(69問)の正答率は、pdfplumber・PyMuPDF4LLM(layout なし)・pypdf・PyMuPDF・PyMuPDF4LLM(layout あり)・MarkItDown の6設定が91.5〜99.3%で、最良の集まり(最良と差があるとは言えない設定)に入りました。Docling は93.8%、unstructured の fast は79.2%、pdfminer.six は70.1%、unstructured の hi_res は60.9%で、最良との差が確認できました。Docling が MarkItDown(91.5%)より高いのに入らなかったのは、最良の pdfplumber と原稿ごとに比べると、Docling は9本で下回り、上回った原稿は0本だったためです(MarkItDown は6本対0本で、差があるとは言えませんでした)。行の並びが0.07以下の3設定(pdfminer.six・unstructured の fast・hi_res)は、最良の集まりに入りませんでした。
- Docling の列の入れ替わり:罫線のある表の PDF 24本(6つの表 × 作り方4種)のうち13本で、行見出しの列を右端の列に配置しました。その13本の表の問いの正答率は82.1%、残りの11本は100.0%でした。
- 部首の文字:Chromium の印刷で Noto Sans CJK JP を使った PDF では、7設定で漢字が部首の文字に変わりました(1,000字あたり約33字)。NFKC(互換文字をそろえる処理)で8割が戻り、「・」と「/」は戻りません。NFKC を掛ける前後で、部首が出る7設定の検索の当たりの平均の差は0.0〜0.6ポイント(120問・69問で1問未満)で、設定ごとの差は最大2.9ポイントでした(検定はしていません)。
用語は次の意味で使います。
- 最良の集まり:最良の設定と、補正後の p が0.05以上で差があるとは言えない設定。p は小さいほど、差が偶然では説明しにくいことを示す。
- 上限:変換せず、正解の原稿そのものを LLM に渡した時の値。
- 正答率:検索で絞り込まず、変換した文書1本を丸ごと LLM に渡して測った値。
- 当たり:上位5件に正解を含む区切りがある問いの割合(hit@5)。
- 行の並び:正解の各行の行見出しと値が、出力の中で行の順に並んでいる割合(0〜1)。
用途別の候補
根拠は、実測表以降の各節にあります。ライセンスは配布元の表示です。
本文が中心の PDF(議事録・報告書のような文書を想定)
- 候補:PyMuPDF(AGPL-3.0 か商用)か、pypdf(BSD-3-Clause)
- 根拠:横書きの本文の問いの正答率は PyMuPDF が97.4%、pypdf が96.5%で、10設定すべてが最良の集まり。段1の本文の再現(正解の文が出力にある割合)は PyMuPDF が最良で、1ページあたり0.05秒と最も速い
- 向かない場面:Markdown の見出しや表は出力しない。pypdf は、ブラウザーの印刷(Chromium・Noto Sans CJK JP)で作った PDF で漢字が部首の文字になるため、NFKC を掛ける。PyMuPDF は AGPL-3.0 のため、自社の製品に組み込む時は条件の確認か商用ライセンスが必要
数値の表がある PDF(実測表・料金表のような文書を想定)
- 候補:pdfplumber(MIT)。PyMuPDF4LLM の layout なし(AGPL-3.0 か商用)も候補
- 根拠:表の問いの正答率が99.3%で最も高い値(最良の集まりは6設定で、その中の順位は付けられない)。罫線のある表と第1列が折り返す表を、Markdown の表として出力する
- 向かない場面:罫線の無い表と結合セルのある表は、Markdown の表として出力しない。ページをまたぐ表は分割される。PyMuPDF4LLM の layout なしは、数値と見出しの対応付けが低く、表の直前の見出しを表の見出し行に取り込む PDF があった。Markdown の表が不要なら、pypdf や PyMuPDF(表の問いの正答率98.6%)も候補
縦書きの PDF
- 候補:pypdf か PyMuPDF
- 根拠:縦書きの本文の再現が99%を超えたのは、この2設定だけ(原稿4本)
- 向かない場面:pdfplumber・MarkItDown・PyMuPDF4LLM の layout ありは、本文の再現が33%以下だった(縦書きは4本の記述で、検定していない)
ヘッダー・フッター・ページ番号を落としたい
- 候補:Docling(既定で落とす)、PyMuPDF4LLM(
header=False, footer=Falseを渡す)、unstructured の fast(要素の種類 Header・Footer を除く) - 向かない場面:Docling は表の列が入れ替わることがある(後述)。unstructured の hi_res は、フッターの文を Footer ではなく本文の要素として出力する PDF が多く、要素を除いても残った
自社の製品に組み込む(ライセンス)
- MIT・BSD・Apache-2.0 の設定:pypdf、pdfminer.six、pdfplumber、MarkItDown、Docling(モデルの重みは別の表示)、unstructured
- AGPL-3.0 か商用:PyMuPDF と PyMuPDF4LLM。PyMuPDF 2.1 の配布物のライセンス文は、COPYING の1行「Dual Licensed - GNU AFFERO GPL 3.0 or Artifex Commercial License」(二重ライセンス。AGPL か Artifex の商用ライセンス)だけで、layout のフォルダに別のライセンス文や非商用の語を含むファイルは無かった。PyMuPDF4LLM 2.1 は PyMuPDF 2.1 に依存し、PyMuPDF4LLM 自身と layout のパッケージは、メタデータのライセンス欄が空だった(ライセンス文は PyMuPDF の COPYING で確認した)。layout 機能の学習済みモデル(ONNX の重み)には、単独のライセンス表示を確認できなかった
実測表:表の問いの正答率は、6設定が最良の集まりに入り、Docling・unstructured・pdfminer.six の4設定は最良との差が確認できた
実測表:変換した文書を読ませた LLM の表の問いの正答率は、6 設定が91.5〜99.3%で最良の集まり(最良と差があるとは言えない設定)に入り、Docling(93.8%)など 4 設定は最良との差が確認できた。横書きの本文の問いは 10 設定すべてが最良の集まり
| 設定 | 表の問い (69問) 正答率 (%) | 本文 (横書き 120問) 正答率 (%) |
|---|---|---|
| pdfplumber | 99.3 ○ | 95.4 ○ |
| PyMuPDF4LLM(layout なし) | 99.3 ○ | 96.8 ○ |
| pypdf | 98.6 ○ | 96.5 ○ |
| PyMuPDF | 98.6 ○ | 97.4 ○ |
| PyMuPDF4LLM(layout あり) | 96.0 ○ | 96.0 ○ |
| Docling | 93.8 | 95.3 ○ |
| MarkItDown | 91.5 ○ | 94.8 ○ |
| unstructured(fast) | 79.2 | 95.8 ○ |
| pdfminer.six | 70.1 | 95.8 ○ |
| unstructured(hi_res) | 60.9 | 95.6 ○ |
| 上限(正解の原稿そのもの) | 100.0 | 96.7 |
横書きの本文の問いは、10設定すべてが最良の集まりでした。最良の PyMuPDF(97.4%)と最も低い MarkItDown(94.8%)の差は2.6ポイントで、差があるとは言えません。最良との対の比較で補正後の p が最も小さかった Docling は、7本対0本(補正後 p=0.141)、MarkItDown は7本対1本(p=0.563)です。表の問いで最良の集まりに入った6設定の中では、順位を付けられません。
表の問いの正答率は設定で60.9〜99.3%に分かれ、本文の問いは94.8〜97.4%に収まった
- 本文の問い(横書き。10 設定とも最良の集まり)
- 表の問い(最良の集まり)
- 表の問い(最良と差があった)
表の問いは、罫線のある表とページをまたぐ表で pdfminer.six と unstructured が低く、MarkItDown もページをまたぐ表で低かった
表の問いの正答率は、見出し行を繰り返すページまたぎの表(原稿 2 本)で、MarkItDown・pdfminer.six・unstructured の 4 設定が41.7〜54.2%、ほかの 6 設定は 100.0% だった
| 設定 | 罫線あり (72) | 罫線なし (60) | 結合セル (60) | 第1列が 折り返す表 (36) | ページまたぎ (見出し行を 繰り返す) (24) | ページまたぎ (繰り返さない) (24) |
|---|---|---|---|---|---|---|
| pdfplumber | 100.0 | 100.0 | 98.3 | 97.2 | 100.0 | 100.0 |
| PyMuPDF4LLM(layout なし) | 100.0 | 100.0 | 100.0 | 94.4 | 100.0 | 100.0 |
| pypdf | 100.0 | 100.0 | 98.3 | 91.7 | 100.0 | 100.0 |
| PyMuPDF | 100.0 | 100.0 | 96.7 | 94.4 | 100.0 | 100.0 |
| PyMuPDF4LLM(layout あり) | 100.0 | 98.3 | 98.3 | 80.6 | 100.0 | 91.7 |
| Docling | 90.3 | 91.7 | 96.7 | 91.7 | 100.0 | 100.0 |
| MarkItDown | 100.0 | 100.0 | 98.3 | 77.8 | 52.1 | 87.5 |
| unstructured(fast) | 81.9 | 93.3 | 83.3 | 73.6 | 54.2 | 58.3 |
| pdfminer.six | 59.0 | 93.3 | 70.0 | 58.3 | 50.0 | 83.3 |
| unstructured(hi_res) | 59.7 | 58.3 | 76.7 | 63.9 | 41.7 | 45.8 |
| 上限(正解の原稿そのもの) | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 | 100.0 |
条件ごとの原稿は2〜6本と少なく、検定はしていません。
- 罫線のある表:pdfminer.six が59.0%、unstructured の hi_res が59.7%と低い。Docling は90.3%
- ページをまたぐ表:原稿は4本。見出し行を繰り返す2本では、MarkItDown・pdfminer.six・unstructured の4設定が41.7〜54.2%、ほかの6設定は100.0%。見出し行を繰り返す2本と繰り返さない2本は別の表なので、差を見出し行の繰り返しのせいとは言えない
- 第1列が折り返す表:MarkItDown が77.8%で、数値と見出しの対応がほぼ失われた
表の変換:行の並びが0.07以下の3設定は、表の問いの最良の集まりに入らなかった
表を Markdown の表として出力しない pypdf と PyMuPDF は表の問いの最良の集まりに入り、行の並びが0.07以下の 3 設定(pdfminer.six・unstructured の fast・hi_res)は入らなかった
| 設定 | 表として 出力した割合(%) | TEDS | 数値の 対応付け | 行の並び | (参考)LLM の 表の問いの 正答率(%) |
|---|---|---|---|---|---|
| pdfplumber | 47.8 | 0.992 | 0.899 | 0.885 | 99.3 |
| PyMuPDF4LLM(layout なし) | 47.8 | 0.925 | 0.263 | 0.976 | 99.3 |
| pypdf | 0.0 | — | — | 0.893 | 98.6 |
| PyMuPDF | 0.0 | — | — | 1.000 | 98.6 |
| PyMuPDF4LLM(layout あり) | 91.3 | 0.943 | 0.690 | 0.817 | 96.0 |
| Docling | 89.1 | 0.838 | 0.538 | 0.813 | 93.8 |
| MarkItDown | 82.6 | 0.919 | 0.726 | 0.658 | 91.5 |
| unstructured(fast) | 0.0 | — | — | 0.000 | 79.2 |
| pdfminer.six | 0.0 | — | — | 0.070 | 70.1 |
| unstructured(hi_res) | 100.0 | 0.727 | 0.119 | 0.016 | 60.9 |
Markdown の表を出力しない pypdf と PyMuPDF は、表の問いの正答率が98.6%で、最良の集まりに入りました。この2設定の行の並びは、PyMuPDF が1.00、pypdf が0.89です。行の並びが0.07以下の3設定(pdfminer.six・unstructured の fast・hi_res)は、最良の集まりに入りませんでした。pdfminer.six は、冒頭の例のように行見出しを先に並べ、値を後に並べました。
Markdown の表を出力する設定には、次の特徴がありました。
- pdfplumber と PyMuPDF4LLM(layout なし):罫線のある表と第1列が折り返す表は表として出力し、罫線の無い表と結合セルのある表は出力しない。ページをまたぐ表は、半分で表として出力する
- MarkItDown:ページをまたぐ表以外は表として出力する。第1列が折り返す表では数値と見出しの対応がほぼ失われ、ページをまたぐ表は16本とも表として出力しなかった
- unstructured の hi_res:表の中身を、PDF の文字データではなく OCR(tesseract)の結果から取る。表の構造と数値の対応は、表を出力する設定の中で最も低かった
Docling は、罫線のある表の PDF 24本のうち13本で、行見出しの列を右端の列に配置した
Docling は罫線のある表の PDF 24 本のうち 13 本で行見出しの列を右端の列に配置し、その 13 本の表の問いの正答率は82.1%、残りの 11 本は100.0%だった
- 正解の表(見出し行とデータ行 3 行)
- ソフト | 日付・時刻 (16文) | 難読語・地名 (20文)
VOICEVOX | 16 | 18
AivisSpeech | 15 | 18
COEIROINK | 16 | 18 - Docling の出力(Markdown の表。見出し行とデータ行 3 行)
- ソフト | 日付・時刻 (16文) | 難読語・地名 (20文)
16 | 18 | VOICEVOX
15 | 18 | AivisSpeech
16 | 18 | COEIROINK
列が入れ替わった13本の表の問い(39問)の正答率は82.1%、入れ替わらなかった11本(33問)は100.0%でした。
設定を変えても入れ替わりは残りました。罫線のある表の PDF 24本のうち、セルの突き合わせを止めた設定では12本、FAST(表の認識を速くしたモード)では19本です。
ただし、列の入れ替わりだけが原因とは言えません。正解の原稿の表で行見出しの列を機械的に右端に移した文書(見出し行はそのまま)では、表の問いの正答率は100.0%から97.1%に下がっただけで、下がった原稿は23本中2本でした(p=0.50)。
列が入れ替わった13本の問い39問を2回ずつ測った78件の答えのうち、誤答は14件で、PDF と問いの組では7組です(2回とも同じ誤答)。誤答した値は、正解と同じ行の別の列にあった組が1組、次の行にあった組が2組、離れた行にあった組が4組でした。13本は5つの表から作った PDF で、誤答7組のうち5組は1つの表の2問から出ています。因果までは言えません。
ページをまたぐ表を1つの表として出力できた設定は、各設定16本のうち1本ずつしかなかった
ページをまたぐ表を、各設定 16 本の PDF のうち 1 つの表として出力できたのは Docling と PyMuPDF4LLM(layout あり)の各 1 本だけで、ほかは 2 つ以上に分割されるか、表を出力しなかった
- 1 つの表として出力した
- 2 つ以上に分割された
- 表を出力しなかった
表の原稿は、2列・61〜71行の縦長で、ページの先頭から始まります。1つの表として出力したのは、Docling が1本、PyMuPDF4LLM の layout ありが1本だけでした。見出し行を繰り返さない PDF 8本のうち、分割された表の2つ目に列見出しが付いた出力は、どの設定も0本でした。
漢字が部首の文字に変わる PDF がある
Chromium の印刷で Noto Sans CJK JP を使った PDF では、7 設定で漢字が部首の文字に変わった(1,000 字あたり32〜33字)。BIZ UDPGothic・Typst・ReportLab・LibreOffice の PDF では 0 字だった
| 設定 | Chromium (Noto Sans CJK JP) | Chromium (BIZ UDPGothic) | Chromium (IPAex ゴシック) | Typst | ReportLab | LibreOffice |
|---|---|---|---|---|---|---|
| pypdf | 33.0 | 0.0 | 33.0 | 0.0 | 0.0 | 0.0 |
| pdfminer.six | 33.0 | 0.0 | 33.0 | 0.0 | 0.0 | 0.0 |
| pdfplumber | 32.1 | 0.0 | 32.7 | 0.0 | 0.0 | 0.0 |
| PyMuPDF | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| PyMuPDF4LLM(layout あり) | 33.0 | 0.0 | 33.1 | 0.0 | 0.0 | 0.0 |
| PyMuPDF4LLM(layout なし) | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| MarkItDown | 33.0 | 0.0 | 33.0 | 0.0 | 0.0 | 0.0 |
| Docling | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| unstructured(fast) | 33.0 | 0.0 | 33.0 | 0.0 | 0.0 | 0.0 |
| unstructured(hi_res) | 32.9 | 0.0 | 33.0 | 0.0 | 0.0 | 0.0 |
Chromium の印刷で Noto Sans CJK JP を使った PDF では、pypdf・pdfminer.six・pdfplumber・PyMuPDF4LLM(layout あり)・MarkItDown・unstructured の7設定で、「文」が「⽂」(康熙部首)のような、見た目の同じ別の文字として出力されました。BIZ UDPGothic を使った PDF では0字、IPAex ゴシックを使った PDF では Noto Sans CJK JP と同じく約33字でした。Typst・ReportLab・LibreOffice の PDF では0字です。
PDF は、見た目に使う文字と、検索やコピーに使う正しい文字を別に持つことがあります。確認できたことは3点です。
- Chromium の PDF は、各文字列に元の文字列(
/ActualText)を付けている(確認した1本で245か所)。同じ PDF の文字の対応表(ToUnicode)は、字形に対して部首を返す - Noto Sans CJK JP は、漢字と康熙部首の216対のうち214対で同じ字形を割り当てている。BIZ UDPGothic の文字表には、康熙部首の字が無い(216対のうち両方がある対は0)
- PyMuPDF の
get_textは既定で/ActualTextを使うので0字で、TEXT_IGNORE_ACTUALTEXTを付けると233字が部首になる。PyMuPDF4LLM の layout ありは、この指定を含む設定で文字を取る
pypdf・pdfminer.six・pdfplumber が /ActualText を読まないことは、コードで確認しておらず、出力が部首になることから推定しました。Docling は出力に部首が0字でしたが、呼び出しのコードは確認していません。
置き換わった文字のうち NFKC で戻ったのは、pypdf では4,902字中4,008字(81.8%)で、「・」「/」を中心に894字は戻らなかった
- NFKC で戻る
- NFKC で戻らない
NFKC は互換文字を通常の文字にそろえる処理で、部首の文字はこれで戻ります。一方、U+30FB(・)が U+2027(‧)に変わると戻りません。段1の数値の対応付けと、段2の正解の区切りの判定では、この違いで値が一致しません。段3の採点は同じ値として扱います。
NFKC を掛ける前後の検索の当たりの差は、設定ごとに最大2.9ポイントでした(検定はしていません)。Chromium の PDF で部首が出る7設定は、本文の問い(120問)で BM25 が平均0.6ポイント、ruri-v3-310m が0.6ポイント、表の問い(69問)で BM25 が0.6ポイント上がり、ruri-v3-310m は0.0ポイントで、いずれも1問未満の差です。部首の置き換えを同じ頻度で入れた正解の原稿でも、BM25 の本文の問いの当たりは93.3%で、置き換えなしの検索の上限94.2%との差は1問程度でした。
2段組みと縦書きは、設定で崩れ方が大きく違った
2 段組みでは pdfplumber(本文の再現67.0%)と MarkItDown(75.9%)が低く、縦書きでは pypdf と PyMuPDF だけが本文の再現99%を超え、pdfplumber・MarkItDown・PyMuPDF4LLM(layout あり)は33%以下だった
| 設定 | 2 段組み(原稿 5 本) | 縦書き(原稿 4 本) | ||||
|---|---|---|---|---|---|---|
| 本文の再現(%) | 読む順序(%) | LLM の正答率(%) | 本文の再現(%) | 字間の空白(1,000字あたり) | LLM の正答率(%)Chromium / LibreOffice | |
| Docling | 99.7 | 99.6 | 85.8 | 80.9 | 770 | 92 / 83 |
| PyMuPDF | 99.6 | 100.0 | 90.8 | 99.5 | 1 | 92 / 92 |
| pypdf | 99.5 | 100.0 | 91.7 | 99.6 | 1 | 92 / 83 |
| PyMuPDF4LLM(layout なし) | 99.4 | 99.9 | 89.2 | 76.7 | 2 | 83 / 75 |
| unstructured(hi_res) | 98.9 | 99.4 | 90.0 | 69.7 | 664 | 67 / 83 |
| PyMuPDF4LLM(layout あり) | 98.8 | 99.7 | 88.3 | 33.0 | 796 | 17 / 0 |
| unstructured(fast) | 94.5 | 99.3 | 91.7 | 76.6 | 836 | 63 / 83 |
| pdfminer.six | 81.7 | 94.9 | 85.0 | 77.1 | 1 | 67 / 83 |
| MarkItDown | 75.9 | 94.1 | 85.0 | 27.9 | 770 | 0 / 8 |
| pdfplumber | 67.0 | 92.5 | 80.0 | 28.0 | 764 | 0 / 17 |
| 上限(正解の原稿そのもの) | — | — | 93.3 | — | — | 100 / — |
2段組みでは、本文の再現が pdfplumber で67.0%、MarkItDown で75.9%、pdfminer.six で81.7%に下がりました。LLM の本文の問い15問の正答率は、2段組みでは80.0〜91.7%に収まりました。
縦書きでは、字間の空白が1,000字あたり600個を超える設定が6つありました(Docling・MarkItDown・pdfplumber・PyMuPDF4LLM の layout あり・unstructured の fast と hi_res)。pdfplumber・MarkItDown・PyMuPDF4LLM の layout ありは、縦書きの12問の正答率が、Chromium と LibreOffice のどちらの作り方でも0〜16.7%でした。
縦書きの検索では、日本語の文字に挟まれた空白と改行を削除すると、BM25 の当たりが上がりました。pypdf では70.8%から95.8%です(縦書き12問 × Chromium と LibreOffice の2種 = 24件)。
ヘッダーとフッターの文を既定で落としたのは Docling だけだった
ヘッダーとフッターの文を既定で落としたのは Docling だけで、ほかの 9 設定は、ページ数と同じ回数以上、出力に残した。PyMuPDF4LLM は引数で、unstructured(fast)は要素の種類で落とせた
| 設定 | ヘッダーの文 | フッターの文 | ページ番号 |
|---|---|---|---|
| Docling | 0 | 0 | 0 |
| pypdf | 100 | 100 | 100 |
| pdfminer.six | 100 | 100 | 100 |
| pdfplumber | 100 | 100 | 100 |
| PyMuPDF | 100 | 100 | 100 |
| PyMuPDF4LLM(layout あり) | 100 | 100 | 0 |
| PyMuPDF4LLM(layout なし) | 100 | 100 | 0 |
| MarkItDown | 100 | 100 | 52.5 |
| unstructured(fast) | 100 | 100 | 100 |
| unstructured(hi_res) | 100 | 100 | 100 |
| PyMuPDF4LLM(layout あり) header=False, footer=False | 6.6 | 0.0 | 0.0 |
| unstructured(fast) Header・Footer の要素を除く | 0 | 0 | 0 |
| unstructured(hi_res) Header・Footer の要素を除く | 0 | 100 | 45.8 |
ヘッダーとフッターの文は、ほかの9設定が、ページ数と同じ回数以上、出力に残しました(図の注に割り方を書きました)。ページ番号は設定で違い、PyMuPDF4LLM の2設定は出力せず、MarkItDown は約半分のページで出力しました。PyMuPDF4LLM の layout ありに header=False, footer=False を渡すと、ヘッダーの文は6.6%に下がり、フッターの文とページ番号は0%でした。
検索の当たりは、横書きの本文では道具の差を分けられず、表では変換以外の条件にも左右された
検索の上位 5 件に正解が入った割合は、横書きの本文の問いでは BM25 で89.6〜96.9%と道具の差を分けられず、表の問いでは ruri-v3-310m で Docling(67.8%)、BM25 で PyMuPDF(54.7%)が最良だった
| 設定 | 本文の問い(横書き 120 問) | 表の問い(69 問) | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ruri-v3-310m | BM25 | ruri-v3-310m | BM25 | |||||||||
| そのまま | NFKC | NFKC+空白と改行の削除 | そのまま | NFKC | NFKC+空白と改行の削除 | そのまま | NFKC | NFKC+空白と改行の削除 | そのまま | NFKC | NFKC+空白と改行の削除 | |
| PyMuPDF | 89.8 ○ | 88.5 ○ | 88.3 ○ | 95.8 ○ | 95.8 ○ | 95.8 ○ | 54.7 ○ | 55.1 ○ | 55.1 ○ | 54.7 ○ | 54.7 ○ | 55.4 ○ |
| PyMuPDF4LLM(layout なし) | 88.5 ○ | 87.5 ○ | 87.7 ○ | 96.0 ○ | 96.0 ○ | 96.9 ○ | 57.6 ○ | 57.6 ○ | 53.3 ○ | 46.0 ○ | 46.0 ○ | 42.0 ○ |
| pdfplumber | 79.8 | 80.0 ○ | 81.5 ○ | 89.6 ○ | 89.6 ○ | 89.8 ○ | 48.9 ○ | 51.4 ○ | 58.0 ○ | 50.0 ○ | 50.7 ○ | 51.4 ○ |
| pypdf | 89.0 ○ | 89.0 ○ | 88.8 ○ | 94.8 ○ | 95.2 ○ | 95.8 ○ | 48.6 | 48.6 | 50.0 ○ | 48.6 | 48.9 ○ | 50.4 ○ |
| MarkItDown | 81.3 ○ | 81.7 ○ | 81.9 ○ | 91.9 ○ | 91.7 ○ | 91.3 ○ | 45.3 ○ | 45.3 ○ | 47.1 ○ | 22.5 | 21.7 | 23.6 |
| Docling | 85.6 ○ | 84.6 ○ | 86.3 ○ | 94.0 ○ | 93.8 ○ | 93.1 ○ | 67.8 ○ | 67.8 ○ | 64.1 ○ | 29.7 | 30.1 | 27.2 |
| unstructured(fast) | 87.5 ○ | 87.5 ○ | 86.9 ○ | 94.8 ○ | 94.8 ○ | 94.8 ○ | 33.7 | 33.7 | 34.8 ○ | 35.5 ○ | 35.9 ○ | 37.3 |
| PyMuPDF4LLM(layout あり) | 86.9 ○ | 86.9 ○ | 87.1 ○ | 96.0 ○ | 96.5 ○ | 96.0 ○ | 48.9 | 51.1 ○ | 52.2 ○ | 37.3 | 37.3 | 38.4 |
| unstructured(hi_res) | 87.1 | 87.5 ○ | 89.0 ○ | 95.4 ○ | 95.8 ○ | 95.8 ○ | 36.2 | 35.9 | 39.5 ○ | 37.0 ○ | 37.0 ○ | 38.4 |
| pdfminer.six | 86.0 ○ | 85.2 ○ | 84.6 ○ | 92.3 ○ | 92.5 ○ | 92.5 ○ | 29.7 | 30.1 | 30.1 | 32.2 | 32.6 | 33.7 |
| 上限(正解の原稿そのもの) | 88.3 | 88.3 | 87.5 | 94.2 | 94.2 | 94.2 | 62.3 | 59.4 | 56.5 | 46.4 | 46.4 | 49.3 |
「組」は、検索の方法2通り・前処理3通り・問いの種類2通りの12通りです。横書きの本文の問いの6組のうち5組では、10設定すべてが最良の集まりに入り、道具の差を分けられませんでした。
表の問いは、行見出しと値の両方を含む区切りが無いと正解になりません。正解の原稿そのものを検索した値(検索の上限)でも、BM25 は46.4〜49.3%、ruri-v3-310m は56.5〜62.3%でした。別の表にも同じ型番や名称があることが一因と考えられます(推定)。検索の上限は Markdown 風に組んだ文字で、道具の出力と書式が違うため、Docling(ruri-v3-310m で67.8%)が検索の上限を上回る組もあります。表の問いの当たりには、区切りの位置と書式の影響もあり(推定)、変換の出来とは分けていません。
行見出しと値の両方を含む区切りが1つも無い表の問い(NFKC、BM25)の割合は、pdfminer.six が39.9%、unstructured の fast が42.8%、hi_res が37.7%、MarkItDown が31.9%、PyMuPDF が0%でした。pdfminer.six と unstructured は値と行見出しが離れて出力されるためと考えられます(推定)。縦書きでは、pdfplumber・PyMuPDF4LLM の layout あり・MarkItDown に正解の区切りが全問で無く、当たりは0%でした。検索の当たりでは Docling の列の入れ替わりの影響は測れず、段3の正答率で測りました。
速さ(参考値)は、PyMuPDF の0.05秒から unstructured の hi_res の3.2〜5.8秒まで
速さ(参考値):1 ページあたり PyMuPDF の0.05秒に対し、Docling は1.0〜1.4秒、unstructured(hi_res)は3.2〜5.8秒だった
共用の計算サーバーで測りました。測った時の負荷(ロードアベレージ)は60〜161で、絶対値は本来の性能より遅い側に寄る可能性があります(推定)。参考値です。GPU は使っていません。pypdf を1とすると、Docling は17.7〜23.5、unstructured の hi_res は55.9〜102.7です。
測っていない対象と理由
- Word・Excel から書き出した PDF:測った PDF は、Chromium の印刷・Typst・ReportLab・LibreOffice の4つの作り方で作った物だけです。
- スキャンした PDF(文字の層が無い PDF):今回の範囲外です。OCR のモデルはOCR の実測表で測りました。
- 非商用ライセンスの重みの道具:marker(surya の重みが CC BY-NC-SA 4.0)、YomiToku(コードも重みも CC BY-NC-SA 4.0)、Nougat(重みが CC BY-NC 4.0)。
- GOT-OCR 2.0:PyPI に無く、配布元のコードの実行が必要なため。
- PaddleOCR(PP-StructureV3)・olmOCR・MinerU:GPU と OCR を使う道具で、今回は文字の層がある PDF に絞ったため。
- 有料のサービス:API キーや契約が必要なサービスは測っていません。
文書の検索に使う埋め込みモデルの比較はRAG の実測表、ほかの実測表は実測表の一覧にあります。
測定の条件
下の欄を開くと、原稿・PDF の作り方・道具の呼び出し方・指標の定義・問いの作り方と確認・LLM に渡した依頼文・検定が表示されます。
測定の条件の詳細を開く
原稿:44本。AIコンパスの公開済みの記事の文面(40本。基準4・罫線のある表6・罫線の無い表5・結合セルのある表5・第1列が折り返す表3・ページをまたぐ表4・2段組み5・脚注4・箇条書き4)と、青空文庫の作品(縦書き4本。パブリックドメイン)。構造つきのデータ(見出し・段落・表のセル)で保存し、それを正解とします。ヘッダー・フッター・ページ番号は、原稿の半分(22本)に付けました。表のある23本は、1ページに収まっているか(ページまたぎを除く)、セルが折り返していないか(第1列が折り返す表を除く)を PDF ごとに確認してから、採点しました。
原稿の元:AIコンパスの記事9本の文面と表です。RAG の埋め込み・高画質化・翻訳・OCR・ローカル LLM・文字起こし・読み上げ・背景透過・ゲームの翻訳の各実測表の記事です。原稿を作った時点の repo のコミットは記録していません。2026年11月11日時点の公開の文面で、原稿を組む台本は commit b614f806c と 4318d58c0 です。縦書きの4本は、青空文庫の次の作品です(作品ファイルの URL)。蜘蛛の糸(芥川龍之介)・走れメロス(太宰治)・山月記(中島敦)・注文の多い料理店(宮沢賢治)。
PDF の作り方:Chromium 140(Playwright の page.pdf、Noto Sans CJK JP)、Typst 0.15.2、ReportLab 5.1.0、LibreOffice 26.8.2.2(python-docx で組んだ .docx を変換)。Chromium は、フォントを BIZ UDPGothic と IPAex ゴシックに変えた PDF を、10本の原稿で追加しました。縦書きは Chromium と LibreOffice の2種だけです。合計188本の PDF は、横書き40本 × 4種 = 160本、縦書き4本 × 2種 = 8本、フォント違い 20本(10本の原稿 × 2種)です。
道具:pypdf(単独の環境)、pdfminer.six、pdfplumber、PyMuPDF(get_text)、PyMuPDF4LLM(既定と use_layout(False))、MarkItDown 0.1.9(内部で pdfplumber と pdfminer.six を使う)、Docling(既定。OCR を含む)、unstructured(fast と、hi_res に languages=["jpn"])。道具ごとに環境を分けました。
測った道具 8 つ(10 設定)の版・ライセンス・呼び出し方
| 設定 | 版 | ライセンス(配布元の表示) | 呼び出し方 | 配布元(確認日) |
|---|---|---|---|---|
| pypdf | 7.0.1 | BSD-3-Clause | PdfReader の extract_text | PyPI(2026-11-11) |
| pdfminer.six | 20260107 | MIT | extract_text | PyPI(2026-11-11) |
| pdfplumber | 0.11.10 | MIT | extract_text | PyPI(2026-11-11) |
| PyMuPDF | 2.1 | AGPL-3.0 か商用(Artifex) | page.get_text() | PyPI(2026-11-11) |
| PyMuPDF4LLM(layout あり) | 2.1 | AGPL-3.0 か商用(Artifex) | pymupdf4llm.to_markdown(既定) | PyPI(2026-11-11) |
| PyMuPDF4LLM(layout なし) | 2.1 | AGPL-3.0 か商用(Artifex) | use_layout(False) のあと to_markdown | PyPI(2026-11-11) |
| MarkItDown | 0.1.9 | MIT | MarkItDown().convert | PyPI(2026-11-11) |
| Docling | 2.150.0 | MIT(モデルの重みは cdla-permissive-2.0 と Apache-2.0) | DocumentConverter().convert(既定。OCR を含む) | PyPI(2026-11-11) |
| unstructured(fast) | 0.27.37 | Apache-2.0 | partition_pdf(strategy='fast') | PyPI(2026-11-11) |
| unstructured(hi_res) | 0.27.37 | Apache-2.0(重みは MIT と Apache-2.0) | partition_pdf(strategy='hi_res', infer_table_structure=True, languages=['jpn']) | PyPI(2026-11-11) |
指標:本文の再現は、正解の見出し・段落ごとに、出力の中で最も近い箇所との一致率(NFKC と空白の除去の後)を平均した値です。表は、出力に Markdown の表があるか、TEDS(表の構造と内容が正解の表とどれだけ近いかを示す指標。0〜1)、数値の対応付け(数値のセルが、正しい行見出しと列見出しの下にあるか)、行の並び(正解の各行の行見出しと値が、出力の中でこの順に並んでいるか)で採点しました。分割された表は、列数が同じ連続した表を縦につないで、正解に最も近い物で採点します。
検索(段2):変換した文字を400字(100字重ね)で区切り、ruri-v3-310m と BM25(fugashi と unidic-lite の分かち書き)で検索しました。前処理は、そのまま・NFKC・NFKC のあと日本語の文字に挟まれた空白と改行を削除する、の3通りです。正解は、答えの語を含み根拠の文との一致率が80以上の区切り(本文)、答えのセルの値と行見出しの両方を含む区切り(表)です。
回答(段3):Qwen3 14B(Apache-2.0)を vLLM 0.33.0 で実行しました。思考の過程(thinking)を出力しない設定にし、温度は0、出力は最大64トークン、コンテキスト長は16,384です。変換した出力1本分を前処理なしで丸ごと渡し、2回測りました。依頼文は全条件で同じで、次の全文です(<document> に変換した出力、<question> に問いが入る)。
次の文書を読んで、質問に答えてください。答えだけを短く書いてください。文書から分からない時は「不明」と書いてください。
【文書】
<document>【質問】
<question>
数値の答えは、正解に含まれる数の並びが答えに順番どおり現れれば正解、数値でない答えは NFKC と空白の除去の後に正解の文字列を含めば正解としました。「不明」と別の数は不正解です。
問い:201問(本文132〔横書き120・縦書き12〕・表69)を、利用者が検索に入力する疑問文の形式で書きました。測定の後に、別の確認者が201問を確認し、21問を直しました(表13・本文8。直した理由の14問は「言い方が数字の意味と合わない」)。保留は7問、欠陥なしは173問です。直した後に、段2と段3を全問で測り直しました。直す前の結果と比べると、段3は最良の集まりの構成が同じでした。段2は12組のうち3組で、1設定ずつ出入りがありました(ruri-v3-310m・表の問い・NFKC に PyMuPDF4LLM の layout あり、ruri-v3-310m・表の問い・NFKC+空白と改行の削除から pdfminer.six が最良の集まりに入らなくなり、BM25・表の問い・そのままに unstructured の fast が入った)。縦書きの12問は、青空文庫の作品の本文を載せないため、公開のデータには問いと答えだけを載せました。
差の判定:単位は原稿です。作り方をまたいで平均し、最良の設定と各設定を、対の正確な符号検定と Holm の補正で比べました。補正後の p が0.05以上の設定を最良の集まりに入れています。検索は問いを単位にせず、原稿を単位にしました。
測定の揺れ:LLM の2回の測定で、答えの文字列は8,139件中99.6%、採点結果(正解・不正解・不明)は99.9%が一致しました。
環境:段1の変換と速さは、共用の計算サーバーの CPU 8コアです。段2のベクトル検索と段3の LLM は、GPU 1基で実行しました(BM25 は CPU)。公開のデータは /assets/data/pdf-markdown-benchmark/ にあります(問い201問と、道具別の集計。青空文庫の作品の本文と、道具の出力の全文は含みません)。
この実測表で分からないこと
- Word・Excel から書き出した PDF とスキャンした PDF:測っていません。測った PDF は、Chromium の印刷・Typst・ReportLab・LibreOffice の4つの作り方で作った PDF だけで、それ以外の結果は、この表から言えません。
- LLM の種類:段3は Qwen3 14B 1種に、変換した文書1本を丸ごと読ませた値です。ほかのモデル(ローカル LLM の実測表)や、検索で絞った文書を渡す RAG の構成では、結果が変わりうる。
- 原稿の偏り:原稿は AIコンパスの記事から作った日本語の文書で、公的機関の文書や契約書とは書き方が違います。表は数値が6割以上のものを使い、表の問いは1原稿に3問です。
- 道具の設定:原則として既定の設定で測りました。引数を変えれば、結果が変わりうる。
- Docling の原因:列の入れ替わりが正答率を下げたかは、因果までは言えません。正解の原稿の列を機械的に移した文書では、差を分けられませんでした。
- 問いの出来:問いは1人が書き、別の確認者が確認して21問を直しました。上限(正解の原稿)でも誤答する問いが横書きの本文に4問あり、道具間の比較は上限に対する割合で読む必要があります。
- 縦書きと2段組み:縦書きは原稿4本、2段組みは原稿5本で、検定をしていません。
- 速さ:共用の計算サーバーで、道具を1回ずつ順番に3周した参考値です。GPU は使っていません。
- ライセンス:配布元の表示を転記したもので、法的な判断ではありません。unstructured の hi_res が使うレイアウトのモデル(yolo_x_layout)と表のモデル(table-transformer)は、モデルのページのライセンス欄が空で、リポジトリの LICENSE はそれぞれ Apache-2.0 と MIT です。OCR に使う tesseract 5.5.3 と jpn の学習データのライセンスは、確認していません。
よくある質問
日本語の PDF を RAG に入れる前に、変換の道具は何を選べばよいですか。
編集部の測定(2026年11月)では、横書きの本文なら10設定のどれでも、変換した文書を LLM に読ませた時の本文の問い(120問)の正答率は94.8〜97.4%で、差があるとは言えませんでした。ただし2段組みと縦書きでは設定で差が出ました(縦書きの3設定は正答率0〜16.7%)。表のある PDF では、pdfplumber・PyMuPDF・pypdf・PyMuPDF4LLM(2設定)・MarkItDown の6設定が91.5〜99.3%で最良の集まり(最良と差があるとは言えない設定)に入り、Docling(93.8%)、unstructured の fast(79.2%)、pdfminer.six(70.1%)、unstructured の hi_res(60.9%)は最良との差が確認できました。Docling が MarkItDown(91.5%)より高いのに入らなかったのは、最良の pdfplumber と原稿ごとに比べると、Docling は9本で下回り、上回った原稿が0本で差があり、MarkItDown は6本対0本で差があるとは言えなかったためです。これは、文字の層がある188本の自作の PDF を、Qwen3 14B に1本丸ごと読ませた値です。使う PDF の種類で順位が変わりうるため、自社の PDF の一部で2〜3設定を試すことを勧めます。
表の多い PDF は、Markdown の表に変換できる道具を選ぶべきですか。
測った範囲では、行の並び(正解の各行の行見出しと値が、出力の中で行の順に並んでいる割合)が0.07以下の3設定(pdfminer.six・unstructured の fast・hi_res)が、表の問いで最良の集まりに入りませんでした。Markdown の表を出力しない pypdf と PyMuPDF は、表の問いの正答率が98.6%で最良の集まりに入りました。Docling は表を出力しますが、罫線のある表の PDF 24本のうち13本で行見出しの列を右端の列に配置し、その13本の表の問いの正答率は82.1%でした。ただし列の入れ替わりだけが原因とは言えません。
無料で使えますか。商用の製品に組み込めますか。
測った8つはどれも無料で入手できます。配布元の表示では、pypdf は BSD-3-Clause、pdfminer.six・pdfplumber・MarkItDown・Docling は MIT、unstructured は Apache-2.0 です。PyMuPDF 2.1 は、配布物のライセンス文が COPYING の1行「Dual Licensed - GNU AFFERO GPL 3.0 or Artifex Commercial License」(二重ライセンス。AGPL か Artifex の商用ライセンス)です。PyMuPDF4LLM 2.1 は PyMuPDF 2.1 に依存し、PyMuPDF4LLM 自身と layout のパッケージは、メタデータのライセンス欄が空でした。ライセンス文は PyMuPDF の COPYING で確認しています。どちらも、自社の製品に組み込む場合は AGPL の条件を満たすか、商用ライセンスの契約が必要です。これは配布元の表示で、法的な判断ではありません。商用で使う前に、配布元でライセンスの全文を確認してください。
スキャンした PDF や画像の PDF にも使えますか。
今回は測っていません。測ったのは、Chromium の印刷・Typst・ReportLab・LibreOffice(python-docx で組んだ .docx を変換)の4つの方法で作った、文字の層がある PDF だけです。Word や Excel から書き出した PDF と、紙をスキャンして文字の層が無い PDF は測っていません。文字の層が無い PDF は、画像から文字を読み取る OCR が必要です。OCR のモデルの比較は、別の実測表(/ocr-benchmark/)にあります。
「文」が部首の「⽂」に変わる問題は、検索に影響しますか。
測った範囲では、部首が出る7設定で、NFKC を掛ける前後の検索の当たりの平均の差は0.0〜0.6ポイント(1問未満)、設定ごとの差は最大2.9ポイントでした(検定はしていません)。Chromium の印刷で Noto Sans CJK JP を使った PDF では、7設定で1,000字あたり約33字の漢字が部首の文字に変わりましたが、検索の上位5件に正解が入った割合は、NFKC(互換文字を通常の文字にそろえる処理)を掛けても、本文の問い(横書き120問)では BM25 が0.6ポイント、ruri-v3-310m が0.6ポイント、表の問い(69問)では BM25 が0.6ポイント上がり、ruri-v3-310m は0.0ポイントでした。いずれも1問未満の差です。ただし「・」と「/」は別の記号に変わり、NFKC でも戻りません。表の値に「・」が含まれる場合は、値を完全一致で比べると誤りになります。