Skip to content
NLEN
Illustration: Comparing chunking strategies quantitatively for RAG

Comparing chunking strategies quantitatively for RAG

By Ivo Donker — compiled with AI assistance (Claude & Gemini)

The choice of chunking strategy largely determines the success or failure of a Retrieval-Augmented Generation (RAG) pipeline. When source documents are split into fragments that are too large, irrelevant text floods the language model's context window. If, on the other hand, you make fragments too small, coherence is lost and necessary preconditions for factually answering a question are missing. In practice, this decision is too often made based on rules of thumb or arbitrary defaults such as 500 tokens with 10% overlap.

A well-considered architecture requires a quantitative evaluation: how does a specific splitting method perform on your corpus in terms of accuracy, signal-to-noise ratio, and eventual answer quality? In this article, we formulate a reproducible measurement setup with which different splitting strategies are objectively compared with each other. For a broader overview of the interaction between the retrieval and generation steps, we refer to the foundation in the article on RAG evaluation, which dissects the complete chain from search step to model response.

The trade-offs between fixed, semantic, and structural splitting

Before calculating measurement values, it is necessary to classify the fundamental splitting mechanisms. There are roughly four dominant chunking approaches, each with specific assumptions about text structure and semantic density:

When documents are extremely long and narrative in nature, a chunking strategy can even compete with reading documents directly via huge context windows. Anyone considering offering documents in their entirety without an intermediate vector index would do well to consult the overview of models for summarizing long documents to understand the costs and processing limits of unsplit contexts.

Isolating the search phase from the generation phase

A common methodological mistake is judging chunking based solely on the final model answers. If a model fails, this could be due to a poor chunk (retrieval error), but equally to a reasoning error by the generator or hallucination despite perfect context. To purely quantify a chunking strategy, we split the evaluation into two isolated phases:

1. Retrieval quality (before the LLM): Are the correct passages retrieved from the database? Do the retrieved vectors contain the source data needed to answer the question?

2. Generation efficiency (through the LLM): How much noise do the retrieved chunks contain, and does the fragmented context lead to loss of coherence or unnecessary token costs?

Because the retrieval layer's accuracy is directly tied to the chosen vector representation, the influence of chunk size must always be evaluated in combination with the embedding model used. See also the guide for evaluating embedding models to verify how the effective dimensions and context capacities of embedding vectors relate to your chunk length.

Quantitative retrieval statistics: recall, MRR, and precision

To measure retrieval objectively, a curated evaluation set with pairs of questions and ground-truth document passages is required. We define a query $q$, a set of relevant document IDs $R_q$, and an ordered list of $k$ retrieved chunks $K_q = [c_1, c_2, \dots, c_k]$.

Metric Formula What it measures for chunking
Recall@k $$\frac{|R_q \cap K_q|}{|R_q|}$$ Whether the required information is present at all in the top-$k$ results.
Mean Reciprocal Rank (MRR) $$\frac{1}{|Q|} \sum_{i=1}^{|Q|} \frac{1}{\text{rank}_i}$$ How high the first relevant chunk appears in the ranking.
Context Precision $$\frac{\sum_{r=1}^k P@r \cdot \mathbb{I}(c_r \in R_q)}{|R_q|}$$ Whether relevant chunks are at the top and irrelevant chunks are avoided.
Context Token Efficiency $$\frac{\text{Number of relevant tokens in top-}k}{\text{Total number of retrieved tokens}}$$ The signal-to-noise ratio within the context window.

Small chunks (e.g., 128 tokens) often score high on Context Precision and Context Token Efficiency, but can yield lower Recall@k if an argument is spread across multiple sentences. Large chunks (e.g., 1024 tokens) easily achieve high Recall@k, but significantly reduce Context Token Efficiency because hundreds of irrelevant tokens are injected.

Illustrative example: The figures below show a hypothetical comparison between three splitting variants on a technical test corpus of 500 documents.

Strategy Recall@3 MRR Context Token Efficiency Avg. retrieval latency
Fixed window (128 tokens, overlap 20) 0.68 0.54 78% 12 ms
Recursive (512 tokens, overlap 50) 0.89 0.76 52% 15 ms
Structural / Markdown sections 0.93 0.84 69% 18 ms

Context fragmentation and measuring faithfulness

When a chunking algorithm splits a document, the surrounding context is cut away. This introduces the risk of context fragmentation: a chunk might contain the answer "In this case, the notice period is three months," but the condition "if the contract was signed before 2021" is in the preceding paragraph, which was not retrieved.

To evaluate how sensitive a chunking strategy is to fragmentation, we measure the Faithfulness and Answer Relevance of the generating model under controlled conditions. A low faithfulness score indicates that the generative model has to invent facts because preconditions are missing from the supplied chunk text.

The assessment of faithfulness and factual consistency can be automated using calibrated prompt evaluators. To ensure the reliability of such assessment models, we refer to the systematics in the article on setting up LLM-as-a-Judge, which discusses methods for correcting judge bias and position preferences.

Pitfalls in the Dutch language area

When benchmarking chunking on Dutch-language corpora, specific linguistic complications arise that remain invisible in standard English-language evaluation runs:

Token costs, indexing time, and storage quantification

A quantitative evaluation is not complete without weighing in the operational cost side. Smaller chunks with a lot of overlap lead to an explosion in the total number of vectors in the database, which increases storage costs and the computation time for building the index. Moreover, the total chunk size directly affects the number of input tokens per LLM call.

For a methodological breakdown of how token counts translate into operational budgets, see the methodology for managing evaluation costs. In the calculation below, we lay out how data density and API calls scale per splitting variant.

# Voorbeeld: Formule voor vectorindex-omvang en API-overhead
# N = aantal brondocumenten
# W = gemiddeld aantal tokens per document
# C = chunk-grootte in tokens
# O = overlap in tokens

aantal_chunks = (W - O) / (C - O)
totale_index_vectoren = N * aantal_chunks
totale_invoer_tokens_per_rag_call = k * C

If a corpus of 10,000 documents of 2,000 tokens each is split with $C=256$ and $O=50$, this results in approximately 94,660 chunks. If you choose $C=1024$ with $O=100$, this drops to approximately 20,550 chunks. That is a factor of 4.6 difference in database size and initial embedding costs.

A reproducible experimental test protocol

To run a benchmark yourself that is resistant to random fluctuations, we use a standardized step-by-step plan. All variables outside the chunking method are kept strictly constant.

1. Determine the sample size

Ensure a representative set of at least 100 to 250 test questions with verified source passages. To calculate whether your sample offers statistically sufficient discriminating power, you can consult the statistical framework for test size to correctly interpret confidence intervals around your recall scores.

2. Fix all remaining parameters

Keep the following factors identical across all test variants:

3. Run the comparison script

Below is a reference setup in Python for logging retrieval statistics across different chunking configurations:

from dataclasses import dataclass
from typing import List, Set

@dataclass
class RetrievalResult:
  query_id: str
  retrieved_chunk_ids: List[str]
  ground_truth_chunk_ids: Set[str]

def calculate_metrics(results: List[RetrievalResult], k: int = 3):
  total_recall = 0.0
  total_mrr = 0.0

  for res in results:
    top_k = res.retrieved_chunk_ids[:k]
    hits = [cid for cid in top_k if cid in res.ground_truth_chunk_ids]
    
    # Recall@k
    recall = len(hits) / max(1, len(res.ground_truth_chunk_ids))
    total_recall += recall
    
    # Reciprocal Rank
    rr = 0.0
    for rank, cid in enumerate(top_k, start=1):
      if cid in res.ground_truth_chunk_ids:
        rr = 1.0 / rank
        break
    total_mrr += rr

  count = max(1, len(results))
  return {
    f"Recall@{k}": round(total_recall / count, 4),
    "MRR": round(total_mrr / count, 4)
  }

Decision tree for chunking selection

Once the quantitative measurement results have been collected, the final architecture choice can be determined based on the decision rules below:

By no longer setting splitting parameters based on intuition but structurally measuring via Recall@k, Context Token Efficiency, and faithfulness scores, you transform the chunking step from an uncertain guess into an optimized engineering choice.