BookRAGは、書籍・技術マニュアル・ハンドブックのように章立てを持つ長い文書を対象にしたRAG(検索拡張生成)の手法です。文書の見出し階層をツリーとして、本文に出てくる用語どうしの関係をナレッジグラフとして索引にし、質問の種類に応じてエージェントが検索手順を組み立てます。香港中文大学(深セン)のShu Wang氏らが2025年12月3日にarXiv(2512.03413)で公開し、データベース分野の国際会議VLDB 2026に採録されました。
固定長のチャンクに刻む一般的なRAGでは、「第4章の表はいくつあるか」「5章の結果と4章の実験設定を比べると」といった構造をまたぐ質問で根拠を取りこぼします。この記事では、PVLDB掲載の論文と公式リポジトリ(2026年10月1日時点)をもとに、BookRAGの仕組み、ベンチマーク結果の読み方、実装を動かすときの環境とライセンス、日本語文書に使うときの注意点を整理します。
まとめ:BookRAGの要点
- 索引はBookIndexの3要素:見出し階層のツリー(Tree)、用語と関係のナレッジグラフ(KG)、用語がどの節に出てきたかを結ぶGT-Link。
- 質問を3種類に分けて手順を変える:単一箇所で答えが出る質問、複数箇所の根拠を合わせる質問、文書全体を数える・まとめる質問。11個のオペレーターを組み合わせて検索する。
- 論文の結果は既存手法を大きく上回る:完全一致率はMMLongBenchで43.8%(次点27.5%)、M3DocVQAで61.0%(次点43.0%)。ただしLLMはQwen3-8B、評価対象は構造の読めない文書を除いた英語文書。
- 実装はGitHubのsam234990/BookRAG:Python 3.12、PDF解析にMinerU 2.1.11、LLM・VLM・埋め込み・リランカーの各サーバーとGPUが別途必要。pipパッケージやリリース版はなく、自分のPDFへの質問はデータセットモードで実行する。
- MinerUと組み合わせた全体はAGPL-3.0:独自コードはApache-2.0とのデュアルだが、既定構成のまま配布する場合や、改変してネットワーク越しに提供する場合はAGPLの義務を負う。
BookRAGの仕組み:BookIndexとエージェント型の検索
BookRAGの処理は、文書ごとに索引を作るオフライン段階と、質問を受けて検索・回答するオンライン段階の2段に分かれます。設計の下敷きは情報採餌理論(Information Foraging Theory)で、手がかり(scent)を頼りに情報の集まった場所(patch)へ移動してから読み込む人の行動を、検索手順に置き換えています。
BookIndexの3要素:Tree・KG・GT-Link
論文はBookIndexを B=(T, G, M) の3つ組で定義しています。
- Tree(T):章・節を内部ノード、本文・表・画像・数式のブロックを葉ノードとする木。目次の役割を果たし、「第5章の配下」のように範囲を指定して読むときの単位になる。
- Knowledge Graph(G):各ノードから抽出したエンティティ(用語・固有名)と関係。離れた章に出てくる同じ概念をつなぐ。
- GT-Link(M):エンティティから、それが抽出された木ノードの集合への対応。グラフ上で重要と判定した用語を、文書のどの節を読めばよいかに変換する。
GraphRAGは用語の関係を索引の中心に置き、章立てを索引として持ちません。ツリーで探す方式は章立てを持つ一方、用語が別の章のどこに出てくるかを索引として持ちません。GT-Linkで両者を明示的に結んだ点がBookRAGの核です。
索引の作り方:レイアウト解析・見出しの補正・エンティティ統合
ツリーはPDFのレイアウト解析から作ります。実装ではMinerUでページをテキスト・表・画像・数式・見出しのブロックに分け、読み順に並べます。MinerUは見出しの階層レベルを付けず、図のキャプションや罫線のない表の見出しを見出しと誤認することがあるため、BookRAGは見出し候補だけをLLMに渡し、文字列・フォントサイズ・ページ番号から「本当に見出しか」「何階層目か」を判定させます(Section Filtering)。誤りと判定したブロックは本文に戻します。
グラフは各ノードから作ります。テキストのノードはLLMで、画像を含むノードはVLM(画像も読めるモデル)でエンティティと関係を抽出します。図表も検索対象に含める点はマルチモーダルRAGと共通です。表は表そのものを1つのエンティティにし、行見出し・列見出しを「ContainedIn」関係でつなぎます。
抽出の後には、同じ概念が別名で分かれたエンティティを統合する処理(Gradient-based Entity Resolution)が入ります。新しいエンティティに似た既存エンティティをリランカーで採点し、スコアが急に落ちる位置(勾配の閾値g、既定0.6)で候補を切り、迷う場合だけLLMに選ばせます。名前の完全一致で統合する方式と比べ、エンティティ数は約12%減り、グラフの密度は20%以上上がったと報告されています。
質問の3分類と11個のオペレーター
質問を受けると、エージェントがまず種類を判定します。実装(Core/rag/gbc_plan.py)では simple・complex・global の3値で、論文のSingle-hop・Multi-hop・Global Aggregationに対応します。
| 分類 | 質問の例 | 検索手順 |
|---|---|---|
| Single-hop | Information Scentの定義は? | Extract→Select→Reason→Skyline→Reduce |
| Multi-hop | 2つの方式の違いは? | Decompose→各小問にSingle-hop→Map→Reduce |
| Global Aggregation | 第4章の図はいくつ? | Filter_Modal/Filter_Range→Map→Reduce |
手順を組む部品が11個のオペレーターで、役割ごとに4種類に分かれます。
- Formulator(2個):Decomposeが複合質問を小問に分け、Extractが質問中の用語をグラフのエンティティに対応づける。
- Selector(4個):Filter_Modal(表・画像などの種類)とFilter_Range(ページ・節の範囲)で絞り込み、Select_by_EntityとSelect_by_Sectionで該当する節の部分木を丸ごと取り出す。
- Reasoner(3個):Graph_Reasoningが部分グラフでPageRankを回して用語の重要度を出し、GT-Linkで節の点数に変換する。Text_Reasoningは質問との意味的な関連を採点し、Skyline_Rankerが2つの点数で候補を絞る。
- Synthesizer(2個):Mapが個々の根拠から部分回答を作り、Reduceがそれらを最終回答にまとめる。
先に範囲を絞ってから採点する順序(narrow-then-reason)が効率を左右します。Selectorを外した構成では、Qasperで使用トークンが2倍を超え、検索で取得されたノード数は平均8.6から15.9に増えました。
Skylineで根拠ノードを絞る仕組み
Skyline_Rankerは、グラフ由来の点数とテキスト由来の点数のどちらで見ても他のノードに負けている(支配されている)ノードを捨て、残りを根拠にします。上位k件のように件数を決めず、2つの点数を足し合わせもしないため、片方の点数だけが突出したノードも残ります。次はGT-Linkによる点数の変換とSkylineの判定を最小構成で再現したPythonコードです(エンティティの重要度は仮の値)。
# GT-Link でエンティティ重要度を木ノードへ写し、Skyline で残すノードを決める最小例
entity_score = {"LSTM-ELMo": 0.42, "accuracy": 0.35, "cosine distance": 0.23} # PageRank 後の I_G を仮置き
gt_link = { # エンティティ -> 出現した木ノード(M)
"LSTM-ELMo": ["4.2", "5.1"],
"accuracy": ["5.1", "5.2", "5.3"],
"cosine distance": ["3.1", "5.2"],
}
text_score = {"3.1": 0.85, "4.2": 0.55, "5.1": 0.80, "5.2": 0.62, "5.3": 0.20} # S_T(クエリとの意味的関連)
graph_score = {n: 0.0 for n in text_score} # S_G = I_G x M
for ent, nodes in gt_link.items():
for n in nodes:
graph_score[n] += entity_score[ent]
def dominated(a, b): # b が a を支配するか(両方の軸で以上・どちらかで超える)
return (b[0] >= a[0] and b[1] >= a[1]) and (b[0] > a[0] or b[1] > a[1])
pts = {n: (round(graph_score[n], 2), text_score[n]) for n in text_score}
skyline = [n for n in pts if not any(dominated(pts[n], pts[m]) for m in pts if m != n)]
top2 = sorted(pts, key=lambda n: sum(pts[n]), reverse=True)[:2]
for n in sorted(pts):
print(n, "S_G=%.2f S_T=%.2f" % pts[n], "残す" if n in skyline else "-")
print("Skyline:", sorted(skyline))
print("合計点の上位2件:", top2)
Python 3.9で実行した出力です。
3.1 S_G=0.23 S_T=0.85 残す
4.2 S_G=0.42 S_T=0.55 -
5.1 S_G=0.77 S_T=0.80 残す
5.2 S_G=0.58 S_T=0.62 -
5.3 S_G=0.35 S_T=0.20 -
Skyline: ['3.1', '5.1']
合計点の上位2件: ['5.1', '5.2']
なお公開実装(Core/rag/gbc_retrieval.py)では、Skylineで残ったノードが topk(既定10)に満たず候補が10件以上あると、グラフとテキストそれぞれの上位5件を追加するフォールバックが入ります。上の最小例ではこの処理を省いています。
合計点で上位2件を取ると、テキストの関連が最も高い節3.1が落ち、5.1と点数の傾向が似た5.2が入ります。Skylineは3.1を残し、5.2を捨てます。論文の実験では、Skyline後に残ったノードはMMLongBenchで平均9.87件、M3DocVQAで6.86件、Qasperで8.6件で、件数は上位10件の検索と同程度でした。
BookRAGのベンチマーク結果と数値の読み方
3データセットでの正解率と検索再現率
論文は、長文PDFのMMLongBench(85文書・平均42.16ページ)、Wikipedia由来のM3DocVQA(500文書)、科学論文のQasper(192文書)で、11の手法と比べています。主な結果は次のとおりです(論文のTable 4より抜粋。MMLongBenchとM3DocVQAは完全一致率、Qasperは正解率、単位は%)。
| 手法 | MMLongBench | M3DocVQA | Qasper |
|---|---|---|---|
| BookRAG | 43.8 | 61.0 | 55.2 |
| DocETL | 27.5 | 40.9 | 42.3 |
| GraphRanker | 21.2 | 43.0 | 32.9 |
| RAPTOR | 21.3 | 34.3 | 39.4 |
| Vanilla RAG | 16.5 | 36.5 | 40.6 |
| Tree-Traverse | 12.7 | 33.3 | 27.3 |
| GraphRAG-Local | 7.7 | 23.7 | 35.9 |
根拠ブロックの検索再現率も、BookRAGは57.6%・71.2%・63.5%で、レイアウト解析を使う他手法の最大値(M3DocVQAでGraphRankerの44.5%)を上回りました。論文の「次点を18.0%上回る」は、M3DocVQAの完全一致率61.0%と43.0%の差で、比率ではなくポイント差です。
BookRAGの評価条件:文書選別・質問合成・使用モデル
この結果をそのまま自社文書での期待値にしないでください。論文の実験には次の条件があります。
- 文書を選別している:画像の劣化がひどい文書と、プレゼン資料のように論理的な階層を持たない文書は、比較の公平性のために評価から除外された。
- 集計型の質問を合成している:M3DocVQAとQasperには「数える・まとめる」質問がほぼないため、データセットごとに125問を人手確認つきで合成し追加した(評価全体の20%未満)。
- モデルは小型で統一:全手法でLLMはQwen3-8B、VLMはQwen2.5VL-30B(論文の表記)、埋め込みはQwen3-Embedding-0.6B、リランカーはQwen3-Reranker-4B。上位k件の手法はk=10。GPUはNVIDIA RTX A5000×8。
- Tree-TraverseはPageIndexそのものではない:論文がPageIndexに着想を得て実装した比較用の手法で、製品版のPageIndexの性能を示す数字ではない。
コスト面では、MMLongBenchでの質問処理のトークン消費がDocETLの5,300万超に対しBookRAGは500万未満、索引の保存容量は1文書平均52.4MBでした。一方、索引の構築時間はMMLongBench全体で145,107秒(85文書で割ると1文書あたり約28分)かかっており、GraphRAGの172,625秒と同じ水準です。
BookRAGの構成要素別評価:Planning除去による精度低下
部品を1つずつ外した比較(MMLongBenchの完全一致率)では、質問の分類と手順の組み立てを外した「w/o Planning」が43.8%から30.8%へ最も大きく落ちました。プランもオペレーターも使わず、ツリーとグラフの上位k件をLLMに渡すだけの構成は21.1%です。BookIndexを作っても、質問ごとに手順を変えなければ効果の大半は出ません。
GraphRAG・PageIndex・RAPTORとBookRAGの違い
「ナレッジグラフを使うRAG」としてGraphRAGと並べて語られますが、グラフの使い方が違います。
| 手法 | 索引の中心 | 文書の章立て | 検索手順 |
|---|---|---|---|
| BookRAG | ツリー+KG+GT-Link | 見出し階層をそのまま使う | 質問ごとに動的 |
| GraphRAG | KGのコミュニティ要約 | 使わない | Local/Global/DRIFTなど |
| RAPTOR | チャンクの再帰的クラスタ要約 | 使わない(意味で再構成) | 固定 |
| PageIndex | 目次ツリー(ページ範囲) | 見出し階層を使う | LLMがツリーを推論で探索 |
GraphRAGはコーパス全体をLeidenアルゴリズムでコミュニティに分けて要約する方式で、多数の文書から全体の傾向を問う質問向けです。1冊単位の質問が中心の論文の比較では、GraphRAG-GlobalはMMLongBenchで5.3%にとどまりました。PageIndexは目次ツリーを使う点でBookRAGに近く、違いは用語のグラフとGT-Linkを持つかどうかです。
GitHub実装(sam234990/BookRAG)の動かし方
公式実装はGitHubのsam234990/BookRAGで公開されています。2026年10月1日時点で最終コミットは2026年7月22日(ライセンス表記の追加)、スターは132件、リリース版はなく、PyPIにもbookragというパッケージはありません。論文の実験を再現するためのコードで、任意のPDFに質問するアプリとしては作られていません。
動作環境とモデルサーバーの準備
READMEの要件はPython 3.12で、environment.yml から作るconda環境名は gbc-rag です。requirements.txtはtorch 2.7.1・transformers 4.51.3・chromadb 1.0.13などを固定しており、MinerUは2.1.11に固定されています。PyPIのMinerU最新版は4.0.10なので、MinerUを最新に上げると互換が崩れる可能性があります。
BookRAG自体はモデルを内蔵せず、OpenAI互換などのAPIで外部のサーバーを呼びます。論文の設定を収めた config/gbc.yaml では、次の5つのサービスをlocalhostの別ポートで立て、さらにGPU上でローカルのモデルを読み込む構成です。
- LLM(Qwen3-8B-AWQ、ポート8003)とVLM(Qwen2.5-VL、ポート8000)
- MinerUのPDF解析サーバー(
vlm-sglang-client方式、ポート30000) - 埋め込み(Qwen3-Embedding-0.6B、ポート8007)とリランカー(Qwen3-Reranker-4B、vLLM、ポート8011)
- ローカル読み込み:画像も扱う埋め込み・リランカーのgme-Qwen2-VL-2B-Instruct(
vdb.embedding_configとrag.mm_reranker_configのdeviceでGPUを指定)
雛形の config/default.yaml は、これらのモデル名・api_base・device・mineru.server_url などが TODO のままです。すべて埋めないと動きません。OpenAIなどの外部APIをLLMに指定することもできますが、その場合は文書の内容が索引作成の段階で外部へ送られます。
自分のPDFに質問するときの実行手順と実装上の制約
main.pyには、データセット設定(-d)を渡すデータセットモードと、省略したときの単一ファイルモードがあります。2026年7月22日時点のソースを読むと、単一ファイルモードには次の制約があります。
rag -qは動かない:単一ファイルモードはrun_inference(config=..., queries=[...])を呼ぶが、関数の引数はconfig・data_df・dataset_nameで、queriesを受け取らない。そのまま実行するとTypeErrorになる。--stageが無視される:単一ファイルモードのbuild_index呼び出しはstageを渡さないため、常に全段階(all)を実行する。--numの既定値が2:--numが偶数のとき、MinerUの接続先は設定ファイルにかかわらずlocalhost:30001に上書きされる。
このため、自分のPDFに質問するならデータセットモードを使います。READMEの形式(question・answer・doc_uuid・doc_path)で質問のJSONを作り、Scripts/cfg/example-m3docVQA.yaml を雛形にデータセット設定(dataset_path・working_dir)を書いてから、次のように実行します。
git clone https://github.com/sam234990/BookRAG.git
cd BookRAG
conda env create -f environment.yml
conda activate gbc-rag
# -c と -d、--num・--nsplit はサブコマンドより前に置く
python main.py -c config/gbc.yaml -d my_dataset.yaml --num 1 --nsplit 1 index --stage tree
python main.py -c config/gbc.yaml -d my_dataset.yaml --num 1 --nsplit 1 index --stage graph
python main.py -c config/gbc.yaml -d my_dataset.yaml --num 1 --nsplit 1 index --stage vdb
python main.py -c config/gbc.yaml -d my_dataset.yaml --num 1 --nsplit 1 rag
データセットモードでは --stage が反映されます。all はツリーから作り直すため、最初に tree だけを実行して見出し階層を確かめ、graph・vdbの順に進めるほうが手戻りが少なくなります。索引は working_dir の下に doc_uuid ごとに保存されます。
ライセンス:Apache-2.0とAGPL-3.0の範囲
リポジトリ直下のLICENSEはAGPL-3.0ですが、LICENSE_SCOPE.mdによると、Core配下の独自コードとmain.pyは「Apache-2.0 OR AGPL-3.0-only」のデュアルライセンスです。一方、既定構成が依存するMinerU 2.1.11はAGPL-3.0で、MinerUのコードを含む・改変したファイルはAGPL-3.0-onlyに限られます。MinerUと組み合わせた全体にはAGPLが適用されます。配布時の対応ソース提供条件に加え、改変版をネットワーク経由で利用させる場合には、その利用者へ対応ソースを取得する手段を提供する義務があります。
商用サービスに組み込むなら、PDF解析をDocling(MIT)などへ差し替えるのが選択肢になります。ただし、差し替えだけでCore全体がApache-2.0になるわけではなく、MinerU由来のファイルや第三者のライセンス通知を個別に確認する必要があります。AGPLの条件を満たして商用提供する構成も選べます。評価データ(datasets)・スクリプト・設定ファイル・論文PDFはソフトウェアのライセンス対象外で、論文自体はCC BY-NC-ND 4.0です。
日本語の文書にBookRAGを使うときの確認点
論文が評価に使った3データセットはいずれも英語の文書で、日本語での精度は報告されていません。日本語の社内規程やマニュアルに適用するなら、次の4点を先に確認してください。
- MinerUの言語設定:設定ファイルの既定は
mineru.lang: en。日本語PDFでは解析方式に合わせて言語指定を見直し、データセットモードの--stage treeで見出しが拾えているかを確かめる。 - プロンプトが英語:質問分類やエンティティ抽出のプロンプトは英語で書かれている。日本語の質問・本文でどこまで動くかはLLMの多言語性能しだいで、論文では検証されていない。日本語の文書で使うなら、プロンプトの日本語化やエンティティ名の出力言語の指定を検討する。
- 見出し判定がフォントに依存する:Section Filteringはフォントサイズとページ番号を手がかりにするため、見出しのスタイルが統一されていないPDFでは階層の判定を誤る可能性がある。
- 表記ゆれの統合:エンティティ統合はリランカーの点数で判断する。全角・半角や「ナレッジグラフ」「知識グラフ」の統合は、日本語に強いリランカーを選ぶかどうかで結果が変わる。
BookRAGを採用すべきでない場面
BookRAGは「章立てのある長い文書1冊に、構造をまたぐ質問をする」用途に絞った手法です。次の条件に当てはまるなら、通常のRAGパイプラインを改善するほうが早く効果が出ます。
- 文書が短い・階層がない:論文は、論理的な階層を持たない文書の例としてスライドを挙げ、評価から除外している。FAQ集やチャットログについても、章立てがなければ本記事では採用候補から外す。見出し階層がなければツリーが機能しない。
- 更新のたびに索引を作り直す余裕がない:MMLongBench(平均42ページ)の索引構築は、GPU 8枚の論文環境で1文書あたり平均約28分かかり、LLMとVLMの呼び出しも伴う。更新される文書数×約28分が、更新から回答に反映するまでの許容時間に収まるかで判断する。
- 応答の速さが最優先:論文自身が、テキストだけのRAGのほうが遅延とトークン消費は小さいと書いている。BookRAGは質問ごとに分類・抽出・採点・統合のLLM呼び出しを重ねる。
- そのまま本番に載せたい:パッケージ化されておらず、モデルサーバー5種の運用とAGPLの扱いを自前で引き受ける必要がある。
論文でも、固定長のチャンクをレイアウト解析に基づく意味的な分割に変えたLayout+Vanillaは、Vanilla RAGを上回りました(MMLongBenchで16.5%→18.1%)。チャンク設計を見直してから、それでも構造をまたぐ質問に答えられない文書群にだけBookRAGの考え方を持ち込むのが現実的です。
BookRAGに関するよくある質問
BookRAGは無料で使えますか?
BookRAGは論文の手法と研究用のオープンソース実装で、有料のサービスや料金プランはありません。かかるのは、LLM・VLM・埋め込みモデルを動かすGPUやAPIの費用です。
BookRAGのGitHubリポジトリはどこですか?
github.com/sam234990/BookRAG です。論文のフルバージョンPDF(BOOKRAG_VLDB_2026_full.pdf)、実験で使った絞り込み済みの質問ファイル、比較手法(RAPTOR・GraphRAGなど)の設定ファイルも同じリポジトリに入っています。
BookRAGの論文はどこで読めますか?
arXivの2512.03413で読めます(初版は2025年12月3日公開)。VLDB 2026採録版はPVLDB第19巻第9号の2358〜2371ページに掲載されており、リポジトリには付録を含むフルバージョンのPDFがあります。
BookRAGは書籍にしか使えませんか?
書籍に限りません。論文が想定するのは、技術ハンドブック、APIリファレンス、運用ガイド、財務報告書など、目次と多段の章立てを持つ長い文書全般です。名前のBookは「本のような構造」を指しています。
BookRAGとGraphRAGはどちらを選べばよいですか?
1冊のマニュアルや報告書から特定の表・節を探す質問が中心ならBookRAG、多数の文書から全体の傾向をまとめる質問が中心ならGraphRAGが向きます。