← Blog

Les limites du RAG : quand la recherche sémantique ne suffit plus

J’ai écrit mes premiers articles sur le RAG début 2024 (les principes, puis une première mise en production). À l’époque, la question était encore : « est-ce que ça marche ? ». Deux ans plus tard, elle ne se pose plus. Monter un RAG est devenu une affaire de quelques heures : un service d’OCR, un modèle d’embedding, une base vectorielle, et c’est parti.

La question est devenue : jusqu’où ça marche ? Le scénario se répète d’un projet à l’autre. La démo impressionne, les premières questions donnent de bonnes réponses, puis un utilisateur pose une question parfaitement légitime, « quels produits tiennent au-delà de 200 °C ? », et le système répond n’importe quoi avec un aplomb parfait.

Ce type d’échec ne se corrige pas en ajustant les paramètres. Il tient à une limite structurelle de l’approche, et cette limite dit assez précisément où s’arrête un RAG et par quoi il faut le compléter.

Rappel express : pourquoi ça marche

Un RAG (Retrieval Augmented Generation) attache une base de connaissance externe à un modèle de langage. Le modèle ne connaît pas vos documents et ne peut pas tous les avaler d’un coup : on lui fournit donc, à chaque question, seulement les extraits utiles.

Principe du RAG

Le RAG attache une base de connaissance externe à un LLM

Pour choisir ces extraits, on utilise les embeddings : chaque morceau de texte devient un vecteur de plusieurs centaines de dimensions qui encode son sens. La question est convertie de la même façon, et on récupère les morceaux dont le vecteur est le plus proche.

La force de l’approche, c’est qu’elle travaille sur le sens et non sur les mots. « Comment coller du silicone sur de l’aluminium ? » va remonter une fiche qui parle d’« adhérence sur substrats métalliques et élastomères », sans partager un seul mot avec la question. C’est aussi pourquoi les démos sont si convaincantes : on teste spontanément des questions descriptives en langage naturel, qui sont exactement le terrain de jeu des embeddings.

Où ça casse

Les questions réelles des utilisateurs ne ressemblent pas aux questions de démo. Dans un métier technique, elles se répartissent en deux familles, et une seule des deux est sémantique.

Un vecteur ne sait pas comparer des nombres. Pour un modèle d’embedding, « résistance thermique : 180 °C » et « résistance thermique : 220 °C » sont deux phrases quasiment identiques : l’écart entre 180 et 220 est un détail de surface. À la question « quels produits tiennent au-delà de 200 °C ? », la recherche par similarité remonte donc les deux, dans le désordre. Le LLM filtre ensuite ce qu’il reçoit, mais il ne peut pas filtrer ce qu’il n’a jamais vu. Les embeddings encodent du sens, pas des valeurs : comparer, trier et compter relèvent de SQL.

Le RAG ne voit jamais la base entière. Une recherche vectorielle retourne un top-k : les 10 ou 20 meilleurs extraits, jamais les dizaines de milliers de chunks de la base. Toute question qui suppose une vue d’ensemble est donc hors d’atteinte : « combien de références résistent aux UV ? », « quel est le produit le plus fin de la gamme ? ». Et rien ne le signale : le système répond sur ses 10 extraits comme si c’était le corpus complet.

Le chunk ne connaît pas la notion de produit. Un RAG classique indexe des morceaux de texte. Or un catalogue de 50 pages parle de dizaines de produits, et un même produit apparaît dans 5 documents (fiche fournisseur, brochure, catalogue) parfois contradictoires, avec des unités et des langues différentes. Le produit, seul objet qui intéresse l’utilisateur, n’existe nulle part dans l’index : il n’y a que des fragments de pages qui en parlent.

Les rustines, et jusqu’où elles vont

L’écosystème a produit une belle boîte à outils. Elle est utile, mais il faut voir ce que chaque outil règle vraiment.

TechniqueCe que ça amélioreCe que ça ne règle pas
Recherche hybride (vecteurs + mots-clés)Les références exactes, les acronymes, le jargon maisonLes comparaisons numériques
Reranking (un modèle reclasse le top-50)La précision du haut de classementL’exhaustivité : on reclasse un échantillon
Multi-query / réécritureLes questions mal formulées ou multi-facettesLe fait qu’aucune formulation ne sait dire > 200 °C
Chunks plus gros / plus de contexteLa cohérence des extraitsLe coût, la latence, et la dilution de l’attention

La recherche hybride est celle qui apporte le plus, et je la considère aujourd’hui comme un minimum vital : combiner similarité sémantique, recherche full-text et mots-clés, puis fusionner les classements (par exemple en Reciprocal Rank Fusion). Mais toutes ces techniques travaillent sur le même objet, le classement d’extraits de texte non structuré. Aucune ne fabrique l’information qui manque.

Reste l’objection des fenêtres de contexte géantes : avec un million de tokens, pourquoi ne pas tout envoyer au modèle ? Sur un petit corpus, c’est une option raisonnable, et souvent la meilleure. Mais 2 000 PDF techniques restent très au-delà de la fenêtre, et même quand ça rentre, on paie le contexte complet à chaque question, avec une latence qui suit et une attention du modèle qui se dilue sur les documents longs. La fenêtre repousse le seuil à partir duquel il faut chercher, sans le supprimer.

Changer de problème : structurer avant d’indexer

À force de tourner autour, j’ai fini par admettre que je m’y prenais à l’envers. Tant qu’on indexe du texte brut, on optimise une recherche floue sur une donnée floue. D’où le déplacement :

Et si on utilisait les LLM pour transformer ces documents en base de données, plutôt que pour fouiller dedans ?

L’effort se déplace de la recherche vers l’ingestion. Au lieu de découper des PDF en chunks, on en extrait les entités métier et leurs caractéristiques dans un schéma normalisé. Le LLM sert d’abord à structurer la donnée, et seulement ensuite à répondre.

flowchart LR
pdf[/"PDF bruts"/] --> ocr["OCR"]
ocr --> ext["Extraction des références<br/>et liaison aux pages"]
ext --> enr["Enrichissement<br/>2 passes LLM"]
enr --> db[("Produits + specs typées")]
db --> sem["Recherche sémantique"]
db --> ft["Recherche full-text"]
db --> filt["Filtres structurés"]

Le pipeline tient en trois temps.

1. OCR. Le PDF devient du markdown propre, page par page, tableaux compris. C’est l’étape la plus banalisée aujourd’hui, et aussi celle où une erreur silencieuse se propage jusqu’au bout.

2. Identification des entités. L’ordre compte, et il est contre-intuitif : on ne demande pas au modèle d’extraire les caractéristiques techniques d’un catalogue de 50 pages, c’est trop de travail d’un coup et la qualité s’effondre. On lui demande d’abord une seule chose : quelles références produit apparaissent, et à quelles pages ? On obtient un graphe produit ↔ pages, où un produit peut pointer vers plusieurs documents et un document alimenter plusieurs produits.

3. Enrichissement, en deux passes. Pour chaque produit, on rassemble toutes ses pages sources, dans tous les documents. Une première passe rédige une synthèse libre en markdown, une seconde la convertit en JSON strict conforme au schéma. Les fusionner dégrade nettement le résultat : on demande alors au modèle de raisonner et de se tenir à un schéma en même temps, et il fait mal les deux.

Les deux sorties sont conservées, et c’est tout l’intérêt. Chaque article finit avec une face texte, la synthèse rédigée, vectorisée, qui alimente la recherche sémantique, et une face données, les caractéristiques typées, qui alimentent les filtres. C’est la somme des deux qui permet de faire du RAG et de la requête structurée sur le même objet.

Une fois les caractéristiques normalisées, « tous les produits qui résistent au-delà de 200 °C et font moins de 0,5 mm » devient une simple requête SQL : exacte, exhaustive et instantanée. Ce n’est plus un problème d’IA.

Reste à décider qui fixe la liste des caractéristiques. Laissé libre, le modèle invente ses propres clés au fil des documents et l’on se retrouve avec temp_max, temperature_maximale et resistance_thermique_c pour désigner la même chose : la méthode qui fonctionne consiste à lui faire proposer un premier schéma sur un échantillon de documents, à le faire nettoyer et valider par un expert métier, puis à lancer l’ingestion complète sur ce schéma verrouillé, que le modèle n’a plus le droit d’étendre.

Ce que ça ouvre

Avec cette double face, le RAG ne disparaît pas, il devient un mode de recherche parmi d’autres. Trois cohabitent sur le même catalogue :

  • la recherche sémantique sur les descriptions, pour les questions d’usage : « un adhésif qui tient sur du polypropylène en extérieur » ;
  • la recherche full-text pour les références exactes et le vocabulaire maison ;
  • les filtres structurés pour tout ce qui est chiffré, borné ou catégoriel, comme dans un configurateur produit.

Surtout, les trois se combinent : une question en langage naturel et une restriction à une plage de température, une marque et une couleur, les filtres s’appliquant en amont de la fusion des classements. Un commercial a besoin des trois dans la même journée, parfois dans la même recherche.

Ajouter un agent outillé

Plutôt qu’un pipeline figé qui fait une recherche et passe le top-k au modèle, on donne à un agent des outils et on le laisse mener l’enquête : explorer le schéma disponible, lancer une recherche filtrée, ouvrir une fiche produit, recommencer autrement si le résultat est vide.

flowchart LR
U["Question en<br/>langage naturel"] --> AG(["Agent"])
AG -->|"explore, cherche, affine"| T["Outils de la base<br/>schéma des filtres<br/>recherche hybride<br/>fiche produit"]
T -->|"résultats"| AG
AG --> R["Réponse sourcée"]

Une base bien structurée expose vite 130 filtres et des centaines de valeurs possibles. Aucun humain ne se repère dans un formulaire de recherche à 130 critères, et personne n’a envie d’essayer. Un agent, lui, lit ce schéma sans effort, retient les deux ou trois critères qui comptent pour la question posée et formule une requête bien plus précise que celle qu’un utilisateur aurait construite à la main. La masse de filtres, qui rend l’outil inutilisable pour un humain, devient un avantage dès qu’une machine s’en sert. C’est de loin la brique qui fait le plus de différence sur la qualité des réponses.

Une demande d’équivalent produit illustre bien la bascule. En RAG classique, « donne-moi une alternative au 3M 9472LE » lance une recherche sémantique sur la chaîne « 3M 9472LE », qui remonte évidemment le 3M 9472LE. L’agent procède comme un commercial expérimenté : il cherche d’abord la référence cible, lit ses caractéristiques, puis lance une seconde recherche filtrée sur ces caractéristiques en excluant le produit d’origine.

Cette approche se justifie quand la donnée est intrinsèquement tabulaire mais enfermée dans du PDF, ce qui est exactement le cas des catalogues et des fiches techniques. Sur un corpus rédigé et homogène, des comptes rendus ou des procédures, un bon RAG hybride reste le plus adapté, et je continue d’en déployer.

Pharios

J’ai fini par industrialiser tout ça dans un produit, Pharios.

Le point de départ, c’est Adezif, distributeur d’adhésifs techniques, accompagné depuis 2022 : d’abord un catalogue produit classique, puis le RAG de 2024 décrit dans mon précédent article, et enfin cette refonte. Trois générations d’outil pour le même besoin, chacune ayant buté sur la limite suivante.

Pharios reprend la chaîne complète : dépôt des PDF, OCR, extraction des références, enrichissement en deux passes, schéma de caractéristiques typées avec ses outils de nettoyage, recherche hybride avec filtres structurés, et agent conversationnel outillé. Il s’intègre soit en chatbot embarqué dans une application métier existante, soit via un serveur MCP pour se brancher sur un agent que le client utilise déjà. Le tout tourne en production sur plus de 2 000 documents, interrogés au quotidien par une équipe commerciale en mobilité.

Si vous distribuez ou transformez des produits techniques, avec quelques centaines à quelques milliers de références, plusieurs fournisseurs et une documentation PDF qui s’accumule depuis des années, la démo se fait sur vos propres documents, seul moyen honnête de savoir si ça tient sur votre corpus.

Découvrir Pharios