2. ChunkingIntermédiaire

Stratégies de Chunking : Optimiser la Segmentation des Documents

25 janvier 2025
15 min de lecture
Équipe de Recherche Ailog

Maîtrisez les techniques de découpage de documents pour améliorer la qualité de la récupération. Apprenez les tailles de chunks, les chevauchements, les divisions sémantiques et les stratégies avancées.

En bref

  • La taille des chunks compte : 500-1000 tokens équilibrent contexte et précision
  • Le chunking sémantique (découpage par signification) surpasse le découpage à taille fixe en qualité (+15-30% de précision de récupération)
  • Le chevauchement (10-20%) évite de perdre le contexte aux limites
  • Meilleur choix pour la plupart des cas : Recursive text splitter avec 512 tokens, chevauchement de 50 tokens
  • Essayez maintenant : Testez différentes stratégies sur la plateforme Ailog

Le problème du chunking

La plupart des documents sont trop longs pour :

  • Être intégrés en un seul vecteur (limites de fenêtre de contexte)
  • Être utilisés entièrement comme contexte LLM (limites de tokens)
  • Être récupérés avec précision (trop d'informations non pertinentes)

Le chunking divise les documents en morceaux plus petits et gérables tout en préservant le sens sémantique.

Pourquoi le chunking est important

Un mauvais chunking conduit à :

  • Contexte fragmenté : Informations importantes divisées entre les chunks
  • Récupération non pertinente : Les chunks contiennent un mélange de contenu pertinent et non pertinent
  • Perte de contexte : Les limites des chunks coupent les informations critiques
  • Génération médiocre : Le LLM manque de contexte complet pour répondre avec précision

Un bon chunking permet :

  • Récupération précise : Trouver exactement l'information pertinente
  • Contexte complet : Les chunks contiennent des pensées ou concepts complets
  • Utilisation efficace des tokens : Pas de gaspillage de contexte sur du texte non pertinent
  • Meilleures réponses : Le LLM a ce dont il a besoin, rien de plus

Chunking à taille fixe

Basé sur les caractères

Diviser le texte tous les N caractères.

DEVELOPERpython
def chunk_by_chars(text, chunk_size=1000, overlap=200): chunks = [] start = 0 while start < len(text): end = start + chunk_size chunks.append(text[start:end]) start += chunk_size - overlap return chunks

Avantages :

  • Implémentation simple
  • Tailles de chunks prévisibles
  • Traitement rapide

Inconvénients :

  • Coupe au milieu des mots, des phrases
  • Ignore les limites sémantiques
  • Casse le code, les tableaux, les listes

Utiliser quand :

  • Un prototype rapide est nécessaire
  • La structure du texte est homogène
  • La précision n'est pas critique

Basé sur les tokens

Diviser par nombre de tokens (correspond à la tokenisation du modèle).

DEVELOPERpython
import tiktoken def chunk_by_tokens(text, chunk_size=512, overlap=50): encoding = tiktoken.get_encoding("cl100k_base") tokens = encoding.encode(text) chunks = [] start = 0 while start < len(tokens): end = start + chunk_size chunk_tokens = tokens[start:end] chunks.append(encoding.decode(chunk_tokens)) start += chunk_size - overlap return chunks

Avantages :

  • Respecte précisément les limites de tokens
  • Fonctionne avec n'importe quel modèle d'embedding
  • Coûts d'embedding prévisibles

Inconvénients :

  • Ignore toujours les limites sémantiques
  • Overhead de tokenisation
  • Peut diviser un contexte important

Utiliser quand :

  • Budget de tokens strict
  • Le nombre de tokens est critique (coûts API)
  • Le modèle d'embedding a des limites strictes de tokens

Tailles fixes recommandées

Cas d'usageTaille de chunkChevauchementJustification
FAQ courtes128-256 tokens0-20Contexte minimal nécessaire
Docs générales512-1024 tokens50-100Équilibre précision et contexte
Docs techniques1024-2048 tokens100-200Plus de contexte pour sujets complexes
Code256-512 tokens50-100Préserver le contexte fonction/classe

Chunking sémantique

Diviser aux limites sémantiques naturelles.

Basé sur les phrases

Diviser aux limites de phrases.

DEVELOPERpython
import nltk nltk.download('punkt') def chunk_by_sentences(text, sentences_per_chunk=5): sentences = nltk.sent_tokenize(text) chunks = [] for i in range(0, len(sentences), sentences_per_chunk): chunk = ' '.join(sentences[i:i + sentences_per_chunk]) chunks.append(chunk) return chunks

Avantages :

  • Respecte les limites de phrases
  • Chunks plus lisibles
  • Préserve les pensées complètes

Inconvénients :

  • Tailles de chunks variables
  • La détection de phrases peut échouer
  • Peut ne pas regrouper les phrases liées

Utiliser quand :

  • La lisibilité est importante
  • Les phrases sont autonomes
  • Texte narratif général

Basé sur les paragraphes

Diviser aux sauts de paragraphe.

DEVELOPERpython
def chunk_by_paragraphs(text, paragraphs_per_chunk=2): paragraphs = text.split('\n\n') chunks = [] for i in range(0, len(paragraphs), paragraphs_per_chunk): chunk = '\n\n'.join(paragraphs[i:i + paragraphs_per_chunk]) chunks.append(chunk) return chunks

Avantages :

  • Respecte la structure du document
  • Garde le contenu lié ensemble
  • Unités de lecture naturelles

Inconvénients :

  • Tailles très variables
  • Dépend du formatage
  • Les longs paragraphes restent problématiques

Utiliser quand :

  • Documents bien formatés
  • Les paragraphes représentent des idées complètes
  • Articles de blog, articles

Recursive Character Splitting

Approche LangChain : essayer les divisions par ordre de préférence.

DEVELOPERpython
from langchain.text_splitter import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, separators=["\n\n", "\n", ". ", " ", ""] ) chunks = splitter.split_text(text)

Hiérarchie de division :

  1. Double saut de ligne (paragraphes)
  2. Saut de ligne simple (lignes)
  3. Point + espace (phrases)
  4. Espace (mots)
  5. Caractère

Avantages :

  • Respecte la structure du document quand possible
  • Repli gracieux
  • Équilibre sémantique et taille

Inconvénients :

  • Toujours un peu arbitraire
  • Peut ne pas capturer les vraies unités sémantiques
  • Configuration requise

Utiliser quand :

  • Chunking général
  • Types de documents mixtes
  • Bon choix par défaut

Chunking conscient des métadonnées

Utiliser la structure du document pour informer le chunking.

Chunking Markdown

Diviser par en-têtes, en préservant la hiérarchie.

DEVELOPERpython
def chunk_markdown(text): chunks = [] current_h1 = "" current_h2 = "" current_chunk = [] for line in text.split('\n'): if line.startswith('# '): if current_chunk: chunks.append({ 'content': '\n'.join(current_chunk), 'h1': current_h1, 'h2': current_h2 }) current_chunk = [] current_h1 = line[2:] elif line.startswith('## '): if current_chunk: chunks.append({ 'content': '\n'.join(current_chunk), 'h1': current_h1, 'h2': current_h2 }) current_chunk = [] current_h2 = line[3:] current_chunk.append(line) if current_chunk: chunks.append({ 'content': '\n'.join(current_chunk), 'h1': current_h1, 'h2': current_h2 }) return chunks

Avantages des métadonnées :

  • Les en-têtes fournissent du contexte pour la recherche
  • Peut filtrer par section
  • Meilleur scoring de pertinence

Chunking HTML/XML

Diviser par balises HTML sémantiques.

DEVELOPERpython
from bs4 import BeautifulSoup def chunk_html(html): soup = BeautifulSoup(html, 'html.parser') chunks = [] # Diviser par sections for section in soup.find_all(['section', 'article', 'div']): if section.get('class') in ['content', 'main']: chunks.append({ 'content': section.get_text(), 'tag': section.name, 'class': section.get('class') }) return chunks

Chunking de code

Diviser par limites de fonction/classe.

DEVELOPERpython
import ast def chunk_python_code(code): tree = ast.parse(code) chunks = [] for node in ast.walk(tree): if isinstance(node, (ast.FunctionDef, ast.ClassDef)): chunk_lines = code.split('\n')[node.lineno-1:node.end_lineno] chunks.append({ 'content': '\n'.join(chunk_lines), 'type': type(node).__name__, 'name': node.name }) return chunks

Avantages :

  • Préserve les unités logiques (fonctions, classes)
  • Les métadonnées facilitent la découverte
  • Limites de code naturelles

Inconvénients :

  • Analyse spécifique au langage
  • Implémentation complexe
  • Peut manquer le contexte inter-fonctions

Techniques de chunking avancées

Basé sur la similarité sémantique

Regrouper les phrases par similarité sémantique.

DEVELOPERpython
from sentence_transformers import SentenceTransformer from sklearn.cluster import AgglomerativeClustering def semantic_chunking(text, model, max_chunk_size=512): sentences = nltk.sent_tokenize(text) embeddings = model.encode(sentences) # Regrouper les phrases similaires clustering = AgglomerativeClustering( n_clusters=None, distance_threshold=0.5 ) labels = clustering.fit_predict(embeddings) # Grouper les phrases par cluster chunks = {} for sent, label in zip(sentences, labels): chunks.setdefault(label, []).append(sent) return [' '.join(sents) for sents in chunks.values()]

Avantages :

  • Regroupement vraiment sémantique
  • Gère les changements de sujet
  • Densité d'information optimale

Inconvénients :

  • Coûteux en calcul
  • Nécessite un modèle d'embedding
  • Complexe à ajuster

Fenêtre glissante avec chevauchement contextuel

Ajouter du contexte environnant à chaque chunk.

DEVELOPERpython
def sliding_window_chunk(text, window_size=512, context_size=128): tokens = tokenize(text) chunks = [] for i in range(0, len(tokens), window_size): # Fenêtre principale start = max(0, i - context_size) end = min(len(tokens), i + window_size + context_size) chunk = { 'content': detokenize(tokens[i:i+window_size]), 'context': detokenize(tokens[start:end]), 'position': i } chunks.append(chunk) return chunks

Avantages :

  • Chaque chunk a du contexte environnant
  • Réduit la perte d'information
  • Meilleur pour les requêtes aux limites

Inconvénients :

  • Besoins de stockage plus importants
  • Plus d'embeddings nécessaires
  • Redondance potentielle

Chunking hiérarchique hybride

Découper à plusieurs granularités.

DEVELOPERpython
def hierarchical_chunk(document): # Niveau 1 : Document doc_embedding = embed(document['content']) # Niveau 2 : Sections sections = split_by_headers(document['content']) section_embeddings = [embed(s) for s in sections] # Niveau 3 : Paragraphes paragraph_chunks = [] for section in sections: paragraphs = section.split('\n\n') paragraph_chunks.extend([ {'content': p, 'section': section} for p in paragraphs ]) para_embeddings = [embed(p['content']) for p in paragraph_chunks] return { 'document': {'embedding': doc_embedding, 'content': document}, 'sections': [{'embedding': e, 'content': s} for e, s in zip(section_embeddings, sections)], 'paragraphs': [{'embedding': e, **p} for e, p in zip(para_embeddings, paragraph_chunks)] }

Stratégie de récupération :

  1. Rechercher au niveau du document
  2. Si correspondance trouvée, rechercher dans les sections
  3. Enfin récupérer les paragraphes spécifiques

Avantages :

  • Plusieurs niveaux de granularité
  • Récupération du général au spécifique
  • Meilleure préservation du contexte

Inconvénients :

  • Implémentation complexe
  • Plus de stockage nécessaire
  • Indexation plus lente

Chevauchement de chunks

Pourquoi le chevauchement ?

Sans chevauchement :

Chunk 1 : "...le schéma de base de données inclut des tables utilisateur"
Chunk 2 : "avec des colonnes pour email et mot de passe..."

Requête : "base de données utilisateur email" pourrait manquer les deux chunks

Avec chevauchement :

Chunk 1 : "...le schéma de base de données inclut des tables utilisateur avec des colonnes pour..."
Chunk 2 : "...tables utilisateur avec des colonnes pour email et mot de passe..."

Maintenant "tables utilisateur avec des colonnes" apparaît dans les deux, améliorant le rappel.

Chevauchement optimal

Taille de chunkChevauchement recommandéRatio
128 tokens10-20 tokens8-15%
512 tokens50-100 tokens10-20%
1024 tokens100-200 tokens10-20%
2048 tokens200-400 tokens10-20%

Compromis :

  • Plus de chevauchement : Meilleur rappel, plus de stockage, recherche plus lente
  • Moins de chevauchement : Moins de stockage, recherche plus rapide, peut manquer le contexte

Chunking pour différents types de contenu

Documentation technique

DEVELOPERpython
# Recommandé : Conscient du Markdown, préserver les blocs de code chunk_size = 1024 overlap = 150 preserve_code_blocks = True preserve_tables = True

Tickets de support client

DEVELOPERpython
# Recommandé : Taille fixe avec chevauchement modéré chunk_size = 512 overlap = 100 split_by_turns = True # Chaque tour Q&R

Articles de recherche

DEVELOPERpython
# Recommandé : Basé sur les sections avec citations split_by_sections = True preserve_citations = True chunk_size = 1024

Dépôts de code

DEVELOPERpython
# Recommandé : Division syntaxique split_by_functions = True include_docstrings = True chunk_size = 512

Logs de chat

DEVELOPERpython
# Recommandé : Basé sur les messages chunk_by_messages = True messages_per_chunk = 10 preserve_threading = True

Évaluer les stratégies de chunking

Métriques de récupération

Tester avec un ensemble de requêtes :

DEVELOPERpython
def evaluate_chunking(queries, ground_truth, chunking_fn): chunks = chunking_fn(documents) embeddings = embed(chunks) precision_scores = [] recall_scores = [] for query, expected_docs in zip(queries, ground_truth): retrieved = search(embed(query), embeddings, k=5) precision = len(set(retrieved) & set(expected_docs)) / len(retrieved) recall = len(set(retrieved) & set(expected_docs)) / len(expected_docs) precision_scores.append(precision) recall_scores.append(recall) return { 'precision': np.mean(precision_scores), 'recall': np.mean(recall_scores) }

Métriques de bout en bout

Tester le pipeline RAG complet :

  • Précision des réponses
  • Utilisation du contexte (combien du contexte récupéré est utilisé)
  • Ancrage des réponses (fidélité aux chunks)

Recommandations pratiques

Cadre de décision

  1. Commencer simple : Taille fixe avec chevauchement (512 tokens, chevauchement de 100)
  2. Mesurer les performances : Utiliser des métriques d'évaluation
  3. Identifier les échecs : Où la récupération échoue-t-elle ?
  4. Itérer : Essayer le chunking sémantique ou conscient des métadonnées
  5. Test A/B : Comparer les stratégies sur de vraies requêtes

Patterns communs

90% des cas d'usage :

  • Recursive character splitting
  • Chunks de 512-1024 tokens
  • Chevauchement de 10-20%

Documents structurés :

  • Chunking conscient du Markdown/HTML
  • Préserver les métadonnées (en-têtes, sections)
  • Tailles variables acceptables

Code :

  • Division consciente de la syntaxe
  • Inclure les docstrings avec les fonctions
  • Chunks plus petits (256-512)

Recherche hybride :

  • Plusieurs tailles de chunks
  • Récupération hiérarchique
  • Vaut la complexité pour les apps à haute valeur

Pièges courants

  1. Chunks trop petits : Perte de contexte, récupération fragmentée
  2. Chunks trop grands : Informations non pertinentes, gaspillage de tokens
  3. Pas de chevauchement : Manque les requêtes aux limites
  4. Ignorer la structure : Divisions arbitraires dans tableaux, code, listes
  5. Taille unique : Différents contenus nécessitent différentes stratégies
  6. Pas d'évaluation : Deviner au lieu de mesurer

Conseil d'expert d'Ailog : En production avec plus de 10M de documents, nous avons constaté que commencer avec des chunks de 512 tokens et 10% de chevauchement fonctionne pour 80% des cas. N'optimisez davantage que si vous constatez des échecs de récupération dans vos métriques d'évaluation. La plus grosse erreur est de sur-ingénier le chunking avant de mesurer les performances réelles. Commencez simple, mesurez, itérez.

Essayer les stratégies de chunking sur Ailog

Vous voulez tester différentes approches de chunking sans écrire de code ?

La plateforme d'Ailog vous permet de :

  • Télécharger des documents et comparer les stratégies de chunking côte à côte
  • Tester le chunking sémantique vs taille fixe instantanément
  • Visualiser les limites et chevauchements des chunks
  • Évaluer la qualité de récupération avec de vraies requêtes
  • Déployer la meilleure stratégie en production en un clic

Essayez gratuitement → Aucune carte de crédit requise.

Prochaines étapes

Avec des documents correctement découpés, l'étape suivante est de sélectionner et configurer une base de données vectorielle pour stocker et rechercher les embeddings efficacement. Ceci est couvert dans le guide suivant sur les bases de données vectorielles.

Tags

découpagedocument processingrécupérationoptimization

Articles connexes

Ailog Assistant

Ici pour vous aider

Salut ! Pose-moi des questions sur Ailog et comment intégrer votre RAG dans vos projets !