Aller au contenu principal

Chapitre 2 : Stratégies de division de texte

Introduction​

La division de texte (chunking) est cruciale pour la performance de RAG. La bonne taille de segment et la bonne stratégie impactent significativement la qualité de la récupération et la précision de la génération.

Pourquoi le Chunking est Important​

Problèmes sans chunking :

  • Les documents entiers sont trop volumineux
  • La récupération renvoie du contenu non pertinent
  • Gaspille la fenêtre de contexte LLM

Paramètres Clés​

Taille du Segment​

Le nombre de caractères/tokens par segment :

Taille du SegmentAvantagesInconvénients
Petit (256)Récupération précisePeut perdre le contexte
Moyen (512-1024)ÉquilibréBon pour la plupart des cas
Grand (2000+)Plus de contexteRécupération moins précise

Chevauchement des Segments​

Texte partagé entre les segments consécutifs :

Segment 1: [_______________]
Segment 2: [_______________]
^chevauchement^

Pourquoi le chevauchement ?

  • Empêche de couper les phrases en plein milieu
  • Préserve le contexte à travers les limites des segments
  • Typique : 10-20% de la taille du segment

Stratégies de Division​

1. Division Récursive par Caractères​

L'approche la plus courante - divise par hiérarchie de séparateurs :

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
separators=["\n\n", "\n", ". ", " ", ""]
)

chunks = splitter.split_documents(documents)

Hiérarchie des séparateurs :

  1. Doubles sauts de ligne (paragraphes)
  2. Sauts de ligne simples
  3. Points (phrases)
  4. Espaces (mots)
  5. Caractères (dernier recours)

2. Division Basée sur les Tokens​

Utilise le comptage réel des tokens (important pour les limites LLM) :

from langchain.text_splitter import TokenTextSplitter

splitter = TokenTextSplitter(
chunk_size=500, # tokens, pas caractères
chunk_overlap=50,
encoding_name="cl100k_base" # Tokenizer GPT-4
)

3. Division par Phrase​

Préserve les limites des phrases :

from langchain.text_splitter import SentenceTransformersTokenTextSplitter

splitter = SentenceTransformersTokenTextSplitter(
chunk_overlap=50,
tokens_per_chunk=256
)

4. Division Sémantique​

Divise en fonction de la similarité sémantique :

from langchain_experimental.text_splitter import SemanticChunker
from langchain.embeddings import OpenAIEmbeddings

splitter = SemanticChunker(
OpenAIEmbeddings(),
breakpoint_threshold_type="percentile"
)

# Segments basés sur la similarité sémantique
semantic_chunks = splitter.split_documents(documents)

5. Division par En-têtes Markdown​

Respecte la structure du document :

from langchain.text_splitter import MarkdownHeaderTextSplitter

headers_to_split_on = [
("#", "En-tête 1"),
("##", "En-tête 2"),
("###", "En-tête 3"),
]

splitter = MarkdownHeaderTextSplitter(
headers_to_split_on=headers_to_split_on
)

Choisir la Taille du Segment​

def optimal_chunk_size(embedding_model, llm_context_window, top_k):
"""
Calculer la taille optimale du segment
"""
# Laisser de la place pour le modèle de prompt et la réponse
available_tokens = llm_context_window * 0.6

# Diviser par le nombre de segments à récupérer
chunk_tokens = available_tokens / top_k

# Convertir en caractères (environ 4 caractères par token)
return int(chunk_tokens * 4)

# Exemple : GPT-4 avec 8K de contexte, récupérant 5 segments
optimal = optimal_chunk_size(
embedding_model="text-embedding-3-small",
llm_context_window=8192,
top_k=5
)
# Résultat : ~3900 caractères par segment

Tableau de Comparaison​

StratégieIdéal PourQualité du Segment
Caractère RécursifUsage généralBon
Basée sur les TokensGestion du contexte LLMExcellent
PhraseSystèmes de Q&RBon
SémantiqueContenu variéExcellent
En-têtes MarkdownDocuments structurésExcellent

Meilleures Pratiques​

  1. Commencez avec les valeurs par défaut - 1000 caractères, 200 de chevauchement
  2. Testez différentes tailles - Évaluez la qualité de la récupération
  3. Adaptez au contenu - Les documents techniques peuvent nécessiter des segments plus grands
  4. Considérez les embeddings - Certains modèles ont des limites de tokens max
  5. Préservez les métadonnées - Suivez la source et la position du segment
# Pipeline de segmentation en production
def chunk_documents(documents, chunk_size=1000, overlap=200):
splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=overlap,
length_function=len,
add_start_index=True # Suivre la position
)

chunks = splitter.split_documents(documents)

# Ajouter l'index du segment aux métadonnées
for i, chunk in enumerate(chunks):
chunk.metadata["chunk_index"] = i
chunk.metadata["total_chunks"] = len(chunks)

return chunks

Résumé​

  • Taille du segment affecte la précision de la récupération vs le contexte
  • Chevauchement prévient la perte d'information aux limites
  • Stratégie doit correspondre à votre type de document
  • Testez et itérez pour trouver les paramètres optimaux

Prochaines Étapes​

Continuez vers Chapitre 3 : Types de fichiers pour apprendre à gérer des documents complexes.