Accueil / Articles

Sélection de chunks sans requête : utilisation de K-Means lorsque RAG n’a aucune question à poser

Sans requête de l’utilisateur, RAG ne peut pas sélectionner de contexte. Considérez K comme le nombre de résultats à générer, regroupez les embeddings des fragments à l’aide de k-means, et conservez les fragments centrés ainsi que leurs sources.

Éditeur : REACTAPP.TOP13 min de lecture3095 mots

Sources: You Don’t Need RAG. You Need Semantic Compression.

Certains problèmes liés aux LLM n’ont ni nom, ni cadre théorique, ni beaucoup de littérature à leur sujet. Celui-ci se présente comme suit : une quantité énorme de texte, sans question de la part de l’utilisateur, et la tâche de choisir quels extraits transmettre à un modèle afin que chaque thème soit abordé et que chaque élément puisse être retracé jusqu’à son origine.

Il ne s’agit ni de génération améliorée par la récupération d’informations, puisqu’aucune recherche n’est effectuée, ni de compression de prompts, ni de résumé. La communauté de recherche ne l’a pas encore clairement défini, et les outils habituels ne le prennent pas en compte. Ce qui suit décrit le problème, montre pourquoi les techniques existantes sont insuffisantes, et présente une solution simple qui coïncide avec des idées académiques tout en comblant une lacune laissée par ces travaux.

Lorsqu’il n’y a rien à rechercher

Tout ceux qui ont travaillé avec des LLM ces dernières années connaissent le cycle RAG : un utilisateur pose une question, la requête est intégrée, des fragments similaires sont récupérés depuis un stock vectoriel, ils sont inclus dans le prompt, et une réponse fondée sur eux est générée. Ce schéma est élégant, bien documenté et pris en charge par tous les principaux frameworks. Il suppose également implicitement l’existence d’une requête.

Souvent, il n’y en a pas. Des frameworks tels que LangChain et LlamaIndex sont conçus autour de la requête et du retraitement des données, et la plupart des articles sur la compression du contexte partent également d’une requête. On cherche des moyens de choisir les meilleurs fragments pour un LLM, et chaque résultat suppose l’existence d’une question de l’utilisateur pour guider ce choix.

Considérons une application d’apprentissage. Les étudiants téléchargent du matériel pédagogique : manuels scolaires, diapositives, transcriptions de vidéos, notes manuscrites, parfois des centaines de pages. Ils ne cherchent rien ; en fait, ils disent : « Voici mes cours, créez-moi du matériel d’étude. » Le système doit alors produire des résultats structurés tels que des fiches de quiz, des cartes mémoire, des résumés et des cartes conceptuelles. Chaque résultat doit couvrir un sujet différent et indiquer sa source, alors que le volume total des données dépasse de loin toute fenêtre de contexte.

Trois exigences en même temps

Les approches existantes échouent chacune au moins sur l’une des trois contraintes imposées simultanément par ce cas d’usage.

  1. Aucun signal de requête. Rien dans les actions de l’utilisateur ne guide le choix, ce qui oblige le système à déterminer ce qui est important uniquement à partir des données.
  2. Couverture thématique garantie. Le résultat est un ensemble de productions qui couvrent globalement l’ensemble du matériel. Omettre un sujet entier constitue une grave erreur ; un quiz de biologie qui ne traite jamais de la génétique est inutile.
  3. Traçabilité des sources. Chaque production doit faire référence à une partie spécifique du texte original, par exemple « basé sur le chapitre 3, pages 12 à 14 du manuel de biochimie ». En matière d’éducation, cela n’est pas facultatif, car les étudiants doivent savoir où poursuivre leurs lectures.

Aucune méthode existante ne répond simultanément aux trois critères. C’est là le manque.

Ce que la littérature propose, et où elle s’arrête

Pourquoi envoyer tout le contenu échoue

La méthode naïve consiste à verser tout le matériel dans la fenêtre de contexte. Étant donné que les modèles peuvent gérer de 128 000 à 200 000 tokens, il est tentant de penser que cela fonctionne. Ce n’est pas le cas. L’étude « Lost in the Middle » a montré une courbe de performance en forme de U : les modèles traitent bien le début et la fin du contexte, mais manquent systématiquement du contenu situé au milieu. La précision a chuté de plus de 30 % lorsque le contenu clé s’est déplacé des bords vers le centre, même pour les modèles conçus pour des contextes longs.

Même lorsque tout tient dans la fenêtre de contexte, de grandes parties du matériel sont ignorées. Le quiz couvrirait alors les premiers et derniers chapitres en sautant le reste. Plus de contexte ne signifie pas nécessairement un meilleur contexte.

La compression des prompts répond à une question différente

De plus en plus de recherches visent à raccourcir les entrées en supprimant des tokens redondants avant qu’ils n’atteignent le modèle.

Selective Context dispose d’un petit modèle de langage capable de calculer l’auto-information des unités lexicales, qu’il s’agisse de tokens, de phrases nominales ou de phrases, et élimine celles qui en contiennent peu. Il n’a pas besoin de requête, ce qui répond à la première contrainte. Cependant, il filtre à l’intérieur du texte existant, produisant une copie compressée du même texte plutôt qu’une sélection de contenus représentatifs couvrant différents sujets. Il ne peut pas garantir une couverture complète, et le texte modifié perd son lien direct avec les segments originaux, ce qui fait échouer la deuxième et la troisième contraintes.

LLMLingua et LLMLingua-2 développent cette idée grâce à une compression itérative et à des classificateurs de tokens appris, atteignant des ratios allant jusqu’à 20 fois. Ils partagent la même limite fondamentale : le texte est compressé pour la machine, et non organisé pour une personne. Le résultat est un prompt que le modèle peut interpréter, et non un ensemble structuré de contenus pouvant être retracé.

RECOMP entraîne des compresseurs capables de résumer ou d’extraire des informations à partir de documents récupérés, tant dans une approche extractive que dans une approche abstractive. C’est le plus sophistiqué du groupe, mais il a besoin explicitement d’une requête pour décider de ce qu’il convient de conserver, ce qui le rend inadapté à la première contrainte.

En bref, la compression par prompt réduit le nombre de tokens. Elle ne sélectionne pas de contenu représentatif, ne garantit pas une couverture complète des sujets et ne conserve pas la structure d’origine.

Le classement par graphe représente mais ne organise pas

TextRank et LexRank construisent un graphe de similarité entre les phrases et appliquent PageRank pour identifier celles qui sont les plus centrales, c’est-à-dire celles qui représentent le mieux l’ensemble du document. Ils n’ont pas besoin de requête, et depuis deux décennies, ils constituent la norme pour la synthèse extractive non supervisée. Leur faiblesse connue est la redondance : des phrases similaires obtiennent une centralité similaire, de sorte que les choix les plus pertinents se répètent souvent sous des mots différents. Un résumé généré par TextRank à partir d’un manuel de biologie pourrait contenir trois phrases sur la réplication de l’ADN et aucune sur la synthèse des protéines, simplement parce que la réplication est mentionnée plus fréquemment.

Cela nuit à la couverture, même si les thèmes principaux ont tendance à apparaître, et comme ces méthodes fonctionnent sur des phrases, la traçabilité n’est que partiellement assurée.

Le clustering est le plus proche

La synthèse basée sur le clustering, utilisant K-means, HDBSCAN ou des méthodes similaires appliquées aux embeddings de phrases, regroupe les phrases similaires en clusters thématiques et en sélectionne une représentative pour chacun. Cela élimine efficacement la redondance : chaque cluster contribue d’une seule phrase, et les différents clusters couvrent des thèmes distincts.

La recherche la plus récente et la plus performante dans ce domaine, intitulée « Graphs in Clusters », combine K-means avec TextRank. Le clustering est utilisé en premier pour assurer une couverture complète, suivi d’un classement au sein de chaque cluster pour déterminer l’importance des phrases. Cette méthode surpasse les méthodes purement graphiques et celles purement basées sur le clustering sur des benchmarks de documents longs tels qu’ArXiv et PubMed.

C’est le parent le plus proche, mais il diffère à plusieurs égards importants. Son objectif est de produire un résumé de texte unique et plat, tandis que ici l’objectif est d’obtenir N sorties structurées. Il ajuste la valeur de K à l’aide de la méthode du coude, alors que ici K provient de la demande de l’utilisateur. Il fonctionne sur des phrases, alors que ici une granularité par blocs est nécessaire pour conserver les métadonnées sources. Ses clusters constituent une étape intermédiaire invisible, tandis que ici ce sont les résultats finaux. De plus, il ne prend pas en compte la nécessité d’un suivi obligatoire des sources.

Comparaison côte à côte

Face à ces trois contraintes, un schéma se dégage. RAG conserve les sources mais nécessite une requête et ne peut pas garantir une couverture complète. Selective Context et LLMLingua n’ont pas besoin de requête, mais perdent la structure des sources et ne peuvent pas assurer une couverture exhaustive. RECOMP exige une requête. TextRank et LexRank fonctionnent sans requête, mais produisent des résultats redondants et une traçabilité faible. La synthèse par clustering répond aux deux premières contraintes, ne nécessitant pas de requête et garantissant une couverture, mais elle opère au niveau des phrases, ce qui rompt la liaison avec les sources.

Aucune méthode établie pour la sélection des blocs de texte ne permet d’éviter les requêtes, de garantir une couverture complète et de assurer une traçabilité vers les sources.

Revoir l’approche par clustering

La solution réside dans l’inversion de la manière dont le clustering est généralement utilisé en NLP. Dans la littérature, K est un hyperparamètre. Les chercheurs testent successivement les valeurs K=5, K=10, K=50, représentent les scores de silhouette ou les courbes d’inertie, puis choisissent une valeur « optimale ». Les clusters sont des objets mathématiques au service de l’algorithme, et aucun utilisateur ne les voit jamais.

Dans ce cadre, K correspond à une spécification de produit. Un étudiant qui demande 10 fiches de quiz fixe K à 10. Cinq pages de résumé signifient K=5, et trente cartes mémoire signifient K=30. Chaque cluster correspond à un seul résultat. Le cluster n’est pas une abstraction intermédiaire ; c’est le produit final. Un quiz sur la mitose existe parce qu’un cluster de segments liés à la mitose se trouve dans l’espace sémantique du contenu téléchargé.

Les méthodes existantes utilisent le clustering pour compresser du texte à l’intention de la machine. Celle-ci, en revanche, utilise le clustering pour organiser du contenu à l’intention de l’être humain.

En aval, cela change tout. Traditionnellement, K est ajusté mathématiquement et les clusters restent cachés, et ce qui suit le clustering est la génération d’un résumé simplifié. Ici, K provient de la demande : chaque cluster devient quelque chose que l’utilisateur reçoit, et chaque cluster déclenche une appel à un LLM qui produit une sortie citant sa source.

Le pipeline en cinq étapes

1. Fragmentation. Les documents sont divisés à l’aide d’outils standard de LlamaIndex ou LangChain, ou selon des règles personnalisées. Chaque fragment conserve son texte, son fichier source, son numéro de page, sa position ainsi que tout autre métadonnée. Une taille typique se situe entre 500 et 1000 tokens, avec une superposition des fragments voisins de 10 à 20 %, ce qui constitue un compromis entre le maintien de l’intégrité des idées et une granularité fine des clusters. Les fragments peuvent être enrichis, si nécessaire, de résumés, de mots-clés ou de balises d’entités, ce qui facilite le clustering mais n’est pas obligatoire.

2. Incorporation. Chaque morceau devient un vecteur dense. Le modèle dépend de la pile d’outils utilisée : Sentence-Transformers constitue une référence rapide et gratuite, text-embedding-3-small d’OpenAI est performant sur plusieurs langues, tandis que Mistral Embed ou Cohere Embed offrent des alternatives compétitives. Ce qui importe, c’est que des morceaux sémantiquement proches produisent des vecteurs proches, quel que soit le vocabulaire.

3. K-means. C’est l’étape clé. K-means divise l’espace des embeddings en exactement K groupes, où K correspond au nombre de résultats souhaités par l’utilisateur :

from sklearn.cluster import KMeans
n_outputs = 10  # User wants 10 quiz sheets
kmeans = KMeans(n_clusters=n_outputs, random_state=42, n_init=10)
kmeans.fit(embeddings)

Trois propriétés découlent directement et répondent aux trois contraintes. Aucune requête n’est nécessaire, car K-means regroupe en fonction de la similarité entre les fragments et non en fonction de leur pertinence par rapport à un signal externe. La couverture thématique est garantie, puisque chaque fragment se trouve dans exactement un cluster et que chaque sujet présent dans les données est représenté. La redondance disparaît, car les fragments qui disent la même chose ont des embeddings similaires, se retrouvent ensemble et contribuent à un seul représentant.

4. Sélection du représentant. Pour chaque cluster, prenez le fragment le plus proche du centre de masse, qui exprime le mieux le thème du cluster :

import numpy as np
selected = []
for i in range(n_outputs):
    cluster_indices = np.where(kmeans.labels_ == i)[0]
    centroid = kmeans.cluster_centers_[i]
    distances = np.linalg.norm(
        embeddings[cluster_indices] - centroid, axis=1
    )
    best_local_idx = np.argmin(distances)
    best_global_idx = cluster_indices[best_local_idx]
    selected.append(chunks[best_global_idx])  # Full chunk with metadata

Le fragment sélectionné conserve l’ensemble de ses métadonnées d’origine, de sorte que rien n’est perdu et tout peut être cité. Pour des résultats plus riches, les trois fragments les plus proches par centre de masse peuvent être utilisés à la place d’un seul ; le principe reste le même.

5. Génération. Les fragments choisis de chaque cluster sont envoyés à l’LLM avec une instruction adaptée au type de résultat souhaité, et les métadonnées sources les accompagnent afin que le modèle puisse les citer. Le cluster 1 génère le Quiz 1, en citant les pages 12 à 14 du premier PDF. Le cluster 2 génère le Quiz 2, en citant une transcription vidéo à 14:30. Ce schéma se répète jusqu’au cluster K.

Lorsqu’aucun chiffre n’est indiqué

Chaque utilisateur ne demande pas dix quiz ; certains souhaitent simplement « un quiz » ou « un résumé ». Trois méthodes de secours fonctionnent. Le budget de tokens divise le contexte effectif du modèle par la taille moyenne des blocs : pour un modèle de 16 000 tokens et des blocs de 800 tokens, la valeur de K se situe autour de 20. La méthode du coude teste plusieurs valeurs de K et choisit le point où l’inertie cesse de diminuer de manière significative. Une règle approximative consistant à avoir un cluster par 5 à 10 pages de texte source fonctionne également. En pratique, le budget de tokens est le plus fiable, car il correspond directement à ce que le modèle peut gérer.

Ce que la méthode garantit

Il s’agit de propriétés mathématiques de K-means, et non d’observations empiriques.

  • Couverture. Chaque point est attribué à un cluster, de sorte qu’aucun fragment n’est laissé pour compte. S’il existe un sujet, il appartient à un cluster disposant d’un représentant. En revanche, la récupération Top-K peut retourner K fragments concernant un sujet populaire tout en omettant complètement les autres.
  • Aucune redondance. Les fragments similaires sont regroupés et un seul représente chaque groupe. Deux fragments exprimant la même chose avec des mots différents partagent un cluster, et un seul survit.
  • Granularité ajustable. Un K faible permet des clusters larges couvrant des sujets étendus, tandis qu’un K élevé génère des clusters plus restreints pour des concepts spécifiques ; l’utilisateur peut influencer cela via sa requête.
  • Préservation de la source. Le travail sur des fragments, et non sur des tokens ou des phrases, permet de conserver toute la chaîne de métadonnées de chaque élément sélectionné. La compression au niveau des tokens ne peut pas offrir ce niveau de préservation par conception.
  • Vitesse. K-means sur 500 embeddings de 384 dimensions met moins d’une seconde. Aucune appel à un LLM n’a lieu pendant la sélection, uniquement lors de la génération finale, de sorte que la latence supplémentaire est négligeable.
  • Ses limites

    Suppositions sphériques. K-means suppose des clusters plus ou moins ronds, or les espaces d’embedding ne sont pas toujours aussi ordonnés. Un sujet ayant une forme complexe et non convexe peut être réparti entre plusieurs clusters. HDBSCAN ou les modèles de mélanges gaussiens pourraient aider, bien qu’ils ne garantissent pas précisément K clusters.

    Typique, mais pas nécessairement informatif. Le groupe le plus proche du centre de masse est celui qui est le plus typique. Exécuter TextRank à l’intérieur de chaque cluster, comme le fait l’approche Graphs in Clusters, permettrait de faire un choix plus nuancé, ce qui représente une amélioration prometteuse.

    Les sujets de petite taille sont compressés. Si le contenu est à 95 % biologie et à 5 % chimie, la chimie recevra probablement un seul groupe tandis que la biologie en aura de K à 1. Le groupe consacré à la chimie existe bien, mais il est comprimé proportionnellement. Un système pondéré ou stratifié pourrait y remédier.

    La qualité des blocs détermine tout. Si le découpage divise un concept en deux ou mélange des sujets non liés, le regroupement subit les conséquences négatives. Un bon découpage, basé sur une segmentation sémantique, des chevauchements et un enrichissement par des métadonnées, n’est pas optionnel.

    Comparaison en une seule passe

    RAG est rapide et conserve les sources, mais nécessite une requête et peut retourner K fragments pour un même sujet. Selective Context et LLMLingua sont rapides et ne nécessitent pas de requête, cependant ils éliminent la structure des sources et ne peuvent pas garantir une couverture complète. RECOMP est puissant mais dépend d’une requête. TextRank et LexRank sont rapides et ne nécessitent pas de requête non plus, mais la couverture est partielle en raison de la redondance et la traçabilité s’arrête au niveau de la phrase. Graphs in Clusters ne nécessite pas de requête et offre une bonne couverture, mais il fonctionne uniquement sur des phrases et supprime les métadonnées des sources. La synthèse MapReduce ne nécessite pas non plus de requête, bien que la couverture soit partielle, les liens vers les sources disparaissent au cours des étapes de synthèse, et elle est lente car elle nécessite plusieurs passes avec un LLM.

    La sélection par groupes K-means décrite ici est la seule option qui fonctionne sans requête, garantit une couverture thématique par construction, conserve une traçabilité complète au niveau des groupes, s’achève en moins d’une seconde, et ne nécessite ni des modèles affinés ni une base de données vectorielle.

    Dénomination du problème

    Ce qui rend la tâche difficile, ce n’est pas tant la complexité technique que l’absence d’une désignation claire. En cherchant RAG, des milliers de résultats apparaissent. En cherchant la compression des prompts, on trouve LLMLingua. En cherchant la synthèse extractive, on obtient TextRank, LexRank et des méthodes basées sur BERT. En cherchant comment choisir les meilleurs groupes à partir d’un grand corpus, sans requête, afin de maximiser la couverture thématique tout en préservant la traçabilité de la source, presque rien ne ressort.

    Une désignation appropriée est la compression sémantique sans requête. Ce n’est pas une recherche, car il n’y a pas de requête. Ce n’est pas une synthèse, car aucun nouveau texte n’est généré à ce stade. Ce n’est pas une compression de prompts, car aucun token n’est supprimé du texte existant. Il s’agit plutôt d’une sélection garantissant une couverture complète : choisir l’ensemble le plus restreint de fragments qui représentent la plus grande partie du contenu tout en conservant un lien vers les documents.

    Le problème se pose chaque fois qu’un système transforme de grands volumes de contenu fournis par les utilisateurs en sorties structurées sans intention de recherche explicite. Parmi les exemples, on trouve des matériaux pédagogiques issus de contenus de cours, des rapports provenant de grandes collections de documents, des résumés de réunions à partir d’heures de transcriptions, des synthèses de revues issues de nombreux demandes de modification, ainsi que des analyses juridiques où la couverture des clauses est plus importante que la réponse à une seule question.

    La méthode K-means est une solution, sans doute la plus simple. Des approches hybrides qui combinent le clustering avec un classement basé sur des graphes, une évaluation de la densité d’information ou un bref traitement par un LLM pour la détection de sujets pourraient offrir de meilleurs résultats, et ce domaine reste largement ouvert.

    Tout en code

    Le pipeline complet de sélection tient en moins de 50 lignes :

    from sentence_transformers import SentenceTransformer
    from sklearn.cluster import KMeans
    import numpy as np
    def select_representative_chunks(chunks, n_outputs, model_name='all-MiniLM-L6-v2'):
        """
        Select the most representative chunks from a large corpus
        using K-means clustering. One cluster = one output.
    
        Args:
            chunks: list of dicts with 'text', 'source', 'page', etc.
            n_outputs: number of outputs the user wants (= K)
            model_name: embedding model to use
    
        Returns:
            list of selected chunks with cluster metadata
        """
        # Embed
        model = SentenceTransformer(model_name)
        embeddings = model.encode([c['text'] for c in chunks], show_progress_bar=True)
    
        # Cluster
        kmeans = KMeans(n_clusters=n_outputs, random_state=42, n_init=10)
        kmeans.fit(embeddings)
    
        # Select representatives
        selected = []
        for i in range(n_outputs):
            cluster_indices = np.where(kmeans.labels_ == i)[0]
            centroid = kmeans.cluster_centers_[i]
            distances = np.linalg.norm(embeddings[cluster_indices] - centroid, axis=1)
            best_local_idx = np.argmin(distances)
            best_global_idx = cluster_indices[best_local_idx]
    
            selected.append({
                'cluster': i,
                'chunk': chunks[best_global_idx],
                'distance_to_centroid': float(distances[best_local_idx]),
                'cluster_size': len(cluster_indices),
            })
    
        return selected
    

    Il n’y a ni base de données vectorielle, ni pipeline de recherche, ni modèle affiné, ni appel à un LLM lors de l’étape de sélection. Seuls les embeddings, le clustering et le choix du centre de gravité sont nécessaires.

    Où cela a été mis en pratique

    Le pipeline a été développé et testé au sein d’une application d’apprentissage qui génère des matériaux d’étude interactifs, tels que des quiz, des cartes mémoire, des résumés et des cartes conceptuelles, à partir de tout ce que l’étudiant télécharge : des notes de cours, des manuels, des transcriptions de vidéos et des diapositives. Elle comprend également des outils adaptés aux apprenants atteints de dyslexie, de TDAH ou d’autres difficultés cognitives, ainsi que des éléments de gamification. Le projet est encore en phase de R&D active, disponible actuellement en français, avec une version en anglais prévue.

    Dans ce cadre, la couche K-means s’occupe de la sélection du contenu. Le regroupement de 500 extraits ne prend pas une seconde, elle s’adapte bien et la couverture thématique reste constante quel que soit le type de source, que ce soient des manuels de biologie détaillés ou des enregistrements de cours dispersés.

    Pourquoi l’idée est délibérément simple

    Choisir des extraits représentatifs à partir d’un grand corpus, sans requête spécifique, tout en assurant une couverture thématique et une traçabilité des sources, est un besoin plus courant que ce que la littérature le suggère. Toute personne qui développe des outils d’IA pour l’éducation, la génération de rapports, l’analyse de réunions ou la révision juridique a probablement déjà rencontré une version de ce problème.

    La méthode est délibérément simple. K-means existe depuis des décennies et les embeddings de phrases sont des outils standard. La contribution réside dans la manière de structurer le processus : prendre l’intention de l’utilisateur comme paramètre K, traiter chaque cluster comme un résultat à fournir, et conserver intacte la chaîne entre chaque extrait et sa source tout au long du pipeline.

    Il reste encore des possibilités d’amélioration. Le regroupement des données pourrait être combiné à un classement basé sur des graphes, à une évaluation de la densité d’information ou à des passes légères d’un LLM pour la détection de sujets. Le choix du centreide pourrait être remplacé par une méthode plus subtile, telle qu’un classement au sein des clusters, une sélection pondérée par la diversité ou une petite invocation d’un LLM pour choisir le fragment le plus informatif. L’idée est là pour être reprise, adaptée et améliorée.

    Lectures complémentaires