Réduire les hallucinations dans un pipeline de chatbot médical RAG
Découvrez comment la recherche hybride, le réclassement des résultats et une politique stricte d’interdiction de fabrication se combinent pour créer un chatbot RAG de recherche médicale plus fiable.
Le projet a débuté avec un objectif simple.
On voulait créer un chatbot capable de répondre aux questions en s’appuyant sur des articles de recherche médicale.
Cela devrait être assez simple, n’est-ce pas ?
Il s’est avéré que ce n’était pas le cas.
La première version a suivi une configuration RAG plutôt conventionnelle : ingérer les documents, générer des embeddings, les stocker dans une base de données vectorielle, récupérer les extraits pertinents et les transmettre au LLM.
Cela fonctionnait.
Mais pas de manière fiable.
Dans un contexte médical, « pas fiable » constitue un défaut grave.
Un chatbot qui répond avec assurance mais à tort est bien plus dangereux qu’un autre qui admet : « Je n’ai pas suffisamment d’informations pour répondre à cela. »
Cette prise de conscience a poussé le processus de récupération des informations vers une phase de perfectionnement continu.
Le premier problème : les hallucinations
Le problème le plus urgent à résoudre était l’hallucination.
Les modèles de langage sont remarquablement doués pour générer des réponses qui semblent convaincantes, parfois même trop convaincantes.
Lorsque les documents ne contenaient pas la réponse, le modèle comblait souvent ce vide en s’appuyant sur ses propres connaissances internes plutôt que d’admettre son incertitude.
Ce comportement devait changer.
Les réponses du chatbot devaient provenir exclusivement des documents de recherche fournis, et non de l’imagination du modèle.
Ainsi, la philosophie sous-jacente a évolué.
Plutôt que de considérer le LLM comme une autorité en matière de faits, les documents récupérés sont devenus la véritable source de vérité.
Le rôle du LLM a été réduit à interpréter ce contexte récupéré et à le transformer en une réponse cohérente.
Et lorsque le contexte était insuffisant ?
Le système devait refuser de deviner.
Démarrer avec RAG de base
La première version de cette architecture semblait simple :
Cela représente le schéma RAG standard.
Un document volumineux est divisé en plus petits fragments, chacun étant intégré et stocké dans une base de données vectorielle.
Lorsqu’un utilisateur pose une question, celle-ci est également intégrée.
Le système cherche ensuite des fragments dont les embeddings sont sémantiquement proches.
Théoriquement, c’est simple.
Mais un problème est rapidement apparu.
La proximité sémantique ne garantit pas une pertinence réelle.
Pourquoi la recherche vectorielle n’était pas suffisante
Imaginons qu’un utilisateur demande :
« Quels sont les effets de la résistance à l’insuline ? »
La recherche sémantique est efficace pour comprendre l’intention globale derrière cette question.
C’est utile.
Cependant, les textes médicaux sont remplis de terminologie précise.
Des termes tels que :
- résistance à l’insuline
- HbA1c
- hyperglycémie
- metformine
- tolérance au glucose
Ces termes spécifiques ont une grande importance.
Parfois, il suffit de comprendre le sens général.
D’autres fois, il est nécessaire que le système localise précisément le terme recherché.
Pourquoi se contenter d’une seule fonctionnalité ?
La solution consiste à combiner les deux.
Recherche hybride
C’est là que la recherche hybride est devenue un élément essentiel du design.
Au lieu de s’appuyer uniquement sur une recherche vectorielle, la recherche sémantique a été associée à une recherche par mots-clés.
La logique qui sous-tend cela est assez intuitive.
La recherche sémantique demande essentiellement :
« Quel contenu a un sens similaire ? »
La recherche par mots-clés, quant à elle, demande :
« Où apparaissent réellement les termes clés ? »
Chaque méthode possède ses propres forces.
Et chacune a aussi ses points faibles.
Ensemble, elles couvrent un éventail plus large de requêtes.
Le flux résultant ressemblait à ceci :
User Query
↓
┌─────────┴─────────┐
↓ ↓
Vector Search Keyword Search
↓ ↓
└─────────┬─────────┘
↓
Combined Results
↓
Reranker
↓
Best Context
↓
LLM
↓
Answer
Ce changement a modifié la manière d’aborder la récupération des informations à l’avenir.
Un autre problème persistait cependant.
Récupérer quelque chose ne signifie pas que c’est la meilleure solution
Supposons que l’étape de recherche hybride retourne 20 fragments.
Cela semble prometteur.
Mais chacun de ces fragments est-il vraiment utile ?
Pas nécessairement.
Certains fragments peuvent être très pertinents par rapport au sujet.
D’autres pourraient simplement partager un vocabulaire similaire.
D’autres encore pourraient être seulement indirectement liés sans répondre à la question posée.
Fournir tout cela directement au LLM n’est pas une solution idéale.
Un plus grand volume de contexte récupéré ne se traduit pas automatiquement par de meilleures réponses.
En fait, cela peut nuire au résultat final.
Cela ajoute plus de tokens, plus de bruit irrélevant et plus de latence.
C’est pourquoi une étape supplémentaire a été introduite.
Réclassement.
Pourquoi le réclassement a fait la différence
Le rôle du système de récupération peut être résumé comme suit :
Identifier les candidats possibles.
Le rôle du système de réclassement est différent :
Déterminer quels de ces candidats sont véritablement pertinents.
Ainsi, au lieu de la simple chaîne :
Query → Search → LLM
le processus s’est transformé en :
Query
↓
Hybrid Search
↓
20 Candidate Chunks
↓
Reranker
↓
Top Relevant Chunks
↓
LLM
Ce partage des responsabilités est important.
La première étape de récupération peut privilégier le taux de couverture, en lançant un large filet.
L’étape de réclassement peut alors se concentrer spécifiquement sur la pertinence et la précision.
Pour un chatbot de recherche médicale, cette distinction s’est avérée particulièrement précieuse, car un fragment ne contenant que la terminologie appropriée n’est pas toujours celui qui répond réellement à la question de l’utilisateur.
Le élément le plus important : refuser de fabriquer
Outre la récupération et le réclassement des données, des contraintes strictes ont été mises en place lors de l’étape de génération.
L’instruction principale se résumait à ceci :
Use the provided context to answer.
Do not invent information.If the context doesn't contain enough information,
say that there isn't enough information available.
Cela semble presque trop simple pour avoir de l’importance.
Pourtant, cela modifie considérablement le comportement du chatbot.
Au lieu de forcer le modèle à produire une réponse quoi qu’il arrive, cette approche lui offre une issue lorsque les informations nécessaires ne sont tout simplement pas disponibles.
Cette issue de secours s’avère essentielle.
Parfois, la réponse honnête est quelque chose comme :
« Je n’ai pas trouvé suffisamment d’informations dans les documents de recherche fournis. »
Toute question ne mérite pas une réponse assurée.
Les hallucinations sont-elles donc entièrement éliminées ?
Pas vraiment.
Cela est devenu évident au cours du développement du système.
RAG réduit véritablement les hallucinations et maintient les réponses plus étroitement ancrées dans des sources réelles.
Mais prétendre à zéro hallucination serait exagéré.
De nombreux points de défaillance subsistent.
Le récupérateur pourrait sélectionner le mauvais fragment.
La segmentation elle-même pourrait enlever des éléments contextuels importants.
Le réordonneur pourrait classer les éléments de manière inadéquate.
Les documents de base pourraient manquer d’informations dès le départ.
Même lorsque tout fonctionne correctement, le LLM peut encore interpréter à tort ce qu’il a récupéré.
Ainsi, l’objectif réel n’est pas :
« Créer un chatbot qui ne se trompe jamais. »
C’est plutôt :
« Construisez un système présentant moins de risques d’erreur, et un système capable de reconnaître les limites de ce qu’il sait réellement. »
C’est un objectif bien plus réalisable.
Le design en blocs s’avère essentiel
Une constatation marquante : diviser les documents en blocs n’est pas une simple étape de prétraitement à configurer une seule fois.
Les blocs trop grands incluent du contenu non pertinent.
Les blocs trop petits peuvent priver l’énoncé des contextes auxquels il fait référence.
Il est utile de considérer chaque bloc comme une unité de connaissance autonome plutôt que simplement un morceau arbitraire de texte.
Des blocs bien conçus permettent une récupération d’informations plus efficace.
Et une récupération plus efficace conduit généralement à de meilleures réponses finales.
Accélérer le processus
La correction n’était qu’une partie du défi ; le temps de réponse en était une autre.
Une seule demande RAG peut déclencher plusieurs opérations distinctes :
User Query
↓
Embedding
↓
Vector Search
↓
Keyword Search
↓
Merge Results
↓
Reranking
↓
LLM
Exécuter toutes ces opérations strictement l’une après l’autre ralentit tout.
Afin de remédier à cela, les étapes de récupération indépendantes ont été modifiées pour être exécutées de manière asynchrone chaque fois que c’était possible.
Le flux révisé ressemblait approximativement à ceci :
User Query
↓
┌──────┴──────┐
↓ ↓
Vector Search Keyword Search
↓ ↓
└──────┬──────┘
↓
Rerank
↓
LLM
Cela a réduit le temps d’attente inutile entre des étapes qui ne dépendaient pas réellement les unes des autres.
L’exactitude seule ne constitue pas l’ensemble des critères pour un bon système RAG.
Les utilisateurs ne veulent pas rester assis à attendre une réponse.
L’architecture résultante
Après plusieurs rounds de perfectionnement, le flux a fini par ressembler à ceci :
Medical Research Documents
↓
Document Processing
↓
Chunking
↓
Embeddings
↓
Vector Database
↓
User Query
↓
┌──────────┴──────────┐
↓ ↓
Semantic Search Keyword Search
↓ ↓
└──────────┬──────────┘
↓
Result Fusion
↓
Reranker
↓
Relevant Context
↓
Grounded Prompt
↓
LLM
↓
Final Response
Chaque composant de ce diagramme a une responsabilité bien définie.
Cette séparation est devenue l’une des leçons les plus précieuses tirées du projet.
La base de données vectorielle n’a pas pour but de répondre aux questions.
Le moteur de recherche n’a pas pour but de générer des réponses.
Le LLM n’est pas conçu pour tout savoir par défaut.
Chaque composant s’occupe d’une tâche précise.
Et idéalement, il la remplit bien.
Leçons tirées du développement
La principale leçon de toute cette expérience est que RAG va bien au-delà du simple mélange d’un LLM et d’une base de données vectorielle. Il existe plusieurs éléments en jeu, et chacun mérite une attention particulière.
La qualité de la recherche est indispensable
Même le modèle linguistique le plus performant ne peut compenser un contexte insuffisant. Si vous lui fournissez des résultats de recherche de mauvaise qualité, vous obtiendrez des réponses de même qualité. C’est un cas classique du principe « ce que l’on met dedans, on le retrouve dehors ».
La recherche hybride justifie son utilisation
La recherche sémantique excelle à comprendre le sens et l’intention. La recherche par mots-clés est plus efficace lorsque des termes précis sont essentiels. Comme la recherche médicale est riche en termes exacts et en formulations spécifiques, combiner ces deux approches s’est avéré être la meilleure solution.
Le réclassement mérite plus d’attention
Filtrer vingt résultats potentiels constitue déjà un défi. En réduire le nombre à cinq meilleurs en est un autre complètement distinct. Le réclassement se situe entre ces deux étapes et comble cette lacune.
Des fenêtres de contexte plus larges ne garantissent pas de meilleures réponses
On pensait au début que l’inclusion de plus de contenus retrouvés améliorerait naturellement les résultats. Cette hypothèse s’est avérée fausse. En pratique, cinq extraits fortement pertinents surpassent souvent vingt extraits médiocres.
Admettre l’incertitude est un atout, pas une faiblesse
Ce pourrait être la leçon la plus importante de toutes. Un système fiable ne devrait pas se sentir obligé de fournir une réponse en tout cas. Lorsque les informations pertinentes ne sont simplement pas disponibles, le système doit être prêt à l’indiquer.
Où cela nous mène
Il reste beaucoup de place pour des améliorations. Les domaines à explorer ensuite incluent :
- Méthodes d’évaluation plus robustes du récupération des données
- Réécriture des requêtes
- Filtrage des métadonnées
- Modèles de réclassement améliorés
- Réponses incluant des citations
- Évaluation de la confiance et logique d’abstention
- Mieux comprendre le processus de récupération des données
- Ensembles de données d’évaluation automatisés
- Améliorations supplémentaires en matière de mise en cache et de latence
Il est particulièrement important de mettre en place un pipeline d’évaluation adéquat, car examiner manuellement quelques-unes des réponses générées par un chatbot n’est pas une méthode fiable pour évaluer la qualité. Les questions qui méritent d’être mesurées incluent le fait de savoir si les informations correctes ont bien été récupérées en premier lieu, si la réponse générée repose réellement sur ces données récupérées, et avec quelle fréquence le système échoue à fournir le contexte approprié. Ces indicateurs sont bien plus importants qu’une impression subjective selon laquelle une réponse « sonne juste ».
Conclusion
Ce qui a commencé comme un chatbot RAG simple s’est transformé en une leçon beaucoup plus approfondie sur le fonctionnement réel des systèmes de récupération d’informations. Les discussions autour des applications d’intelligence artificielle ont tendance à se concentrer sur le modèle de langage, mais dans une configuration RAG, c’est le pipeline de récupération qui effectue la majeure partie du travail en coulisses.
Une configuration minimale pourrait consister en des documents qui arrivent dans une base de données vectorielle avant d’être transmis à un LLM. Une version plus fiable implique plutôt que les documents soient d’abord divisés en blocs, puis soumis à une recherche hybride, suivie d’un réclassement, pour finalement arriver sous forme de contexte contextualisé avant d’être traités par l’LLM. Même ce flux de travail laisse encore de la marge pour évoluer.
C’est finalement ce qui rend la création de systèmes RAG si intéressante : il ne s’agit pas seulement de faire produire du texte à un modèle linguistique. Il s’agit plutôt de s’assurer que ce texte soit ancré dans les informations appropriées avant même que le modèle ne parle.
Remarque : ce projet est destiné uniquement à des fins de recherche et d’expérimentation techniques. Il ne remplace en aucun cas un conseil médical professionnel, un diagnostic ou un traitement.
Lectures complémentaires
- Un plan hiérarchisé des concepts d’ingénierie IA et du moment où ils sont importants — Découvrez quels concepts d’ingénierie IA déterminent si un système fonctionne ou non, lesquels sont essentiels une fois que vous développez pour la production, et lesquels peuvent attendre.
- Second Brain : Transformer les transcriptions de réunion en un graphe de connaissances interrogeable — Explique comment un système agent extrait des entités à partir des transcriptions de réunion et les stocke dans Cosmos DB afin de permettre la récupération par langage naturel et l’exploration du graphe de connaissances.