技術ブログ

RAG Engineering

RAGのチャンキング:原文位置を保持し検索単位を検証する

オフセットを保持するPythonの分割例と、文脈、表、文書版、トークン制限を検証する手順です。

RAGO-X公開 更新
#RAG#Chunking#Architecture
RAGのために文書をチャンクへ分割する概念図

文書を一定の長さに切るだけでは、回答に使える根拠になりません。「電源を切ってからカバーを開ける」の条件と操作が別のチャンクに分かれると、操作だけが検索される可能性があります。重要なのは、回答に必要な文脈と原文位置を一緒に保持することです。

Python 3で文字単位の基準となる分割器を作り、その限界を確認します。サイズと重複幅は実験用で、RAGO-Xの本番既定値ではありません。

分割前に抽出結果を確認する

段組みPDFの読み順、繰り返されるヘッダー、表セルの順序が崩れている場合、チャンクサイズの調整だけでは修復できません。見出し、段落、表、脚注を原文と比較します。まず節や段落を単位とし、長い段落だけをさらに分割する方法を検討します。

表の行には列名や単位が必要です。長い表を分ける場合は、表題と列見出しを各部分に関連付け、ページ境界を残します。見出しを追加するなら、原文の区間と検索用に付けた文脈を分けて保存します。

オフセットを保持する分割例

以下をchunk_demo.pyとして保存し、python3 chunk_demo.pyを実行します。半開区間[start, end)なので、text[start:end]がチャンク本文になります。

python
def split_text(text, size=80, overlap=15):
    if size <= 0 or not 0 <= overlap < size:
        raise ValueError("require size > 0 and 0 <= overlap < size")
    start = 0
    while start < len(text):
        end = min(start + size, len(text))
        yield {"start": start, "end": end, "text": text[start:end]}
        if end == len(text):
            break
        start = end - overlap


text = "Pump X17: disconnect power. Wait 30 seconds. Check the inlet filter."
chunks = list(split_text(text, size=40, overlap=10))
print([(c["start"], c["end"]) for c in chunks])
assert [(c["start"], c["end"]) for c in chunks] == [(0, 40), (30, 68)]
assert all(text[c["start"]:c["end"]] == c["text"] for c in chunks)
assert set().union(*(set(range(c["start"], c["end"])) for c in chunks)) == set(range(len(text)))
assert list(split_text("")) == []

出力は[(0, 40), (30, 68)]です。10文字が重複し、入力全体をカバーします。空の入力からはチャンクを作らず、不正な重複幅はエラーにします。空白を除去・正規化せず、位置の比較を保ちます。

Python文字列の長さは、バイト数、見た目の文字のまとまり、モデルのトークン数とは異なります。入力上限はモデルのトークナイザーで別途確認してください。この例は見出しや文の境界を考慮しないため、そのまま完成した分割器として扱うべきではありません。

保存するメタデータ

情報 目的
文書IDと改訂版 新旧の内容を区別
チャンクIDと分割設定の版 再処理を追跡
ページ、節、開始・終了位置 原文を確認
組織、キャビネット、アクセス範囲 許可された文書のみ検索
原文区間と追加文脈 引用と検索補助情報を区別

オフセットには、基準とした抽出テキストの版も必要です。OCRや空白の処理が変われば、同じ位置でも内容がずれます。文書更新時はチャンクと索引を整合的に切り替え、旧版が混入しないことを検証します。表は設計項目であり、公開APIのフィールド仕様ではありません。

正解の根拠を決めてから比較する

実際の質問に答える原文区間を先に指定し、二つの分割設定を比較します。検索上位に答えと例外条件が含まれるか、出典を開くと同じ版が表示されるかを確認します。チャンク数や回答の長さだけで改善を判断しません。

問題 最初に試す変更
条件と結論が分離 文・段落境界を優先し必要な隣接文脈を追加
複数の話題が混在 見出しごとに分割して比較
同じ根拠が重複 重複幅を減らすか隣接候補を整理
表の数値を誤解 列名、単位、脚注を保持
引用位置が不一致 抽出版と位置対応を確認

重複は境界での情報損失を減らす一方、保存量と重複候補を増やします。普遍的な最適サイズを想定せず、質問集合、入力トークン、遅延、引用精度を記録します。ハイブリッド検索の比較根拠から回答までの設計も参照してください。

LinkedInで共有