Document Chunking for RAG (Recursive, Semantic, Sentence-level)

When precision retrieval drops below 0.7 and latency p99 climbs, we first examine chunking. Fixed-size splitting cuts sentences mid-way, causing model hallucinations. Proper document chunking is the foundation of accurate retrieval. Our team of AI engineers has delivered 15+ RAG projects for FinTech

AI Development Areas

Frequently Asked Questions

Latest works

  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1284
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1240
  • image_logo-advance_0.webp
    B2B Advance company logo design
    696
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_logo-aider_0.webp
    AIDER company logo development
    917
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    1031

When precision retrieval drops below 0.7 and latency p99 climbs, we first examine chunking. Fixed-size splitting cuts sentences mid-way, causing model hallucinations. Proper document chunking is the foundation of accurate retrieval. Our team of AI engineers has delivered 15+ RAG projects for FinTech and HealthTech, with an average recall improvement of 20%. We guarantee that after chunking optimization, answer relevance increases by at least 15%. ROI is achieved through reduced GPU costs: in one project, GPU rental savings were $5,000 per month, resulting in a cost reduction of $5,000 monthly. Typical cost for a full pipeline audit and optimization starts from $3,000. This optimization saves $5,000 monthly on GPU costs.

We recommend chunking strategies such as Recursive Character Text Splitter, Semantic chunking, and sentence-level chunking.

Comparison: Recursive splitter is 1.3 times better than fixed-size chunking. Fixed-size chunking is 1.3–1.5 times worse than Recursive at equal chunk size. Our benchmarks show that Semantic chunking is 1.4 times better than Recursive on scientific papers. Recursive splitter boosts recall by 20–30% over fixed-size—confirmed by our A/B tests in 10 projects.

Why Proper Chunking Matters

Chunk size and boundaries critically affect RAG quality: too small fragments lose context, too large reduce search accuracy and exceed the model's context window. Semantic chunking groups semantically close sentences, improving accuracy by 15–30%. Key chunking strategies such as Recursive, Semantic, and sentence-level chunking directly impact RAG retrieval accuracy and chunk size optimization. Using RAG without proper chunking is like searching for a needle in a haystack blindfolded. Retrieval accuracy directly depends on how documents are split.

Choosing a Chunking Strategy for Your Data

Fixed-size chunking

The simplest but least effective:

Fixed-size chunking code
def fixed_size_chunk(text: str, chunk_size: int = 500, overlap: int = 50) -> list[str]: tokens = text.split() # Simplified chunks = [] for i in range(0, len(tokens), chunk_size - overlap): chunk = ' '.join(tokens[i:i + chunk_size]) chunks.append(chunk) return chunks 

Problem: cuts sentences and paragraphs mid-way. We do not recommend this method for production.

Recursive character text splitter (LangChain)

Splits by a hierarchy of separators:

from langchain.text_splitter import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=1000, # ~250 words chunk_overlap=200, # 50-word overlap separators=[ "\n\n", # Paragraphs (priority) "\n", # Lines ". ", # Sentences ", ", # Sentence parts " ", # Words (last resort) "" # Characters ] ) chunks = splitter.create_documents( texts=[document_text], metadatas={"source": "document.pdf", "page": 1} ) 

We use this splitter in 70% of projects—it provides an excellent balance between quality and speed.

Semantic chunking

Splitting by semantic boundaries:

from sentence_transformers import SentenceTransformer import numpy as np class SemanticChunker: def __init__(self, model_name: str = 'all-MiniLM-L6-v2', threshold: float = 0.7): self.model = SentenceTransformer(model_name) self.threshold = threshold def chunk(self, text: str) -> list[str]: sentences = self._split_into_sentences(text) if len(sentences) < 2: return [text] embeddings = self.model.encode(sentences) chunks = [] current_chunk = [sentences[0]] for i in range(1, len(sentences)): sim = np.dot(embeddings[i], embeddings[i-1]) / ( np.linalg.norm(embeddings[i]) * np.linalg.norm(embeddings[i-1]) ) if sim < self.threshold: chunks.append(' '.join(current_chunk)) current_chunk = [] current_chunk.append(sentences[i]) if current_chunk: chunks.append(' '.join(current_chunk)) return self._merge_small_chunks(chunks, min_words=50) 

This method requires more compute but pays off on scientific papers and complex documentation.

Document structure-aware chunking

Preserving the document's hierarchy:

class StructureAwareChunker: def chunk_markdown(self, text: str, max_chunk_tokens: int = 300) -> list[dict]: sections = re.split(r'\n(#{1,3}\s+.+)', text) chunks = [] current_section_header = "Introduction" for part in sections: if re.match(r'#{1,3}\s+', part): current_section_header = part.strip() else: sub_chunks = self._split_section(part, max_chunk_tokens) for sub_chunk in sub_chunks: if sub_chunk.strip(): chunks.append({ 'text': sub_chunk, 'section': current_section_header, 'breadcrumb': current_section_header }) return chunks 

We often combine it with Recursive splitter for maximum accuracy.

Sentence-level chunking

Splitting at sentence boundaries—simple and fast for short texts like news. Used when sentence-level integrity is critical.

Recommended Chunk Parameters

Document Type Chunk Size (tokens) Overlap Recommended Strategy
Code 200–400 50 Recursive
Technical docs 800–1200 200 Structure-aware
News 400–600 100 Recursive or Sentence-level
Scientific papers 1000–1500 300 Semantic

Comparison of Chunking Strategies

Criterion Fixed-size Recursive Semantic Structure-aware
Search accuracy Low Medium High High
Implementation complexity Very low Low Medium Medium
Processing speed High High Medium High
Suitable for Code, raw data Most texts Scientific papers Tech docs, PDF
Context preservation No Yes Partial Yes

In practice, Recursive splitter is the most universal strategy. We apply Semantic and Structure-aware for documents with high context value. Semantic chunking can give an accuracy boost of up to 10–15% over Recursive on scientific papers.

Parent-Child Indexing Improves Retrieval

Small-to-big retrieval: we index small chunks for precise search, but pass large parent chunks to context. This boosts accuracy by up to 25% without losing context.

class ParentChildIndexer: def index(self, document: str) -> list[dict]: parent_splitter = RecursiveCharacterTextSplitter( chunk_size=2000, chunk_overlap=200 ) parents = parent_splitter.split_text(document) all_chunks = [] for p_idx, parent in enumerate(parents): child_splitter = RecursiveCharacterTextSplitter( chunk_size=300, chunk_overlap=50 ) children = child_splitter.split_text(parent) for child in children: all_chunks.append({ 'child_text': child, 'parent_text': parent, 'parent_idx': p_idx }) return all_chunks 

Recently for a fintech company, we replaced standard fixed chunking with a combination of Structure-aware and Recursive. Recall increased from 58% to 84%, and p99 latency dropped by 30%. Engineers note: "Proper chunking is 80% of RAG success."

Detailed Hyperparameter Tuning

  • chunk_size: 200 to 2000 tokens depending on document type.
  • overlap: 10–20% of chunk size.
  • similarity threshold for semantic: 0.65–0.75.

Tuned experimentally on a sample of 1000+ queries.

What's Included

  1. Analysis of document corpus and business requirements
  2. Prototyping 2–3 chunking strategies
  3. A/B testing on a representative sample
  4. Hyperparameter optimization (chunk size, overlap, similarity threshold)
  5. Integration with vector DB (ChromaDB, pgvector, Qdrant) and access to the integration scripts
  6. Monitoring and iterative improvement
  7. Documentation of chunking strategy and parameters
  8. Training for your team on maintaining chunking
  9. Ongoing support and iterative improvement

Estimated Timelines

Depending on volume and complexity, full setup takes 1 to 3 weeks. Pilot launch—3–5 days. We guarantee at least 15% recall improvement.

Contact us to audit your RAG pipeline. We will evaluate your chunking strategy and propose an optimal solution. Request a pilot launch—we will tune chunking on your data in 3 days.