Chunking RAG 2026 : Les 8 Stratégies Avancées que Personne ne Vous Explique
Les 8 stratégies de chunking avancées pour RAG en 2026 : semantic chunking, agentic chunking, late chunking, contextual chunking d'Anthropic (+49% recall), parent-child et plus.
TL;DR
Le chunking est le facteur n1 de qualité dans un pipeline RAG, pourtant 90% des développeurs utilisent encore le découpage fixe par caractères. Ce guide détaille les 8 stratégies avancées de 2026 : du semantic chunking (basé sur les embeddings) au contextual chunking d'Anthropic (+49% de recall), en passant par le late chunking de Jina et l'agentic chunking piloté par LLM. Avec des benchmarks qui prouvent qu'un bon chunking améliore la qualité finale de 15-35% sans toucher au modèle de génération.
Pourquoi le chunking est si important
L'impact mesurable du chunking
| Stratégie de chunking | Recall@5 | Answer Quality | Faithfulness |
|---|---|---|---|
| Fixe (500 chars) | 72.3% | 68.1% | 71.5% |
| Fixe (1000 chars) | 75.8% | 71.2% | 73.8% |
| Récursif (LangChain) | 78.1% | 74.5% | 76.2% |
| Sémantique | 83.5% | 79.8% | 80.1% |
| Contextuel (Anthropic) | 88.2% | 85.1% | 87.3% |
| Late chunking (Jina) | 85.7% | 82.3% | 84.5% |
| Parent-child | 84.1% | 83.7% | 82.8% |
| Proposition-based | 86.3% | 84.2% | 85.9% |
La différence entre le chunking fixe basique et le chunking contextuel est de +22% en recall et +25% en qualité de réponse.
Le problème fondamental
Quand on découpe un document en chunks, on perd du contexte :
Document original :
"Ailog est une plateforme RAG-as-a-Service française.
Elle permet de créer des chatbots en quelques minutes.
Son prix commence à 49€/mois pour les PME."
Chunk 1 : "Ailog est une plateforme RAG-as-a-Service française."
Chunk 2 : "Elle permet de créer des chatbots en quelques minutes."
Chunk 3 : "Son prix commence à 49€/mois pour les PME."
→ Chunk 2 : QUI permet de créer des chatbots ? Contexte perdu !
→ Chunk 3 : Le prix de QUOI ? Contexte perdu !
Les 8 stratégies suivantes résolvent ce problème de différentes manières.
Stratégie 1 : Semantic Chunking
Principe
Au lieu de couper à intervalles fixes, on découpe aux frontières sémantiques : là où le sens du texte change. On utilise les embeddings pour mesurer la similarité entre phrases consécutives.
DEVELOPERpythonfrom sentence_transformers import SentenceTransformer import numpy as np model = SentenceTransformer("all-MiniLM-L6-v2") def semantic_chunking( text: str, threshold: float = 0.3, min_chunk_size: int = 100, max_chunk_size: int = 1500 ): """Découpe le texte aux ruptures sémantiques.""" # Découper en phrases sentences = text.split(". ") if len(sentences) < 2: return [text] # Embeddings de chaque phrase embeddings = model.encode(sentences) # Calculer la distance entre phrases consécutives distances = [] for i in range(len(embeddings) - 1): similarity = np.dot(embeddings[i], embeddings[i + 1]) / ( np.linalg.norm(embeddings[i]) * np.linalg.norm(embeddings[i + 1]) ) distances.append(1 - similarity) # Trouver les points de rupture breakpoints = [] for i, dist in enumerate(distances): if dist > threshold: breakpoints.append(i + 1) # Construire les chunks chunks = [] start = 0 for bp in breakpoints: chunk = ". ".join(sentences[start:bp]) + "." if len(chunk) >= min_chunk_size: chunks.append(chunk) elif chunks: chunks[-1] += " " + chunk start = bp # Dernier chunk remaining = ". ".join(sentences[start:]) if remaining: if len(remaining) >= min_chunk_size: chunks.append(remaining) elif chunks: chunks[-1] += " " + remaining return chunks
| Avantage | Inconvénient |
|---|---|
| Chunks sémantiquement cohérents | Nécessite un modèle d'embedding |
| Meilleur recall (+8-12%) | Plus lent que le chunking fixe |
| Adapté à tout type de texte | Seuil à calibrer par corpus |
Stratégie 2 : Agentic Chunking
Principe
Un LLM décide lui-même où couper et comment grouper les passages. L'agent analyse le document et identifie les unités de sens logiques.
DEVELOPERpythonfrom openai import OpenAI client = OpenAI() def agentic_chunking(text: str, max_chunks: int = 20): """Le LLM décide du découpage optimal.""" response = client.chat.completions.create( model="gpt-4o-mini", messages=[{ "role": "system", "content": ( "Tu es un expert en structuration de documents. " "Découpe le texte suivant en chunks logiques. " "Chaque chunk doit être autonome et compréhensible " "sans contexte supplémentaire. " "Ajoute un titre descriptif à chaque chunk. " "Retourne un JSON : [{\"title\": \"...\", \"content\": \"...\"}]" ) }, { "role": "user", "content": text }], response_format={"type": "json_object"}, temperature=0.1 ) return json.loads(response.choices[0].message.content)["chunks"]
| Avantage | Inconvénient |
|---|---|
| Compréhension profonde du contenu | Très coûteux (appel LLM par document) |
| Chunks parfaitement autonomes | Lent (secondes par chunk) |
| Titres générés automatiquement | Non déterministe |
Stratégie 3 : Late Chunking (Jina AI)
Principe
L'innovation de Jina AI : au lieu d'encoder chaque chunk indépendamment, on encode d'abord le document entier puis on découpe les embeddings. Chaque chunk hérite du contexte global.
DEVELOPERpythonfrom transformers import AutoModel, AutoTokenizer # Charger jina-embeddings-v2 (supporte 8192 tokens) model = AutoModel.from_pretrained( "jinaai/jina-embeddings-v2-base-en", trust_remote_code=True ) tokenizer = AutoTokenizer.from_pretrained( "jinaai/jina-embeddings-v2-base-en" ) def late_chunking(text: str, chunk_size: int = 256): """Late chunking : encode le document entier, découpe ensuite.""" # Étape 1 : tokeniser le document entier inputs = tokenizer( text, return_tensors="pt", max_length=8192, truncation=True, return_offsets_mapping=True ) # Étape 2 : obtenir les embeddings token-level outputs = model(**{k: v for k, v in inputs.items() if k != "offset_mapping"}) token_embeddings = outputs.last_hidden_state[0] # Étape 3 : découper les embeddings en chunks num_tokens = token_embeddings.shape[0] chunks = [] for start in range(0, num_tokens, chunk_size): end = min(start + chunk_size, num_tokens) # Moyenne des embeddings token dans le chunk chunk_embedding = token_embeddings[start:end].mean(dim=0) # Récupérer le texte correspondant offsets = inputs["offset_mapping"][0][start:end] chunk_text = text[offsets[0][0]:offsets[-1][1]] chunks.append({ "text": chunk_text, "embedding": chunk_embedding.detach().numpy() }) return chunks
| Avantage | Inconvénient |
|---|---|
| Chaque chunk a le contexte du document | Limité par la fenêtre du modèle (8K) |
| Pas de perte de coréférence | Nécessite un modèle Jina spécifique |
| +7-10% recall vs semantic chunking | Calcul plus intensif |
Stratégie 4 : Contextual Chunking (Anthropic)
Principe
L'approche d'Anthropic publiée dans leur article sur le "Contextual Retrieval" : on ajoute un résumé contextuel au début de chaque chunk. Le LLM génère un contexte qui situe le chunk dans le document global.
DEVELOPERpythonimport anthropic client = anthropic.Anthropic() CONTEXT_PROMPT = """ <document> {document} </document> Voici un chunk extrait de ce document : <chunk> {chunk} </chunk> Génère un contexte court (2-3 phrases) qui situe ce chunk dans le document global. Inclus les informations essentielles pour comprendre le chunk de manière autonome. Commence directement par le contexte, sans préfixe. """ def contextual_chunking(document: str, chunks: list) -> list: """Ajoute un contexte à chaque chunk (approche Anthropic).""" enriched_chunks = [] for chunk in chunks: response = client.messages.create( model="claude-sonnet-4-20250514", max_tokens=200, messages=[{ "role": "user", "content": CONTEXT_PROMPT.format( document=document[:15000], # Tronquer si nécessaire chunk=chunk ) }] ) context = response.content[0].text enriched_chunk = f"{context}\n\n{chunk}" enriched_chunks.append(enriched_chunk) return enriched_chunks # Exemple de résultat : # Contexte : "Ce passage est extrait de la politique de retour # d'Ailog, une plateforme RAG-as-a-Service. Il détaille # les conditions de remboursement pour les abonnements mensuels." # # "Le remboursement est effectué sous 14 jours ouvrés..."
Résultats d'Anthropic
Anthropic mesure le taux d'échec de retrieval (1 − recall@20, soit le pourcentage de passages pertinents qui n'apparaissent pas dans le top 20). Les résultats publiés :
| Configuration | Taux d'échec (1 − recall@20) | Réduction vs référence |
|---|---|---|
| Chunks bruts (référence) | 5.7% | - |
| + Contextual Embeddings | 3.7% | −35% |
| + Contextual BM25 | 2.9% | −49% |
| + Reranking | 1.9% | −67% |
Le fameux « −49% » correspond donc à la combinaison des embeddings contextuels et de BM25 contextuel, pas au chunking contextuel seul (qui réduit les échecs de 35%).
| Avantage | Inconvénient |
|---|---|
| −49% d'échecs de retrieval (embeddings contextuels + BM25) | Coût : 1 appel LLM par chunk |
| Chunks autonomes et compréhensibles | Latence à l'indexation |
| Compatible avec tout type de chunking | Document entier doit tenir en contexte |
Stratégie 5 : Parent-Child Chunking
Principe
On crée deux niveaux de chunks : des petits chunks (enfants) pour la recherche précise, et de grands chunks (parents) pour le contexte. Lors du retrieval, on cherche par les enfants mais on retourne les parents.
DEVELOPERpythonfrom dataclasses import dataclass from typing import List, Optional @dataclass class ChunkNode: id: str text: str parent_id: Optional[str] children_ids: List[str] level: str # "parent" ou "child" def parent_child_chunking( text: str, parent_size: int = 2000, child_size: int = 400, overlap: int = 50 ) -> tuple: """Crée une hiérarchie parent-child de chunks.""" # Niveau 1 : grands chunks (parents) parents = [] for i in range(0, len(text), parent_size - overlap): parent_text = text[i:i + parent_size] parent = ChunkNode( id=f"parent_{i}", text=parent_text, parent_id=None, children_ids=[], level="parent" ) parents.append(parent) # Niveau 2 : petits chunks (enfants) au sein de chaque parent children = [] for parent in parents: for j in range(0, len(parent.text), child_size - overlap): child_text = parent.text[j:j + child_size] child = ChunkNode( id=f"child_{parent.id}_{j}", text=child_text, parent_id=parent.id, children_ids=[], level="child" ) children.append(child) parent.children_ids.append(child.id) return parents, children def search_with_parent_context(query: str, top_k: int = 5): """Recherche sur les enfants, retourne les parents.""" # Recherche vectorielle sur les enfants child_results = vector_search(query, collection="children", top_k=top_k) # Récupérer les parents uniques parent_ids = set() for child in child_results: parent_ids.add(child.metadata["parent_id"]) # Retourner le texte des parents parents = fetch_documents(list(parent_ids), collection="parents") return parents
| Avantage | Inconvénient |
|---|---|
| Précision de recherche + richesse de contexte | Double stockage |
| Pattern bien supporté (LangChain, LlamaIndex) | Complexité de maintenance |
| Fonctionne sans LLM | Overlap à calibrer |
Stratégie 6 : Sliding Window avec chevauchement intelligent
Principe
Un classique amélioré : le chevauchement n'est pas fixe mais s'adapte aux frontières de phrases.
DEVELOPERpythondef smart_sliding_window( text: str, window_size: int = 512, target_overlap: int = 100 ) -> list: """Sliding window avec chevauchement aux frontières de phrases.""" sentences = text.split(". ") chunks = [] current_chunk = [] current_length = 0 for sentence in sentences: sent_len = len(sentence) if current_length + sent_len > window_size and current_chunk: chunk_text = ". ".join(current_chunk) + "." chunks.append(chunk_text) # Overlap intelligent : garder les dernières phrases overlap_chunk = [] overlap_len = 0 for s in reversed(current_chunk): if overlap_len + len(s) <= target_overlap: overlap_chunk.insert(0, s) overlap_len += len(s) else: break current_chunk = overlap_chunk current_length = overlap_len current_chunk.append(sentence) current_length += sent_len if current_chunk: chunks.append(". ".join(current_chunk)) return chunks
Stratégie 7 : Document-Structure-Aware Chunking
Principe
Exploiter la structure du document (titres, sous-titres, paragraphes) pour créer des chunks logiques.
DEVELOPERpythonimport re def structure_aware_chunking( markdown_text: str, max_chunk_size: int = 1500 ) -> list: """Chunking basé sur la structure Markdown.""" # Détecter les sections sections = re.split(r'\n(#{1,3}\s+.+)\n', markdown_text) chunks = [] current_section = "" current_headers = [] for i, part in enumerate(sections): # C'est un header if re.match(r'^#{1,3}\s+', part): level = len(re.match(r'^(#+)', part).group(1)) # Mettre à jour la hiérarchie des headers current_headers = current_headers[:level - 1] current_headers.append(part.strip()) continue # C'est du contenu if not part.strip(): continue header_context = " > ".join(current_headers) if len(part) <= max_chunk_size: chunks.append({ "text": part.strip(), "headers": current_headers.copy(), "context": header_context }) else: # Subdiviser les sections trop longues sub_chunks = split_by_paragraphs(part, max_chunk_size) for sc in sub_chunks: chunks.append({ "text": sc.strip(), "headers": current_headers.copy(), "context": header_context }) return chunks
Stratégie 8 : Proposition-Based Chunking
Principe
Chaque chunk est une proposition : une affirmation autonome et factuelle. Un LLM décompose le texte en propositions atomiques.
DEVELOPERpythondef proposition_chunking(text: str) -> list: """Décompose le texte en propositions atomiques.""" response = client.chat.completions.create( model="gpt-4o-mini", messages=[{ "role": "system", "content": ( "Décompose le texte en propositions atomiques. " "Chaque proposition doit être : " "1) Autonome (compréhensible seule) " "2) Factuelle (une seule information) " "3) Décontextualisée (pas de pronoms ambigus) " "Retourne un JSON : {\"propositions\": [\"...\"]}" ) }, { "role": "user", "content": text }], response_format={"type": "json_object"}, temperature=0.0 ) return json.loads( response.choices[0].message.content )["propositions"] # Exemple : # Input: "Ailog a été fondée en 2024. Elle est basée à Paris # et propose du RAG-as-a-Service." # # Output: # - "Ailog a été fondée en 2024." # - "Ailog est basée à Paris." # - "Ailog propose du RAG-as-a-Service."
Le grand comparatif : quelle stratégie choisir ?
| Stratégie | Recall@5 | Coût/1K docs | Latence indexation | Complexité | Meilleur cas d'usage |
|---|---|---|---|---|---|
| 1. Sémantique | 83.5% | $0.01 | ~2s/doc | Faible | Texte libre, articles |
| 2. Agentic | 85.8% | $2.00 | ~30s/doc | Élevée | Documents critiques |
| 3. Late (Jina) | 85.7% | $0.01 | ~3s/doc | Moyenne | Docs longs, coréférences |
| 4. Contextuel | 88.2% | $0.50 | ~15s/doc | Moyenne | Usage général (meilleur ROI) |
| 5. Parent-child | 84.1% | $0.01 | ~1s/doc | Faible | FAQ, docs structurés |
| 6. Sliding window | 79.2% | $0.00 | ~0.1s/doc | Très faible | Volume élevé, budget limité |
| 7. Structure-aware | 82.8% | $0.00 | ~0.5s/doc | Faible | Markdown, HTML, docs structurés |
| 8. Propositions | 86.3% | $1.50 | ~20s/doc | Élevée | Fact-checking, précision max |
Arbre de décision
Quel est votre budget ?
├─ Limité ($0)
│ ├─ Documents structurés ? → Structure-aware (#7)
│ └─ Texte libre ? → Semantic (#1) ou Sliding window (#6)
├─ Modéré ($0.50/1K docs)
│ └─ → Contextual chunking (#4) ← RECOMMANDÉ
└─ Élevé ($2+/1K docs)
├─ Précision maximale ? → Propositions (#8)
└─ Documents critiques ? → Agentic (#2)
Type de documents ?
├─ FAQ, documentation → Parent-child (#5)
├─ Longs documents techniques → Late chunking (#3)
├─ Articles, blog posts → Semantic (#1)
└─ Mixte → Contextual (#4)
Combinaisons gagnantes
Les meilleures performances viennent de la combinaison de stratégies :
Combo 1 : Contextuel + Parent-Child (recommandé)
DEVELOPERpythondef combo_contextual_parent_child(document: str): """Meilleur combo pour un RAG de production.""" # Étape 1 : Structure-aware chunking pour les parents parents = structure_aware_chunking(document, max_chunk_size=2000) # Étape 2 : Semantic chunking pour les enfants children = [] for parent in parents: child_chunks = semantic_chunking( parent["text"], threshold=0.3, max_chunk_size=500 ) for chunk in child_chunks: children.append({ "text": chunk, "parent_id": parent["id"] }) # Étape 3 : Enrichir les enfants avec le contexte enriched_children = contextual_chunking( document=document, chunks=[c["text"] for c in children] ) return parents, enriched_children
Combo 2 : Propositions + Clustering
Décomposer en propositions, puis regrouper les propositions similaires.
Résultats des combinaisons
| Combinaison | Recall@5 | Answer Quality |
|---|---|---|
| Contextuel seul | 88.2% | 85.1% |
| Parent-child seul | 84.1% | 83.7% |
| Contextuel + Parent-child | 90.5% | 88.3% |
| Propositions + Clustering | 89.1% | 87.5% |
| Semantic + Late chunking | 87.3% | 84.8% |
FAQ
Le contextual chunking d'Anthropic est-il vraiment +49% ?
Le chiffre de 49% publié par Anthropic correspond à une réduction du taux d'échec de retrieval (mesuré par 1 − recall@20), et il est obtenu en combinant les embeddings contextuels avec la recherche BM25 contextuelle. Les embeddings contextuels seuls réduisent les échecs de 35%, et l'ajout d'un reranker monte à 67%. Ce n'est donc pas un « +49% de recall » du chunking contextuel seul. Le plus gros gain vient bien de la combinaison avec la recherche hybride BM25, comme décrit dans notre guide sur la recherche hybride.
Quel est le coût du contextual chunking en production ?
Pour 10 000 documents de 5 pages en moyenne : environ $25-50 d'appels LLM (avec Claude Haiku ou GPT-4o-mini). C'est un coût unique à l'indexation, pas récurrent à chaque requête. Le ROI est excellent vu l'amélioration de qualité. Voir notre guide sur l'optimisation des coûts RAG.
Peut-on combiner le late chunking avec le contextual chunking ?
Théoriquement oui, mais en pratique ils résolvent le même problème (perte de contexte) par des approches différentes. Le late chunking préserve le contexte via les embeddings, le contextual chunking via du texte ajouté. Combiner les deux n'apporte pas de gain significatif par rapport à l'un ou l'autre seul.
Quelle taille de chunk est optimale ?
Il n'y a pas de réponse universelle. Nos benchmarks montrent : 200-500 tokens pour le retrieval précis (FAQ), 500-1000 tokens pour le retrieval contextuel (documents techniques), 1000-2000 tokens pour la génération longue. Le parent-child chunking permet de combiner les avantages des petits et grands chunks. Voir notre guide sur les stratégies de chunking.
Comment évaluer la qualité de mon chunking ?
Trois métriques clés : 1) Recall@k sur un dataset de test, 2) Chunk coherence (un LLM note la cohérence de 1 à 5), 3) Answer quality end-to-end. Automatisez ces métriques dans votre pipeline CI/CD. Voir notre guide sur les métriques d'évaluation RAG pour l'implémentation.
Le chunking est le levier d'optimisation RAG le plus sous-estimé. Passer d'un chunking fixe à un chunking contextuel peut transformer un chatbot médiocre en assistant fiable. Testez Ailog pour bénéficier d'un chunking intelligent automatique sur vos documents.
Tags
Articles connexes
RAG Multimodal : Images, PDFs et au-delà du texte
Étendez votre RAG au-delà du texte : indexation d'images, extraction de PDFs, tableaux et graphiques pour un assistant vraiment complet.
Fondamentaux du Parsing de Documents
Commencez votre parcours RAG : apprenez à extraire le texte, les métadonnées et la structure des documents pour la recherche sémantique.
Document Intelligence 2026 : L'IA qui Lit vos PDFs Mieux qu'un Humain (OCR, Tableaux, Graphiques)
Comparatif complet des outils de Document Intelligence en 2026 : Azure DI, AWS Textract, LlamaParse, Docling. OCR, extraction de tableaux, compréhension de graphiques et benchmarks de précision.