JA EN
体系RAG・検索拡張
·★ 会員·12分で読めます

チャンキング戦略 — 分け方で検索は決まる

RAGの精度の大半は「文書をどう切るか」で決まる。固定長とオーバーラップの算数、構造分割、意味分割、親子チャンク、そして鬼門である表と数式の扱いまでを1から解説する。

対象textタスクretrieval

分厚いマニュアルを、裁断機にかける

手元に500ページの業務マニュアルがあるとします。必要なときに必要な箇所だけ取り出せるようにしたい。あなたは綴じを落としてバラにし、ファイルすることにしました。ここで最初の決断が必要になります。どの単位で束ねるかです。

1枚ずつバラバラにすれば、狙ったページをピンポイントで取り出せます。しかし1ページ目の途中で始まった説明が2ページ目に続いていたら、片方だけ取り出しても意味が通りません。逆に章ごとに束ねれば話は途切れませんが、「この30ページの束のどこかに書いてある」という粗さになり、束そのものが何の話なのかもぼやけます。

RAG(検索拡張生成)におけるチャンキングは、まさにこの裁断作業です。そして厄介なことに、この工程は検索のにあります。切り方を間違えると、後段でどんなに高性能な埋め込みモデルやリランカーを使っても取り返せません。全体の流れはRAGの基礎と設計パターンにありますが、この記事はその一工程だけを深掘りします。

なぜ分けなければならないのか

理由は3つあり、どれも独立しています。

1つ目は、埋め込みが1本のベクトルだからです。テキストを数百次元の数値に変換するとき、入力が長いほど「その中の多様な話題」が1本の向きに押し込められます。休暇規程と経費精算と防災訓練が同居した塊は、どの話題からも中途半端に遠い、当たり障りのない方向を向いてしまいます。埋め込みの仕組みは埋め込み(Embedding)を1から理解するを参照してください。

2つ目は、LLMに渡せる量に上限があることです。コンテキスト窓は有限で、トークン数はそのまま費用と応答時間になります。

3つ目は、引用の粒度がそのまま根拠の粒度になることです。「この30ページのどこかが根拠です」と言われても、利用者は検証できません。

大きすぎる失敗と、小さすぎる失敗は形が違う

チャンクが大きすぎるとき起きるのは希釈です。質問と本当に関係があるのは塊の中の3行なのに、残りの数百行が平均化に加わり、類似度が薄まって上位に上がってこない。運よく上位に来ても、無関係な文がコンテキストの大半を占め、生成側が根拠を取り違える確率が上がります。

チャンクが小さすぎるとき起きるのは文脈の欠落です。「同社は」「この場合は」といった指示語の参照先が別チャンクに残る。表の1行だけが切り出されて列見出しが失われる。条文の但し書きだけが単独で検索に引っかかる。どれも、断片としては正しいのに答えとしては誤りを生みます。

つまり両側に別種の事故があり、最適値は文書の種類ごとに違う。「万能のチャンクサイズ」が存在しない理由がここにあります。

さらに、チャンク長を変えると埋め込みベクトルの長さ(ノルム)の分布まで動きます。正規化していない内積で検索していると、それだけで長いチャンクが不当に上位へ入り込みます。下の図でクエリをドラッグし、物差しを内積・コサイン・L2で切り替えてみてください。同じ文書集合でも上位の顔ぶれが入れ替わります。

FIG 1物差し(内積/コサイン/L2)を変えるとtop-5の顔ぶれが変わる。正規化しない内積では、向きが少しずれていても長いベクトルが割り込む。チャンク長はこのノルムを動かす

固定長分割: まず算数を押さえる

もっとも単純な方法は、一定の長さで機械的に切り、境界で文が途切れる問題をオーバーラップ(前のチャンクの末尾を次の先頭に重ねる)で緩和するやり方です。実装は RecursiveCharacterTextSplitter のような分割器に chunk_sizechunk_overlap を渡すだけで、多くの現場の出発点になっています。

押さえるべきは、この2つがインデックスの規模と費用を直接決めるという点です。文書全体の長さを LL、チャンク長を cc、オーバーラップを oo とすると、チャンクの個数は次のようになります。

N=LocoN = \left\lceil \frac{L - o}{c - o} \right\rceil
(1)

つまりこの式は「文書は何枚に切れるか」を数えているだけです。1枚ぶんの長さ cc のうち、末尾の oo は次の紙にもう一度写すので、前へ進む距離は coc - o しかない。最後に半端が出たらそれも1枚と数える、というのが両側の切り上げ記号  \lceil\ \rceil の意味です。

分母の coc - o が「1チャンク進むごとに新しく読む量」(ストライド)です。オーバーラップを増やすと1歩の幅が縮むので、同じ文書でもチャンク数が増えます。オーバーラップ率を r=o/cr = o / c と置くと、埋め込みに投げる総トークン数はもっと直感的な形になります。

NcL1rN \cdot c \approx \frac{L}{1 - r}
(2)

左辺の NcN \cdot c は全チャンクの長さを足し合わせた量、つまり埋め込みモデルに実際に読ませる総量です。これが元の文書の長さ LL1r1 - r で割った値に近づく、というのがこの式の言っていることです。

オーバーラップ20%なら埋め込み費用とインデックス容量は約1.25倍、50%なら約2倍という意味です。式(2)は「重ねた分だけ同じ文字を二度買っている」と言っているにすぎません。オーバーラップは無料の保険ではありません。

もう1つの落とし穴は長さの単位です。日本語は1文字が複数トークンになることも珍しくなく、「1000文字」のつもりが埋め込みモデルの入力上限を超えて末尾が黙って捨てられる、という事故が起きます([トークナイザを1から理解する](/ja/a/tokenizers-explained/))。分割器には本番と同じトークナイザを渡すのが原則です。

この先にあるもの

§

ここから先は会員限定です

解説記事371本・教科書26章・学生モード48単元・論文精読6本が、月額¥490ですべて読み放題になります。新しい解説は毎日3本ずつ増えます。いつでも解約でき、解約後も期間の終わりまで読めます。

会員の方はログインすると続きが表示されます

コメント

コメントにはログインが必要です