small-to-big と文脈圧縮 — 検索する単位と渡す単位を分ける
チャンクを小さくすると当たるが文脈が足りない、大きくすると当たらないというジレンマを解消できる。親子チャンク・窓の拡張・文脈圧縮の3手法を使い分けられるようになる。
- チャンクの粒度に最適解が無いのは、検索と生成という目的の違う2つの要求を1つの単位に兼ねさせているから。分離すれば両立できる。
- small-to-bigは小さい単位で検索して、当たったら親の大きい単位を生成へ渡す。索引と本文を別に持つだけで実装でき、費用対効果が最も高い。
- 逆方向が文脈圧縮で、引いた文書から質問に関係する部分だけを抽出してから渡す。文脈枠の節約と、無関係な記述に引きずられる事故の抑制に効く。
チャンク分割の設計で触れたジレンマを、正面から解きます。
チャンクを小さくする
→ 1本のベクトルが1つの話題を表すので検索は当たる
→ しかし断片だけでは意味が完結せず、生成に必要な文脈が足りない
チャンクを大きくする
→ 生成に十分な文脈が渡せる
→ しかし複数の話題が混ざったベクトルになり、検索が当たらない
粒度をどう調整しても片方が犠牲になるのは、目的の違う2つの要求を1つの単位に兼ねさせているからです。分ければ両立します。
横にスクロール
small-to-big:小さく引いて、大きく渡す
考え方は単純です。検索の索引には小さい単位を入れ、当たったらその親である大きい単位を生成へ渡します。
索引に入れる(検索用) 生成に渡す(回答用)
小チャンク A-1 ──親──┐
小チャンク A-2 ──親──┼──> 大チャンク A(節まるごと)
小チャンク A-3 ──親──┘
検索で A-2 が当たる → 生成には A 全体を渡す
実装は、チャンクにメタデータとして親のIDを持たせ、検索後に親を引き直すだけです。ベクトルDBには小チャンクだけを入れ、親の本文は通常のキーバリューストアや元文書から取得します。追加のモデルもコストもかからず、これだけで体感がはっきり変わることが多い手法です。
親の単位は文書の構造から決めます。見出し1つぶん、あるいは節1つぶんが自然な単位です。
| 方式 | 索引に入れるもの | 生成に渡すもの | 向く場面 |
|---|---|---|---|
| 親子チャンク | 小チャンク(文〜段落) | 親チャンク(節・見出し単位) | 文書に見出し構造がある |
| 窓の拡張 | 小チャンク | 当たったチャンクの前後N個 | 構造が無いプレーンテキスト |
| 要約索引 | 各節の要約文 | 節の本文 | 本文が長く冗長、要約で意味が代表できる |
| 文書単位で渡す | 小チャンク | 元文書まるごと | 文書が短く、文脈枠に収まる |
窓の拡張は、構造が無い文書向けの簡易版です。当たったチャンクの前後 N 個を機械的に連結して渡します。実装が最も簡単で、議事録や書き起こしのような構造の乏しいテキストに向きます。
要約索引は逆向きの発想で、各節の要約を索引に入れ、当たったら本文を渡します。長く冗長な文書では、本文をそのままベクトル化するより要約のほうがクリーンな意味表現になります。ただし要約の生成に一度コストがかかり、要約が落とした情報は永久に検索できなくなる点に注意が要ります。
small-to-bigでは、同じ親を持つ小チャンクが複数ヒットすることが頻繁に起こります。素朴に実装すると同じ親を3回渡してしまい、文脈枠を3倍無駄に消費します。親のIDで重複排除する工程を必ず入れてください。上位5件を引いたのに親が2つしかない、というのは正常な挙動です。
文脈圧縮:引いた後に削る
small-to-big が「渡す量を増やす」方向なら、文脈圧縮は逆に「引いた文書から要らない部分を削る」方向です。両者は矛盾せず、順に適用できます。
検索で引いた文書(節まるごと、2000字)
↓ 質問に関係する部分だけを抽出
渡す文脈(300字)
抽出の方法は2通りあります。
抽出型は、文書を文単位に分け、質問との関連度が高い文だけを残します。軽量なモデルや、そもそも文単位の類似度計算で実現でき、コストが低いのが利点です。ただし文をまたぐ文脈(「この設定は」の指示語)が壊れることがあります。
生成型は、LLMに「この文書のうち質問に答えるのに必要な部分を抜き出せ」と指示します。指示語を解決した形で書き直せる一方、LLM呼び出しが文書の数だけ増えるのでコストが跳ねます。
文脈圧縮が効くのは次の2点です。
- 文脈枠の節約。 圧縮すればより多くの文書を渡せます。
- 無関係な記述に引きずられる事故の抑制。 これが本命です。長い文書の中に質問と無関係だが紛らわしい記述があると、LLM がそちらを拾って誤答します。渡す量を増やすほど、この事故の確率は上がります。
長い文脈窓を持つモデルが増え、「全部渡せばいい」という発想が出てきますが、実際には文脈が長くなるほど中央の情報への注意が薄くなる傾向が知られています。加えて、無関係な文書が混じると回答が悪化することも報告されています。文脈枠に余裕があるからといって無条件に詰め込むのは、精度・コスト・レイテンシのすべてを悪化させる可能性があります。
組み合わせる順序
3つの手法は次の順に効きます。
1. 小チャンクで検索 (当てる精度を上げる)
2. リランキングで並べ替え (順位を正す)
3. 親チャンクを引き直す (文脈を十分に)
4. 文脈圧縮で削る (無関係な部分を落とす)
3と4は一見矛盾していますが、役割が違います。3は足りない文脈を補う工程、4は入り込んだ無関係な部分を落とす工程です。親チャンクが十分小さいなら4は不要ですし、親が大きく冗長なら4が効きます。
導入の順序としては、まず small-to-big だけを入れて測るのが賢明です。追加コストがほぼゼロで効果が大きく、これで足りるなら文脈圧縮のコストを払う必要はありません。
まとめ
- チャンク粒度に最適解が無いのは、検索と生成という目的の違う要求を1単位に兼ねさせているから。分ければ両立する。
- small-to-big は小さい単位で検索し、当たったら親の大きい単位を渡す。追加のモデルもコストもかからず、費用対効果が最も高い。
- 構造の無い文書には窓の拡張、長く冗長な文書には要約索引が代替になる。
- 同じ親が複数ヒットするので、親IDでの重複排除は必須。
- 文脈圧縮は逆向きに、引いた文書から質問に関係する部分だけを残す。本命の効果は文脈枠の節約より、無関係な記述に引きずられる事故の抑制。
- 文脈は多いほど良いわけではない。長いほど中央への注意が薄れ、無関係な文書は回答を悪化させる。
RAG設計パターンの記事ガイド
small-to-big と文脈圧縮 — 検索する単位と渡す単位を分けるを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
RAG
比較で見る軸
難易度: advanced / カテゴリ: RAG設計パターン / タグ数: 5
導入後に効く点
small-to-bigは小さい単位で検索して、当たったら親の大きい単位を生成へ渡す。索引と本文を別に持つだけで実装でき、費用対効果が最も高い。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- RAG設計パターン
- タグ数
- 5
判断チェックリスト
- 自社の用途が「RAG / チャンク分割」に近いか確認する。
- 強みである「チャンクの粒度に最適解が無いのは、検索と生成という目的の違う2つの要求を1つの単位に兼ねさせているから。分離すれば両立できる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。