チャンクとトークンは、どちらも文章を小さく分けた単位ですが、決める主体が違います。チャンクは開発者が決める「検索で返す文章のまとまり」、トークンはモデルのトークナイザーが決める「文字列を数える最小単位」です。チャンクは数百トークンの集まりで、RAG(検索拡張生成)ではこのチャンク単位で文書を検索して生成AIへ渡します。
実務で混乱が起きるのは、チャンクの大きさを測る物差しがツールごとに違う点です。この記事で比較するLangChainのRecursiveCharacterTextSplitterは既定で文字数、LlamaIndexのSentenceSplitterはトークン数でchunk_sizeを数えます。以下では、その違いを日本語の文章で実測したうえで、チャンク分割の手法、サイズとオーバーラップの決め方、AI検索でいう「チャンク」との違い、切り方を変えたときの評価までを順に説明します。
まとめ:チャンクとトークンの違いとチャンク分割の要点
- チャンクは検索とLLMへの受け渡しの単位で、人が設計します。トークンはモデルが課金・上限・計算に使う単位で、トークナイザーが機械的に決めます
- 日本国憲法の前文と条文9,445字は、o200k_baseで8,238トークン、cl100k_baseで11,181トークンでした(tiktoken 0.14.0で実測)。チャンクサイズを「トークン」で決めるなら、どのトークナイザーで数えるかまで決めます
- LangChainの
RecursiveCharacterTextSplitterは既定でchunk_size=4000文字・chunk_overlap=200文字、LlamaIndexのSentenceSplitterは1,024トークン・200トークンです。数字が近く見えても単位が違います - オーバーラップを800トークン中400トークンにすると、同じ文書の索引トークンは重なりなしの1.82倍、チャンク数は15から27に増えました。まずは10〜20%から始めます
- 日本語を
RecursiveCharacterTextSplitterで切るときは、区切り文字に「。」を足し、keep_separator="end"を指定します。既定の保持方法のままだと句点1字だけのチャンクが生まれることがあります - AI検索(GoogleのAIによる概要など)向けに記事を細かく分ける必要はない、とGoogleは公式ガイドで述べています。RAGのチャンクは自分の検索システムのための設計です
チャンクとトークンの違い:決める主体と数える単位
| 観点 | チャンク | トークン |
|---|---|---|
| 決める主体 | 開発者(分割の設定) | モデルのトークナイザー |
| 大きさの目安 | 数百〜千トークン程度 | 1字未満〜複数文字 |
| 使われる場面 | 検索・索引・LLMへの受け渡し | 課金・入力上限・計算 |
| 変えると起きること | 検索で返る内容が変わる | 同じ文章の数え方が変わる |
| 例 | 規程の1条、FAQの1問 | 「チャ」「ンク」 |
トークンが集まってチャンクを構成する関係なので、チャンクの大きさはトークン数で表すのが普通です。トークンの切れ方そのもの(BPEやUnigramの仕組み)はトークナイザーの仕組みと日本語での実装判断で扱っています。
なお、心理学の「チャンク」は人が短期記憶で一度に扱う情報のまとまりを指し、RAGのチャンクとは別の概念です。心理学の意味で調べている場合はマジカルナンバー7±2とチャンクの意味を参照してください。
同じ日本語がトークナイザーで1.36倍に割れる実測
e-Gov法令APIから取得した日本国憲法の前文と各項の本文を、各号の番号は残し、条名・見出しを除いて数えました。改行を除くと9,445字で、トークン数はこの9,445字をtiktoken 0.14.0で数えました。分割の実測には、項の間に改行2つを入れた9,765字を入力し、langchain-text-splitters 1.1.3を使いました。区切り文字は改行2つ、改行1つ、句点、読点、空文字の順で、keep_separator=”end”を指定しています。後述の512トークン上限の実測はオーバーラップ0です。
| エンコーディング | トークン数 | 1トークンあたりの文字数 | 主な対応モデル |
|---|---|---|---|
| o200k_base | 8,238 | 1.15字 | GPT-5、GPT-4o |
| cl100k_base | 11,181 | 0.84字 | text-embedding-3-small/large |
同じ9,445字でも、cl100k_baseはo200k_baseの約1.36倍のトークンになりました。後述の架空の経費規程326字では239と359トークン(約1.5倍)で、比率は文章によって変わります。o200k_baseでも「チャンク」は「チャ」「ンク」、「経費精算」は1字ずつの4トークンに分かれます。
チャンクの上限は埋め込みモデルの入力上限に合わせて決めます。OpenAIの埋め込みガイドは、text-embedding-3-small/largeの入力上限を8,192トークンとし、数えるときはcl100k_baseを使うよう書いています。生成モデルのo200k_baseで数えたチャンクを換算で済ませず、埋め込みと同じエンコーディングで直接数えます。コンテキストの上限と数え方の詳細はコンテキストウィンドウのトークン上限の数え方にまとめています。
LangChainとLlamaIndexのchunk_sizeの単位差
チャンクとトークンを混同しやすい原因の一つは、設定値の単位が見た目で区別できないことです。インストールしたライブラリの既定値を確かめると、単位は次のとおりでした。
- LangChain(langchain-text-splitters 1.1.3):
length_functionの既定がPythonのlenなので、chunk_size=4000は4,000文字です - LlamaIndex(llama-index-core 0.14.25):
SentenceSplitterのchunk_size=1024はトークン数で、既定のトークナイザーはcl100k_baseです
LangChainでトークン数を基準にしたいときは、RecursiveCharacterTextSplitter.from_tiktoken_encoder(encoding_name="cl100k_base", ...)のように数え方を切り替えます。英語の資料にある換算も日本語には当てはまりません。Azure AI Searchのチャンク設計は「512トークン(約2,000文字)」と書いていますが、日本国憲法をcl100k_baseの512トークン上限で切ると、25チャンクの平均は389字(最小204字・最大449字)でした。
チャンク分割(チャンキング)とは:生成AIのRAGで検索単位を決める前処理
チャンク分割は、PDFや社内規程などの長い文書を、検索で返す単位へ切り分ける前処理です。チャンキング、チャンク化、チャンク分けも同じ処理を指します。RAGでは「テキスト抽出→チャンク分割→埋め込み(ベクトル化)→索引登録」の順に取り込み、質問が来たら質問に近いチャンクを数件取り出して生成AIに渡します。工程全体の分け方はRAGパイプラインの工程設計で説明しています。
チャンク化とベクトル化は別の工程です。チャンク化は文章をどこで切るかを決める処理で、ベクトル化はそのチャンク1件ずつを埋め込みモデルで数値の列に変える処理です。ベクトルはチャンクの数だけ作られるので、チャンク化の設定を変えると、分割結果が変わったチャンクは埋め込みと索引の登録をやり直します。サイズやオーバーラップを変えれば境界がずれるので、1チャンクに収まる短い文書を除き、ほとんどのチャンクが対象になります。
文書を丸ごと埋め込まない理由は2つあります。1つは前述の入力上限です。もう1つは精度で、長い文書を1本のベクトルにすると複数の話題が混ざり、特定の箇所を問う質問に当たりにくくなります。話題の境界に沿って分割すると関連箇所を検索しやすくなりますが、小さくしすぎると必要な文脈が失われます。埋め込みモデル側の選び方は埋め込みモデルの仕組みと日本語モデルの選び方にまとめました。
チャンク分割の手法と文書の種類による選び分け
| 手法 | 切り方 | 向く文書 | 代表的な実装 |
|---|---|---|---|
| 固定長 | 一定の文字数・トークン数 | ログ、均質な短文 | TokenTextSplitter |
| 再帰的分割 | 設定した区切りを順に試す | 一般の文書 | RecursiveCharacterTextSplitter |
| 文書構造ベース | 見出し・条・表の単位 | Markdown、規程、マニュアル | MarkdownHeaderTextSplitter |
| セマンティック | 隣接文の埋め込みの距離 | 話題が段落をまたぐ長文 | SemanticSplitterNodeParser |
| 階層(親子) | 小さく検索し大きく渡す | 契約書、長い手順書 | HierarchicalNodeParser |
最初の1本は再帰的分割にします。段落や改行など、設定した区切りを優先して切るので、固定長分割より自然な境界を保ちやすく、分割位置の判定に埋め込みモデルやLLMを呼び出す必要もありません。見出しや条番号がはっきりした文書は、文書構造ベースのほうが「第何条」「どの手順」という単位をそのまま保てます。
文書構造ベースで注意したいのは見出しの行き先です。MarkdownHeaderTextSplitterに「# 経費規程」「## 出張旅費」の文書を渡すと、チャンク本文は「宿泊費の上限は1泊12,000円です。」だけになり、見出しは{'h1': '経費規程', 'h2': '出張旅費'}というメタデータへ移りました。LangChainの通常のベクトルストア登録では本文とメタデータを別々に渡すため、メタデータへ移した見出しは、そのままでは埋め込み用の本文に含まれません。この例では「出張」の語が本文から外れます。見出しも検索に効かせたいならstrip_headers=Falseを指定するか、見出しの階層を本文の先頭に付け直してから埋め込みます。
セマンティック分割は、分割の段階で全文を埋め込むため、取り込みのコストが再帰的分割より大きくなります。再帰的分割で評価して、話題の切れ目がずれていると分かってから試す順序で十分です。仕組みと採否の判断はセマンティックチャンキングの実装と採否判断で詳しく扱っています。
主要ツールの既定値から決めるチャンクサイズとオーバーラップ
| ツール | 既定のサイズ | 既定のオーバーラップ | 単位 |
|---|---|---|---|
| LangChain RecursiveCharacterTextSplitter | 4,000 | 200 | 文字 |
| LlamaIndex SentenceSplitter | 1,024 | 200 | トークン |
| LlamaIndex TokenTextSplitter | 1,024 | 20 | トークン |
| LlamaIndex HierarchicalNodeParser | 2,048/512/128 | 20 | トークン |
| OpenAI file_search(vector store) | 800 | 400 | トークン |
| Vertex AI RAG Engine | 1,024 | 256 | トークン |
| Amazon Bedrock Knowledge Bases | 約300 | 記載なし | トークン |
| Azure AI Search(推奨の開始値) | 512 | 128(25%) | トークン |
LangChainとLlamaIndexはインストールした版で、ほかは2026年10月時点の公式ドキュメントで確認した値です。OpenAIのRetrievalガイドでは、サイズは100〜4,096トークンの範囲で変えられ、オーバーラップはサイズの半分までです。Amazon Bedrock Knowledge Basesの取り込み設定は、分割方法を指定しない場合に「文の境界を保ちながら約300トークン」に分けると書いています。Vertex AI RAG Engineの分割設定の既定は1,024トークン・256トークンで、コーパスの作り方はVertex AI RAG Engineのチャンク設定と料金で扱っています。
チャンクが小さすぎる・大きすぎるときに出る症状
小さすぎるチャンクは、答えの条件が別のチャンクへ落ちます。「宿泊費の上限は1泊12,000円」だけが検索に当たり、「東京23区と大阪市の場合」という条件が隣のチャンクに残る、という形です。大きすぎるチャンクは、1つに複数の話題が入り、質問と無関係な部分まで埋め込みに混ざって、狙った箇所が上位に来にくくなります。LLMへ渡すトークン数も増えるので、1回の回答あたりの料金と応答時間も増えます。
出発点としては、FAQのような1問1答は1問=1チャンク、一般の文書は512トークン前後から1,000トークンの間で始め、評価で当たり外れを見て半分・倍に振ります。
オーバーラップで増える索引トークンとチャンク数の実測
オーバーラップは、チャンクの境目で文が切れても前後の文脈が片方に残るよう、隣のチャンクと一部を重ねる設定です。重ねた分だけ同じ文章が何度も索引に入ります。日本国憲法(cl100k_baseで11,181トークン)を、from_tiktoken_encoderで800トークン上限・句点区切りにし、オーバーラップだけを変えて分割しました。
| オーバーラップ | チャンク数 | 索引に入るトークン | 重なりなしとの比 |
|---|---|---|---|
| 0 | 15 | 11,181 | 1.00倍 |
| 100(12.5%) | 17 | 12,252 | 1.10倍 |
| 200(25%) | 18 | 13,705 | 1.23倍 |
| 400(50%) | 27 | 20,302 | 1.82倍 |
800トークン・400トークンはOpenAIのfile_searchの既定と同じ比率です(OpenAI側の分割器は別実装なので、数は目安です)。今回の例では、埋め込み対象のトークン数が約1.82倍、チャンク数が1.8倍になりました。同じトークン単価なら埋め込み費用は約1.82倍、同じ次元数・データ型ならベクトル本体の保存量は1.8倍になります。取り込み時間の増加率は未測定です。また、同じ内容のチャンクが検索上位に並んで他の候補を押し出すこともあります。まずは10〜20%で始め、境目で条件が落ちる失敗が評価で見つかったときだけ増やします。
日本語でRecursiveCharacterTextSplitterを使うときの落とし穴と実測
LangChainのRecursiveCharacterTextSplitterは、既定の区切り文字が["\n\n", "\n", " ", ""]で、句点「。」を含みません。英文は空白で単語境界を拾えますが、空白の少ない日本語では最後の""(1文字単位)まで落ちて、文の途中で切れます。架空の経費規程326字(段落の長さは121字・111字・90字)をchunk_size=120、chunk_overlap=30で分割した結果を比べます。
from langchain_text_splitters import RecursiveCharacterTextSplitter
text = (
"経費精算の締め日は毎月25日です。25日を過ぎた申請は翌月分として処理されます。"
"領収書は原本を経理部へ提出してください。電子帳簿保存法に対応したスキャン保存を利用する場合は、"
"受領から約2か月と概ね7営業日以内にアップロードする必要があります。\n\n"
"出張旅費は事前申請が必要です。国内出張は所属長の承認、海外出張は所属長と担当役員の承認を得てから手配します。"
"宿泊費の上限は地域ごとに定められており、東京23区と大阪市は1泊12,000円、それ以外は1泊10,000円です。\n\n"
"交際費は1人あたり5,000円を超える場合に事前申請が必要です。参加者の氏名と所属、目的を申請書に記載してください。"
"社内の打ち合わせに伴う飲食は交際費ではなく会議費として扱います。"
) # 分割検証専用の架空データ。法令や実際の経費規程の解説ではありません。
assert len(text) == 326
# A: 既定の区切り文字
a = RecursiveCharacterTextSplitter(chunk_size=120, chunk_overlap=30)
# B: 句点・読点を追加(keep_separatorは既定のTrue)
b = RecursiveCharacterTextSplitter(
chunk_size=120, chunk_overlap=30,
separators=["\n\n", "\n", "。", "、", ""])
# C: 句点を前の文の末尾に残す
c = RecursiveCharacterTextSplitter(
chunk_size=120, chunk_overlap=30,
separators=["\n\n", "\n", "。", "、", ""],
keep_separator="end")
for s in (a, b, c):
print([len(x) for x in s.split_text(text)])
| 設定 | 各チャンクの文字数 | 起きたこと |
|---|---|---|
| A 既定 | 120, 31, 111, 90 | 第1段落が文中で切れ、31字の断片が残る |
| B 句点追加 | 120, 1, 111, 90 | 「。」1字だけのチャンクができる |
| C keep_separator=”end” | 60, 81, 111, 90 | 文の境目で切れ、1文が重複する |
Aの2番目のチャンクは「ら約2か月と概ね7営業日以内に…」という、語の途中から始まる31字でした。120字で切った残り1字(句点)に、オーバーラップの30字を足したものです。
Bは区切り文字に「。」を足したのに悪化しました。RecursiveCharacterTextSplitterのkeep_separatorは既定がTrueで、区切り文字を次の断片の先頭に付けます。第1段落の最後の句点が次の断片の頭に回り、ほかにつなげる文が無いため「。」だけのチャンクが索引に入ります。
Cのkeep_separator="end"にすると句点は前の断片の末尾に残り、各チャンクが文末で終わります。1番目の末尾と2番目の先頭には「領収書は原本を経理部へ提出してください。」(20字)が重複しており、オーバーラップが文単位で効いています。
ただし、文末で終わるのは1文がchunk_sizeに収まる場合だけです。同じCの設定で「短い文×3、151字の1文、短い文」を分割すると、151字の文は文字単位まで分割されて120字と61字の2チャンクになり、この2つの間には30字の重複が付きました。短い文のチャンクと文字単位のチャンクの間には重複が付きません。重なる量は、実際に結合される断片の単位で決まります。
トークン数で揃えたい場合は、同じ区切り文字のままfrom_tiktoken_encoder(encoding_name="o200k_base", chunk_size=80, chunk_overlap=20, ...)に置き換えます(埋め込みにtext-embedding-3を使うならcl100k_base)。o200k_baseでは同じ文章が43〜67トークンの5チャンクに分かれました。LangChainでRAG全体を組む手順はLangChainでRAGを構築する手順にあります。
チャンク単体で意味が通らない問題への対処:親子チャンクとコンテキスト付与
切り方をいくら詰めても、「前年同期比で3%増えた」のように主語や時期が前の段落にある文は、チャンク単体では意味が通りません。対処は2通りあります。
親子チャンクの検索粒度とLLMへの受け渡し単位
子チャンク(小さい単位)で検索し、ヒットしたら親チャンク(大きい単位)をLLMへ渡す方式です。検索は細かい粒度のほうが当たりやすく、回答には周辺の文脈が要るという矛盾をまとめて解きます。LlamaIndexのHierarchicalNodeParserは既定で2,048・512・128トークンの3階層を作ります。Amazon Bedrock Knowledge Basesの階層チャンキングは親と子の2階層で、設定手順はAmazon BedrockでRAGを実装する手順で扱っています。
コンテキスト付与によるチャンクの文脈補完
Anthropicが2024年9月19日に公開した「Contextual Retrieval」は、各チャンクの前に「この文書の中でこのチャンクが何を述べているか」をLLMに書かせ(通常50〜100トークン)、付け足してから埋め込む方法です。同社がGemini Text 004の埋め込みを用いて複数の知識領域で測った平均では、上位20件の検索失敗率(1 − Recall@20)が、文脈を付与しない埋め込みの5.7%から、コンテキスト付与で3.7%(35%減)、BM25側にも文脈を付けるContextual BM25との併用で2.9%(49%減)、さらにリランキングを加えて1.9%(67%減)まで下がりました。
代わりに、取り込み時にチャンクの数だけLLMを呼びます。文書が頻繁に更新される環境では、その都度の再生成費用を見込んでから採用します。BM25との併用とリランキングは、それぞれBM25とベクトル検索を統合するハイブリッド検索とリランクモデルの種類と選び方で詳しく説明しています。
AI検索でいう「チャンク」とRAGのチャンクの違い
SEOの文脈では「AI検索はページをチャンク単位で読むので、記事を短い塊に分けて書くべきだ」という主張を見かけます。RAGのチャンクは自社の検索システムのために開発者が決める単位で、Googleなど外部の検索エンジンがページ内部をどう扱うかとは別の話です。
Googleは生成AI検索向けの最適化ガイド(2026年7月10日更新)の「Mythbusting」で、”Chunking” contentを気にしなくてよい項目に挙げています。理由は、Googleのシステムが1ページに複数の話題があっても理解し、関連する部分を利用者に示せるためで、理想的なページの長さも無いと書いています。同じ項目にはllms.txtや生成AI専用のマークアップも並んでいます。
記事を書く側がやることは、AIのために細切れにすることではなく、読者が探す問いに見出しと段落で答えることです。生成AIに引用される記事の作り方はLLMOとは?SEOとの違いと生成AIに引用される記事の作り方で扱っています。社内文書を検索させるRAGを作る側なら、この記事の手法と評価がそのまま当てはまります。
切り方を変えたときの評価:検索段階で測る指標と手順
チャンクの良し悪しは、回答の印象ではなく検索段階の数字で判定します。質問と「正解が書かれている箇所」の組を50問ほど用意し、切り方ごとに、上位k件に正解箇所を含むチャンクが1件以上入った質問の割合(Hit Rate@k)を比べます。回答文の良し悪しまで測ると、LLMやプロンプトの影響が混ざってチャンクの効果が見えなくなるためです。1つの質問に正解箇所が複数ある場合は、正解集合のうち上位k件で取得できた割合(Recall@k)も併せて見ます。
比べるときは埋め込みモデル・k・質問セットを固定し、チャンクの設定だけを1つずつ変えます。サイズとオーバーラップを同時に動かすと、どちらが効いたのか分かりません。ただし、同じkでも大きいチャンクほど取得する文章量が増えるため、取得総トークン数も記録します。採用前には、LLMへ渡す総トークン数の上限を揃えた比較も行います。検索と生成を分けて測る指標とRagasでの実装はRAG評価の指標と実装にまとめています。評価セットの作り方から社内文書の取り込みまでを一緒に組む場合は、RAG構築支援でも相談を受けています。
チャンクを変えても精度が伸びない3つの場面
- PDFの抽出が壊れている:表が1列ずつばらばらに並ぶ、ヘッダーとフッターが本文に混ざる、といった状態では、どう切っても壊れたテキストが索引に入ります。抽出結果を目で見て、Markdown化できるツールに替えるのが先です(PyMuPDF4LLMでのMarkdown変換、DoclingによるPDFのMarkdown化)
- 対象全件の取得が必要な集計質問:「部署ごとの件数を合計して」のような集計では、検索上位のチャンクだけでは対象を取りこぼします。SQLや構造化データの検索を組み合わせる設計の問題です
- 固有名詞や型番で探す質問:型番の完全一致が必要な検索では、意味の近さで探すベクトル検索に加え、BM25などのキーワード検索を比べます。切り方より検索方式を見直します
評価セットで取りこぼした質問を1件ずつ見て、境界での条件の分断、無関係な話題の混在、重複チャンクによる検索結果の偏りがあれば、チャンク設定を見直します。
よくある質問
チャンクとトークンの違いを一言で言うと?
チャンクは開発者が決める検索とLLM受け渡しの単位で、トークンはモデルのトークナイザーが決める数え方の最小単位です。チャンクは数百〜千トークンを束ねたもので、RAGでは質問に近いチャンクを数件取り出してLLMに渡します。料金や入力上限はトークンで決まるため、チャンクの大きさもトークン数で管理するのが普通です。
チャンク分割とチャンキング、チャンク化は違うものですか?
同じ処理を指します。英語のchunkingを片仮名にしたのがチャンキングで、日本語の資料ではチャンク分割、チャンク化、チャンク分けとも書かれます。どれも長い文書を検索単位へ切り分ける前処理です。心理学で使う「チャンク化(情報をまとまりにして覚える)」は別の意味です。
日本語は1文字あたり何トークンになりますか?
トークナイザーで変わります。日本国憲法9,445字で測ると、o200k_baseは8,238トークン(1トークン約1.15字)、cl100k_baseは11,181トークン(約0.84字)でした。今回確認したo200k_baseでは、「経費精算」は4トークン、「チャンク」は2トークンでした。文字種だけでは分割数を決められず、語彙とエンコーディングによって変わります。正確な数は、使うモデルのトークナイザーで実際に数えてください。
チャンクサイズは何トークンから試すのがよいですか?
一般の文書なら500〜1,000トークン、FAQのような1問1答なら1問を1チャンクにして始めます。LlamaIndexのSentenceSplitterとVertex AI RAG Engineは1,024トークン、OpenAIのファイル検索ツールは800トークンが既定です。評価セットで取りこぼした質問を見て、答えの条件が隣のチャンクに落ちていれば大きく、無関係な話題が混ざっていれば小さくします。
チャンク数とは何ですか?
1つの文書または索引全体を分割して作られたチャンクの個数です。チャンクを小さくするほど、またオーバーラップを大きくするほど数は増えます。日本国憲法を800トークン上限で切ると、重なりなしで15、400トークン重ねると27でした。検索時に上位何件を取り出すか(k)を指して「チャンク数」と呼ぶこともあり、こちらはLLMへ渡すトークン量に直結します。