{"id":161,"date":"2026-09-30T15:57:58","date_gmt":"2026-09-30T13:57:58","guid":{"rendered":"https:\/\/www.ranksignal.fr\/blog\/?p=161"},"modified":"2026-10-07T21:00:06","modified_gmt":"2026-10-07T19:00:06","slug":"comment-utiliser-ragas","status":"publish","type":"post","link":"https:\/\/www.ranksignal.fr\/blog\/rag\/comment-utiliser-ragas\/","title":{"rendered":"RAGAS : mesurer enfin la qualit\u00e9 de ton RAG, pas \u00e0 pas"},"content":{"rendered":"<p>Ton assistant r\u00e9pond correctement \u00e0 \u00ab Qui a gagn\u00e9 la Coupe du monde de cricket 2023 ? \u00bb en s&rsquo;appuyant sur une page Wikip\u00e9dia. Bravo. Mais sur la milli\u00e8me question, sans personne pour relire, comment sais-tu qu&rsquo;il ne ment pas ? Un <a href=\"\/blog\/rag\/a-quoi-ressemble-un-systeme-rag\/\" title=\"syst\u00e8me RAG\">syst\u00e8me RAG<\/a> se juge sur des chiffres, pas sur une impression de d\u00e9monstration. RAGAS est la bo\u00eete \u00e0 outils qui te les donne, et \u00e0 la fin de cet article tu sauras g\u00e9n\u00e9rer un jeu de test, lancer l&rsquo;\u00e9valuation et lire les scores sans te tromper.<\/p>\n<h2>L&rsquo;essentiel en 30 secondes<\/h2>\n<ul>\n<li>RAGAS est un cadre d&rsquo;\u00e9valuation con\u00e7u pour les syst\u00e8mes RAG : il calcule des m\u00e9triques de qualit\u00e9 \u00e0 partir de la question, du contexte r\u00e9cup\u00e9r\u00e9, de la r\u00e9ponse g\u00e9n\u00e9r\u00e9e et d&rsquo;une r\u00e9ponse de r\u00e9f\u00e9rence.<\/li>\n<li>Il peut fabriquer lui-m\u00eame un jeu de test \u00e0 partir de tes documents, sans annotation humaine massive.<\/li>\n<li>Chaque m\u00e9trique repose sur un <a href=\"\/blog\/inference\/qu-est-ce-qu-un-llm\/\" title=\"LLM\">LLM<\/a> qui joue le juge : d\u00e9composer la r\u00e9ponse en affirmations, v\u00e9rifier chacune, compter la proportion de bonnes.<\/li>\n<li>Trois scores se lisent ensemble : le contexte r\u00e9cup\u00e9r\u00e9 est-il utile, la r\u00e9ponse est-elle fid\u00e8le \u00e0 ce contexte, r\u00e9pond-elle \u00e0 la question ?<\/li>\n<li>Le juge n&rsquo;est pas infaillible : choisis-le diff\u00e9rent du mod\u00e8le qui g\u00e9n\u00e8re et compl\u00e8te les chiffres par un regard humain.<\/li>\n<\/ul>\n<h2>L&rsquo;intuition : trois relations \u00e0 surveiller<\/h2>\n<p>Quand un RAG se trompe, le coupable n&rsquo;est pas toujours le m\u00eame. Soit la r\u00e9cup\u00e9ration a rat\u00e9 l&rsquo;information utile ou ramen\u00e9 du hors-sujet ; soit le LLM a ignor\u00e9 le contexte qu&rsquo;on lui donnait ; soit il s&rsquo;est laiss\u00e9 distraire par un passage sans rapport avec la question.<\/p>\n<p>Ces trois pannes correspondent \u00e0 trois relations dans le syst\u00e8me. Entre la question et le contexte r\u00e9cup\u00e9r\u00e9, on regarde la <strong>pertinence du contexte<\/strong> : l&rsquo;information ramen\u00e9e est-elle bien celle qu&rsquo;il fallait ? Entre le contexte et la r\u00e9ponse, on regarde la <strong>fid\u00e9lit\u00e9<\/strong> (<em>faithfulness<\/em>, aussi appel\u00e9e <em>groundedness<\/em>) : la r\u00e9ponse s&rsquo;appuie-t-elle vraiment sur ce qui a \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9 ? Entre la r\u00e9ponse et la question, on regarde la <strong>pertinence de la r\u00e9ponse<\/strong> : r\u00e9pond-elle \u00e0 ce qui \u00e9tait demand\u00e9 ?<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef46c30d58&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef46c30d58\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1849\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_triade_evaluation-scaled.png\" alt=\"Triangle d'\u00e9valuation d'un RAG : la question est reli\u00e9e au contexte r\u00e9cup\u00e9r\u00e9 par la pertinence du contexte, \u00e0 la r\u00e9ponse g\u00e9n\u00e9r\u00e9e par la pertinence de la r\u00e9ponse, et le contexte est reli\u00e9 \u00e0 la r\u00e9ponse par la fid\u00e9lit\u00e9\" class=\"wp-image-158\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_triade_evaluation-scaled.png 2560w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_triade_evaluation-300x217.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_triade_evaluation-1024x739.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_triade_evaluation-768x555.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_triade_evaluation-1536x1109.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_triade_evaluation-2048x1479.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\">Regarde les trois c\u00f4t\u00e9s du triangle : chacun porte un score, et c&rsquo;est en les lisant ensemble que tu localises la panne.<\/figcaption><\/figure>\n\n\n<blockquote>\n<p><strong>\ud83d\udca1 Intuition<\/strong> Ces scores ne se remplacent pas. Une forte pertinence du contexte am\u00e9liore en g\u00e9n\u00e9ral la fid\u00e9lit\u00e9, mais une forte fid\u00e9lit\u00e9 ne garantit pas que la r\u00e9ponse traite la question : un syst\u00e8me peut recopier fid\u00e8lement son contexte sans jamais r\u00e9pondre directement.<\/p>\n<\/blockquote>\n<h2>Sous le capot : comment RAGAS calcule ses scores<\/h2>\n<p>RAGAS ne compare jamais deux textes avec une r\u00e8gle m\u00e9canique. Il confie le jugement \u00e0 un LLM, guid\u00e9 par des consignes pr\u00e9cises. Le principe est toujours le m\u00eame : d\u00e9couper, v\u00e9rifier, compter. Voici les m\u00e9triques que tu croiseras.<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef46c31171&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef46c31171\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1240\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b2_ch08_metriques_ragas-scaled.png\" alt=\"Sch\u00e9ma des trois m\u00e9triques RAGAS : \u00e0 partir du contexte r\u00e9cup\u00e9r\u00e9 et de la r\u00e9ponse g\u00e9n\u00e9r\u00e9e, le rappel de contexte demande si l'information n\u00e9cessaire a \u00e9t\u00e9 retrouv\u00e9e, la fid\u00e9lit\u00e9 si la r\u00e9ponse est align\u00e9e sur le contexte, l'exactitude si la r\u00e9ponse est conforme au vrai r\u00e9sultat\" class=\"wp-image-159\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b2_ch08_metriques_ragas-scaled.png 2560w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b2_ch08_metriques_ragas-300x145.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b2_ch08_metriques_ragas-1024x496.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b2_ch08_metriques_ragas-768x372.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b2_ch08_metriques_ragas-1536x744.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b2_ch08_metriques_ragas-2048x992.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\">Le sch\u00e9ma part d&rsquo;un m\u00eame bloc, le contexte r\u00e9cup\u00e9r\u00e9 et la r\u00e9ponse g\u00e9n\u00e9r\u00e9e, d&rsquo;o\u00f9 partent trois fl\u00e8ches : une par question pos\u00e9e. La fid\u00e9lit\u00e9 y est mise en \u00e9vidence en orange.<\/figcaption><\/figure>\n\n\n<h3>Fid\u00e9lit\u00e9 : la r\u00e9ponse invente-t-elle quelque chose ?<\/h3>\n<p>RAGAS commence par d\u00e9composer la r\u00e9ponse en affirmations atomiques, sans pronoms, pour qu&rsquo;on puisse les v\u00e9rifier une \u00e0 une. Le LLM juge ensuite, pour chacune, si elle peut \u00eatre directement d\u00e9duite du contexte, avec un verdict binaire. La fid\u00e9lit\u00e9 est la proportion d&rsquo;affirmations jug\u00e9es fid\u00e8les, et son inverse est le taux d&rsquo;hallucination.<\/p>\n<h3>Rappel de contexte : a-t-on tout retrouv\u00e9 ?<\/h3>\n<p>Cette m\u00e9trique mesure combien d&rsquo;informations pertinentes ont r\u00e9ellement \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9es. Un score \u00e9lev\u00e9 indique que la r\u00e9cup\u00e9ration capte bien tout le contexte n\u00e9cessaire pour r\u00e9pondre. Le prompt d&rsquo;\u00e9valuation examine chaque phrase et la classe 0 ou 1 selon qu&rsquo;elle peut \u00eatre rattach\u00e9e au contexte fourni.<\/p>\n<h3>Exactitude de la r\u00e9ponse : est-elle juste et compl\u00e8te ?<\/h3>\n<p>Elle \u00e9value \u00e0 quel point la r\u00e9ponse traite pr\u00e9cis\u00e9ment et compl\u00e8tement la question, en combinant exactitude factuelle et pertinence. Elle reprend la d\u00e9composition en affirmations, puis range chacune dans l&rsquo;une de trois cases : vrai positif (pr\u00e9sente dans la r\u00e9ponse et soutenue par la r\u00e9f\u00e9rence), faux positif (pr\u00e9sente mais non soutenue), faux n\u00e9gatif (pr\u00e9sente dans la r\u00e9f\u00e9rence mais absente de la r\u00e9ponse), avec une justification \u00e0 chaque fois.<\/p>\n<h3>Pertinence de la r\u00e9ponse et pertinence du contexte<\/h3>\n<p>Pour la pertinence de la r\u00e9ponse, RAGAS demande au LLM d&rsquo;inventer plusieurs questions \u00e0 partir de la r\u00e9ponse produite, puis mesure la similarit\u00e9 cosinus moyenne entre ces questions et la question d&rsquo;origine. L&rsquo;id\u00e9e : si la r\u00e9ponse traite bien le sujet, les questions qu&rsquo;on en reconstruit doivent lui ressembler. La pertinence du contexte, elle, est la proportion de phrases du contexte r\u00e9cup\u00e9r\u00e9 r\u00e9ellement utiles pour r\u00e9pondre.<\/p>\n<blockquote>\n<p><strong>\ud83d\udccc Bon \u00e0 savoir<\/strong> Une m\u00e9trique voisine, la couverture, mesure la proportion des affirmations pertinentes du contexte effectivement reprises dans la r\u00e9ponse.<\/p>\n<\/blockquote>\n<h2>Le voir tourner : \u00e9valuer un pipeline de bout en bout<\/h2>\n<p>Reste \u00e0 brancher tout cela sur un vrai pipeline. Notre fil conducteur reste la Coupe du monde de cricket : un pipeline RAG construit sur une page Wikip\u00e9dia, que l&rsquo;on \u00e9value en trois temps. D&rsquo;abord on fabrique les questions de test, ensuite on fait r\u00e9pondre le pipeline, enfin on note les r\u00e9ponses.<\/p>\n<h3>\u00c9tape 1 : g\u00e9n\u00e9rer le jeu de test<\/h3>\n<p>\u00c9crire \u00e0 la main des centaines de couples question-r\u00e9ponse est fastidieux. RAGAS propose donc un g\u00e9n\u00e9rateur : un premier module cr\u00e9e des questions \u00ab germes \u00bb \u00e0 partir de tes documents, puis un module d&rsquo;\u00e9volution les complexifie en versions multi-contextes, conditionnelles ou de raisonnement, avant que les r\u00e9ponses ne soient g\u00e9n\u00e9r\u00e9es.<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef46c31511&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef46c31511\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"485\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on--pointerdown=\"actions.preloadImage\" data-wp-on--pointerenter=\"actions.preloadImageWithDelay\" data-wp-on--pointerleave=\"actions.cancelPreload\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch05_ragas_synthetic-scaled.png\" alt=\"Pipeline en cinq \u00e9tapes de g\u00e9n\u00e9ration d'un jeu de test synth\u00e9tique : documents, g\u00e9n\u00e9rateur de questions germes, \u00e9volueur, g\u00e9n\u00e9ration de r\u00e9ponses, jeu de test\" class=\"wp-image-160\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch05_ragas_synthetic-scaled.png 2560w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch05_ragas_synthetic-300x57.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch05_ragas_synthetic-1024x194.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch05_ragas_synthetic-768x146.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch05_ragas_synthetic-1536x291.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch05_ragas_synthetic-2048x388.png 2048w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\tdata-wp-bind--aria-label=\"state.thisImage.triggerButtonAriaLabel\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.thisImage.buttonRight\"\n\t\t\tdata-wp-style--top=\"state.thisImage.buttonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\">Suis les fl\u00e8ches de gauche \u00e0 droite : tes documents entrent d&rsquo;un c\u00f4t\u00e9, un jeu de test complet sort de l&rsquo;autre, sans annotation humaine lourde.<\/figcaption><\/figure>\n\n\n<p>Dans le code ci-dessous, la premi\u00e8re ligne installe la biblioth\u00e8que depuis le notebook ; <code>html_data_transformed<\/code> d\u00e9signe les documents LangChain tir\u00e9s de la page Wikip\u00e9dia, pr\u00e9par\u00e9s dans les \u00e9tapes pr\u00e9c\u00e9dentes du pipeline. Le LLM qui \u00e9crit les questions est <code>gpt-4o-mini<\/code>, accompagn\u00e9 d&rsquo;un mod\u00e8le d&#8217;embeddings d&rsquo;OpenAI.<\/p>\n<pre><code>%pip install ragas==0.2.13\n\nfrom ragas.llms import LangchainLLMWrapper\nfrom ragas.embeddings import LangchainEmbeddingsWrapper\nfrom ragas.testset import TestsetGenerator\nfrom langchain_openai import ChatOpenAI, OpenAIEmbeddings\n\ngenerator_llm = LangchainLLMWrapper(ChatOpenAI(model=&quot;gpt-4o-mini&quot;))\ngenerator_embeddings = LangchainEmbeddingsWrapper(\n    OpenAIEmbeddings(model=&quot;text-embedding-3-small&quot;)\n)\ngenerator = TestsetGenerator(\n    llm=generator_llm,\n    embedding_model=generator_embeddings\n)\ntestset = generator.generate_with_langchain_docs(\n    html_data_transformed,\n    test_size=20,\n)\n<\/code><\/pre>\n<p>R\u00e9sultat : 20 questions, chacune li\u00e9e au fragment de document dont elle vient et \u00e0 une r\u00e9ponse de r\u00e9f\u00e9rence, la <em>ground truth<\/em>. Retiens les enveloppes <code>LangchainLLMWrapper<\/code> et <code>LangchainEmbeddingsWrapper<\/code> : elles adaptent des mod\u00e8les LangChain pour que RAGAS puisse les appeler.<\/p>\n<h3>\u00c9tape 2 : faire r\u00e9pondre ton pipeline<\/h3>\n<p>Il faut maintenant ex\u00e9cuter ton RAG sur chaque question. Le plus simple est de l&rsquo;encapsuler dans une fonction r\u00e9utilisable qui renvoie \u00e0 la fois le contexte r\u00e9cup\u00e9r\u00e9 et la r\u00e9ponse, car RAGAS a besoin des deux. Ici, elle charge un index FAISS, r\u00e9cup\u00e8re les deux passages les plus proches, construit un prompt qui impose de r\u00e9pondre seulement d&rsquo;apr\u00e8s le contexte (ou de dire \u00ab I don&rsquo;t know \u00bb) puis interroge le LLM.<\/p>\n<pre><code>from langchain_community.vectorstores import FAISS\nfrom langchain_openai import OpenAIEmbeddings, ChatOpenAI\n\ndef rag_function(query, db_path, index_name):\n    embeddings = OpenAIEmbeddings(model=&quot;text-embedding-3-small&quot;)\n    db = FAISS.load_local(\n        folder_path=db_path,\n        index_name=index_name,\n        embeddings=embeddings,\n        allow_dangerous_deserialization=True\n    )\n    retrieved_docs = db.similarity_search(query, k=2)\n    retrieved_context = [retrieved_docs[0].page_content\n                          + retrieved_docs[1].page_content]\n    augmented_prompt = f&quot;&quot;&quot;\nGiven the context below, answer the question.\nQuestion: {query}\nContext : {retrieved_context}\nRemember to answer only based on the context\nprovided and not from any other source.\nIf the question cannot be answered based\non the provided context, say I don't know.\n&quot;&quot;&quot;\n    llm = ChatOpenAI(\n        model=&quot;gpt-4o-mini&quot;,\n        temperature=0,\n        max_tokens=None,\n        timeout=None,\n        max_retries=2\n    )\n    response = llm.invoke([(&quot;human&quot;, augmented_prompt)])\n    answer = response.content\n    return retrieved_context, answer\n<\/code><\/pre>\n<p>Note le <code>k=2<\/code> : seuls les deux passages les plus proches alimentent le prompt, ce qui a un effet direct sur le rappel de contexte que tu mesureras plus tard.<\/p>\n<h3>\u00c9tape 3 : assembler et noter<\/h3>\n<p>Tu regroupes, pour chaque question, la r\u00e9ponse g\u00e9n\u00e9r\u00e9e, le contexte r\u00e9cup\u00e9r\u00e9 et la r\u00e9ponse de r\u00e9f\u00e9rence dans un <code>EvaluationDataset<\/code>. Dans le code, cette collection s&rsquo;appelle <code>dataset_to_eval<\/code>, une liste construite \u00e0 partir des r\u00e9sultats de l&rsquo;\u00e9tape pr\u00e9c\u00e9dente. Un second LLM, l&rsquo;\u00e9valuateur, note ensuite chaque exemple sur les cinq m\u00e9triques choisies.<\/p>\n<pre><code>from ragas import EvaluationDataset, evaluate\nfrom ragas.metrics import (\n    LLMContextRecall,\n    Faithfulness,\n    FactualCorrectness,\n    AnswerCorrectness,\n    ResponseRelevancy)\n\nevaluation_dataset = EvaluationDataset.from_list(dataset_to_eval)\nevaluator_llm = LangchainLLMWrapper(ChatOpenAI(model=&quot;gpt-4o-mini&quot;))\n\nresult = evaluate(\n    dataset=evaluation_dataset,\n    metrics=[LLMContextRecall(), Faithfulness(), AnswerCorrectness(),\n             ResponseRelevancy(), FactualCorrectness()],\n    llm=evaluator_llm)\n<\/code><\/pre>\n<p>Tu reconnais les noms : <code>LLMContextRecall<\/code> pour le rappel de contexte, <code>Faithfulness<\/code> pour la fid\u00e9lit\u00e9, <code>AnswerCorrectness<\/code> et <code>FactualCorrectness<\/code> pour l&rsquo;exactitude, <code>ResponseRelevancy<\/code> pour la pertinence de la r\u00e9ponse. Le r\u00e9sultat donne un score par m\u00e9trique et par exemple.<\/p>\n<h3>Une variante sur un graphe de connaissances<\/h3>\n<p>Le m\u00eame principe fonctionne sur un agent qui interroge une base de graphe. L\u00e0, la v\u00e9rit\u00e9 terrain n&rsquo;est pas une phrase fig\u00e9e : c&rsquo;est une requ\u00eate Cypher de r\u00e9f\u00e9rence, ex\u00e9cut\u00e9e au moment du test, ce qui garde le benchmark valable m\u00eame quand les donn\u00e9es \u00e9voluent. Le jeu de test est lu depuis un CSV.<\/p>\n<pre><code>test_data = pd.read_csv(&quot;..\/data\/benchmark_data.csv&quot;, delimiter=&quot;;&quot;)\n<\/code><\/pre>\n<p>Ici, <code>test_data<\/code> est ce tableau pandas ; une boucle parcourt ensuite chaque ligne : elle ex\u00e9cute la requ\u00eate de r\u00e9f\u00e9rence, g\u00e9n\u00e8re la r\u00e9ponse de l&rsquo;agent, mesure la latence et enregistre le contexte r\u00e9cup\u00e9r\u00e9. Dans ce cadre, les r\u00e9ponses manquantes sont remplac\u00e9es par \u00ab I don&rsquo;t know \u00bb, car RAGAS exige des valeurs non nulles, avant de lancer l&rsquo;\u00e9valuation sur trois m\u00e9triques. Cette fois, elles se passent directement sous forme de fonctions (<code>answer_correctness<\/code>, <code>context_recall<\/code>, <code>faithfulness<\/code>) et le tableau est converti en <code>Dataset<\/code>, le format Hugging Face.<\/p>\n<pre><code>dataset = Dataset.from_pandas(test_data.fillna(&quot;I don't know&quot;))\n\nresult = evaluate(\n    dataset,\n    metrics=[\n        answer_correctness,\n        context_recall,\n        faithfulness,\n    ],\n)\n<\/code><\/pre>\n<h2>Lire les r\u00e9sultats<\/h2>\n<p>Sur ce benchmark de 17 exemples, le r\u00e9sum\u00e9 donne une exactitude de r\u00e9ponse de 0,7774, un rappel de contexte de 0,7941 et une fid\u00e9lit\u00e9 de 0,9657.<\/p>\n<p>Que dire de ces trois chiffres ? Avec une exactitude proche de 0,78, le mod\u00e8le r\u00e9pond juste la plupart du temps mais se trompe encore dans pr\u00e8s d&rsquo;un quart des cas. Le rappel de 0,79 montre que la r\u00e9cup\u00e9ration fonctionne plut\u00f4t bien sans toujours ramener toute l&rsquo;information utile. La fid\u00e9lit\u00e9, elle, est excellente : le mod\u00e8le invente rarement et reste coll\u00e9 \u00e0 son contexte.<\/p>\n<p>Le diagnostic est donc clair : le g\u00e9n\u00e9rateur est sage, c&rsquo;est la r\u00e9cup\u00e9ration qu&rsquo;il faut am\u00e9liorer. Pistes cit\u00e9es : enrichir la couverture de r\u00e9cup\u00e9ration, affiner la reformulation des requ\u00eates, mieux faire correspondre les entit\u00e9s pour les questions ambigu\u00ebs.<\/p>\n<blockquote>\n<p><strong>\ud83d\udca1 Intuition<\/strong> Quand la fid\u00e9lit\u00e9 est haute et que l&rsquo;exactitude est plus basse, le LLM fait correctement son travail avec ce qu&rsquo;on lui donne. Le probl\u00e8me se situe en amont, dans ce qu&rsquo;on lui donne.<\/p>\n<\/blockquote>\n<p>Descendre au niveau des exemples est tout aussi instructif. La latence est nettement plus basse quand la question \u00e9vite text2cypher, puisqu&rsquo;on \u00e9conomise un appel LLM. Et sur la question \u00ab Who has the longest name among all actors ? \u00bb, le syst\u00e8me \u00e9choue faute de g\u00e9n\u00e9rer la bonne requ\u00eate Cypher : on pourrait y rem\u00e9dier avec un exemple few-shot ou un outil d\u00e9di\u00e9.<\/p>\n<h2>Pi\u00e8ges et limites<\/h2>\n<blockquote>\n<p><strong>\u26a0\ufe0f Pi\u00e8ge<\/strong> Le juge est un LLM, donc sa fiabilit\u00e9 d\u00e9pend de sa qualit\u00e9. Dans l&rsquo;exemple plus haut, l&rsquo;\u00e9valuateur est le m\u00eame mod\u00e8le que celui qui g\u00e9n\u00e8re les r\u00e9ponses : c&rsquo;est pr\u00e9cis\u00e9ment le cas d&rsquo;auto-r\u00e9f\u00e9rence qu&rsquo;on cherche \u00e0 \u00e9viter.<\/p>\n<\/blockquote>\n<p>Plusieurs limites m\u00e9ritent d&rsquo;\u00eatre gard\u00e9es en t\u00eate :<\/p>\n<ul>\n<li><strong>Un LLM juge peut se tromper.<\/strong> Sur l&rsquo;exemple \u00ab Hello \u00bb, certains scores ont paru incoh\u00e9rents. Il est conseill\u00e9 d&rsquo;\u00e9chantillonner r\u00e9guli\u00e8rement les jugements et d&#8217;employer plusieurs LLM juges, diff\u00e9rents du LLM de g\u00e9n\u00e9ration.<\/li>\n<li><strong>Pas de standard.<\/strong> Chaque framework calcule les m\u00e9triques \u00e0 sa fa\u00e7on ; comparer plusieurs frameworks aide \u00e0 relativiser un score.<\/li>\n<li><strong>Le g\u00e9n\u00e9rique ne suffit pas.<\/strong> Compl\u00e8te par des crit\u00e8res propres \u00e0 ton m\u00e9tier et par un retour humain : avis d&rsquo;utilisateurs, \u00e9valuation d&rsquo;experts.<\/li>\n<li><strong>Un benchmark vieillit.<\/strong> Pr\u00e9f\u00e8re un jeu adapt\u00e9 \u00e0 ton domaine, qui continue \u00e0 s&rsquo;enrichir, plut\u00f4t qu&rsquo;une confiance aveugle dans un score g\u00e9n\u00e9rique.<\/li>\n<li><strong>Mesure aussi le reste.<\/strong> Latence, co\u00fbt, biais et toxicit\u00e9 des r\u00e9ponses ne sont pas captur\u00e9s par ces scores.<\/li>\n<\/ul>\n<h2>Aller plus loin<\/h2>\n<ul>\n<li><strong>ARES<\/strong> entra\u00eene un classifieur au lieu d&rsquo;utiliser des prompts heuristiques, et fournit des intervalles de confiance. Il exige un jeu de validation d&rsquo;environ 150 annotations humaines et au moins cinq exemples few-shot : plus robuste, plus lourd. RAGAS privil\u00e9gie la rapidit\u00e9, ARES la robustesse statistique.<\/li>\n<li><strong>TruLens, DeepEval, RAGChecker<\/strong> sont d&rsquo;autres frameworks utilis\u00e9s par la communaut\u00e9 ; le cadre de la triade, lui, a \u00e9t\u00e9 propos\u00e9 par TruEra.<\/li>\n<li><strong>Les m\u00e9triques de r\u00e9cup\u00e9ration classiques<\/strong> (pr\u00e9cision, rappel, F1, MRR, MAP, nDCG) jugent le classement du <a href=\"\/blog\/rag\/qu-est-ce-qu-un-retriever\/\" title=\"retriever\">retriever<\/a> seul ; un MRR ou un nDCG faible signale souvent un probl\u00e8me d&rsquo;algorithme de classement.<\/li>\n<li><strong>Les benchmarks publics<\/strong> (RGB, Multi-hop RAG, CRAG) permettent de comparer des syst\u00e8mes sur des t\u00e2ches standardis\u00e9es.<\/li>\n<\/ul>\n<h2>\u00c0 retenir<\/h2>\n<ul>\n<li><a href=\"\/blog\/rag\/comment-evaluer-la-qualite-d-un-rag\/\" title=\"\u00c9valuer un RAG\">\u00c9valuer un RAG<\/a>, c&rsquo;est surveiller trois relations : question-contexte, contexte-r\u00e9ponse, r\u00e9ponse-question.<\/li>\n<li>Le cycle tient en trois gestes : g\u00e9n\u00e9rer ou construire des questions avec r\u00e9ponse de r\u00e9f\u00e9rence, faire tourner ton pipeline, faire noter le r\u00e9sultat.<\/li>\n<li>Lis les scores ensemble : une fid\u00e9lit\u00e9 haute avec un rappel moyen pointe la r\u00e9cup\u00e9ration, pas le g\u00e9n\u00e9rateur.<\/li>\n<li>Un juge LLM est un instrument, pas un oracle : change de mod\u00e8le, \u00e9chantillonne ses verdicts, ajoute l&rsquo;avis humain.<\/li>\n<\/ul>\n<h2>Questions fr\u00e9quentes<\/h2>\n<p><strong>RAGAS peut-il cr\u00e9er mes questions de test ?<\/strong> Oui : il g\u00e9n\u00e8re un jeu de test synth\u00e9tique \u00e0 partir de ta base de connaissances, via un g\u00e9n\u00e9rateur de questions puis un module d&rsquo;\u00e9volution qui les complexifie.<\/p>\n<p><strong>Faut-il une r\u00e9ponse de r\u00e9f\u00e9rence ?<\/strong> Pour l&rsquo;exactitude de la r\u00e9ponse, oui : elle se mesure par rapport \u00e0 la r\u00e9f\u00e9rence. La fid\u00e9lit\u00e9, elle, n&rsquo;en a pas besoin : elle compare la r\u00e9ponse au contexte r\u00e9cup\u00e9r\u00e9.<\/p>\n<p><strong>Quel LLM choisir comme juge ?<\/strong> Un mod\u00e8le diff\u00e9rent de celui qui g\u00e9n\u00e8re tes r\u00e9ponses, pour \u00e9viter un biais d&rsquo;auto-r\u00e9f\u00e9rence.<\/p>","protected":false},"excerpt":{"rendered":"<p>G\u00e9n\u00e8re un jeu de test, lance les m\u00e9triques de fid\u00e9lit\u00e9, rappel et exactitude, puis lis tes scores : le guide pratique pour \u00e9valuer un RAG avec RAGAS.<\/p>\n","protected":false},"author":1,"featured_media":279,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-161","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-rag"],"_links":{"self":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/161","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/comments?post=161"}],"version-history":[{"count":3,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/161\/revisions"}],"predecessor-version":[{"id":541,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/161\/revisions\/541"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/media\/279"}],"wp:attachment":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/media?parent=161"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/categories?post=161"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/tags?post=161"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}