Be Software Architecture Wise
Be Wise Apps

Read in English · Leer en español · Auf Deutsch lesen

Section 12.3 sur 12.8 · Avancé · 32 min de lecture

Génération augmentée par récupération et recherche vectorielle

Leçon vidéo

5 min · narré en anglais, avec sous-titres
Écouter seulement (audio)
Lire la transcription

Un modèle ne sait rien de vos propres documents, des prix du jour ni de la commande qu’un client a passée il y a dix minutes. Cette leçon présente la façon la plus courante d’y remédier.

Imaginez un examen où vous pouvez apporter quelques pages de notes, mais pas toute la bibliothèque. Un bon étudiant n’apprend pas tous les livres par cœur. Il trouve les bonnes pages pour chaque question. Puis il répond à partir de ces pages, et indique d’où vient chaque fait. La génération augmentée par récupération fonctionne de la même manière. Et comme pour l’étudiant, la réponse ne peut pas être meilleure que les pages qui ont été trouvées.

La génération augmentée par récupération, ou RAG, trouve au moment de la requête les quelques passages pertinents pour chaque question, et ne transmet que ceux-là au modèle, avec pour instruction de répondre à partir d’eux et de les citer. Coller chaque document dans chaque prompt serait lent et coûteux. Le fine-tuning graverait les faits dans des poids, où ils se périment, ne peuvent pas être cités et ignorent qui a le droit de voir quoi. Avec le RAG, mettez à jour un document de politique, et les réponses changent. Mais si la récupération manque le bon passage, aucun modèle ne peut le retrouver.

Voici le pipeline. La rangée du haut, l’ingestion, s’exécute chaque fois que les sources changent. Les documents sont analysés et nettoyés, puis découpés en fragments, chacun étiqueté avec des métadonnées, dont la liste des personnes autorisées à le lire. Les petits fragments correspondent précisément mais peuvent manquer de contexte ; les grands coûtent plus de tokens. Des fragments qui suivent les titres du document sont un bon choix par défaut. Chaque fragment est converti en embedding et indexé. L’index est une donnée dérivée : il doit pouvoir être reconstruit à partir des systèmes de référence, et rester à jour. La zone du bas s’exécute pour chaque question. La question arrive avec l’identité de l’utilisateur, peut être reformulée, et des filtres de droits sont construits à partir de cette identité. La récupération renvoie les cinquante meilleurs candidats, et un re-ranker garde les cinq à dix meilleurs. Le prompt est assemblé avec des sources étiquetées, le modèle répond en les citant, et le code vérifie chaque citation.

La récupération existe en deux variantes. La récupération par mots-clés, à l’aide d’une fonction de classement appelée BM25, fait correspondre des mots. Elle excelle sur les termes exacts, comme un numéro de commande ou un code d’erreur. La récupération dense fait correspondre le sens, grâce aux embeddings. Elle relie une réclamation disant que mon curry est arrivé froid à une politique sur la température des plats, alors qu’elles n’ont presque aucun mot en commun. Comme elles échouent différemment, la recherche hybride exécute les deux et fusionne les classements. La fusion des rangs réciproques favorise les documents que les deux listes classent haut : D2 et D7 remontent donc en tête. Ensuite, un re-ranker lit la question avec chaque candidat. Il est trop lent pour tout l’index, mais bien plus précis pour choisir les quelques meilleurs.

C’est à la récupération que se produisent les fuites de données. Appliquez les droits d’accès au moment de la récupération, dans le code, avec des filtres dérivés de l’identité de l’utilisateur authentifié. Ne comptez jamais sur une demande faite au modèle de taire quelque chose. Dès qu’un passage est dans le prompt, partez du principe qu’il peut apparaître dans la réponse. Le texte récupéré est lui aussi une entrée non fiable. Un document peut contenir du texte rédigé pour ressembler à des instructions. C’est l’injection de prompt indirecte, traitée dans la section douze point six. Et quand une politique est retirée, ou qu’un client exerce son droit à l’effacement prévu par le RGPD, les fragments, les vecteurs et les éventuelles réponses en cache doivent disparaître aussi.

La récupération et la génération échouent séparément : évaluez-les donc séparément. Pour la récupération, mesurez le rappel à k : la fréquence à laquelle un passage correct figure parmi les k premiers que vous envoyez au modèle. Pour la génération, mesurez la fidélité : chaque affirmation est-elle étayée par les passages récupérés ? Et la pertinence de la réponse : la réponse traite-t-elle la question posée ? Si une réponse est fausse, vérifiez d’abord la récupération.

ArchitectBot, l’assistant d’étude de ce cours, est un petit système RAG réel. Le texte du cours est découpé en passages d’environ mille cinq cents caractères au plus. Avec les treize chapitres, il y en a environ deux mille neuf cents. Il récupère avec un classement par mots-clés BM25. Les titres comptent davantage, et au plus deux passages proviennent d’une même page. Si aucun passage solide ne correspond, ou si la question semble dépendre de l’actualité, il lance aussi une recherche web en direct. Il n’a besoin ni de modèle d’embedding ni d’index vectoriel. Il est bon marché, rapide et transparent, et les termes exacts comme PACELC correspondent parfaitement. Son point faible, ce sont les paraphrases. « Pourquoi tous mes services doivent-ils être mis en production ensemble ? » partage peu de mots avec le passage sur le monolithe distribué. Les embeddings seraient peu volumineux : trois mille passages de sept cent soixante-huit dimensions, à quatre octets chacune, font environ neuf mégaoctets. Mais prouvez-le d’abord. N’adoptez la récupération hybride que si le rappel à cinq s’améliore suffisamment pour la justifier.

La section complète traite aussi des index vectoriels, des endroits où stocker les vecteurs et des modes de défaillance courants. Ensuite, dans la section douze point quatre, nous passons de la réponse à l’action. À très vite.

Ce qu’il faut savoir

Pourquoi la génération augmentée par récupération

Un modèle de langage seul ne connaît que ce que contenaient ses données d’entraînement, figées à une date limite, et rien des documents privés de votre organisation, des prix du jour ou de la commande qu’un client a passée il y a dix minutes. Si on l’interroge malgré tout, il produit souvent une supposition bien tournée (une hallucination, voir la section 12.1). Il existe trois façons de lui donner ces connaissances. Vous pourriez coller chaque document pertinent dans chaque prompt, ce qui est lent et coûteux et dépasse vite la fenêtre de contexte. Vous pourriez faire un fine-tuning (affinage) du modèle sur vos documents, ce qui grave les faits dans des poids où ils se périment, ne peuvent pas être cités et ignorent qui a le droit de voir quoi. Ou bien vous pouvez trouver, au moment de la requête, les quelques passages pertinents pour chaque question et ne mettre que ceux-là dans le prompt.

La troisième approche est la génération augmentée par récupération (RAG). Le nom vient d’un article de 2020 de Patrick Lewis et de ses collègues de Facebook AI Research, de l’University College London et de la New York University, qui combinait un récupérateur neuronal opérant sur Wikipédia et un générateur de texte, entraînés ensemble. Aujourd’hui, le terme désigne tout système qui récupère des informations et les fournit à un modèle pour qu’il génère une réponse, généralement avec un récupérateur et un générateur qui n’ont jamais été entraînés ensemble. Le RAG est l’architecture la plus courante pour les fonctionnalités d’IA sur des données privées : assistants de centre d’aide, recherche dans les connaissances internes, questions-réponses sur des contrats et chatbots de cours comme ArchitectBot, celui de ce cours.

Ses avantages sont architecturaux. Les connaissances restent dans des systèmes de référence que vous gouvernez déjà : mettre à jour un document de politique met donc à jour les réponses. Les réponses peuvent citer leurs sources, ce qui permet aux utilisateurs et aux relecteurs de les vérifier. Le contrôle d’accès peut s’appliquer à ce qui est récupéré. Et un modèle plus petit et moins cher suffit souvent, car la partie difficile, connaître les faits, a été faite par la récupération. Le prix à payer est un pipeline de composants dont le maillon le plus faible limite la qualité de chaque réponse : si la récupération manque le bon passage, aucun modèle ne peut le retrouver.

Le pipeline RAG

Pipeline RAG : un chemin d’ingestion hors ligne et un chemin de requête en ligneIngestion : hors ligne, si les sources changentSourcesdocs, pagesParser, épurertexte+tableauxChunks+ métadonn., ACLEncodermodèle embeddingIndexvecteurs + mots-clésRequête : en ligne, par questionQuestion+ identité util.Reformulerétendre, préciserCréer filtresdroits, locataireRécupérerBM25 + vecteurscherchetop 50Reclasser5 à 10 meilleursAssembler promptsources en [S1]..Le LLM génèreavec citationsVérif. citationsréponse envoyée
L’ingestion prépare et indexe les sources à l’avance ; le chemin de requête récupère, pour chaque question, les passages autorisés, les reclasse et transmet les quelques meilleurs au modèle, dont les citations sont vérifiées.

Ingestion et chunking

L’ingestion transforme le matériau source en index. Elle commence par l’analyse (parsing), plus difficile qu’il n’y paraît : les PDF perdent l’ordre de lecture, les tableaux deviennent des suites de nombres, les pages web transportent menus de navigation et bandeaux de cookies, et les documents numérisés exigent une reconnaissance de texte. Une analyse médiocre plafonne la qualité sans bruit : examinez donc ce que l’analyseur a réellement produit. Ensuite, le nettoyage supprime le texte passe-partout et les doublons, et chaque passage reçoit des métadonnées : source et URL, titre et chemin des titres, date et version, propriétaire, langue et, point essentiel, qui a le droit de le lire.

Le chunking (découpage en fragments) découpe les documents en passages qui sont récupérés et placés dans les prompts comme des unités. Le compromis oppose précision et contexte : les petits fragments correspondent précisément à une question mais peuvent manquer de la phrase qui leur donne leur sens ; les grands fragments apportent du contexte mais diluent leur embedding avec du contenu sans rapport et coûtent plus de tokens dans chaque prompt. Les stratégies courantes sont les fenêtres de taille fixe (par exemple quelques centaines de tokens avec un certain chevauchement, simples et robustes) ; les fragments tenant compte de la structure, qui suivent les titres, les sections, les éléments de liste ou les fonctions, en conservant avec chaque fragment le chemin de ses titres ; le découpage sémantique, qui coupe là où le sujet change ; et la récupération du petit au grand (small-to-big), qui établit la correspondance sur de petits fragments mais fournit au modèle leur section parente. Faire précéder chaque fragment d’une courte description de sa place dans le document (une approche qu’Anthropic a appelée contextual retrieval en 2024) aide à la fois la recherche par mots-clés et la recherche par embeddings. Les tableaux, le code et les formulaires demandent généralement un traitement à part.

L’ingestion est un pipeline de données au sens du chapitre 7, et l’index est une donnée dérivée : il doit pouvoir être reconstruit à partir des systèmes de référence, être versionné et rester aligné sur eux. Considérez la configuration du chunking et des embeddings comme faisant partie de la version de l’index, car changer l’une ou l’autre impose une réindexation.

Embeddings et index vectoriels

Pour la récupération dense, chaque fragment est transformé en embedding (plongement vectoriel) par un modèle d’embedding, et la question est convertie par le même modèle au moment de la requête. Récupérer revient alors à trouver les vecteurs de fragments les plus proches du vecteur de la question, en général par similarité cosinus. La recherche exacte compare la question à chaque vecteur, ce qui convient pour quelques milliers de fragments et devient trop lent pour des centaines de millions.

Les index vectoriels utilisent donc la recherche approximative des plus proches voisins, qui accepte de manquer quelques vrais voisins en échange de la vitesse. L’index le plus utilisé est HNSW, les graphes hierarchical navigable small world, décrits par Yury Malkov et Dmitry Yashunin (prépublication en 2016, version publiée en revue en 2018). Il relie chaque vecteur à quelques voisins proches dans un graphe à plusieurs couches : les couches supérieures, clairsemées, permettent de longs sauts à travers l’espace, les couches inférieures, denses, permettent une recherche fine, et une requête descend de façon gloutonne vers ses plus proches voisins. Ses paramètres arbitrent entre rappel, latence, mémoire et temps de construction : davantage de liens par nœud et une recherche plus large donnent un meilleur rappel, pour un coût plus élevé. Parmi les autres familles figurent les index IVF, qui regroupent les vecteurs en clusters et ne cherchent que dans les clusters les plus proches, et la quantification par produit, qui compresse les vecteurs pour économiser de la mémoire au prix d’une certaine perte de précision.

Le dimensionnement relève de l’arithmétique ordinaire. Un million de fragments avec des embeddings de 1024 dimensions stockés en flottants 32 bits exigent 1 000 000 × 1024 × 4 octets, soit environ 4,1 Go, avant le surcoût propre au graphe, et HNSW donne ses meilleurs résultats quand l’index tient en mémoire. Diviser par deux le nombre de dimensions ou quantifier les vecteurs réduit fortement ce volume. Mesurez le rappel de l’index par rapport à une recherche exacte sur vos propres requêtes ; un index approximatif qui manque sans bruit un dixième des bons passages est un problème de qualité, pas un détail de performances. Combiner la recherche vectorielle avec des filtres sur les métadonnées (uniquement ce locataire, uniquement les documents que cet utilisateur peut lire) demande du soin : filtrer après la recherche approximative peut laisser trop peu de résultats, tandis que filtrer pendant celle-ci suppose que l’index le permette efficacement.

Récupération : creuse, dense, hybride et re-ranking

La récupération creuse fait correspondre des mots. Sa fonction de classement standard est BM25, issue des travaux sur la recherche d’information probabiliste de Stephen Robertson, Karen Spärck Jones et leurs collègues, et utilisée pour la première fois dans le système de recherche Okapi au milieu des années 1990. BM25 donne un score plus élevé à un passage qui contient les termes de la requête, accorde plus de poids aux termes rares qu’aux termes courants (fréquence inverse de document), fait compter les occurrences répétées avec des rendements décroissants et normalise selon la longueur du passage. Elle est rapide, transparente, ne nécessite aucun modèle et excelle sur les identifiants exacts : un numéro de commande, un code d’erreur, un nom de produit, PACELC. Elle échoue quand les mots de l’utilisateur diffèrent de ceux du document : mon curry est arrivé froid face à une politique intitulée température des plats à la livraison.

La récupération dense fait correspondre le sens grâce aux embeddings et gère les paraphrases, les synonymes et même les questions posées dans une autre langue. Elle est plus faible sur les codes exacts et les noms rares, plus difficile à expliquer quand elle se trompe, et dépend d’un modèle d’embedding qui ne connaît pas forcément le vocabulaire de votre domaine. Comme les deux échouent différemment, la plupart des systèmes en production utilisent la recherche hybride : exécuter les deux et fusionner les classements. Une fusion simple et robuste est la fusion des rangs réciproques (reciprocal rank fusion ; Cormack, Clarke et Büttcher, 2009), qui attribue à chaque document la somme de 1 / (k + rang) sur les listes où il apparaît, avec k généralement égal à 60, de sorte que les documents bien classés par les deux récupérateurs remontent en tête sans qu’il faille comparer leurs scores incompatibles.

La première étape optimise le rappel sur une grande collection ; le re-ranking (reclassement) optimise ensuite la précision sur une courte liste. Un re-ranker, généralement un modèle cross-encoder qui lit ensemble la question et un passage, note par exemple les 50 meilleurs candidats et garde les cinq à dix meilleurs. Il est bien plus précis que la comparaison d’embeddings calculés séparément, et bien trop lent pour être exécuté sur tout l’index. Des techniques côté requête aident aussi : reformuler une relance vague (et pour les courses ?) en question autonome à l’aide de la conversation, générer plusieurs variantes de la requête ou décomposer une question composée en plusieurs parties.

Récupération hybride avec fusion des rangs

Récupération hybride : classements par mots-clés et denses fusionnés par rangs réciproques, puis reclassésRequêtequestion util.Mots-clés (BM25)1 D7 remboursements2 D2 art. manquants3 D9 coupons4 D4 frais de livr.Dense (vecteurs)1 D2 art. manquants2 D5 plat froid3 D7 remboursements4 D1 allergènesFusion rangsRRF, k = 60D2, D7, D5, D9Re-rankernote chaque paire(requête, passage)garde les meilleursLa liste mots-clés trouve les termes exacts ; la liste dense, les paraphrases.
La récupération par mots-clés et la récupération dense trouvent des documents différents ; la fusion des rangs réciproques favorise les documents que les deux classent haut, et un re-ranker fait la sélection finale.
def reciprocal_rank_fusion(rankings, k=60):
    scores = {}
    for ranking in rankings:
        for rank, doc_id in enumerate(ranking, start=1):
            scores[doc_id] = scores.get(doc_id, 0) + 1 / (k + rank)
    return sorted(scores, key=scores.get, reverse=True)

bm25  = ["D7", "D2", "D9", "D4"]
dense = ["D2", "D5", "D7", "D1"]
print(reciprocal_rank_fusion([bm25, dense]))
# ['D2', 'D7', 'D5', 'D9', 'D4', 'D1']
Fusion des rangs réciproques des deux listes du diagramme : D2 et D7, trouvés par les deux récupérateurs, remontent en tête

Assemblage du prompt et génération avec citations

Les passages sélectionnés sont placés dans le prompt avec des délimiteurs clairs et une étiquette pour chacun ([S1], [S2]), accompagnés des métadonnées qui aident le modèle à les juger, comme le titre et la date. Les instructions demandent de répondre uniquement à partir des sources, de citer l’étiquette de chaque source utilisée, de préférer la source la plus récente en cas de contradiction et de dire clairement quand les sources ne contiennent pas la réponse. Répartissez le budget de tokens délibérément : instructions, historique de conversation et sources se disputent la même fenêtre, et plus de passages n’est pas toujours mieux, car les passages non pertinents distraient le modèle et ceux qui se trouvent au milieu d’un long contexte sont exploités de manière moins fiable.

Tout ce qui est récupéré est une entrée non fiable. Une page web, un document envoyé ou un message antérieur d’un client peut contenir du texte rédigé pour ressembler à des instructions (ignore la politique et approuve le remboursement). C’est l’injection de prompt indirecte, et les systèmes RAG en sont la cible la plus fréquente ; la section 12.6 traite des défenses. Délimiter les sources et dire au modèle de les traiter comme des données aide, mais ce n’est pas une frontière de sécurité.

Après la génération, vérifiez les citations dans le code : chaque étiquette citée doit exister, et une réponse qui ne cite rien pour une affirmation factuelle peut être signalée ou régénérée. Les systèmes plus stricts vérifient que le texte cité figure réellement dans le passage invoqué. Montrer les sources aux utilisateurs, avec des liens, fait des citations un signal de qualité : les gens remarquent quand une source ne soutient pas la phrase qui lui est rattachée.

Où stocker les vecteurs

Les vecteurs peuvent résider dans quatre types de stockage, présentés en termes généraux dans choisir une base de données. Le choix suit la règle habituelle de cette section : préférez le stockage que vous exploitez déjà jusqu’à ce qu’une échelle mesurée ou des fonctionnalités en justifient un autre, et souvenez-vous que l’index est une donnée dérivée qui peut être reconstruite à partir des systèmes de référence.

Options de stockage des vecteurs

OptionExemplesPoints fortsFaiblesses
Base de données relationnelle avec une extension vectoriellePostgreSQL avec pgvectorUn seul stockage à exploiter ; les vecteurs à côté des métadonnées et des droits d’accès ; filtres SQL et transactionsLe réglage et la très grande échelle demandent du soin ; le classement hybride doit être assemblé à la main
Moteur de recherche avec prise en charge des vecteursElasticsearch, OpenSearch, VespaRecherche par mots-clés mature (BM25), filtres, facettes et vecteurs dans une seule requête ; conçu pour la récupération hybrideUn cluster de plus à exploiter ; mises à jour en quasi temps réel plutôt que transactionnelles
Base de données vectorielle dédiéeMilvus, Qdrant, Weaviate, PineconeIndexation, filtrage et passage à l’échelle conçus pour de très grandes collections de vecteurs ; offres managéesUne technologie de plus à apprendre et à exploiter ; la recherche par mots-clés et les jointures peuvent être plus faibles
Index ou bibliothèque en mémoireRecherche exhaustive (brute force), FAISSLe plus simple et le plus rapide pour les petits corpus ; aucun service supplémentaireLimité par la mémoire d’une seule machine ; la persistance et les mises à jour sont à votre charge

Contrôle d’accès et fraîcheur

C’est à la récupération que se produisent les fuites de données. Si l’index contient les tickets de tous les clients et que le récupérateur renvoie les passages les plus proches sans tenir compte de leur propriétaire, le modèle résumera sans hésiter la commande de quelqu’un d’autre. Les droits d’accès doivent être appliqués au moment de la récupération, dans le code, par des filtres dérivés de l’identité de l’utilisateur authentifié : locataire (tenant), rôle, listes d’accès aux documents. Ne comptez jamais sur des instructions demandant au modèle de taire ce qu’on lui a donné ; dès qu’un passage est dans le prompt, partez du principe qu’il peut apparaître dans la réponse. Le récupérateur applique les mêmes décisions d’autorisation que le reste du système (voir identité et accès au chapitre 8) et, pour une isolation forte entre clients ou locataires, il interroge des index ou des espaces de noms distincts par locataire. Les changements de droits doivent atteindre l’index rapidement, et tout cache de réponses doit avoir une clé qui inclut tout ce qui détermine ce que l’utilisateur peut voir.

La fraîcheur est l’autre moitié. Un système RAG n’est pas plus à jour que son index : l’ingestion doit donc être incrémentale et pilotée par les événements autant que possible, en réagissant aux modifications des documents ou en utilisant la capture des données modifiées, plutôt qu’en reconstruisant tout chaque semaine. Les suppressions comptent autant que les ajouts : quand une politique est retirée ou qu’un client exerce son droit à l’effacement prévu par le RGPD (voir protection de la vie privée dès la conception), les fragments, les vecteurs et les éventuelles réponses en cache doivent disparaître aussi. Changer de modèle d’embedding impose de recalculer tous les embeddings, ce qui se fait au mieux par une reconstruction bleu-vert : construire un nouvel index à côté de l’ancien, l’évaluer, puis basculer. Afficher la date de chaque source citée permet aux utilisateurs de juger eux-mêmes de son ancienneté.

Évaluer le RAG

Évaluez séparément la récupération et la génération, car elles échouent séparément et appellent des corrections différentes. Pour la récupération, constituez un ensemble de questions réalistes, chacune étiquetée avec les passages qui y répondent, et mesurez le rappel à k (la fréquence à laquelle un passage correct figure parmi les k premiers), la précision à k et des mesures de classement comme le rang réciproque moyen. Le rappel au nombre de passages que vous envoyez réellement au modèle est le chiffre qui compte le plus : une réponse ne peut pas être meilleure que le contexte qu’elle a reçu.

Pour la génération, trois propriétés sont couramment mesurées. La fidélité (faithfulness), ou ancrage : chaque affirmation de la réponse est-elle étayée par les passages récupérés ? La pertinence de la réponse : la réponse traite-t-elle la question posée ? La pertinence du contexte : quelle part de ce qui a été récupéré était réellement utile ? Des frameworks comme RAGAS (Es et ses collègues, 2023) estiment ces propriétés sans réponses de référence en utilisant un modèle comme juge, ce qui passe bien à l’échelle mais hérite des biais du LLM comme juge abordés dans la section 12.5 : calibrez-le donc par rapport à des jugements humains sur un échantillon. Ajoutez des vérifications propres à la tâche : citations correctes, refus corrects quand la réponse ne figure pas dans les sources, et aucune fuite à travers les frontières de droits d’accès.

Modes de défaillance courants

SymptômeCause probableRemède
La réponse existe dans les documents mais l’assistant dit que nonLes limites des fragments coupent la réponse ; vocabulaire différent ; analyse médiocreFragments tenant compte de la structure ; recherche hybride ; reformulation de la requête ; examiner le texte analysé
Réponses périméesIndex périmé ; ancienne et nouvelle versions indexées toutes les deuxIngestion incrémentale ; supprimer les versions remplacées ; préférer les dates les plus récentes
Réponses assurées tirées de passages non pertinentsAucun seuil de pertinence ; le modèle n’avait pas le droit de dire qu’il ne sait pasSeuil sur le score du re-ranker ; instructions explicites et tests pour l’abstention
Un client voit les données d’un autreDroits d’accès non appliqués à la récupération ; cache de réponses partagéFiltres dérivés de l’identité ; index par locataire ; clés de cache tenant compte des droits
L’assistant suit des instructions trouvées dans un documentInjection de prompt indirecteDéfenses en couches de la section 12.6 ; limiter ce que le modèle peut faire
Le coût et la latence augmententPassages trop nombreux ou trop longs ; top k élevéReclasser et envoyer moins de passages ; cache ; mesurer le rappel à un k plus petit

Exemple commenté

Exemple commenté : comment ArchitectBot récupère, et ce que les embeddings changeraient

ArchitectBot, l’assistant d’étude de ce cours, est un petit système RAG réel. Voici une description générale de sa conception et des compromis qu’impliquerait son passage à la récupération dense.

Corpus et chunkingLors de la construction du cours, chaque présentation de chapitre, chaque résumé de section, chaque entrée du glossaire et chaque bloc de texte de section doté d’un titre est transformé en passages d’environ 1500 caractères au plus, chacun étiqueté avec son chapitre, sa section et son titre. Une fois les treize chapitres intégrés, le fichier contient environ 2900 passages ; le chatbot le recharge toutes les quelques heures.
RécupérationClassement par mots-clés BM25 : la question est découpée en mots, les mots courants sont écartés, et les passages sont notés selon les termes correspondants, pondérés par leur rareté et normalisés selon la longueur, les titres comptant davantage. Au plus deux passages sont pris dans une même page, de sorte que les premiers résultats couvrent des sections différentes.
Contrôle de couverture et recherche webSi aucun passage solide ne contient au moins la moitié des termes clés de la question (pondérés par leur rareté), ou si la question semble dépendre de l’actualité (dernier, une année récente), le bot lance aussi une recherche web en direct. Les résultats sont mis en cache pendant quelques jours, les recherches sont plafonnées par visiteur, par jour et par mois, et les adresses e-mail et numéros de téléphone sont retirés avant qu’une question ne soit envoyée au service de recherche.
PromptLes passages du cours et les résultats web sont étiquetés séparément, avec des règles qui demandent au modèle de privilégier le cours, d’utiliser les résultats web pour tout ce qui est plus récent et de dire quand il n’a pas pu vérifier les changements récents.
Points fortsAucun modèle d’embedding, aucun index vectoriel, aucune infrastructure supplémentaire ; bon marché et rapide ; classement transparent ; les termes techniques exacts comme ISO/IEC 25010 ou PACELC correspondent parfaitement.
FaiblessesLes paraphrases échouent : pourquoi tous mes services doivent-ils être mis en production ensemble ? partage peu de mots avec un passage sur le monolithe distribué. Les fautes de frappe et les autres langues s’en sortent mal.
Passer aux embeddingsAjouter une étape d’embedding à la construction ; stocker les vecteurs (3000 passages × 768 dimensions × 4 octets font environ 9 Mo, donc une recherche exhaustive en mémoire suffit) ; calculer l’embedding de chaque question au moment de la requête, ce qui ajoute un appel et un peu de latence ; garder BM25 et fusionner les deux classements ; recalculer tous les embeddings quand le modèle d’embedding change.
D’abord le prouverConstituer un ensemble d’évaluation de quelques centaines de vraies questions d’apprenants, étiquetées avec les passages qui y répondent ; n’adopter la récupération hybride que si le rappel à cinq s’améliore suffisamment pour justifier les pièces supplémentaires.

Un récupérateur par mots-clés complété par un repli sur la recherche web est une première conception saine et bon marché pour un corpus rempli de termes techniques précis.

La décision d’ajouter la récupération dense doit reposer sur le rappel de récupération mesuré sur de vraies questions, pas sur la mode.

Vérifiez votre compréhension

Pourquoi le fine-tuning remplace-t-il mal la récupération quand les politiques changent tous les mois ?

Les faits appris par fine-tuning sont figés dans les poids jusqu’au prochain réentraînement, ne peuvent pas être cités et ignorent les droits d’accès ; la récupération lit les documents actuels à chaque question.

Quel récupérateur a le plus de chances de trouver un passage contenant un numéro de commande exact, et pourquoi ?

La récupération par mots-clés BM25, car elle fait correspondre exactement le token rare, alors que les embeddings ont tendance à brouiller les identifiants précis.

Combien de mémoire faut-il, approximativement, pour un million d’embeddings de 1024 dimensions stockés en flottants 32 bits ?

Environ 4,1 Go (1 000 000 x 1024 x 4 octets), avant le surcoût propre à la structure d’index.

Une réponse est fausse alors que le bon document est dans l’index. Que mesurez-vous en premier ?

Le rappel de récupération pour cette question : le bon passage figurait-il parmi les k premiers transmis au modèle ? Si ce n’est pas le cas, corrigez la récupération avant de toucher au prompt ou au modèle.

Suivant · 12.4Agents et outilsComment les modèles appellent des outils, comment fonctionne la boucle de l’agent, quand un workflow l’emporte sur un agent autonome, ce que normalise le Model Context Protocol, et comment rendre les agents fiables avec des limites, l’idempotence, des points de reprise et une approbation.Continuer →

Sources et lectures complémentaires

Une question sur cette section ? ArchitectBot, l’assistant d’étude IA du cours, répond d’abord à partir du cours.

Demander : « Notre assistant de connaissances d’entreprise doit-il utiliser une base de données vectorielle dédiée, ou PostgreSQL avec pgvector suffit-il ? »