埋め込みと RAG のためのテキスト分割 — トークン分割

埋め込みと RAG のために、長いテキストを重なり付きのトークン単位チャンクへ分割します。単語の途中ではなく文と段落の境目で切り、すべての切れ目を表示します。

埋め込みのためのテキスト分割:どこで切るかが、何を取り出せるかを決める

検索システムは静かに失敗します。コーパスを埋め込み、検索をつなぎ、質問を投げると、話題としては近いが答えになっていないものが返ってくる。まず疑われるのは埋め込みモデルか類似度の指標です。しかし実際には、その手前で起きていることのほうがはるかに多いのです。テキストが「一つひとつが完結した内容を持たない」断片に切られていて、分割の時点で壊れた意味は、どれほど巧妙な再ランキングでも取り戻せません。

このツールはテキストをトークン上限付きのチャンクに重なりを持たせて分割し、固定の位置ではなく、そのとき使えるいちばん意味のある境界で切ります。境界はすべて表示します。まずい分割は、あるチャンクがどこで終わり次がどこから始まるかを読んで初めて見えるものだからです。すべてこのブラウザタブの中で動きます。

再帰的な境界分割

素朴なやり方は N トークンごとに切ることです。速いですが、間違っています。トークンの境界は意味の境界と何の関係もないので、文の途中、ときには単語の途中で切ることになり、できあがるベクトルは誰も書いていない断片を表すことになります。

ここでの方法は区切り文字の梯子を上から下へたどり、収まる大きさの断片を作れる最初の段を使います。順番は、Markdown の見出しの前、空行、任意の改行、文の境界、カンマとセミコロンでの節の境界、そして語と語のあいだの空白です。そのどれも存在しないとき——ミニファイされたバンドル、ひとつの巨大な単語——だけ、トークンの位置で切る方法に落ちます。

実際の効果として、テキストに構造がある限り構造は保たれます。見出しのある文書は節で分かれ、文章は段落で、段落が長すぎれば文で分かれ、切れ目のない文字列は語で分かれます。各チャンクは人が終わらせたであろう場所で終わります。テキストがその機会を与えなかった場合を除いて。

重なりは何のためにあるのか

重なりは、あるチャンクの末尾を次のチャンクの先頭で繰り返すものです。これが必要なのは、事実とそれが指す対象が境界の両側に分かれてしまうことが多いからです。「マイグレーションは夜通し走った。三つめのテーブルで失敗した。」この二文のあいだで切れば、後半のチャンクには主語のない失敗が、前半には結末のないマイグレーションが残ります。どちらも検索の役に立ちません。重なりがあれば、後半のチャンクが先行詞を連れていきます。

代償は重複です。重なった分のトークンは二度保存され、二度埋め込まれ、二度検索されます。チャンクサイズの一割から一割五分あたりが通常の妥協点で、プリセットもそこに置いてあります。統計パネルは重なりが何トークン増やしたかをそのまま報告するので、このトレードオフは感覚ではなく数字になります。

知っておくとよい歯止めがひとつあります。重なりがチャンクサイズ以上になると、各チャンクは前のチャンクが終えたところ全部から始まることになり、処理は前に進みません。ここは固まらせずに値を丸めています。

サイズの選び方

チャンクサイズは精度とコンテキストのトレードオフで、万能の正解はありません。

  • 小さいチャンク、256 トークン前後。マッチは鋭くなります。二、三文にかかるベクトルは、その二、三文が言っていることに支配されます。密度の高い参照資料に対する質問応答に向きます。リスクは、よくマッチはするが実際に答えるのに必要な周辺のコンテキストが足りないチャンクができることです。
  • 中くらいのチャンク、512 前後。よく使われる既定値で、多くの埋め込みモデルがいちばん機嫌よく動く領域です。だいたい、しっかりした段落ひとつ分にあたります。
  • 大きいチャンク、1024 以上。ヒット一件あたりのコンテキストは増えますが、ベクトルは薄まります。四つの話題にまたがるチャンクはその四つの平均の位置に座り、どれにも強くマッチしません。
  • 非常に大きいチャンク、数千トークン。もはや検索の単位ではなく、ページ送りの単位です。長い文書を検索するのではなく、順番にモデルへ流し込むための区切りになります。

四つの分割戦略

スマート分割は上で説明した再帰の梯子で、たいていの文章にはこれが適します。段落単位は段落を丸ごと詰め、決して途中で割りません。段落そのものがすでに思考の単位で、チャンクサイズが不揃いになっても壊れたチャンクよりましだというテキストに向きます。Markdown の見出し単位は一節を一チャンクにします。見出しが下に書かれていることをそのまま名指している文書では、これが自然な選択です。行単位は行を丸ごと詰めるもので、ログ、CSV の抜粋、各行が独立している一覧に向きます。

どのモードでも、上限を超えたままの単位は詰める前に再帰分割器で縮められるので、戦略の選択が上限超えのチャンクを生むことはありません。

カウントと、その数字の意味

トークンは、このサイトがリポジトリの規模を測るのに使っているのと同じトークナイザーで数えています。OpenAI のモデルが使う系統のものです。Claude や Gemini の数え方は多少ずれます——語彙が違えば同じテキストの切り方も違います——が、上限に対してチャンクの大きさを見積もるには十分近い値です。予算が厳しいなら、この数字を厳密なものとして扱わず、余裕を残してください。

もうひとつ、埋め込みモデルが公表している上限は目標ではなく、硬い打ち切り点です。超えれば末尾が黙って捨てられます。エラーを出さずに検索品質だけを落とすので、これは本当に診断しづらい壊れ方です。

そのまま次の工程に渡せる出力

ダウンロードは三種類。プレーンテキストは --- Chunk n/N --- の見出しを任意で付けられ、読んで確かめるのに向きます。JSON は添字・トークン数・本文を持つオブジェクトの配列で、まとめて取り込むスクリプト向けです。JSONL は一行に一オブジェクトで、ストリーミングの取り込みと多くのバッチ埋め込みのエンドポイントが期待する形であり、コーパスが大きすぎて解析済みの配列としてメモリに載らないときに欲しい形でもあります。

これはサイトの他のツールと自然に組み合わさります。リポジトリ、PDF、ウェブページ、字幕の文字起こしをまずテキストにして、その結果をここで分割する。どちらの工程でも何もアップロードされません。