Module 4: Evaluation and Chunking Strategies
Advanced Chunking Patterns
Quick overview
Beyond basic chunking: recursive strategies (LangChain-style), metadata enrichment (headers, source), hierarchical chunks (parent/child), and context preservation. These patterns improve retrieval quality significantly.
You'll learn production-ready advanced patterns.
Recursive Chunking (LangChain-style)
Concept:
# Try to split hierarchically:
# 1. By paragraphs (\n\n)
# 2. If a paragraph is too large → by sentences (\n)
# 3. If a sentence is too large → by spaces
# 4. If a word is too large → by characters
# Guarantees: Never exceed max_chunk_size
Implementation:
from langchain.text_splitter import RecursiveCharacterTextSplitter
import tiktoken
def tiktoken_len(text):
encoding = tiktoken.encoding_for_model("gpt-4")
return len(encoding.encode(text))
# Recursive splitter with tokens
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
length_function=tiktoken_len,
separators=["\n\n", "\n", ". ", " ", ""] # Hierarchy
)
text = """
# Python Guide
Python is a programming language.
## Installation
Download from python.org.
Run the installer.
## First Program
print("Hello World")
"""
chunks = splitter.split_text(text)
print(f"Chunks: {len(chunks)}")
for i, chunk in enumerate(chunks):
print(f"\nChunk {i+1} ({tiktoken_len(chunk)} tokens):")
print(chunk[:100] + "...")
Metadata Enrichment
Add metadata to chunks:
class MetadataChunker:
"""Chunker with metadata"""
def chunk_with_metadata(self, text, source="doc1.md"):
"""Add source, headers, etc."""
# Detect headers (# Markdown)
lines = text.split('\n')
current_header = None
chunks = []
for line in lines:
if line.startswith('#'):
current_header = line.strip('# ')
# ... chunking logic ...
chunk = {
'text': chunk_text,
'metadata': {
'source': source,
'header': current_header,
'tokens': len(tokens)
}
}
chunks.append(chunk)
return chunks
Advantage: Retrieval can filter by source, header, etc.
Hierarchical Chunks (Parent/Child)
Concept:
# Embed small chunks (high precision)
# But retrieve large chunks (more context)
# Parent chunk (800 tokens):
parent = "Full section about Python installation..."
# Child chunks (200 tokens each):
children = [
"Download Python from python.org...",
"Run installer...",
"Verify installation..."
]
# Retrieval:
# 1. Search in children (precision)
# 2. If match → Return parent (full context)
Context Preservation
Windowed chunking:
# Preserve previous/following context:
def windowed_chunking(text, chunk_size=500, window_before=100, window_after=100):
"""Chunks with previous/following context"""
base_chunks = fixed_chunking(text, chunk_size)
windowed = []
for i, chunk in enumerate(base_chunks):
# Add context from the previous chunk
context_before = base_chunks[i-1][-window_before:] if i > 0 else ""
# Add context from the following chunk
context_after = base_chunks[i+1][:window_after] if i < len(base_chunks)-1 else ""
windowed_chunk = context_before + " [...] " + chunk + " [...] " + context_after
windowed.append(windowed_chunk)
return windowed
Summary
What you learned:
- ✅ Recursive: Balance fixed/semantic
- ✅ Metadata: Enriches chunks (source, headers)
- ✅ Hierarchical: Parent/child for precision+context
- ✅ Context preservation: Windowed chunking
Key pattern: Hierarchical chunks = best for RAG.
In the next capsule
Capsule 08: Mini-Project - RAG System with Intelligent Chunking
You'll build a complete RAG system with end-to-end evaluation.
Module 4 - Embeddings Deep Dive Guide Advanced patterns: production-ready chunking