ChangeGamer

← All resources

Chunking Strategies for RAG

Guide · updated 2026-07-15 · Markdown variant

Practitioner reference for chunking documents before embedding: fixed-size, recursive, semantic, late chunking, and contextual retrieval — with a strategy comparison table, chunk-size and overlap tradeoffs, code/table/Markdown handling, embedding model context limits, and evaluation methods.


Chunking is the decision that determines what the retriever can find. Every other RAG optimisation is downstream of it. This guide covers the five main strategies, the tooling that implements them, and how to choose. For the full retrieval pipeline see /resources/rag-retrieval-for-agents; for embedding model selection see /resources/embeddings-vector-search; for upstream parsing of PDFs and scans see /resources/document-extraction-for-agents.

What strategy should I use?

Start with recursive splitting (LangChain RecursiveCharacterTextSplitter, LlamaIndex SentenceSplitter). It respects document structure, is fast at ingest time, and matches or beats semantic chunking in many production settings at far lower cost. Switch strategies only when evaluation shows a real gap.

Strategy comparison

Strategy How it works Best for Key tradeoff
Fixed-size + overlap Split every N tokens; slide an M-token window between adjacent chunks Uniform, unstructured prose; prototyping Fast and simple; cuts mid-sentence, mid-concept
Recursive / structural Split on a hierarchy of separators; stay within a size limit Markdown, HTML, code, structured docs Needs reliable structure; still character-based, not semantic
Semantic Embed adjacent sentences; split where similarity drops below a percentile threshold Dense topic-switching text; academic content High ingest cost; threshold needs dataset-specific tuning
Document-structure-aware Respect element types (Title, Table, ListItem) as boundaries PDFs, DOCX, HTML with layout metadata Requires a parsing step to produce element types first
Late chunking Embed the full document with a long-context model; pool token embeddings after splitting Long documents where local chunks lose context Needs a long-context embedding model; total tokens must fit its window
Contextual retrieval Prepend a short LLM-generated summary to each chunk before embedding and BM25 indexing High-value corpora where recall is critical An LLM call per chunk at ingest; use prompt caching to lower cost

Chunk size and overlap tradeoffs

There is no universal optimal chunk size — it depends on your query distribution and embedding model. Practical guidance:

Chunking for code, tables, and Markdown

Code — split on syntactic boundaries (functions, classes), not character count. LangChain Language splitters use tree-sitter grammars; LlamaIndex CodeSplitter exposes chunk_lines and chunk_lines_overlap.

Tables — never split a table row across chunks; a partial row has no retrievable meaning. unstructured.io isolates Table elements as atomic chunks. For retrieval, convert tables to Markdown text or generate a natural-language summary alongside the raw table.

Markdown / HTML — use structural splitters that split on headings first. LangChain MarkdownHeaderTextSplitter splits on heading levels and preserves header metadata per chunk; LlamaIndex MarkdownNodeParser does the same. Header-as-metadata improves retrieval when queries reference section names.

Embedding model context limits and chunking

An embedding model silently truncates text that exceeds its context window, producing misleading embeddings. Known limits: OpenAI text-embedding-3-large/-small accept 8,191 tokens; jina-embeddings-v4 (current generation, released June 2025) natively supports up to 32,768 tokens, though Jina's hosted Embedding API currently caps input at 8,192 tokens regardless of model — check the live API docs before assuming the full native window is usable; the prior jina-embeddings-v3 accepts 8,192 tokens. Rule of thumb: keep chunks at or below ~75% of the embedding model's context limit to leave headroom and avoid edge-case truncation.

Tooling reference

LangChain (langchain-text-splitters): RecursiveCharacterTextSplitter (configure chunk_size, chunk_overlap), MarkdownHeaderTextSplitter (heading-aware, returns metadata), and Language splitters (tree-sitter, code-aware).

LlamaIndex (llama-index-core): SentenceSplitter (sentence-boundary-aware; chunk_size/chunk_overlap), SemanticSplitterNodeParser (buffer_size, breakpoint_percentile_threshold), and CodeSplitter (tree-sitter; language, chunk_lines).

unstructured.io (unstructured OSS): partition_* produces typed elements; chunk_by_title closes a chunk at each new section title (never merges across sections; max_characters, new_after_n_chars); Table elements stay atomic. Token-based chunking via max_tokens.

How to evaluate chunking choices

Chunking quality is best measured indirectly through retrieval metrics on your actual query distribution, not a generic benchmark.

  1. Build a question set — for each source document, generate 5–10 questions whose answers live in specific passages (LLM-generated or real user queries).
  2. Measure retrieval precision@k and recall@k — how many top-k retrieved chunks are relevant, and how many relevant chunks are in the top-k? Instrument with RAGAS (github.com/explodinggradients/ragas, arXiv:2309.15217).
  3. A/B compare strategies — hold retrieval and generation constant; vary only the chunking strategy and chunk size to isolate the effect.
  4. Check for boundary failures — sample retrieved chunks; chunks starting/ending mid-sentence, mid-table-row, or mid-code-block indicate a poor splitter.

Verified sources

#rag #chunking #embeddings #retrieval #langchain #llamaindex #agents #documents

Category: Guide

Like this? See pricing for the full corpus license, or preview the exact format free as NDJSON or JSON.