0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

仕様書 PDF から RAG 用のコーパスを作る

0
Last updated at Posted at 2026-07-19

この記事は Claude のリサーチ機能で調べた内容を、整理し直したものです。2026 年 7 月時点の情報で、この領域のツールは数か月単位で順位が入れ替わります。ベンチマークの数値やライセンス条件は、導入前に一次情報で確認お願いします。

はじめに

(個人の趣味の範囲で) SystemVerilog の LRM や AMBA の仕様書を LLM に参照させたいのでRAGで参照できるようにしました。とりあえず、Marker(PDF → Markdown)の評判がよさそうだったので、これで全部通せばいいだろうと考えて、仕様書をまるごと突っ込みました。見出しも付きますし、それらしい Markdown が出てくるので、しばらくそれで運用してみました。

しかし、しばらくたってから気がついたのですが、表が正しく変換できていませんでした。セルの区切りがずれていたり、列がまとまってしまっていたり、行の対応が崩れていたりする。表がこれでは、コーパスとして使い物になりません。

結局、表については pdftotext で出し直しました。Markdown の表にはならず桁揃えの文字列のままですが、少なくとも元ページの見た目どおりに並んでいるので、そこから手なり正規表現なりで直せます。機械学習に解釈された表より、解釈せずに座標どおり並べただけの文字列のほうが、直すのが楽だったわけです。

ここまでの経緯を振り返ると、ツールの選び方が場当たり的でしたし、変換の後にやるべきこともよく分かっていませんでした。というわけで、正規化・チャンク分割・メタデータ設計まで含めてベストプラクティスを調べ直したのがこの記事です。

image.png

この記事の要点

先に結論を書いておきます。

  • 変換は一つのツールで完結させないほうがよさそうです。大部分を決定論的な高速ツールで通し、壊れたページだけを VLM 系に回すハイブリッドが、精度と時間と再現性のバランスとして現実的です。
  • 表は変換ツールの出力を信用しすぎないほうがよいです。崩れていても Markdown の表としては成立してしまうので、目視では気づきにくい。重要な表は複数のツールで出して突き合わせるのが安全です。
  • いちばん効くのはチャンク分割です。表・コード例・BNF を分割しないというルールを入れるだけで、検索の当たり方が変わります。
  • 検索側の都合が前段の設計を縛ります。特に uvm_sequence_itemAWVALID のような識別子のトークナイズは、埋め込みモデルの選定より優先度が高いと思います。
  • ライセンスは先に見ておいたほうがよいです。高精度なツールほど、重みの利用条件に制約があります。
  • ML を使う変換は出力が揺れます。コーパスの再現性が要るなら、変換後の Markdown 自体をハッシュで固定する運用にしておくと安全です。

1. なぜ仕様書 PDF は素直に扱えないのか

論文や書籍と比べたときの仕様書の厄介さは、「意味を持つ非文章要素」の比率が高いことです。IEEE 1800-2023 を例にすると、こういう要素が本文中に大量に混ざります。

要素 素朴にテキスト抽出すると 本来必要な扱い
節番号の階層(6.11.2、A.2.2.1) ただの行になる 階層としてメタデータに保持する
信号表・優先順位表 空白で桁揃えされた文字列に潰れる セル構造を保った表として保持する
コード例 インデントが失われる、行が結合される 等幅ブロックとして分割せず保持する
Annex A の BNF 記号と改行が崩れて文法として読めなくなる ひとかたまりの単位として保持する
図(状態遷移図・タイミング図) 完全に消える 画像として抽出するか、キャプションを残す
ヘッダ / フッタ 全ページに規格名とページ番号が混入する 除去する
相互参照(see 23.2.2) ただの文字列 参照先をメタデータ化すると後で効く
目次・索引 本文と同じ重みでチャンク化される 本文からは除外し、節とページの対応表として使う

AMBA の仕様書はさらに表の比率が高く、信号一覧やチャネルのハンドシェイク表が事実上の本体です。ここが崩れると、コーパスとしての価値がかなり落ちます。

もう一点、地味に効くのが単段組であることです。学術論文の PDF 変換でよく問題になる「2 段組の読み順」は、仕様書ではあまり起きません。つまり、VLM 系ツールの強みのうち読み順推定の部分は、仕様書ではそれほど効かないということでもあります。効くのは表と数式まわりです。

2. 変換ツールの二つの系統

2.1 決定論系と VLM 系

ツールは大きく二系統に分かれます。

決定論系は、PDF のコンテンツストリームにあるテキスト描画オペレータを読み、フォントの ToUnicode CMap 経由で Unicode に直し、グリフの座標から行と語間を再構成します。ML を使わないので出力は完全に再現します。速く、CPU だけで動き、1,300 ページでも数分で終わります。

VLM 系は、ページを画像として扱い、レイアウト検出・読み順推定・表構造認識・数式認識をモデルに解かせます。表を Markdown やHTML の表として復元できる代わりに、GPU が要り、遅く、出力が実行ごとに揺れます。

仕様書という用途では、この二つは競合ではなく分担だと考えたほうが実務的だと思います。

2.2 主要ツールの比較

2026 年 7 月時点で名前が挙がるものを整理しました。ベンチマークの数値はそれぞれ測定条件が違うので、横並びの絶対比較にはならない点に注意してください。

ツール 系統 ライセンス 表の再現 速度 / 必要リソース 備考
pdftotext(Poppler) 決定論 GPL-2.0 しない(空白整列のみ) 数秒 / CPU -layout で物理配置を近似、-raw は読み順
pymupdf4llm 決定論 AGPL(PyMuPDF) する(既知バグあり) 速い / CPU 見出しをフォントサイズから推定、header=False でフッタ除去
Docling(IBM) 決定論 + 軽量モデル MIT する(TableFormer) 中 / CPU 可 節階層・座標・本文とフッタの判別を保持、チャンカ内蔵
Marker VLM コードは GPL、重みは要確認 する 中 / GPU 約 3GB Surya ベース、--use_llm で精度向上
MinerU 2.5 VLM Apache 2.0 系 する 遅い / GPU 6〜8GB 1.2B VLM、OmniDocBench で 90.67 と報告。Apple Silicon 向けバックエンドあり
olmOCR 2(AI2) VLM Apache 2.0 する 遅い / GPU olmOCR-Bench 82.4。反復抑制の工夫が入っている
Chandra 2(Datalab) VLM 重みは修正 OpenRAIL-M する 遅い / GPU 8〜12GB olmOCR-Bench 85.9% 前後。商用セルフホストは要ライセンス
Nougat(Meta) VLM 数式に強い 非常に遅い 生成が反復ループに陥る既知の問題あり。仕様書には不向き
GROBID 学術文書特化 表は画像化 速い 論文の書誌・参照抽出用。LRM には合わない

表だけを狙うなら、専用ツールもあります。いずれも MIT で、デジタル PDF 専用です。

ツール 得意 主なパラメータ
Camelot 罫線あり表 flavor=lattice(罫線検出) / flavor=stream(空白整列)
pdfplumber 罫線なし表も vertical_strategylines / text / explicit で切り替え
Tabula 表の検出自体は強い JVM が必要。解析結果は要調整

pdfplumber には page.to_image().debug_tablefinder() という視覚デバッグがあって、閾値を詰めるときに便利です。ただし作者自身が text 戦略は扱いが難しいと述べているようで、パラメータ調整はそれなりに手間がかかります。ページをまたぐ表の結合ロジックは持っていないので、そこは自前で書く必要があります。

2.3 クラウド系をどう考えるか

LlamaParse、Adobe PDF Extract API、Mathpix あたりは精度は高いのですが、PDF をクラウドに送ります。ARM や IEEE の仕様書は再配布に制限があるので、変換のために外部サービスへ丸ごとアップロードしてよいかは、事前に確認しておいたほうがよいと思います。社内文書や機密性のある RTL が混ざる場合はなおさらです。

同じ理由で、Marker や MinerU の --use_llm に相当する精度向上モードにも注意が要ります。既定では Gemini のようなクラウド API を呼ぶ実装が多いので、使うなら Ollama バックエンドなどでローカル完結にしておくのが無難です。

2.4 ハイブリッドに落とす

以上を踏まえると、こういう構成に落ち着きます。

image.png

全ページを VLM に通さない理由は二つあります。時間と、再現性です。1,300 ページを丸ごと VLM にかけると、データセンタ級の GPU でも十数分、手元の GPU なら数時間かかります。そして ML ベースなので、seed を固定しても完全に同じ出力になるとは限りません。コーパスをバージョン管理したいとき、これは地味に困ります。

VLM は「必要なページにだけ効かせる高い薬」と考えて、信号表の章や BNF の章に限定して投入するのが、費用対効果としては素直だと思います。

ただし、ここで一点だけ自分の失敗にも触れておきます。冒頭で書いたとおり、私は Marker の表出力で痛い目を見ました。VLM 系は表に強い、というのは一般論としてはそのとおりなのですが、仕様書の表は列数が多く、セル内で折り返し、結合セルも混ざるので、モデルが構造を取り違えることがあります。そして厄介なのは、取り違えていても Markdown の表としては成立してしまうので、パッと見では気づかないことです。決定論的なツールなら「桁が揃っていない」という分かりやすい形で崩れるので、まだ気づけます。

なので「表は VLM に任せれば安心」ではなく、「重要な表は両方で出して見比べる」くらいの構えが要ると思います。特に信号表のように後段の正誤を左右する表は、目視するか、列数とセル数の突き合わせで検算したほうがよさそうです。

3. 変換品質をどう見張るか

3.1 ベンチマークの読み方

公開ベンチマークをそのまま鵜呑みにするのは危ないので、何を測っているのかだけ整理しておきます。

指標 / ベンチ 測るもの 注意点
TEDS 表を HTML ツリー化した木編集距離。構造のみの TEDS-S もある セル内容込みかどうかで数値が変わる
NED / CER 本文・数式・読み順の文字レベル一致 句読点や空白の無害な差も減点する
OmniDocBench 本文・表・数式・読み順を総合 連続指標なので飽和しやすいと指摘されている
olmOCR-Bench 決定論的な合否テスト(約 1,400 PDF、7,000 超のテスト) ヘッダ / フッタの除去可否も検査対象になっている

OmniDocBench のような連続指標は、意味的に等価な表を「書き方が違う」という理由で減点してしまう傾向があるようです。一方 olmOCR-Bench は「この文字列が出ているか / 出ていないか」という合否形式なので、飽和しにくい設計になっています。両方を見るのがよさそうです。

なお、比較記事の中にはツールベンダ自身が書いたものが混ざります。自社製品が上位に来ている比較は、測定条件を確認してから読んだほうがよいと思います。

3.2 壊れたページを自動で見つける

実務上いちばん重要なのは、絶対精度より「どのページを再処理すべきか」を機械的に決められることです。

失敗モード 検出の手がかり 対処
文字化け・グリフ欠落 U+FFFD(置換文字)の出現率、非印字文字比 OCR を強制する(--force_ocr 相当)
生成の反復ループ 同一行・同一 n-gram の反復、ロジット分散の低下 該当ページだけ別ツールで再変換
表の崩壊 罫線は検出されているのに Markdown の表が出ていない 表特化ツールか VLM で再処理
本文の脱落 ページの本文量が全体の中央値から大きく乖離 目視確認のうえ再処理
ヘッダ / フッタ混入 全ページに共通する行が残っている 正規化側で除去

反復ループの検出には、Nougat の論文で使われている「最大ロジット値のスライディングウィンドウ分散が閾値を下回ったら反復とみなして早期停止する」手法が知られています。後続のモデルもこの考え方を踏襲しているようです。自前で検出するなら、単純に同一行の連続回数を数えるだけでもかなり拾えます。

閾値そのものについては、決定版といえる論文は見当たりませんでした。自分のコーパスで較正するしかなさそうです。

4. 正規化でやること

変換の次に、地味ですが効く工程です。

処理 内容 注意点
Unicode 正規化 unicodedata.normalize("NFKC", text) リガチャ(fi、fl)の大半はこれで解消する
ヘッダ / フッタ除去 全ページに反復する行とページ番号を削る 規格名の行は正規表現で拾いやすい
行末ハイフンの結合 「bench-\nmark」→「benchmark」 識別子中のハイフンや、コード / BNF 内では結合しない
空白の正規化 全角空白、ノーブレークスペース、ゼロ幅文字 連続空白の畳み込みは表を壊さない範囲で
目次 / 索引の分離 本文チャンクからは外す 節とページの対応表としては使える
相互参照の抽出 「see 23.2.2」を正規表現で拾う チャンクのメタデータに関連節として持たせる

ハイフンの結合は、素朴にやると識別子を壊します。「行末のハイフン + 改行 + 次行が小文字始まり」という条件に限り、なおかつコードブロックや BNF の内側では適用しない、というガードを入れておくのが安全だと思います。

リガチャについて一点補足すると、NFKC で直るのは「リガチャが文字として埋まっている」場合です。Type-3 フォントで図形として描かれている場合は、そもそも文字として抽出できないので、OCR に回すしかありません。

5. チャンク分割

ここが一番効きます。

image.png

5.1 構造で切る

基本は二段構えです。まず Markdown の見出し(######)で分割して、見出しをメタデータに保持します。そのうえで、サイズ上限を超えたセクションだけを再帰的に再分割します。オーバーラップはセクションの内側にだけ効かせて、節の境界はまたがせません。

LangChain なら MarkdownHeaderTextSplitterRecursiveCharacterTextSplitter の組み合わせ、Docling なら HybridChunker が同じ思想で作られています。Docling のチャンカは節境界の分割とページ番号・見出しの付与を内蔵しているので、仕様書との相性はよさそうです。

5.2 割ってはいけない単位

仕様書に固有のルールとして、次の三つは分割しないようにします。

表は途中で割らない。どうしてもサイズを超える場合は、ヘッダ行を各断片に複製してから分割します。列名を失った表の断片は、検索でも生成でも使い物になりません。

コードブロックと BNF は、フェンスや構文ブロック単位でひとかたまりとして扱います。SystemVerilog の例は前後の宣言と一体で意味を持つので、途中で切れると誤読の元になります。

見出しは本文から切り離しません。メタデータに持たせるだけでなく、チャンク本文の先頭にも残しておくと、後述する文脈前置がそのまま実現できます。

5.3 サイズとオーバーラップ

実証的な目安としては、再帰分割で 512 トークン前後、オーバーラップ 10 〜 20% あたりが手堅いようです。学術文書 50 本を対象にした 2026 年 2 月のベンチマークでは、再帰分割 512 トークンが検索精度 69%、純粋な意味ベース分割が 54% という結果が報告されています。

埋め込みモデルの窓 目標サイズ 上限 オーバーラップ
512 トークン 480 512 約 15%
8192 トークン 800 1024 約 15%

窓が広いモデルを使っているからといって、チャンクを大きくすればよいわけではありません。大きくすると検索のベクトルがぼやけます。そこで次の話になります。

5.4 親子チャンク

検索する単位と、LLM に渡す単位を分ける考え方です。

image.png

小さい子チャンク(200 〜 300 トークン程度)を埋め込み検索の対象にし、ヒットしたら親チャンク(節まるごと、1,000 トークン前後)を LLM に渡します。LangChain の ParentDocumentRetriever がこの形です。

仕様書は節がきれいに切れるので、この構成と相性がよいと思います。代償はベクトル数がほぼ倍になることですが、節の粒度が明確な文書ではその代償に見合いやすいはずです。

5.5 文脈を前置する

Anthropic が 2024 年に出した Contextual Retrieval は、各チャンクに「文書全体における位置づけ」を 50 〜 100 トークンほど付けてから索引を張る手法です。報告されている効果は次のとおりです。

image.png

コストは、プロンプトキャッシュを使えば百万文書トークンあたり 1 ドル程度とされています。

ただし仕様書の場合、そもそも見出し階層が整っているので、LLM を使わずに「[IEEE 1800-2023 > 6.11 Signal descriptions]」のようなパンくずを機械的に前置するだけでも、かなりの部分が回収できると思います。決定論的で、無料で、再現性も保てます。まずこれを入れてみて、それでも取りこぼす節(主語が省略されている節、相互参照が多い節)にだけ LLM 版を適用する、という順序が現実的です。

5.6 新しめの手法をどう見るか

意味ベース分割(semantic chunking)、late chunking、agentic chunking といった手法が提案されていますが、少なくとも 2026 年時点では「常に効く」とは言えなさそうです。

意味ベース分割については、計算コストの増加に見合う一貫した改善は確認できなかった、という評価が複数あります。late chunking は文脈の保持には有効なものの、意味的な一貫性という点では文脈前置のほうが上、という比較研究もあるようです。

見出しがはっきりしている仕様書に関しては、構造分割 + 親子 + 見出し前置で十分なことが多いのではないかと思います。凝った手法を試すのは、それで足りないと分かってからでよさそうです。

6. メタデータ設計

RAG の答えに「IEEE 1800-2023 の 6.11.2 より」と付けられるかどうかは、この設計で決まります。検証の現場で使うなら、出典を示せないコーパスはかなり価値が下がります。

フィールド 用途
standard ieee1800 / ieee1800.2 / amba-axi 規格横断検索と規格限定検索の切り替え
version 2023 改版時の差し替え単位
section_number 6.11.2 / A.2.2.1 出典提示、階層フィルタ
section_title Signal descriptions 文脈前置に使う
page_number 412 原典の確認、再処理対象の特定
content_type prose / table / code / bnf 種別ごとの検索、チャンク分割ルールの検証
related_sections ["23.2.2"] 相互参照をたどる
parent_id ieee1800-2023#6.11 親チャンクの参照
content_hash sha256 差分更新の判定

ID は ieee1800-2023#6.11.2#chunk3 のように、規格を第一キーにした複合 ID にしておくと扱いやすいです。複数規格を一つのインデックスに混ぜても、フィルタで切り分けられます。

7. 検索側の都合が前段を縛る

7.1 識別子のトークナイズ

ここは仕様書 RAG に固有の、しかしかなり大きな落とし穴です。

uvm_sequence_itemAWVALID$display のような識別子は、汎用のトークナイザにかけると壊れます。アンダースコアで分割されたり、ドル記号が落ちたり、大文字小文字が潰れたりします。BM25 側でこれが起きると、いちばん引きたい語がいちばん引けないという状態になります。

image.png

報告されている改善幅はかなり大きく、識別子全体のトークンと camelCase / snake_case のサブトークンを両方発行する方式で、BM25 の NDCG@10 が 0.309 から 0.563 へ、82% の改善という結果が出ています。興味深いのは、サブトークンだけに分解する方式(0.469)は、両方発行する方式に負けているという点です。AWVALIDawvalid に割るだけでは足りず、AWVALID そのものも残しておく必要があるということですね。

埋め込みモデルを一つ上のグレードに上げるより、こちらを直すほうが先だと思います。

7.2 埋め込みモデル

ローカルで動かす前提だと、2026 年時点の選択肢はこのあたりです。

モデル パラメータ ライセンス 備考
BGE-M3 568M MIT 8192 dense と sparse を 1 パスで出せる。ハイブリッド構成と相性がよい
Qwen3-Embedding 0.6B 〜 8B Apache 2.0 コード検索に強い。MRL で 32 〜 4096 次元を選べる
nomic-embed-text-v2 137M MIT 8192 軽い。とりあえず動かすとき用

ハイブリッド検索を組むなら、BM25 とは別に sparse ベクトルを持つより、BGE-M3 のように一つのモデルで両方出せるほうが構成が単純になります。8GB クラスの GPU なら BGE-M3 か Qwen3-Embedding-0.6B、統合メモリの大きい Apple Silicon なら上位モデルも視野に入る、という感覚でよさそうです。

7.3 リランカ

BGE-reranker-v2-m3 が手堅い既定で、Qwen3-Reranker(Apache 2.0)が候補として上がってきています。リランカを入れて RAGAS の平均が 70.99 から 74.15 に上がったという報告もあります。

ただし、リランカの効きはコーパス依存が大きいので、100 〜 500 件程度のゴールデンセットを自分で作って lift を測ってから採用するかどうかを決めるべきだと思います。「入れれば良くなる」という前提で常用すると、レイテンシだけ増えて何も改善していない、ということが起こり得ます。

8. 運用 ─ 再現性と差分更新

決定論的な変換であれば、出力をハッシュで固定できます。ML ベースの変換はそうはいかないので、変換後の Markdown 自体を git や DVC で版管理して、content hash で固定するのが現実的です。「どの PDF から、どのツールのどのバージョンで、どの Markdown が生成されたか」を台帳に残しておくと、後で追えます。

RAG システム全体の再現性については、ベクトル検索の近似性より、データのバージョン管理・演算精度・データの動的な変化のほうが非決定性の主因である、という指摘があります。つまり ANN のパラメータを気にする前に、コーパスの管理を固めたほうがよいということですね。

差分更新は、document_id / content_hash / ingestion_timestamp を持つ台帳テーブルを作っておいて、ハッシュが変わったチャンクだけ再埋め込みする形にします。削除は tombstone で明示し、位置由来の安定した ID を振っておくと、更新が正しいレコードを置き換えます。規格が改版されたとき、変更のあった節だけ処理し直せるので、1,300 ページを毎回作り直さずに済みます。

9. 手順にまとめると

段階を分けて書きます。いきなり全部やる必要はなくて、下から積み上げるのがよいと思います。

段階 やること 得られるもの
1 Docling でローカル変換 → NFKC 正規化 → 見出しベースのチャンク分割 → メタデータ付与 → 親子構成 決定論的で再現するベースライン
2 BM25 の識別子対応トークナイズ → BGE-M3 で dense + sparse → RRF 融合 → 見出しパンくずの前置 検索品質の大きな改善
3 品質ヒューリスティックで問題ページを検出 → そのページだけ VLM で再変換 → リランカをゴールデンセットで検証 表の多い章のピンポイント改善

段階 1 の時点で、決定論的に再現するコーパスが手に入ります。段階 2 で効きの大きいところを取りに行き、段階 3 は測ってから入れる、という順序です。

判断の目安としては、こうなります。

判断 基準
ページを VLM で再処理するか U+FFFD 率が閾値超、反復検出、本文量が中央値から乖離、罫線があるのに表が無い
リランカを常用するか ゴールデンセットで nDCG@10 か Recall@10 が明確に改善し、レイテンシが許容内
文脈前置を LLM 版に上げるか パンくず前置でも取りこぼす節が残る場合のみ

まとめ

調べてみて意外だったのは、埋め込みモデルの選定のような「新しくて楽しい」部分より、変換とチャンク分割という地味な前工程のほうが効きが大きそうだ、という点でした。表を割らないというだけのルールで検索の当たり方が変わり、トークナイザを識別子に合わせるだけで BM25 が 8 割改善する。上流の設計をきちんとやるのが先で、モデルを上げるのは後です。

もう一つは、ツール選定がライセンスの話とほぼ不可分だという点です。精度の高いツールほど重みの利用条件に制約がある傾向があって、業務で使うなら性能表の隣にライセンス欄を並べて見る必要があります。仕様書そのものの再配布制限もあるので、変換した Markdown をどこに置くか、クラウド API に投げてよいかも含めて、先に整理しておいたほうがよさそうです。

まだやっていないこと

正直ベースで書いておくと、この記事はまだ調査段階のもので、実測はこれからです。

  • 実際に IEEE 1800-2023 を Docling と MinerU の両方に通して、表の再現率を TEDS で比較していません。
  • 識別子対応トークナイズの 82% 改善は他分野のコーパスでの報告なので、SV / UVM の仕様書で同じ幅が出るかは分かりません。
  • ゴールデンセットをまだ作っていないので、リランカを入れるべきかどうかも判断できていません。
  • 1,300 ページを手元の環境で流したときの実時間も測っていません。

このあたりは実際に手を動かしてから、続きを書こうと思います。

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?