Retrieval-augmented generation (RAG) systems are often described in terms of embeddings, vector databases, and large language models. But one of the most important decisions happens before any of those components are used: how the source documents are divided into chunks.
If chunks are too large, retrieval may return a lot of irrelevant information. If they are too small, important context can be separated across multiple chunks. Traditional fixed-size chunking is easy to implement, but enterprise documents often have structure that does not align with arbitrary character or token boundaries.
Semantic chunking attempts to solve this problem by creating chunks around meaningful changes in content rather than simply cutting a document every N tokens.
For enterprise RAG systems, however, semantic chunking should not be adopted simply because it sounds more intelligent. It should be benchmarked against simpler approaches using the actual document corpus and retrieval workload.
This article explains how semantic chunking works, how it differs from fixed and structural chunking, and how to build a practical benchmark for enterprise document retrieval.
Introduction
Consider a 100-page technical document containing:
Architecture descriptions
API specifications
Configuration examples
Troubleshooting procedures
Security requirements
Frequently asked questions
A fixed chunking strategy might split the document every 800 tokens:
Document
|
+---- Chunk 1: 800 tokens
+---- Chunk 2: 800 tokens
+---- Chunk 3: 800 tokens
+---- Chunk 4: 800 tokens
...
The boundaries are convenient, but they may not correspond to the document's logical structure.
A semantic strategy attempts to identify related passages:
Document
|
+---- Authentication Concepts
|
+---- Authentication Configuration
|
+---- Authentication Troubleshooting
|
+---- Authorization Requirements
|
+---- API Security
The second approach can produce more meaningful retrieval units, but it also introduces additional processing, complexity, and tuning.
The right question is therefore not:
"Is semantic chunking better?"
It is:
"Which chunking strategy produces the best retrieval quality for this workload at an acceptable cost and latency?"
What Is Document Chunking?
Chunking is the process of dividing a document into smaller units that can be indexed and retrieved independently.
A typical RAG pipeline looks like this:
Documents
|
v
Parsing
|
v
Chunking
|
v
Embeddings
|
v
Vector Store
|
v
Retriever
|
v
LLM
|
v
Answer
The chunk becomes the basic retrieval unit.
If the chunk does not contain enough context to answer a question, retrieval may return technically relevant but practically incomplete information.
For example, imagine a document containing:
## Connection Pooling
The default pool size is 100.
## Configuration
The maximum pool size can be changed using:
MaxPoolSize=500
If the chunk boundary separates the configuration from the explanation, a question such as:
How do I increase the connection pool size?
may retrieve only the configuration value without enough surrounding context.
Fixed-Size Chunking
The simplest strategy is fixed-size chunking.
For example:
public static IEnumerable<string> ChunkBySize(
string text,
int chunkSize)
{
for (int i = 0; i < text.Length; i += chunkSize)
{
yield return text[
i..Math.Min(i + chunkSize, text.Length)];
}
}
In a real RAG pipeline, token-based chunking is generally more appropriate than character-based chunking because model context and pricing are token-oriented.
Fixed-size chunking has several advantages:
Simple implementation
Predictable chunk sizes
Low processing overhead
Easy benchmarking
Easy operational tuning
Its biggest weakness is that it does not understand document meaning.
Overlapping Chunks
A common improvement is to introduce overlap.
For example:
Chunk 1
|------------------------|
Chunk 2
|------------------------|
Chunk 3
|------------------------|
If the chunk size is 800 tokens and the overlap is 100 tokens, the next chunk begins before the previous one completely ends.
Overlap helps preserve context around boundaries.
However, it also increases:
Number of chunks
Embedding operations
Storage requirements
Retrieval candidates
Potential duplicate context
The overlap should therefore be treated as a benchmark parameter rather than a universal best practice.
Structural Chunking
Many enterprise documents already contain useful structure.
Examples include:
Headings
Sections
Paragraphs
Tables
Lists
Code blocks
Page boundaries
Metadata fields
A structural chunker can use these boundaries.
For example:
Document
|
+-- Chapter
|
+-- Section
|
+-- Paragraph
+-- Paragraph
+-- Table
Instead of cutting text arbitrarily, the chunker attempts to preserve the document's logical organization.
This can be particularly useful for technical documentation, policies, manuals, and reports.
What Is Semantic Chunking?
Semantic chunking uses the meaning of adjacent passages to determine where one chunk should end and another should begin.
A simplified approach is:
Sentence 1
Sentence 2
Sentence 3
Sentence 4
|
v
Calculate semantic similarity
|
v
Detect topic transition
|
v
Create chunk boundary
Suppose the document contains:
The application uses OAuth 2.0.
Access tokens are issued by the identity provider.
Tokens expire after 60 minutes.
The database uses connection pooling.
Connections are reused across requests.
The semantic relationship between the first three sentences is stronger than the relationship between the third and fourth sentences.
A semantic chunker may therefore produce:
Chunk 1:
OAuth authentication and token expiration
Chunk 2:
Database connection pooling
The important point is that semantic chunking is not simply "larger chunks with embeddings." It uses semantic relationships to determine boundaries.
A Basic Semantic Similarity Approach
A simple implementation can represent each sentence as an embedding.
Conceptually:
var embeddings =
await embeddingService.GenerateAsync(sentences);
for (int i = 1; i < embeddings.Count; i++)
{
var similarity =
CosineSimilarity(
embeddings[i - 1],
embeddings[i]);
if (similarity < threshold)
{
CreateBoundary();
}
}
A simplified cosine similarity implementation is:
public static double CosineSimilarity(
IReadOnlyList<float> a,
IReadOnlyList<float> b)
{
double dot = 0;
double magnitudeA = 0;
double magnitudeB = 0;
for (int i = 0; i < a.Count; i++)
{
dot += a[i] * b[i];
magnitudeA += a[i] * a[i];
magnitudeB += b[i] * b[i];
}
if (magnitudeA == 0 || magnitudeB == 0)
{
return 0;
}
return dot /
(Math.Sqrt(magnitudeA) *
Math.Sqrt(magnitudeB));
}
This is a conceptual implementation. Production systems should also consider batching, embedding throughput, memory usage, and model-specific behavior.
The Chunking Threshold Matters
The semantic threshold determines when a topic transition is considered significant.
For example:
Similarity >= 0.85
Keep sentences together
Similarity < 0.85
Consider boundary
But 0.85 is not a universal value.
A threshold that works well for technical manuals may behave differently for:
Legal contracts
Financial reports
Product documentation
Support tickets
Research papers
This is one reason benchmarking is necessary.
Why Enterprise Documents Are Difficult
Enterprise documents are rarely plain paragraphs.
They may contain:
Heading
Paragraph
Table
Bullet list
Code sample
Warning
Footnote
Image
Caption
Appendix
Semantic chunking applied directly to extracted text can lose important relationships.
For example:
Table:
Status | Meaning
200 | Success
404 | Not Found
500 | Server Error
If the table is converted into an unstructured text sequence, the retrieval representation may become less useful.
Therefore, a serious benchmark should evaluate not just the chunking algorithm but also the document parsing and structure preservation pipeline.
Chunk Metadata Matters
A chunk should carry metadata describing where it came from.
For example:
public sealed record DocumentChunk(
string Id,
string Text,
string DocumentId,
string Section,
int PageNumber,
int ChunkIndex);
Metadata enables:
Filtering
Citation generation
Debugging
Document-level grouping
Section-aware retrieval
Retrieval analysis
For example:
Document: SecurityGuide.pdf
Page: 42
Section: Authentication
Chunk: 17
When a retrieved chunk produces a poor answer, this metadata makes the failure easier to investigate.
Designing the Benchmark
The benchmark should compare multiple strategies using the same corpus.
At minimum, consider:
Strategy A:
Fixed-size chunks
Strategy B:
Fixed-size + overlap
Strategy C:
Structural chunks
Strategy D:
Semantic chunks
Keep other variables constant where possible:
Embedding model
Vector store
Query set
Retrieval algorithm
Top-K
Generation model
Prompt
Evaluation criteria
Otherwise, it becomes difficult to determine whether a change in results actually came from chunking.
Build a Representative Evaluation Dataset
Create questions from real document content.
For example:
Question:
What is the default connection pool size?
Expected Source:
Database Configuration section
Question:
How is OAuth token expiration configured?
Expected Source:
Authentication section
Question:
What happens when a request receives HTTP 429?
Expected Source:
Rate Limiting section
The dataset should include both simple and difficult questions.
Useful categories include:
| Question Type | Example |
|---|---|
| Direct fact | What is the default timeout? |
| Configuration | How do I configure X? |
| Multi-part | What are the requirements for X and Y? |
| Cross-section | How does X affect Y? |
| Procedural | What steps are required? |
| Table-based | What does status code 429 mean? |
| Long-context | Summarize the authentication requirements |

Join the conversation! Your thoughts help the community grow.