Les systèmes de génération augmentée par récupération (RAG) sont devenus la norme de l'industrie pour ancrer les grands modèles de langage (LLM) dans des données spécifiques et propriétaires. Cependant, la qualité d'un système RAG est souvent dictée non pas par le LLM lui-même, mais par le prétraitement des données d'entrée. L'étape la plus critique de ce pipeline est le découpage (chunking). Si vos segments sont trop petits, vous perdez le contexte ; s'ils sont trop grands, vous diluez la pertinence sémantique. Choisir la bonne stratégie de découpage fait la différence entre un assistant utile et un robot hallucinant.
Pourquoi le découpage est important
Les LLM ont une fenêtre de contexte finie. Les bases de données vectorielles stockent des embeddings, qui représentent le sens sémantique du texte. Pour s'assurer que la recherche vectorielle peut trouver les informations les plus pertinentes, nous devons diviser les documents en morceaux gérables. L'objectif est de créer des segments qui sont autonomes mais sémantiquement cohérents. Un document mal découpé peut diviser une phrase en deux ou séparer un en-tête de son corps, entraînant des récupérations non pertinentes.
1. Découpage de taille fixe : La référence de base
L'approche la plus simple est le découpage de taille fixe. Cela divise le texte en segments d'un nombre de caractères ou de jetons spécifique, souvent avec un certain chevauchement. C'est rapide et facile à mettre en œuvre, mais cela ignore l'intégrité structurelle du texte.
import textsplitter
def fixed_size_chunk(text, chunk_size=500, overlap=50):
chunks = []
for i in range(0, len(text), chunk_size - overlap):
chunks.append(text[i : i + chunk_size])
return chunks
# Exemple :
# text = "This is a very long document..."
# chunks = fixed_size_chunk(text)
2. Découpage récursif de caractères : L'approche structurelle
La plupart des systèmes de production utilisent le découpage récursif de caractères. Cette méthode essaie d'abord de diviser le texte sur des limites naturelles (comme des paragraphes ou des phrases) avant de recourir aux caractères. Elle respecte la hiérarchie du texte : Paragraphe → Phrase → Mot → Caractère. Cela préserve mieux le sens que les méthodes de taille fixe.
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
length_function=len,
separators=["\n\n", "\n", " ", ""]
)
# Ce découpeur essaiera de garder les paragraphes ensemble,
# puis les phrases, puis les mots, et enfin les caractères.
docs = splitter.split_documents([Document(page_content=raw_text)])
3. Découpage sémantique : La méthode avancée
Le découpage sémantique utilise des embeddings pour détecter où le sens du texte change significativement. Il analyse la similarité cosinus entre les phrases adjacentes. Lorsque la similarité passe sous un seuil, il suppose qu'un nouveau sujet a commencé et crée une coupure de segment.
Bien que coûteux en calcul, cette méthode offre souvent la plus grande précision de récupération car elle regroupe les concepts liés ensemble, indépendamment de la structure du document.
# Pseudocode pour le découpage sémantique
def semantic_chunk(text, threshold=0.8):
sentences = split_into_sentences(text)
embeddings = get_embeddings(sentences)
chunks = []
current_chunk = [sentences[0]]
for i in range(1, len(sentences)):
sim = cosine_similarity(embeddings[i-1], embeddings[i])
if sim < threshold:
chunks.append(" ".join(current_chunk))
current_chunk = [sentences[i]]
else:
current_chunk.append(sentences[i])
chunks.append(" ".join(current_chunk))
return chunks
Bonnes pratiques pour la mise en œuvre
- Le chevauchement est essentiel : Incluez toujours un certain chevauchement (10-20 %) entre les segments pour prévenir la perte de contexte aux limites.
- Respectez les métadonnées : Si vos données sources sont structurées (comme JSON ou Markdown), analysez-les d'abord et découpez par unités logiques (par exemple, par point de terminaison d'API ou par section).
- Expérimentez : Il n'y a pas de solution universelle. Testez différentes tailles de segments et stratégies en utilisant votre jeu de données de requêtes réel pour mesurer la précision de la récupération.
Conclusion
Le découpage n'est pas seulement une étape de prétraitement ; c'est un composant central de votre architecture RAG. Commencez par le découpage récursif de caractères pour une base solide, et passez au découpage sémantique si vous constatez que vos récupérations manquent de contexte nuancé. En alignant votre stratégie de découpage avec la structure de vos données et la sémantique de vos requêtes utilisateur, vous améliorerez considérablement les performances et la fiabilité de vos applications IA.