文書を、検索に使える形へそろえる

前の節で分けた、RAGの「事前の準備」に当たる部分です。検索や生成を始める前に、資料の本文と出典を扱える形へそろえます。

RAGの前半では、元の資料を検索に使える形へ整えます。資料はPDF、Webページ、テキスト、データベースなど、さまざまな場所にあります。形式ごとの読み取り方法は異なりますが、生成へ渡す前には、何が書かれているかと、どこから来た情報かを扱える必要があります。

LangChainのDocument loader(文書を読み込む部品)は、こうした資料をDocumentという共通の形へ読み込むために使います。Documentは、本文と付随情報をまとめたデータです。本文の項目名がpage_content、付随情報の項目名がmetadataです。読み込んだ時点では、モデルによる要約や回答生成が済んだわけではありません。

元のファイルとDocumentが、必ず一対一になるわけではありません。一つのPDFをページごとに読み込めば複数のDocumentになり、長い本文をさらに分割すれば、より小さなDocumentになります。Documentは、アプリケーションが資料の一まとまりを扱うための形だと考えてください。

metadataは、資料の意味と出典を保つ

本文だけを保存すると、その文章がどの文書の何ページにあったのか分からなくなります。metadataには、文書名、出典のURL(Web上の場所を示すアドレス)、ページ、文書ID、更新日、適用対象など、後で必要になる情報を持たせます。出典の表示や検索条件の絞り込みは、この情報を土台にします。

たとえば、本文が「交通費は精算システムで申請する」で、付随情報が「文書名:出張規程、ページ:3、版:2026年度」という形です。本文は回答の材料になり、付随情報は出典の表示や適用する版の確認に使います。これらの情報がすべて自動でそろうとは限らず、読み込み時などに必要な項目を補います。

たとえば同じ「出張規程」という名前の資料でも、年度や所属会社によって内容が違う場合があります。文章がよく似ていても、どの資料を適用するかが異なります。文書の識別情報や版を保持することで、古い規程と新しい規程が混ざる問題を見つけやすくなります。

閲覧できる部署などの情報をmetadataへ持たせることもあります。ただし、情報を書き込むだけではアクセス制御になりません。検索や取得の際に、認証された利用者に応じて条件を適用する必要があります。

なぜ文書をチャンクへ分けるのか

長い文書を小さなまとまりへ分割したものを、チャンクと呼びます。交通費について答えるのに、人事制度全体を毎回渡す必要はありません。適切なまとまりへ分けることで、質問に関係する箇所を取得しやすくし、モデルへ渡す量も管理できます。

分割では、一方を良くすると別の点が悪くなる、トレードオフと呼ばれる関係があります。細かすぎると、条件と結論、見出しと本文、表の項目と数値が離れてしまいます。大きすぎると、無関係な内容が多く混ざり、検索の焦点がぼやけます。よい分割は、文字数だけでなく、文書の構造や質問の種類に依存します。

Text splitterとoverlapの考え方

Text splitterは、文書をチャンクへ分ける部品です。見出しや段落などを利用する方法や、一定の長さを基準にする方法があります。LangChainには複数の分割方法があり、RecursiveCharacterTextSplitterは、段落や区切りを段階的に利用する代表的な選択肢です。

チャンクの境目で文脈が切れることを和らげるために、前後で一部の内容を重ねることがあります。この重なりをoverlapと呼びます。ただし、重ねる量を増やすほどよいとは限りません。似た候補が何度も取得されたり、保存するデータや処理量が増えたりするためです。

また、分割の長さが文字数なのかトークン数なのかは、利用する方法や設定によって異なります。値の単位を確認せずに、別の教材の数字だけを移すと、想定とは違う大きさのチャンクになることがあります。

読み取りが間違えば、その後の検索も困難になる

PDFから読み取った文章では、段組みの順番が崩れたり、表の行と列の関係が失われたりすることがあります。画像だけの資料では、画像から文字を読み取るOCRという処理が必要になる場合もあります。読み込めたというだけで、元の資料の意味が正しく残っているとは限りません。

この段階で生じた誤りは、後からモデルを強力なものへ変更しても解消しないことがあります。たとえば金額と対象者の対応が崩れた表を渡せば、正しい条件を判断できません。RAGを理解するときは、生成の前に、資料の読み取りと構造の保持という仕事があることを押さえます。

次の節では、こうして整えたチャンクを、質問から見つけ出すためのEmbedding、Vector store、Retrieverを説明します。