Le RAG est une technique qui combine génération de texte et recherche d’information. Au lieu de se baser uniquement sur ses connaissances internes, le modèle interroge une base de données externe pour enrichir ses réponses.
Les limites des LLM classiques
Vous n’avez pas le contrôle sur les connaissances des LLM classiques, donc sur vos sujets techniques ils diront beaucoup de choses fausses.
Vous pourriez leur balancer toute votre base de donnée, mais vous vous heurteriez à plusieurs difficultés :
- La plupart des documentations ne sont pas formatées de manière optimale (c’est peu dire) pour être comprises par des LLM (il s’agit souvent de pdf).
- La fenêtre de contexte n’est pas toujours immense. Ainsi, vous ne pouvez envoyer qu’environ 4000 tokens (~3000 mots) à Llama3.2. Certaines bases de données ne rentrent pas même dans les plus grandes fenêtres de contexte.
- Lorsque la fenêtre de contexte est immense (>1M tokens) et suffisante pour accueillir vos connaissances, il y a un autre problème : le résultat est souvent médiocre.
Ainsi, il faut pouvoir n’envoyer que les informations pertinentes au modèle. C’est le principe du RAG.
L’apport du RAG (Retrieval Augmented Generation)
La « Retrieval Augmented Generation » (RAG) est une technique consistant à exploiter une base de données pour concevoir le contexte qui sera envoyé au modèle (LLM, Large Language Model). On ne touche pas à ce dernier, on crée juste une étape préalable pour avoir un contexte ultra-pertinent.
On découpe une base de données en petits morceaux, qu’on transforme en vecteurs (embedding).
Ensuite, chaque fois que le modèle reçoit une question ou un prompt, il recherche dans une base de documents pertinents.
Puis, il utilise ces documents pour produire une réponse plus précise et contextualisée.
Voir le schéma ci-contre.

C’est une technique particulièrement utilisée pour les chatbots, pour permettre d’avoir une IA qui va piocher dans les contenus de votre entreprise spécifiquement.
La comparaison entre RAG et fine-tuning
Le fine-tuning, lui, consiste à entraîner un peu plus le modèle. C’est très différent du RAG, qui n’y touche pas et se contente d’ajouter une étape avant. Les différences pratiques sont considérables. En effet, le fine-tuning
- demande beaucoup plus de capacités de calcul ;
- n’est pas pratique pour les mises à jour (il faut tout refaire à chaque fois) ;
- ne permet pas de récupérer de manière fiable l’information transmise.
En fait, le fine-tuning permet surtout de lui faire mieux comprendre votre style et vos demandes. RAG et fine-tuning sont radicalement différents, mais plutôt complémentaires.
Les limites des RAG et les systèmes pour les renforcer
Les RAG basiques ont néanmoins des limites, qui ont essentiellement trait au fonctionnement du système de récupération. En effet, ce système ne « comprend » pas ce que vous lui envoyez, comme peut sembler le faire un LLM. Il identifie simplement les chunks où il y a le plus de chance d’y avoir l’information pertinente.
- Cela implique que toute l’information doit être dans le chunk.
- Cela implique aussi que vous ne pouvez pas poser de questions trop générales.
- La qualité de la récupération dépend aussi beaucoup de la question.
- Les modèles d’embedding sont conçus pour le cas général, donc si votre secteur utilise un jargon spécifique, ils auront beaucoup de mal à l’identifier
- Il arrive aussi que l’algorithme de sélection se plante simplement et ne trouve pas le passage adéquat, notamment si la base de donnée est gigantesque.
Heureusement, il y a plusieurs manières de contourner ces limites. Nous allons les présenter dans l’ordre logique.
Les systèmes pour améliorer la base de données
Pour améliorer la base de données, la principale chose à faire est de l’enrichir avec des métadonnées.
Reste le problème du jargon : les modèles d’embeddings sont conçus pour le cas général, pas pour les vocabulaires spécifiques. Par exemple, ils ne savent souvent pas qu’en droit « incapacité » et « régime » ou « tutelle » vont souvent ensemble, ou bien que « obligation » est beaucoup plus proche de « responsabilité » et « contrat » que de « devoir » en droit (alors que dans le langage courant c’est l’inverse).
Une solution est de personnaliser le modèle d’embeddings (« custom embeddings). Je n’ai aucune idée de comment faire.
Les systèmes pour améliorer la question
La question peut être un peu floue et souvenez vous que le système de récupération est assez rigide. Il fonctionne très mal avec les questions floues ou utilisant les mauvais mots.
Une solution pour le vocabulaire est simplement de retraiter la question grâce au LLM/RAG : « Voici la question posée. Identifies l’intention de recherche au regard des documents pertinents du corpus et reformules la question avec le bon vocabulaire. »
Pour les requêtes complexes, la solution est de diviser, avec un appel LLM, la question en plusieurs requêtes plus petites (« Query fanout »), qui pourront être rassemblées à la fin. Par exemple, si je demande « Quel est le meilleur isolant thermique ? », on peut découper en « Qu’est-ce qu’un isolant thermique ? », « Quels sont les isolants thermiques communs ? », « Quelles sont les caractéristiques importantes des isolants thermiques ? ».
Vous lancez votre système sur ces différentes requêtes, puis vous passez l’ensemble du résultat au LLM en lui demandant de synthétiser en lui expliquant (« la question initiale est […], nous l’avons décomposée en […], voici les réponses […], maintenant donne une réponse claire et synthétique à la question initiale en devinant l’intention de l’utilisateur. ») Le seul inconvénient est qu’on multiplie le temps de traitement. Néanmoins, cela me semble acceptable au regard de la puissance de ces systèmes.
Les systèmes pour améliorer la récupération (retrieval)
Le prétraitement sémantique avec BM25
Une solution populaire est d’utiliser une pré-sélection grâce à BM25, un algorithme qui se base sur la requête pour classer les documents selon la fréquence de la requête et la rareté relative des termes. Par exemple, dans « Quelle est la citation de Karl Popper dans ce livre ? », « Karl Popper » va être un élément très différenciant parce que c’est un terme extrêmement rare. Ensuite, ce sera « livre » et « citation ».
Néanmoins, cet algorithme a du mal avec les requêtes longues ou si les mots de la question ne sont pas les mêmes que ceux de la base de donnée. Il est surtout utilisé pour faire du prétraitement, vu qu’il consomme peu de ressources.
Reranking ou Cross encoders
Les systèmes de récupération basés sur les embeddings fonctionnent en comparant la similarité entre la requête et les documents de la base. Cependant, cette approche a une limite majeure : elle ne prend pas en compte le contexte global de la requête et des documents. Les embeddings sont générés indépendamment pour chaque élément, ce qui peut conduire à des incompréhensions, surtout pour des requêtes complexes ou des vocabulaires spécifiques.
Les cross encoders proposent une solution à ce problème. Contrairement aux modèles classiques qui encodent la requête et les documents séparément, les cross encoders encodent la paire requête-document ensemble. Cela permet de capturer des interactions plus fines entre les mots de la requête et ceux du document, améliorant ainsi la pertinence des résultats.
Custom ranking
Si vous êtes motivés, vous pouvez même concevoir une fonction spécifique de ranking, en utilisant des signaux relatifs aux documents, d’autres à l’auteur, d’autres aux méta-informations, etc. Par exemple, si vous avez un ecommerce et que votre RAG sert à présenter les produits pertinents, vous pouvez prendre en compte une donnée méta donnant le prix. Bref, il s’agit de faire un algorithme un peu comme Google à ses débuts. Oui il faut être très motivé (et compétent).
Context distillation
Comme nous l’avons vu, la fenêtre de contexte est limitée et plus on envoie de tokens, moins bonne est la réponse. Une solution est de demander au LLM de synthétiser le contexte. En pratique, on peut se dire ce n’est utile que pour les énormes fenêtres de contexte ou si le prompt est extrêmement précis. Néanmoins je pense que cela peut-être aussi intéressant pour les fenêtres classiques (4K tokens), c’est à tester.
Exemples de systè
mes
La récupération hiérarchique
On part d’une base de donnée en étage comme vu plus haut : un livre (ou autre gros document) est résumé en quelques lignes, il contient des résumés de ses chapitres, puis de ses sections, qui enfin contiennent les morceaux.
Pour les récupérer on va également faire un système à étage :
- On demande à un LLM de sélectionner les livres où il est le plus probable qu’il y ait une réponse à la question.
- On utilise la réponse pour sélectionner dans la bdd le livre (avec l’embedding, en principe il ne devrait pas y avoir d’erreur).
- Idem, pour chaque livre, pour le chapitre, etc. Au final on demande le ou les chunks pertinents en sortie.
L’inconvénient est que cela fait énormément d’appels. Pour 5 livres ayant 5 chapitres, 5 sections , cela fait 125 appels … Même avec un petit, c’est assez long.
La récupération hiérarchique inversée
Une variante de la méthode précédente est, encore en partant d’un classement hiérarchique, de faire une recherche par embeddings classique (mettons 5 résultats), plus une recherche IMB25 (idem), puis de rassembler les chunks avant et après chacun et on fait passer chaque bloc dans un LLM pour savoir s’il est pertinent. On ne transmet, lors de l’appel final, que les blocs pertinents.
Cela permet de mieux contextualiser les chunks.
