この回のゴール
- チャンク分割 が RAG 精度に直結する理由を理解する
- 主要な分割戦略(固定長・段落単位・再帰的・セマンティック)の特徴を比較する
- overlap(重複) の役割を腹落ちさせる
1. なぜチャンク分割が重要か
前回は短い FAQ(各 300〜500 文字)をそのまま 1 文書として扱いました。でも現実は:
- 社内 Wiki の 1 ページ = 数千〜数万字
- 技術書 1 冊 = 数十万字
- 論文 1 本 = 数千〜1 万字
これを 1 ベクトルで表現したら? - 意味が「平均化」されて個別トピックが検索ヒットしない - 埋め込みモデルの入力上限(512 トークンが多い)を超える
👉 適切なサイズに区切る = チャンク分割 が必要。
2. 4 つの戦略
戦略①: 固定長分割 (Fixed-size)
[あなた] ──── tools=[calculator] を付けて request ───▶ [Claude]
│
│ 「計算が必要だな、
│ calculator ツールを呼ぼう」
│
[あなた] ◀── tool_use ブロック (input={expression: "..."}) ── [Claude]
│
│ (あなたのコードで実行)
│ eval("2+3*4") → 14
│
[あなた] ──── tool_result (content="14") を付けて request ─▶ [Claude]
│
│ 「結果は 14 か、
│ これで答えられる」
│
[あなた] ◀── text: "答えは 14 です" ───── [Claude]
- 利点: シンプル、予測可能
- 欠点: 文や段落の途中で切れる → 意味的に壊れやすい
戦略②: 段落単位 (Paragraph)
response1 = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
tools=[{
"name": "calculator",
"description": "数式を評価して結果を返す。",
"input_schema": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Python の式として評価可能な数式。例: '2+3*4'"
}
},
"required": ["expression"],
}
}],
messages=[
{"role": "user", "content": "734521 × 892143 はいくつ?"}
],
)
- 利点: 意味的にまとまっている
- 欠点: 段落サイズがバラバラ(10 字〜数千字)
戦略③: 再帰的分割 (Recursive)
LangChain の RecursiveCharacterTextSplitter が有名。
response1.stop_reason # "tool_use"
response1.content # [ToolUseBlock(name="calculator", id="toolu_ABC", input={"expression": "734521 * 892143"})]
- 利点: 段落の構造を尊重しつつサイズを揃えられる
- 欠点: やや複雑
戦略④: セマンティック分割
- 埋め込みの 変化点 で区切る(隣接文が似てない箇所で分割)
- 例:
SemanticChunker(LangChain) - 利点: 意味の境界に沿う
- 欠点: 計算コスト、パラメータ調整が必要
3. Overlap(重複)の役割
チャンク間を 少し重ねる ことで、境界の情報欠落 を防ぎます:
tool_use_block = next(b for b in response1.content if b.type == "tool_use")
expression = tool_use_block.input["expression"] # "734521 * 892143"
result = eval(expression) # 655199895003
質問「夏季休暇は?」で、どちらのチャンクでもヒット可能。
overlap サイズの目安
- チャンクサイズの 10〜20% が実務の定番
- 例: チャンク 500 トークン → overlap 50〜100 トークン
4. チャンクサイズの選び方
| サイズ | 特徴 | 向く用途 |
|---|---|---|
| 100 トークン前後 | ピンポイント、高精度 | FAQ・短い事実 |
| 300〜500 トークン | 実務の標準 | 技術ドキュメント |
| 1000〜2000 トークン | 文脈豊富 | 長文推論・物語 |
トレードオフ: - 小さい: 正確性↑ だが文脈が足りず LLM が答えにくい - 大きい: 文脈豊富だが検索精度↓・トークン料金↑
5. トークンか文字か
日本語では 文字とトークンが乖離 します(第 3 章):
- 日本語: 約 1 トークン/文字
- 英語: 約 3〜4 文字/トークン
実装の簡単さでは 文字数基準 が多いですが、厳密なら tiktoken で計測します。
6. 前処理の重要性
チャンク分割の前に:
- HTML/Markdown の除去(タグがノイズになる)
- 改行の正規化
- 重複行・空白の圧縮
を忘れると、埋め込みが「改行」や「空白」を重みに入れてしまい精度が落ちます。
7. メタデータを付ける
各チャンクに メタデータ を紐付けると検索の質が上がります:
response2 = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
tools=[...], # 同じ tools
messages=[
{"role": "user", "content": "734521 × 892143 はいくつ?"},
{"role": "assistant", "content": response1.content}, # 👈 全部含める
{
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use_block.id, # 👈 ID マッチング
"content": str(result),
}]
}
],
)
検索時に 出典表示・カテゴリフィルタ・新しい文書を優先 などが可能。
まとめ
- チャンク分割は RAG 精度を左右する要素
- 4 戦略: 固定長 / 段落 / 再帰的 / セマンティック。実務は 再帰的 が定番
- Overlap (10〜20%) で境界の情報欠落を防ぐ
- チャンクサイズの実務標準は 300〜500 トークン
- 前処理(HTML 除去等)とメタデータ付与で品質向上
この回の限界(次への動機)
検索とチャンク分割は揃った。これらを Claude と統合してエンドツーエンドの RAG チャットを作る番。 👉 次回「Claude with RAG」で、完成形のパイプライン + citation(引用元表示)を実装します。
参考文献
- LangChain docs: Text Splitters
- Anthropic: Contextual Retrieval