← 一覧へ

chunk の山ではなく地図を渡す 第5回:PageIndex と階層型検索

この記事の読み方
前回は Agentic RAG を見ました。

前回は Agentic RAG を見ました。

一回検索して答えるのではなく、足りなければ調べ直す。
答える前に、「この情報で十分か」を見る。

ここで自然に出てくる次の問題があります。

Agent は、どこを見に行けばよいのか。

検索器が候補を返すだけでは、まだ足りません。
長い文書、大量の PDF、PPT、Excel、フォルダに散らばった社内資料では、候補が多すぎます。

似ている chunk は返ってくる。
でも、どの章を読めばよいのか分からない。
どの表が本体なのか分からない。
同じ言葉が出ているだけの関係ないページも混ざる。
モデルは大量の断片を読まされ、途中で迷う。

この問題に対する一つの考え方が PageIndex です。

PageIndex の本質は、長い文書を平たい chunk の集まりとして扱わないことです。
文書を、上から下へたどれる地図にする。

第5回では、PageIndex と階層型検索を見ます。

flat chunk の限界

多くの RAG では、文書を chunk に分けます。

PDF を数百文字ごとに切る。
Markdown を見出しごとに切る。
スライドをページごとに切る。
表を行やセルに分ける。

そのうえで、それぞれを embedding し、質問に近い chunk を取ってきます。

これは分かりやすい方法です。
実装もしやすい。

ただし、長い文書では問題が出ます。

まず、文書全体の構造が消えます。

第 1 章の背景。
第 2 章の前提。
第 3 章の実験。
第 4 章の例外。
付録の表。

人間が文書を読むときは、この構造を見ています。
目次を見て、必要そうな章を開き、そこから該当箇所に進みます。

ところが flat chunk にすると、文書は断片の山として扱われます。

検索器は、質問と似ている断片を拾います。
でも、その断片が文書全体のどこにあるのか、前後に何があるのか、上位の章が何を言っているのかは見えにくい。

次に、ノイズが増えます。

長い文書には、似た言葉が何度も出ます。
契約書なら「解約」「支払い」「例外」。
技術仕様なら「認証」「エラー」「制限」。
調査報告なら「リスク」「影響」「対応」。

質問に近い言葉が出ている chunk は多い。
でも、本当に読むべき箇所は少ない。

RAG の失敗は、見つからないことだけではありません。
見つかりすぎることでも起きます。

LLM は、関係ない文脈を入れられると迷います。
似ているが違う断片が混ざると、答えがぼやけます。

だから、長い文書では「多く拾う」より「読む順番を作る」ほうが大事になる場面があります。

PageIndex は文書を木にする

PageIndex の考え方は、文書を木構造にすることです。

一番上には、文書全体の要約があります。
その下に章や大きなまとまりがあります。
さらにその下に、実際に読むべき本文の単位があります。

ざっくり書くと、こうです。

root:
  文書全体の概要
  ページ範囲

section:
  章ごとの概要
  ページ範囲

leaf:
  実際の本文
  人間が一度に読める量

Agent は、いきなり本文の断片を大量に読まされません。

まず root を見る。
次に、関係がありそうな section を選ぶ。
必要なら、さらに下の section に進む。
最後に leaf の本文を読む。

これは、人間の読み方に近いです。

本を読むとき、いきなりランダムな 20 ページを渡されると困ります。
まず目次を見る。
章タイトルを見る。
必要な章を開く。
その中で該当箇所を読む。

PageIndex は、この読み方を Agent に渡すための構造です。

サマリは「きれいな要約」ではなく「判断材料」

ここで重要なのは、各ノードのサマリです。

サマリというと、ただ短くまとめた文章を想像しがちです。
でも PageIndex で必要なサマリは、きれいな要約ではありません。

Agent が次に進むべきか判断するための材料です。

つまり、次のような情報が入っている必要があります。

この範囲に何が書かれているか
重要な用語
数値
日付
条件
例外
関係するページ範囲

ふわっとしたサマリでは判断材料として不十分です。

「本章ではシステムの概要を説明する」だけでは、Agent は判断できません。
「本章では OAuth 認証、API key、rate limit、401/403 エラーの扱いを説明する」と書かれていれば、次に進むべきか判断できます。

PageIndex のサマリは、読み物として美しい必要はありません。
検索と判断のために、具体的である必要があります。

これは RAG の前処理としてかなり効きます。

よい chunking は、ただ文書を切ることではありません。
あとで Agent が選べる形に、文書の構造と手がかりを残すことです。

物理構造も見る

PageIndex が面白いのは、意味だけでなく物理構造も見るところです。

ページ範囲が連続しているか。
子ノードの範囲が親ノードの中に収まっているか。
章の順番が崩れていないか。
スライドなら slide index があるか。
Excel なら sheet name や表頭が分かるか。

地味ですが、かなり大事な点です。

LLM は意味を読むのは得意です。
でも、文書処理では「場所」も効いてきます。

契約書の第 8 条なのか。
付録の表なのか。
スライド 12 なのか。
Excel の「料金表」シートなのか。
フォルダのどのファイルなのか。

企業文書では、この位置情報が根拠として効きます。

あとから人間が確認するときも、ページやスライドやシート名がないと困ります。

だから PageIndex は、意味の地図であると同時に、文書の位置を保つ仕組みでもあります。

PageIndex が効く場面

PageIndex が特に効くのは、文書が長く、構造を持っていて、ノイズが多い場面です。

たとえば、次のような資料です。

長い PDF
契約書
仕様書
社内規程
調査報告書
PPT
Excel
フォルダに分かれたプロジェクト資料

こうした文書は、単純なテキストではありません。

目次があります。
章があります。
ページがあります。
表があります。
補足資料があります。
ファイル名やフォルダ名にも意味があります。

flat chunk RAG は、この構造を壊しやすい。

PageIndex は、逆にその構造を使います。

Agent は、まず大きな地図を見る。
必要な枝を選ぶ。
下に進む。
最後に本文を読む。

この流れにすると、余計な chunk を読む量を減らせます。
また、なぜその箇所を読んだのかも説明しやすくなります。

PageIndex がいらない場面

もちろん、PageIndex がいつも必要なわけではありません。

短い記事。
構造の単純な Markdown。
すでに高品質な見出しで分かれている文書。
数千件の短い FAQ。
ログやコードのように grep や BM25 が効きやすい対象。

こうしたものに、無理に木構造を作る必要はありません。

むしろ、PageIndex の構築コストのほうが重くなります。

木を作るには、文書を読み、サマリを作り、範囲を確認し、ノード粒度を決める必要があります。
大量の文書に対して LLM で高品質なサマリを作るなら、コストもかかります。

また、サマリの質が悪いと、Agent は間違った枝に進みます。
上位ノードの説明が薄いと、そもそも正しい下位ノードを選べません。

PageIndex は、よい地図を作れたときに効きます。
地図が雑なら、迷い方が変わるだけです。

PageIndex と Agentic RAG の関係

第4回の Agentic RAG と PageIndex は、かなり相性がよいです。

Agentic RAG は、足りなければもう一度探す仕組みでした。
PageIndex は、次にどこを探すかを選びやすくする文書地図です。

つまり、こうつながります。

Agentic RAG:
  足りない情報を見つける

PageIndex:
  その情報がありそうな場所へ下りる

たとえば、契約の返金条件を調べているとします。

最初に root を見る。
契約全体に「料金」「解約」「例外」「付録」があると分かる。
次に「解約」章を見る。
そこには通知期限があるが、返金額は付録の料金表に依存すると分かる。
次に「付録:料金表」へ進む。
最後に該当する表を読む。

これは、単なる top-K 検索ではありません。

調査の経路です。

PageIndex があると、Agentic RAG の「次に何を探すか」が具体化しやすくなります。

ベクトル検索の装飾ではない

ここで誤解しやすい点があります。

PageIndex は、ベクトル検索で拾った chunk を少し整理するための飾りではありません。
発想としては、もっと手前から違います。

ベクトル検索は、質問に近い断片を探します。
PageIndex は、文書の構造を見ながら、どの枝をたどるべきかを選びます。

つまり、中心にあるのは類似度ではなく、探索の経路です。

Agent は、まず文書全体や章のサマリを読む。
そこで「この章に答えがありそうだ」と判断する。
必要なら、さらに下の節へ進む。
最後に本文を読む。

この流れは、ベクトル検索なしでも成り立ちます。
root から順に Agent が読んで選んでもよい。
BM25 でノードのサマリを探してもよい。
もちろん、実装上は上位ノードのサマリにベクトル検索を使ってもよい。

ただし、その場合でも主役はベクトル検索ではありません。

検索対象が「本文 chunk だけ」ではなくなります。

本文そのもの。
章のサマリ。
ページ範囲。
表の見出し。
スライド名。
ファイル名。
フォルダ構造。

これらを使って、Agent が「次にどこを読むか」を決める。
ここが PageIndex の肝です。

だから PageIndex は、検索器の種類ではありません。
文書を、推論しながらたどれる形に変える設計です。

ベクトル検索は「近いもの」を探します。
PageIndex は「読む筋道」を作ります。

文書処理は RAG の地味な本丸

RAG の話をすると、ついモデルやベクトルデータベースに目が行きます。

でも、企業 RAG で本当に負担が大きいのは、文書を AI が読める形にするところです。

PDF のテキスト抽出が崩れる。
表が壊れる。
脚注が本文に混ざる。
スライドの読み順が分からない。
Excel の表頭が消える。
ファイル名やフォルダ名にある意味が落ちる。

この状態で、どれだけ高性能な検索器を入れても解決しにくくなります。

モデルが間違えたように思えても、実は入力文書が壊れている。
検索が弱いように思えても、実は chunking で文脈を切りすぎている。
回答がぼやけるように思えても、実はノイズ chunk を入れすぎている。

PageIndex の価値は、ここを正面から扱うところです。

RAG の前処理は、単なるデータ整形ではありません。
後続の Agent がどう考えるかを決める、認知の入口です。

最小構成で試すなら

PageIndex の考え方を小さく試すなら、最初から大きなツールを作る必要はありません。

一つの長い文書に対して、次の 4 つを作ればよいです。

document_summary
section_summaries
leaf_texts
page_or_location_ranges

そして、Agent にこう使わせます。

まず document_summary を読む
関係しそうな section を選ぶ
必要なら leaf_text を読む
答えに使った location を残す

これだけでも、単純な chunk 検索とは違う動きをします。

さらに余裕があれば、各 section summary に具体的な手がかりを入れます。

用語
数値
日付
条件
例外
表や図の有無
関連ページ

ここが薄いと、地図として使えません。

PageIndex の品質は、サマリの品質です。

第5回の結論

長い文書を RAG に入れるとき、問題は「どの chunk が質問に近いか」だけではありません。

どの章を見るべきか。
どの表が根拠か。
どのページ範囲に答えがありそうか。
どの順番で読めばよいか。

これを失うと、RAG は断片の山を読むだけになります。

PageIndex は、文書を山ではなく地図にする考え方です。

Agentic RAG が「足りないならもう一度探す」仕組みだとすれば、PageIndex は「次にどの枝をたどるか」を助ける仕組みです。

次回は、ここまで作ってきた RAG をどう評価するかを見ます。
検索できているか。
根拠に沿っているか。
ノイズで壊れていないか。
失敗をどう集め、どう直すか。

第6回では、評価と失敗モードを扱います。

―― AI未来編集室「AIウォッチ」

← 一覧へ