💭

構造を壊さないチャンク化|RAG検索精度を高める設計パターンと実践知

はじめに

RAGの精度はチャンクの設計でほぼ決まる

RAG(Retrieval-Augmented Generation)を導入する際、最初の大きな壁になるのが企業ドキュメントの巨大さです。

PDF・Wordなどのドキュメントは、数万〜数十万文字規模になることが珍しくありません。
この巨大ドキュメントをそのまま埋め込むという運用を取ってしまうと、

  • 意味が混ざった状態のベクトルが生成される
  • ノイズが増え、類似度検索が安定しない
  • 「一見関係ありそうだけれど本質的には外れた」文脈が返ってくる

といった問題につながり、最終的には「質問に対して正しいドキュメントが引けない」というRAGの典型的な失敗を引き起こします。

重要なのは、こうした問題の多くは埋め込みモデルの性能ではなく、チャンク化の設計に問題がある可能性があるという点です。

よくある失敗例:埋め込みは正しく行ったのに精度が出ない

多くのプロジェクトではこんな状況が起きます。

・埋め込みモデルの精度は十分
・ベクトルDBにも正しく格納
・検索は成功している
...にも関わらず、回答がずれてしまう。

その原因の一つが、
文書構造を壊してしまうチャンク化です。
例えば、

  • タイトルと本文が離れた
  • 表と説明文が別チャンクに行ってしまった
  • 前後関係が途切れて意味が薄まってしまった
  • 1チャンクが大き過ぎて何の話かがわからなくなってしまった

こうしたチャンクは、Embeddingモデルから見ても「意味のまとまり」として理解しづらく、結果として検索精度が落ちる要因にもなってしまいます。

本記事の目的

この記事では、企業ドキュメントを扱う実務者の方向けに、

  • 構造を壊さないチャンク設計の考え方
  • チャンクの種類と使い分け
  • 実務で使える設計パターン
    について紹介していきます。

チャンク化とは何か

チャンク化とは、大きな文章を「意味のまとまりごと」に分割して扱うための前処理です。
単純に文字数で切るのではなく、タイトル・段落・箇条書きなど、文章の構造を壊さずに小さなブロックへ整理することが重要になります。

チャンク化が必要な理由

チャンクが適切に設計されていると、

  • 類似度検索の精度が安定する
  • LLMに渡すコンテキストが正しくなる
  • 回答が根拠に忠実になり、ハルシネーションが減る

といったメリットが得られます。

なぜ文章をそのままEmbeddingに投げてはいけないのか?

文章を大きいまま埋め込むと、

  • 全く異なる話題が同じベクトルに混ざる
  • タイトルと説明文が離れる
  • 表と解説が別扱いになる
  • 1チャンクに複数のテーマが入り、「平均化」されたベクトルができる

などの問題が発生します。

埋め込みモデルは、意味のまとまりを前提に設計されているため、
まとまりのないチャンク → ノイズが増える → 検索精度が不安定
という失敗につながります。

チャンク化の種類

チャンク化といっても、1つの方法で万能に対応できるわけではありません。
文書の種類や目的に応じて複数のアプローチが存在します。ここでは、RAGでよく使われる主要なチャンク手法と、その特徴をまとめて比較します。

手法 特徴 メリット デメリット 向いているケース
固定長チャンク
(Fixed-size)
一定トークン数で機械的に分割 実装が最も簡単/高速/予測可能 文書構造が壊れやすい Web記事など構造が強くない文書
オーバーラップチャンク
(Sliding window)
前後の文脈を重ねて分割 文脈が切れにくい/検索の安定性UP 冗長でDB容量が増える FAQ、会話ログなど前後関係が重要な文書
構造ベースチャンク
(Markdown/段落/見出しルール)
段落・見出しなどの構造で分割 構造を壊さない メイン手法/品質安定 文書の書き方に依存 マニュアル、仕様書、議事録
セマンティックチャンク
(LLM-driven)
意味のまとまりに応じて自動で分割 表・図・複雑な構造に強い/精度が高い コスト高/モデル依存 大規模PDF、研修資料、外部の複雑文書
ハイブリッド 構造 × 意味 × オーバーラップを組合せ 最も安定・高精度/実務の最適解 設計に多少の知識が必要 企業内文書すべて(最も汎用)

固定長チャンク(Fixed-size)

固定長チャンクは、一定のトークン数で機械的に文章を分割する最もシンプルな方法です。

いつ使うか

  • 文書の構造が弱い(ブログ記事、短い業務文書など)
  • まずRAGを動かしたい場合
  • 文書の品質にばらつきがあり、構造ベースのルールが当てにくい時

チューニングの目安

  • chunk_size = 300〜500tokenが日本語文書の定番
  • overlapは0が基本

最小実装

from langchain_text_splitters import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=400,
    chunk_overlap=0
)
docs = splitter.split_text(text)

品質チェック

  • 固定長で精度が安定しない場合、構造ベースorオーバーラップへ切り替え

よくある失敗

  • chunkを大きくし過ぎ、1チャンクに複数のテーマが混ざって検索がブレる

※固定長チャンクは、機械的に分割するため、セパレーターは入らない。

オーバーラップチャンク(Sliding window)

オーバーラップチャンクは、前後の文脈が連続する文書に強い手法です。

いつ使うか

  • FAQ/ 会話ログ/ 手順書のように「一つ前の文」が意味を持つ文書
  • 固定長では文脈が切れてしまう場合

チューニングの目安

  • chunk_size = 512tokens / overlap 80〜120tokens
  • 容量が増えるため、ベクトルDBのコストに注意

最小実装

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=100,
    separators=["\n\n", "\n", "。", "、", " "]
)
docs = splitter.split_text(text)

品質チェック

  • 容量が爆増していないか確認

よくある失敗

  • overlapを増やし過ぎてLLMの入力が肥大化する

構造ベースチャンク

構造ベースチャンクは、見出し・段落・Markdown構造を活かしたチャンク化で、最も堅実で品質の安定する手法です。

いつ使うか

  • 社内マニュアル、仕様書、議事録、研究資料
  • 文書構造(H1/H2、段落、箇条書き)が整っている

チューニングの目安

  • 見出し単位で粗く切る → 段落ごとに微調整
  • 大きすぎる段落は chun_size=200〜400tokensを上限に再分割
  • 「タイトル+本文」を1チャンクにまとめる

最小実装

from llama_index.core import Document
from llama_index.core.node_parser import MarkdownNodeParser

parser = MarkdownNodeParser()
documents = [Document(text=textdata)]
nodes = parser.get_nodes_from_documents(documents)

品質チェック

  • タイトルと本文が必ず同じチャンクに含まれているか
  • 表・箇条書きが分断されていないか

よくある失敗

  • Markdownタグが崩れているPDFを直接使い、意図しない分割になる

以下の写真のように自分でMarkdownの文書を用意し、チャンク化してみましたが、「Node」の行は自分でプログラミングで出力したものですが、とても綺麗にチャンクができているといった印象でした。

セマンティックチャンク

セマンティックチャンクは、LLMが文意から自然なまとまりを判断して分割する手法で、表・図・複雑文書への耐性が高いのが特徴です。

いつ使うか

  • 表・図・箇条書きが複雑に入り混じるPDF
  • LlamaParse/ LlamaIndexなど高度なパーサーを使える環境

チューニングの目安

  • コスト見積もりを必ず実施(PDF1冊で数十円〜)

最小実装

from langchain_experimental.text_splitter import SemanticChunker
from langchain_openai import AzureOpenAIEmbeddings

# OSで「AZURE_OPENAI_API_KEY」、「AZURE_OPENAI_ENDPOINT」、
#「AZURE_OPENAI_API_VERSION」は指定
embed = AzureOpenAIEmbeddings(
    azure_deployment="text-embedding-3-small"
)

splitter = SemanticChunker(
    embeddings=embed,
    breakpoint_threshold_type="percentile",
    breakpoint_threshold_amount=0.95, # 調整箇所
)

chunks = splitter.split_text(text)

品質チェック

  • 表 + 説明が同じチャンクに入っているか
  • 意味的に微妙な分割が発生していないか

よくある失敗

  • セマンティックを全体に強引に適用 → コスト爆増

ハイブリッドチャンク

ハイブリッドは、構造 * 意味 * オーバーラップを組み合わせた実務最適解です。企業のドキュメントは複雑なため、単一手法だけだと限界があります。

いつ使うか

  • 大半の社内文書(マニュアル、手順書、内部資料)
  • 各文書の性質が異なり、1つの手法で統一できないプロジェクト

最小サンプル(Flow)

構造ベース分割 → セマンティック補正 → Sliding Window少量追加

品質チェック

  • ハイブリッド後にプロンプト総トークンが増えていないか確認

よくある失敗

  • 最初からハイブリッドを使い、設計が複雑化
  • 複数手法の適用順序を誤り品質が安定しない

文書タイプ別:最適なチャンク化戦略

文書の種類によって、最適なチャンク化戦略は大きく異なります。
同じ「RAG」の仕組みでも、それぞれの文書によって、構造や依存関係が全く違うため、手法を単一化することは難しいと考えています。

そんな中でも文書毎のチャンク化の最適を一覧化致します。

文書タイプ 推奨チャンク手法 理由(なぜ相性が良いか) 注意点
業務マニュアル / 手順書 構造ベース + オーバーラップ少量 見出し・番号・段落構造が明確で機械的に分割しやすい/ステップ間の文脈依存が強く、流れを切らないことが重要 大段落が長い場合や図表を含む場合は、部分的にセマンティックで補正
FAQ Q&A単位の構造ベース or 小さめの固定長チャンク 質問と回答がセットで意味を持つため、Question + Answerを1チャンクにする 質問だけ検索したい場合は別インデックス推奨
契約書 / 規約 構造ベース(条項単位) + オーバーラップ 条項が独立しつつ相互参照が発生するため 定義セクションは特に依存関係が強い
技術資料 / 設計書 構造ベース + セマンティック補正 図表・箇条書き・段落差が大きい キャプションが分離しないよう調整
PDF(表・図・画像多め) セマンティック or LlamaParse 構造が崩れがち/図表と本文の紐付けが必須 OCR誤認識や表のズレに注意

設計パターン集

パターンA:階層構造ベース

見出しや章構造が明確な文書のパターンです。
大枠を見出し単位で分割し、必要に応じて段落毎に粒度を整えます。

パターンB:段落ごとの差分が大きい文書向け

段落の長さや密度にばらつきがある文書では、そのまま構造ベースで切ると粒度が合いません。
このパターンでは、見出しで大枠を取りつつ、長すぎる段落だけをセマンティックチャンクで調整します。

パターンC:PDFの図表が多い文書向け

図表・キャプション・本文が多く出てくるPDFでは、構造ベースだと誤分割が発生しやすいです。
このパターンでは、LlamaParseやセマンティックを使い、図と説明が同じチャンクに入るように補正します。

パターンD:混在文書

見出し・段落・図表・箇条書きが混じっており、単一手法では品質が安定しないケースです。
構造ベースで大枠を作り、難しい箇所でセマンティックで補正し、必要に応じて少量オーバーラップを追加していきます。

まとめ

  • RAGの精度は、埋め込みモデルそのものよりもチャンク設計に大きく依存します。
  • 文書の種類毎に適切なチャンク化手法を選択することで、検索精度を安定させることができる。
  • 図表・表・画像などが混在する文書では、単一の手法では限界があり、複数手法を組み合わせたアプローチを検討する必要がある。

関連記事

チャンク設計がRAG全体の精度にどう影響するのかを、評価観点から整理した記事はこちら
https://zenn.dev/startspace/articles/4bd3129246f19f

StartSpace Tech Blog

Discussion