Aller au contenu
Développement medium

Chunking sémantique : découper là où le sens change

10 min de lecture

logo python

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.

  • 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.

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.

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.

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.

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.

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 documentStratégie conseillée
Markdown, HTML structuréChunking par sections — la structure existe déjà
Texte hétérogène, sans structureTaille fixe avec recouvrement
Prose continue, thèmes enchaînésChunking sémantique
SymptômeCause probableSolution
Aucune rupture détectéeTexte trop homogèneNormal : un seul thème, un seul chunk
Trop de rupturesTexte très varié, seuil sensibleÉlargir le seuil (moyenne − 1,5 écart-type)
Frontières incohérentesModèle d'embedding inadapté à la langueChoisir un modèle multilingue
Indexation lenteUne vectorisation par phraseRéserver le sémantique à la prose qui le justifie
Chunks d'une seule phrasePhrases très dissemblablesVérifier la segmentation en amont
  • 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.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn