
Les stratégies de chunking classiques découpent par forme : un nombre de mots, une fin de phrase, un titre. Aucune ne regarde le sens — et un chunk peut donc mélanger deux idées sans rapport, ou couper une idée en deux. Le chunking sémantique corrige cela : il mesure la similarité entre phrases voisines et place une frontière là où le sens bascule. Ce guide montre comment embarquer chaque phrase, calculer les ruptures de thème avec un seuil adaptatif, et découper le texte aux bons endroits. C'est la stratégie de chunking la plus fine — et la plus coûteuse. Public visé : développeur dont le RAG bute sur des chunks au contenu hétérogène.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Pourquoi les chunkings par forme atteignent leur limite.
- Mesurer la similarité entre phrases consécutives.
- Détecter une rupture de thème avec un seuil adaptatif.
- Découper un texte à ses frontières sémantiques.
- Quand le chunking sémantique vaut son coût.
Prérequis
Section intitulée « Prérequis »- Connaître les stratégies de chunking de base.
- Comprendre les embeddings et la similarité cosinus.
- Une instance Ollama avec
nomic-embed-text, et Python 3.10+.
La limite des chunkings par forme
Section intitulée « La limite des chunkings par forme »Le guide sur le chunking présentait trois stratégies : taille fixe, par phrases, par sections. Elles ont un point commun — elles découpent selon la forme du texte. Le nombre de mots, la ponctuation, les titres : autant de repères syntaxiques, jamais le sens.
D'où deux défauts persistants. Un chunk de taille fixe peut enjamber un changement de sujet : sa première moitié parle d'une chose, sa seconde d'une autre, et son embedding devient un mélange flou. À l'inverse, une idée développée sur plusieurs phrases peut se retrouver coupée parce qu'on a atteint la limite de mots.
Le chunking sémantique part d'un autre principe : la frontière d'un chunk doit tomber là où le sens change — pas là où un compteur atteint sa limite.
Mesurer la similarité entre phrases
Section intitulée « Mesurer la similarité entre phrases »L'idée centrale : deux phrases qui parlent de la même chose ont des embeddings proches ; deux phrases de sujets différents, des embeddings éloignés. On peut donc lire le texte phrase par phrase et repérer où la proximité chute.
On découpe d'abord le texte en phrases, on embarque chacune, puis on calcule la similarité de chaque phrase avec la suivante.
def chunk_semantique(texte: str) -> list[str]: phrases = segmenter_phrases(texte) if len(phrases) <= 1: return phrases vecteurs = _vectoriser(phrases) similarites = [ _cosinus(vecteurs[i], vecteurs[i + 1]) for i in range(len(phrases) - 1) ] ...La liste similarites est une courbe : pour chaque couple de phrases voisines, un score entre 0 et 1. Là où la courbe plonge, le texte change de thème. Reste à décider ce que « plonger » veut dire.
Détecter une rupture avec un seuil adaptatif
Section intitulée « Détecter une rupture avec un seuil adaptatif »On pourrait fixer un seuil absolu — « rupture si la similarité passe sous 0,7 ». C'est fragile : les niveaux de similarité varient d'un texte à l'autre, d'un modèle d'embedding à l'autre. Un seuil qui marche sur un texte rate les ruptures du suivant.
La bonne approche est relative. Une rupture n'est pas une similarité basse dans l'absolu — c'est une similarité nettement plus basse que les autres du même texte. On calcule donc un seuil adaptatif à partir des similarités observées.
import statistics
def seuil_adaptatif(similarites: list[float]) -> float: """Seuil de rupture : sous la moyenne moins un écart-type.""" if len(similarites) < 2: return 0.0 return statistics.mean(similarites) - statistics.pstdev(similarites)
def trouver_ruptures(similarites: list[float], seuil: float) -> list[int]: """Indices i tels qu'une rupture survient après la phrase i.""" return [i for i, s in enumerate(similarites) if s < seuil]Le seuil est la moyenne moins un écart-type des similarités. Une transition qui descend sous ce niveau est, statistiquement, une anomalie dans le flux du texte — donc une frontière. Ce seuil se recalcule pour chaque document : il s'adapte, là où un nombre figé échouerait.
Découper aux frontières sémantiques
Section intitulée « Découper aux frontières sémantiques »Les ruptures connues, le découpage est mécanique : on accumule les phrases et on ferme un chunk après chaque rupture.
ruptures = set(trouver_ruptures(similarites, seuil_adaptatif(similarites)))
chunks, courant = [], []for i, phrase in enumerate(phrases): courant.append(phrase) if i in ruptures: # rupture de sens après cette phrase chunks.append(" ".join(courant)) courant = []if courant: chunks.append(" ".join(courant))Sur un texte à deux thèmes — trois phrases sur les volumes Docker, trois sur le langage Python —, le découpage isole les sujets :
1. Un volume Docker conserve les données du conteneur. Le volume survit à la suppression du conteneur. Plusieurs conteneurs peuvent partager...2. Python est un langage interprété réputé pour sa lisibilité. Sa syntaxe claire en fait un bon premier langage.3. Python dispose d'un vaste écosystème de bibliothèques.La frontière la plus nette tombe exactement entre le dernier paragraphe Docker et le premier paragraphe Python. Aucun chunk ne mélange les deux thèmes : chaque embedding portera un sens homogène, et la recherche en sera plus précise.
Quand le chunking sémantique vaut son coût
Section intitulée « Quand le chunking sémantique vaut son coût »Le chunking sémantique est la stratégie la plus fine — mais pas la plus rentable dans tous les cas.
Son coût est réel : il faut vectoriser chaque phrase du corpus, là où un chunking par taille fixe ne coûte rien. Sur un grand corpus, cela représente beaucoup d'appels au modèle d'embedding.
Son terrain est la prose continue : un long texte sans structure apparente, où les thèmes s'enchaînent sans titres pour les séparer. C'est là qu'il révèle des frontières qu'aucune règle de forme ne verrait.
| Type de document | Stratégie conseillée |
|---|---|
| Markdown, HTML structuré | Chunking par sections — la structure existe déjà |
| Texte hétérogène, sans structure | Taille fixe avec recouvrement |
| Prose continue, thèmes enchaînés | Chunking sémantique |
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
| Aucune rupture détectée | Texte trop homogène | Normal : un seul thème, un seul chunk |
| Trop de ruptures | Texte très varié, seuil sensible | Élargir le seuil (moyenne − 1,5 écart-type) |
| Frontières incohérentes | Modèle d'embedding inadapté à la langue | Choisir un modèle multilingue |
| Indexation lente | Une vectorisation par phrase | Réserver le sémantique à la prose qui le justifie |
| Chunks d'une seule phrase | Phrases très dissemblables | Vérifier la segmentation en amont |
À retenir
Section intitulée « À retenir »- Les chunkings par forme ignorent le sens — un chunk peut mélanger deux idées.
- Le chunking sémantique coupe là où la similarité entre phrases voisines chute.
- Le seuil de rupture doit être adaptatif — relatif au texte, pas un nombre figé.
- Une rupture = une similarité nettement sous la moyenne des similarités du document.
- Son coût : une vectorisation par phrase — à réserver à la prose continue.
- Si le document est structuré, le chunking par sections suffit et coûte moins.