08 / 08 Du retrieval au RAG
  1. ← Chercher par le sens : bases vectorielles et retrieval
  2. 00 Avant-propos
  3. 01 Embeddings et géométrie de la similarité
  4. 02 Recherche exacte et malédiction de la dimension
  5. 03 HNSW : naviguer dans un graphe de proximité
  6. 04 Le paysage des index ANN
  7. 05 Tester l'approximatif : l'oracle différentiel
  8. 06 Rendre l'index durable
  9. 07 Le versant lexical : BM25 et recherche hybride
  10. 08 Du retrieval au RAG
Chercher par le sens : bases vectorielles et retrieval · 08 / 08

Du retrieval au RAG

On sait retrouver les bons passages, par le sens, par la lettre, par leur fusion. Mais retrouver n'est pas répondre. Comment brancher notre moteur sur un modèle de langage pour qu'il compose une réponse fondée, sans inventer ?

Au chapitre précédent, on a marié les deux mondes de la recherche : le sens, capté par les vecteurs, et la lettre, épinglée par BM25, fusionnés par le rang pour rester robustes. On sait donc retrouver les bons passages dans une base, quelle que soit la forme de la requête. C’est un aboutissement. Mais c’est aussi une frustration qui monte depuis huit chapitres : quand tu poses une vraie question à ta base, tu ne veux pas une pile de documents à lire toi-même. Tu veux une réponse, rédigée, et fondée sur ces documents. Retrouver n’est pas répondre. Ce dernier chapitre franchit ce pas.

Le candidat brillant qui n’a pas le droit d’ouvrir ses fiches

Imagine un candidat exceptionnel à un grand oral. Il a une culture générale immense, il parle avec aisance, il enchaîne les raisonnements. Mais il passe l’épreuve les mains vides : interdiction d’ouvrir la moindre fiche. Pose-lui une question de culture générale, il brille. Demande-lui le montant exact de ta facture numéro 8831, et il est perdu : cette information n’a jamais fait partie de ce qu’il a appris. Un modèle de langage seul, c’est ce candidat.

Il souffre de trois manques, très précis :

Un modèle de fondation Modèle de fondation Réseau de neurones de très grande taille entraîné sur une quantité massive de données généralistes, qui peut ensuite être adapté à de nombreuses tâches spécifiques. Le terme a été popularisé par Bommasani et al. en 2021. Exemples typiques en 2026 : GPT-4, Claude, Gemini. Source : Bommasani et al., 2021 est donc merveilleux sur le général et aveugle sur ton particulier. Le problème n’est pas qu’il soit bête, il est brillant. Le problème est qu’on lui a confisqué ses fiches. Toute l’idée de ce chapitre tient dans le geste inverse : lui rendre les fiches, au bon moment.

L’idée du RAG : lui glisser les bonnes fiches avant qu’il réponde

Et si, juste avant de laisser le modèle répondre, on allait chercher dans ta base les passages qui parlent de la question, pour les lui poser sous les yeux ? Il ne répondrait plus de mémoire, mais en lisant. C’est exactement l’architecture qu’on appelle la génération augmentée par la recherche RAG Generation augmentee par la recherche (Retrieval-Augmented Generation) : architecture qui, avant de laisser un modele de langage repondre, va d abord retrouver les passages pertinents dans une base documentaire, puis les lui fournit en contexte pour qu il fonde sa reponse dessus. Popularisee par Lewis et al. en 2020. Source : Lewis et al., 2020 , ou RAG. Elle se décompose en trois temps, et le premier t’est déjà parfaitement familier.

C=top-k(hybride(q))1. retrouverp=prompt(q,C)2. assemblerr=LLM(p)3. geˊneˊrer\underbrace{\mathcal{C} = \text{top-}k\big(\text{hybride}(q)\big)}_{\text{1. retrouver}} \qquad \underbrace{p = \text{prompt}(q, \mathcal{C})}_{\text{2. assembler}} \qquad \underbrace{r = \text{LLM}(p)}_{\text{3. générer}}

Cette chaîne se lit ainsi. D’abord, pour une question qq, on construit le contexte C\mathcal{C} en retenant les kk meilleurs passages remontés par la recherche hybride du chapitre précédent. Ensuite, on assemble un prompt pp qui contient la question et ces passages. Enfin, on donne ce prompt au modèle, qui produit la réponse rr. Le point remarquable est le premier terme : le retrieval du RAG, ce n’est rien d’autre que la recherche qu’on a bâtie tout au long du cours. Le RAG ne remplace pas ce qu’on a appris, il le couronne. Embeddings, plus proches voisins, HNSW, index durable, fusion hybride : tout cela était la fondation qui rend ce dernier étage possible.

Ancrer la réponse, ou se taire

Donner les passages au modèle ne suffit pas : encore faut-il exiger qu’il s’en serve, et seulement d’eux. C’est la notion d’ ancrage Ancrage Fait de contraindre la reponse d un modele de langage a s appuyer uniquement sur des sources fournies (les passages recuperes), plutot que sur sa memoire interne. Un modele bien ancre cite ses sources et refuse de repondre quand le contexte ne contient pas l information, au lieu d inventer. : la réponse doit reposer sur le contexte fourni, pas sur la mémoire interne du modèle, et elle doit citer ses sources pour qu’on puisse vérifier. Un lecteur doit pouvoir remonter de chaque affirmation au passage qui la soutient.

Vient alors la question qui fait toute la différence : que se passe-t-il quand le contexte ne contient pas la réponse ? La tentation du modèle, on l’a vu, est de combler le vide. Le bon comportement est l’inverse : le dire. Répondre « je ne trouve pas cette information dans tes documents » est une bonne réponse, pas un échec. C’est le remède direct à l’hallucination : on ne demande plus au modèle de savoir, on lui demande de lire, de citer, et d’avouer quand la source manque. Le refus honnête est une fonctionnalité, pas un défaut.

Ce basculement a une conséquence lourde, qu’il faut regarder en face : la qualité de la réponse est désormais plafonnée par la qualité du retrieval. Si le bon passage n’est pas remonté, ou s’il n’entre pas dans le contexte, le modèle le mieux ancré du monde ne pourra que refuser. C’est exactement ce que le composant qui suit te met entre les mains.

À toi de brancher le pipeline

Le composant ci-dessous fait tourner le pipeline complet sur une petite base personnelle. Choisis une requête, puis bascule entre les deux mondes : le modèle seul, qui répond de mémoire, et le modèle plus RAG, qui lit d’abord les passages récupérés. En mode RAG, un levier règle le budget de contexte kk, c’est-à-dire le nombre de passages qu’on autorise à entrer sous les yeux du modèle. Regarde ce qui se passe quand tu le serres.

Requête

Modèle

Budget de contexte k

Passages récupérés

  1. #1dans le contexte

    Réunion de conseil stratégique du 12 mars, compte rendu.

  2. #2hors budget

    Facture FR-2024-8831, prestation de conseil, montant 4 200 euros.

  3. #3hors budget

    Facture FR-2024-2207, hébergement annuel.

  4. #4hors budget

    Note de frais, déplacement à Lyon.

  5. #5hors budget

    Règlement intérieur du personnel.

  6. #6hors budget

    Facture FR-2023-1180, licence logicielle.

Réponse

refus honnête

Je ne trouve pas cette information dans les passages fournis.

Aucune source.

Ce que tu observes

Le bon passage existe et a bien été récupéré, mais ton budget k est trop serré : il reste juste sous la barre, hors du contexte. Le modèle, honnête, refuse plutôt que d'inventer. Élargis k pour le laisser entrer.

Trois questions à te poser en jouant :

  1. Sur la requête « montant de la facture de conseil », reste en mode LLM seul. Que répond le modèle, et ce chiffre vient-il de ta base ? Bascule ensuite en LLM plus RAG avec un budget k=1k = 1 : que se passe-t-il, et pourquoi le bon passage n’est-il pas encore là ?
  2. Toujours sur cette requête, augmente kk à 22. La réponse change de statut. Quel passage vient d’entrer dans le contexte, à quel rang était-il, et pourquoi le modèle peut-il enfin répondre ?
  3. Passe à la requête « date d’échéance de la facture 2207 ». Compare le modèle seul et le RAG. Lequel invente, lequel refuse ? En quoi le refus est-il ici la meilleure des réponses ?

Trois horizons pour aller plus loin

Le pipeline qu’on vient de brancher est le RAG dans sa forme la plus simple. Trois raffinements le séparent des systèmes réels. On les formalise ici, car ce sont eux que tu rencontreras dès que tu quitteras le corpus jouet.

Découper avant d’indexer : le chunking

Jusqu’ici, un passage égalait un document. Mais un vrai document fait quarante pages. L’indexer d’un bloc serait absurde : sa réponse noierait le paragraphe utile dans un océan de texte, et il ne tiendrait jamais dans le contexte du modèle. On le coupe donc en morceaux courts avant de l’indexer. C’est le découpage en passages Decoupage en passages Operation qui coupe un document long en morceaux plus courts (les passages, ou chunks) avant de les indexer. On indexe et on recupere des passages, pas des documents entiers, pour cibler la reponse et tenir dans la fenetre de contexte du modele. La taille et le chevauchement des passages sont des reglages sensibles. .

Reste à choisir la taille. Trop grand, chaque passage mélange plusieurs idées et gaspille le budget ; trop petit, on tranche une idée en deux et chaque morceau devient incompréhensible isolé. On fait donc se chevaucher les passages : chaque morceau reprend la fin du précédent, pour qu’une phrase coupée par une frontière se retrouve entière dans au moins un passage. Si un document a une longueur LL (en tokens), qu’on choisit des passages de taille ss avec un chevauchement oo, le nombre de passages produits vaut environ :

npassagesLsso+1n_{\text{passages}} \approx \left\lceil \frac{L - s}{s - o} \right\rceil + 1

Cette formule se lit : chaque nouveau passage avance de sos - o tokens (la taille, moins ce qu’on reprend du précédent), le pas d’une fenêtre qui glisse. On compte combien de pas il faut pour couvrir toute la longueur, plus le passage initial. Plus le chevauchement oo est grand, plus le pas est petit, donc plus on produit de passages : la sécurité contre les coupures se paie en volume d’index.

La fenêtre de contexte : un budget qu’on ne peut pas dépasser

On a manipulé le levier kk sans le nommer vraiment. Ce qui le borne est une contrainte dure du modèle : sa fenêtre de contexte Fenetre de contexte Quantite maximale de texte, mesuree en tokens, qu un modele de langage peut lire d un coup en entree. Elle est bornee : on ne peut donc pas verser toute une base documentaire dans le prompt, seulement les k meilleurs passages retenus par le retrieval. Ce budget limite est ce qui rend le classement du retrieval decisif. , la quantité maximale de texte, mesurée en tokens, qu’il peut lire d’un coup. On ne peut donc pas verser toute la base dans le prompt, seulement les kk meilleurs passages. C’est précisément ce plafond qui rend le classement du retrieval décisif : si le bon passage sort au rang 1212 et que le budget n’en tient que 88, il est perdu, exactement comme dans le composant à k=1k = 1.

De là vient un raffinement très utile en pratique : le reclassement Reclassement Deuxieme etage de tri applique aux passages deja recuperes. Un premier retrieval rapide (BM25, vecteurs) remonte un lot de candidats ; un modele plus couteux, souvent un cross-encoder qui lit ensemble la requete et chaque passage, les reordonne finement pour que les meilleurs occupent les premieres places, celles qui tiendront dans la fenetre de contexte. . On laisse d’abord le retrieval rapide (BM25, vecteurs) remonter un large lot de candidats, disons cinquante. Puis un modèle plus coûteux, mais plus fin, souvent un cross-encoder qui lit ensemble la requête et chaque passage, les réordonne pour que les tout meilleurs occupent les premières places, celles qui tiendront dans la fenêtre. Deux étages : un premier rapide qui ratisse large, un second précis qui trie serré.

Le modèle qui cherche lui-même : le retrieval agentique

Dans tout ce qui précède, le pipeline est un aller simple : une requête, une recherche, une réponse. Mais certaines questions ne se laissent pas résoudre en une seule recherche. « Compare le montant de ma facture de conseil avec mon budget annuel formation » demande d’aller chercher deux choses distinctes, puis de les confronter. Un aller simple échoue.

L’idée qui lève cette limite est de donner au modèle la recherche non plus comme une étape fixe, mais comme un outil qu’il actionne lui-même, autant de fois qu’il le juge utile. C’est la boucle ReAct (pour Reasoning and Acting, Yao et al. 2022), qui alterne trois gestes jusqu’à ce que le modèle estime pouvoir conclure :

Raisonner    Agir (chercher)    Observer    Raisonner    \text{Raisonner} \;\rightarrow\; \text{Agir (chercher)} \;\rightarrow\; \text{Observer} \;\rightarrow\; \text{Raisonner} \;\rightarrow\; \cdots

Le modèle raisonne sur ce qui lui manque, décide quoi chercher, observe les passages remontés, puis recommence en fonction de ce qu’il vient d’apprendre. Le retrieval devient dynamique, piloté par le modèle lui-même. C’est le pont vers ce qu’on appelle aujourd’hui les agents : un modèle qui ne se contente plus de répondre, mais qui va chercher, en boucle, ce dont il a besoin pour répondre.

Exercices

En une phrase

Le RAG transforme une recherche en réponse : il retrouve les meilleurs passages (par la recherche hybride du cours), les glisse dans le contexte borné du modèle, et lui demande de composer une réponse ancrée sur eux en citant ses sources, ou de refuser honnêtement quand la source manque, de sorte que la qualité de la réponse reste plafonnée par celle du retrieval.

Quiz
  1. 1. Pourquoi un modèle de langage seul hallucine-t-il un montant de facture privé ?

  2. 2. Dans le pipeline RAG, que désigne le contexte donné au modèle ?

  3. 3. Que révèle le fait que le RAG refuse à k=1 mais répond à k=2 sur une même requête ?

Le mot de la fin

Nous voici au bout du fil. Repense au chemin : on est parti d’une idée presque philosophique, le sens comme une position dans l’espace, et on a construit, marche après marche, tout ce qu’il fallait pour en faire un moteur réel. Représenter un texte par un vecteur. Mesurer la proximité, et se heurter à la malédiction de la dimension. Contourner la comparaison exhaustive avec HNSW, puis situer ce choix dans le paysage des index approchés. Se donner un oracle différentiel pour vérifier sans se mentir. Rendre l’index durable, capable de survivre à un redémarrage. Le marier au versant lexical pour ne plus rater ni un synonyme ni un numéro exact. Et, aujourd’hui, brancher tout cela sur un modèle de langage pour passer du document retrouvé à la réponse rédigée.

Chaque chapitre répondait à une limite laissée par le précédent, et ce dernier ferme la boucle : le RAG n’existe que parce que tout le reste existe d’abord. C’est ce qui fait la beauté de cette chaîne, et c’est ce que je voulais partager en l’écrivant. Le moteur souverain que je construis continuera d’évoluer, il deviendra la mémoire d’un assistant personnel qui lit mes propres documents pour me répondre. Mais l’essentiel est désormais entre tes mains : tu sais ce qui se cache derrière ces mots à la mode, non pas la version marketing, la version qui compile. Merci d’avoir fait ce chemin.

Sources

  • Lewis, P. et al. (2020). « Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. » NeurIPS 2020. arXiv:2005.11401
  • Karpukhin, V. et al. (2020). « Dense Passage Retrieval for Open-Domain Question Answering. » EMNLP 2020. arXiv:2004.04906
  • Yao, S. et al. (2022). « ReAct: Synergizing Reasoning and Acting in Language Models. » ICLR 2023. arXiv:2210.03629

Pour aller plus loin

  • Ji, Z. et al. (2023). « Survey of Hallucination in Natural Language Generation. » ACM Computing Surveys 55(12), 1-38. DOI 10.1145/3571730
  • Gao, Y. et al. (2023). « Retrieval-Augmented Generation for Large Language Models: A Survey. » arXiv:2312.10997