{"id":552,"date":"2026-10-09T11:12:51","date_gmt":"2026-10-09T09:12:51","guid":{"rendered":"https:\/\/www.ranksignal.fr\/blog\/?p=552"},"modified":"2026-10-14T17:21:20","modified_gmt":"2026-10-14T15:21:20","slug":"qu-est-ce-qu-un-agent-retriever","status":"publish","type":"post","link":"https:\/\/www.ranksignal.fr\/blog\/agentic\/qu-est-ce-qu-un-agent-retriever\/","title":{"rendered":"Agent retriever : un outil de recherche que l&rsquo;IA choisit"},"content":{"rendered":"<p><\/p>\n<p>\u00ab Quels sont les trois films de Steven Spielberg les mieux not\u00e9s, et leur note moyenne ? \u00bb Pose cette question \u00e0 un assistant branch\u00e9 sur une base de films : aucune recherche par similarit\u00e9 ne peut y r\u00e9pondre, car on ne lui demande pas de retrouver ce qui ressemble \u00e0 la question, mais de calculer. Quelqu&rsquo;un doit donc aller chercher l&rsquo;outil capable de ce calcul. Cet outil, c&rsquo;est un agent retriever : en fin de lecture, tu sauras le d\u00e9finir, lire sa \u00ab fiche d&rsquo;identit\u00e9 \u00bb et ne plus le confondre avec ce que le mot \u00ab agent \u00bb te fait imaginer.<\/p>\n<p><strong>Sommaire<\/strong><\/p>\n<ul>\n<li><a href=\"#l-essentiel-en-30-secondes\">L&rsquo;essentiel en 30 secondes<\/a><\/li>\n<li><a href=\"#deux-situations-ou-un-seul-moteur-de-recherche-ne-suffit-pas\">Deux situations o\u00f9 un seul moteur de recherche ne suffit pas<\/a><\/li>\n<li><a href=\"#une-capacite-de-recherche-mise-sous-etiquette\">Une capacit\u00e9 de recherche mise sous \u00e9tiquette<\/a><\/li>\n<li><a href=\"#lire-une-etiquette-l-outil-de-repli\">Lire une \u00e9tiquette : l&rsquo;outil de repli<\/a><\/li>\n<li><a href=\"#derriere-l-etiquette-des-corps-tres-differents\">Derri\u00e8re l&rsquo;\u00e9tiquette, des corps tr\u00e8s diff\u00e9rents<\/a><\/li>\n<li><a href=\"#trois-facons-de-choisir-le-retriever-a-appeler\">Trois fa\u00e7ons de choisir le retriever \u00e0 appeler<\/a><\/li>\n<li><a href=\"#trois-idees-recues\">Trois id\u00e9es re\u00e7ues<\/a><\/li>\n<\/ul>\n<h2 id=\"l-essentiel-en-30-secondes\">L&rsquo;essentiel en 30 secondes<\/h2>\n<ul>\n<li>Un agent retriever est <strong>une capacit\u00e9 de recherche mise sous \u00e9tiquette<\/strong> : un outil de r\u00e9cup\u00e9ration que le syst\u00e8me tient \u00e0 disposition, parmi d&rsquo;autres, pour trouver l&rsquo;information d&rsquo;une r\u00e9ponse.<\/li>\n<li>Il a deux faces : <strong>une \u00e9tiquette que lit le mod\u00e8le<\/strong> (nom, description, param\u00e8tres) et un corps qui s&rsquo;ex\u00e9cute derri\u00e8re, qu&rsquo;il s&rsquo;agisse d&rsquo;une requ\u00eate, d&rsquo;une <a href=\"\/blog\/rag\/qu-est-ce-qu-une-recherche-vectorielle\/\" title=\"recherche vectorielle\">recherche vectorielle<\/a> ou des deux.<\/li>\n<li>Il peut \u00eatre tr\u00e8s g\u00e9n\u00e9ral ou tr\u00e8s \u00e9troit : recherche vectorielle, text2cypher, ou <strong>gabarit de requ\u00eate cod\u00e9 en dur<\/strong>.<\/li>\n<li>On en multiplie parce qu&rsquo;<strong>une seule recherche par similarit\u00e9<\/strong> ne sait ni agr\u00e9ger des donn\u00e9es ni cloisonner des bases s\u00e9par\u00e9es.<\/li>\n<li>Le mot \u00ab agent \u00bb est trompeur : <strong>le pouvoir de d\u00e9cision reste au routeur<\/strong>, qui choisit le retriever \u00e0 appeler.<\/li>\n<\/ul>\n<h2 id=\"deux-situations-ou-un-seul-moteur-de-recherche-ne-suffit-pas\">Deux situations o\u00f9 un seul moteur de recherche ne suffit pas<\/h2>\n<p>Reprenons la question sur Spielberg. Pour y r\u00e9pondre, il faut une requ\u00eate construite expr\u00e8s, ici en Cypher, le langage de requ\u00eate des bases de donn\u00e9es de graphe comme Neo4j. Sa notation se lit comme un dessin : les parenth\u00e8ses d\u00e9signent des entit\u00e9s, les fl\u00e8ches les liens qui les relient.<\/p>\n<pre><code>MATCH (:Reviewer)-[r:REVIEWED]-&gt;(m:Movie)&lt;-[:DIRECTED]-(:Director {name:\n'Steven Spielberg'})\nRETURN m.title, AVG(r.score) AS avg_rating\nORDER BY avg_rating DESC\nLIMIT 3\n<\/code><\/pre>\n<p>Lis-la de gauche \u00e0 droite. Un critique (<code>Reviewer<\/code>) a not\u00e9 (<code>REVIEWED<\/code>) un film (<code>Movie<\/code>), et ce film a \u00e9t\u00e9 r\u00e9alis\u00e9 (<code>DIRECTED<\/code>) par un <code>Director<\/code> nomm\u00e9 Steven Spielberg. La note de chaque critique se trouve dans <code>r.score<\/code>, <code>AVG<\/code> en fait la moyenne pour chaque film, puis on trie du meilleur au moins bon et on garde les trois premiers.<\/p>\n<p>Cette requ\u00eate ne cherche pas les entit\u00e9s les plus proches de la question : elle <strong>agr\u00e8ge des donn\u00e9es d&rsquo;une fa\u00e7on pr\u00e9cise<\/strong>. D\u00e8s que tu veux autre chose que des voisins proches, ou que tu veux agr\u00e9ger, il te faut un retriever capable de produire ce genre de requ\u00eate. C&rsquo;est le terrain de text2cypher, que tu verras en d\u00e9tail plus bas.<\/p>\n<p>Deuxi\u00e8me situation, sans aucun calcul cette fois. Une entreprise propose des services de banque, d&rsquo;assurance et de finance, et un m\u00eame assistant r\u00e9pond aux clients sur leurs comptes et transactions, leurs polices et sinistres, leurs conseils et placements. Pour des raisons de r\u00e9glementation et de vie priv\u00e9e, il ne doit pas aller chercher dans les donn\u00e9es d&rsquo;un client rattach\u00e9es \u00e0 un autre service. Fouiller toutes les bases \u00e0 chaque question serait de toute fa\u00e7on inefficace : de la latence, et des r\u00e9sultats hors sujet.<\/p>\n<p>Dans les deux cas, la r\u00e9ponse n&rsquo;est pas un moteur plus puissant mais <strong>plusieurs moteurs, chacun cantonn\u00e9 \u00e0 son terrain<\/strong>, et un \u00e9tage qui choisit lequel appeler.<\/p>\n<h2 id=\"une-capacite-de-recherche-mise-sous-etiquette\">Une capacit\u00e9 de recherche mise sous \u00e9tiquette<\/h2>\n<p>Un <strong>agent retriever<\/strong> est une capacit\u00e9 de recherche pr\u00e9sent\u00e9e comme un outil. Le syst\u00e8me en garde tout un \u00e9ventail \u00e0 disposition, et \u00e0 chaque question l&rsquo;un d&rsquo;eux, ou plusieurs, est appel\u00e9 pour aller chercher les donn\u00e9es. Dans l&rsquo;impl\u00e9mentation la plus courante, un mod\u00e8le de langage choisit l&rsquo;outil gr\u00e2ce \u00e0 sa capacit\u00e9 \u00e0 appeler des outils, que l&rsquo;on nomme <em>function calling<\/em>.<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef468e17b6&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef468e17b6\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"986\" 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\/10\/b1_ch05_architecture_agentic_rag-scaled.png\" alt=\"Une question entre \u00e0 gauche, un routeur de retrievers choisit parmi trois agents retrievers plac\u00e9s en parall\u00e8le (vectoriel, text2cypher, sp\u00e9cifique), puis une critique de r\u00e9ponse contr\u00f4le le r\u00e9sultat\" class=\"wp-image-549\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_architecture_agentic_rag-scaled.png 2560w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_architecture_agentic_rag-300x116.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_architecture_agentic_rag-1024x394.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_architecture_agentic_rag-768x296.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_architecture_agentic_rag-1536x592.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch05_architecture_agentic_rag-2048x789.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 la colonne du milieu : ce sont les agents retrievers qui vont r\u00e9ellement chercher les donn\u00e9es. Autour d&rsquo;eux, un routeur d\u00e9signe qui appeler et une critique v\u00e9rifie le r\u00e9sultat. Remarque aussi que la mention \u00ab LLM \u00bb n&rsquo;appara\u00eet que sur ces deux \u00e9tages : ce sont eux qui d\u00e9cident et qui jugent.<\/figcaption><\/figure>\n\n\n<p>Ce qui d\u00e9finit l&rsquo;agent retriever, c&rsquo;est la s\u00e9paration de ses deux faces. L&rsquo;<strong>\u00e9tiquette<\/strong> est ce que lit le mod\u00e8le : un nom, une description en langage courant, la liste des param\u00e8tres \u00e0 fournir. Le <strong>corps<\/strong> est ce qui s&rsquo;ex\u00e9cute quand l&rsquo;outil est appel\u00e9 : une requ\u00eate de base de donn\u00e9es, une recherche vectorielle, ou les deux encha\u00een\u00e9es.<\/p>\n<table>\n<thead>\n<tr>\n<th><\/th>\n<th>\u00c9tiquette<\/th>\n<th>Corps<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Ce qu&rsquo;elle contient<\/td>\n<td>nom, description, param\u00e8tres attendus<\/td>\n<td>la fonction qui interroge la base<\/td>\n<\/tr>\n<tr>\n<td>Qui s&rsquo;en sert<\/td>\n<td>le mod\u00e8le qui choisit l&rsquo;outil<\/td>\n<td>le syst\u00e8me qui ex\u00e9cute l&rsquo;appel<\/td>\n<\/tr>\n<tr>\n<td>Ce qu&rsquo;elle d\u00e9termine<\/td>\n<td>quel outil est retenu, avec quels arguments<\/td>\n<td>ce qui est r\u00e9ellement cherch\u00e9 et renvoy\u00e9<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<blockquote>\n<p><strong>\ud83d\udca1 Intuition<\/strong> Pense \u00e0 une caisse \u00e0 outils dont chaque outil porte une \u00e9tiquette. Le chef de chantier ne d\u00e9monte rien pour savoir \u00e0 quoi sert un outil : il lit l&rsquo;\u00e9tiquette, puis dit \u00ab passe-moi celui-l\u00e0, avec ces r\u00e9glages \u00bb.<\/p>\n<\/blockquote>\n<p>C&rsquo;est ce qui distingue un agent retriever d&rsquo;un retriever tout court, qui re\u00e7oit une requ\u00eate et rend des documents class\u00e9s par pertinence. La fiche permet \u00e0 un mod\u00e8le de le choisir parmi d&rsquo;autres, et son corps ne se limite pas \u00e0 classer des documents : celui que tu vas lire maintenant renvoie des lignes de r\u00e9sultat d&rsquo;une requ\u00eate.<\/p>\n<h2 id=\"lire-une-etiquette-l-outil-de-repli\">Lire une \u00e9tiquette : l&rsquo;outil de repli<\/h2>\n<p>Dans la bo\u00eete \u00e0 outils de l&rsquo;exemple, deux outils \u00e9troits existent : l&rsquo;un retrouve un film par son titre, l&rsquo;autre par un acteur. Aucun ne sait agr\u00e9ger des notes, et c&rsquo;est un troisi\u00e8me outil, s&rsquo;appuyant sur text2cypher, qui prend les autres questions. Voici les deux faces de cet outil dans le m\u00eame extrait.<\/p>\n<pre><code>text2cypher_description = {\n    &quot;type&quot;: &quot;function&quot;,\n    &quot;function&quot;: {\n        &quot;name&quot;: &quot;text2cypher&quot;,\n        &quot;description&quot;: &quot;Query the database with a user question. When other\ntools don't fit, fallback to use this one.&quot;,\n        &quot;parameters&quot;: {\n            &quot;type&quot;: &quot;object&quot;,\n            &quot;properties&quot;: {\n                &quot;question&quot;: {\n                    &quot;type&quot;: &quot;string&quot;,\n                    &quot;description&quot;: &quot;The user question to find the answer for&quot;,\n                }\n            },\n            &quot;required&quot;: [&quot;question&quot;],\n        },\n    },\n}\n\ndef text2cypher(question: str):\n    &quot;&quot;&quot;Query the database with a user question.&quot;&quot;&quot;\n    t2c = Text2Cypher(neo4j_driver)\n    t2c.set_prompt_section(&quot;question&quot;, question)\n    cypher = t2c.generate_cypher()\n    records, _, _ = neo4j_driver.execute_query(cypher)\n    return [record.data() for record in records]\n<\/code><\/pre>\n<p>Le premier bloc, <code>text2cypher_description<\/code>, est l&rsquo;\u00e9tiquette : un dictionnaire au format JSON schema. Il donne le nom de l&rsquo;outil, sa description et un unique param\u00e8tre obligatoire, <code>question<\/code>, une cha\u00eene de caract\u00e8res qui re\u00e7oit la question de l&rsquo;utilisateur telle quelle. Compare avec les outils \u00e9troits de la m\u00eame bo\u00eete, dont l&rsquo;un demande un <code>title<\/code> et l&rsquo;autre un <code>actor<\/code> : <strong>outil \u00e9troit, param\u00e8tres pr\u00e9cis<\/strong> : plus il se resserre, plus ses param\u00e8tres se pr\u00e9cisent, alors que le retriever de repli se contente de la question brute.<\/p>\n<p>Regarde la seconde phrase de la description : \u00ab When other tools don&rsquo;t fit, fallback to use this one \u00bb. Le r\u00f4le de l&rsquo;outil est \u00e9crit en toutes lettres. Le mod\u00e8le qui choisit sait ainsi qu&rsquo;il doit y recourir seulement quand aucun outil plus sp\u00e9cifique ne convient, sans qu&rsquo;aucune r\u00e8gle suppl\u00e9mentaire soit n\u00e9cessaire dans le syst\u00e8me.<\/p>\n<p>Le second bloc, la fonction <code>text2cypher<\/code>, est le corps. <code>neo4j_driver<\/code> relie le code \u00e0 la base de graphe Neo4j. La question est d&rsquo;abord gliss\u00e9e dans une section du prompt de la classe <code>Text2Cypher<\/code>, qui fabrique la requ\u00eate Cypher (<code>generate_cypher<\/code>) ; <code>execute_query<\/code> la lance, et chaque ligne du r\u00e9sultat devient un dictionnaire.<\/p>\n<h2 id=\"derriere-l-etiquette-des-corps-tres-differents\">Derri\u00e8re l&rsquo;\u00e9tiquette, des corps tr\u00e8s diff\u00e9rents<\/h2>\n<p>Rien n&rsquo;oblige un retriever \u00e0 chercher d&rsquo;une fa\u00e7on plut\u00f4t qu&rsquo;une autre : la similarit\u00e9 vectorielle est la m\u00e9thode la plus courante, sans \u00eatre la seule. Derri\u00e8re une \u00e9tiquette, on peut donc loger des corps tr\u00e8s diff\u00e9rents :<\/p>\n<ul>\n<li>un gabarit de requ\u00eate cod\u00e9 en dur, \u00e9troit mais tr\u00e8s performant sur ce pour quoi il a \u00e9t\u00e9 con\u00e7u ;<\/li>\n<li>une requ\u00eate g\u00e9n\u00e9r\u00e9e \u00e0 la demande par un mod\u00e8le, comme dans text2cypher ;<\/li>\n<li>une recherche par similarit\u00e9 vectorielle, adapt\u00e9e aux sources non structur\u00e9es.<\/li>\n<\/ul>\n<p>Les deux premiers s&rsquo;opposent par un compromis connu : un mod\u00e8le de requ\u00eate pr\u00e9d\u00e9fini est rigide mais fiable, une requ\u00eate produite par un LLM est plus souple mais pas fiable \u00e0 100 %.<\/p>\n<p>Un corps peut aussi faire travailler deux moteurs \u00e0 la fois. Voici une <a href=\"\/blog\/rag\/qu-est-ce-qu-une-recherche-hybride\/\" title=\"recherche hybride\">recherche hybride<\/a>, test\u00e9e sur un article consacr\u00e9 aux brevets et inventions d&rsquo;Einstein : elle interroge un index vectoriel et un index de texte int\u00e9gral dans la m\u00eame requ\u00eate.<\/p>\n<pre><code>CALL {\n    \/\/ vector index\n    CALL db.index.vector.queryNodes('pdf', &#36;k, &#36;question_embedding)\nYIELD node, score\n    WITH collect({node:node, score:score}) AS nodes, max(score) AS max\n    UNWIND nodes AS n\n    \/\/ Normalize scores\n    RETURN n.node AS node, (n.score \/ max) AS score\n    UNION\n    \/\/ keyword index\n    CALL db.index.fulltext.queryNodes('ftPdfChunk', &#36;question, {limit: &#36;k})\n    YIELD node, score\n    WITH collect({node:node, score:score}) AS nodes, max(score) AS max\n    UNWIND nodes AS n\n    \/\/ Normalize scores\n    RETURN n.node AS node, (n.score \/ max) AS score\n}\n\/\/ deduplicate nodes\nWITH node, max(score) AS score ORDER BY score DESC LIMIT &#36;k\nRETURN node, score\n<\/code><\/pre>\n<p>Les trois mots pr\u00e9c\u00e9d\u00e9s d&rsquo;un <code><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-514949b0f884080844ac3ca2f9373bcd_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#96;&#32;&#40;&#96;\" title=\"Rendered by QuickLaTeX.com\" height=\"19\" width=\"15\" style=\"vertical-align: -5px;\"\/>k<\/code>, <code><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-37e72fe9a3caf9fb818d6be528c753bc_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#113;&#117;&#101;&#115;&#116;&#105;&#111;&#110;&#95;&#101;&#109;&#98;&#101;&#100;&#100;&#105;&#110;&#103;&#96;&#44;&#32;&#96;\" title=\"Rendered by QuickLaTeX.com\" height=\"16\" width=\"167\" style=\"vertical-align: -4px;\"\/>question<\/code>) sont des param\u00e8tres que le syst\u00e8me remplit \u00e0 chaque appel : le nombre de r\u00e9sultats voulus, le vecteur de la question et son texte. Chaque moiti\u00e9 de la requ\u00eate divise ses scores par le meilleur d&rsquo;entre eux, si bien que <strong>le premier de chaque liste vaut 1<\/strong>. <code>UNION<\/code> r\u00e9unit les deux listes, puis on garde pour chaque n\u0153ud son meilleur score, on trie et on coupe \u00e0 <code>&#36;k<\/code>.<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef468e1d17&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef468e1d17\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1132\" 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_recherche_hybride-scaled.png\" alt=\"Une question se divise en deux branches parall\u00e8les, recherche vectorielle par cosinus et recherche plein texte, dont les scores sont normalis\u00e9s puis fusionn\u00e9s\" class=\"wp-image-123\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_recherche_hybride-scaled.png 2560w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_recherche_hybride-300x133.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_recherche_hybride-1024x453.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_recherche_hybride-768x340.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_recherche_hybride-1536x679.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/09\/b1_ch02_recherche_hybride-2048x905.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\">Les deux branches du sch\u00e9ma sont ce que la requ\u00eate ci-dessus ex\u00e9cute en parall\u00e8le, et la bo\u00eete de droite correspond \u00e0 la normalisation et \u00e0 la fusion. Sur la m\u00eame question, le r\u00e9sultat hybride garde en t\u00eate le fragment que la recherche vectorielle pla\u00e7ait d\u00e9j\u00e0 premier, d&rsquo;o\u00f9 son score de 1,0. Le deuxi\u00e8me r\u00e9sultat change : la recherche plein texte a trouv\u00e9 une meilleure correspondance, un passage sur le d\u00e9part d&rsquo;Einstein de l&rsquo;office des brevets pour l&rsquo;universit\u00e9 de Zurich. Associ\u00e9es, les deux m\u00e9thodes font mieux que chacune prise isol\u00e9ment. Et pour le routeur, rien de cela ne se voit : il ne lit que l&rsquo;\u00e9tiquette.<\/figcaption><\/figure>\n\n\n<h2 id=\"trois-facons-de-choisir-le-retriever-a-appeler\">Trois fa\u00e7ons de choisir le retriever \u00e0 appeler<\/h2>\n<p>Le choix le plus courant passe par la lecture des \u00e9tiquettes : un mod\u00e8le de langage re\u00e7oit la question et la liste des fiches, puis d\u00e9signe l&rsquo;outil retenu et ses arguments.<\/p>\n<p>On peut aussi se passer de cette lecture. Tu pr\u00e9pares une liste de questions d&rsquo;exemple, chacune associ\u00e9e \u00e0 sa route (la base de la banque, celle de l&rsquo;assurance, celle de la finance). Ces questions sont transform\u00e9es en vecteurs et stock\u00e9es ; \u00e0 l&rsquo;arriv\u00e9e d&rsquo;une nouvelle question, on cherche les exemples les plus semblables et l&rsquo;on prend <strong>la route du meilleur d&rsquo;entre eux<\/strong>.<\/p>\n<p>Troisi\u00e8me voie : classer la question, par son intention, par des m\u00e9tadonn\u00e9es ou par sa ressemblance avec un jeu de requ\u00eates pr\u00e9d\u00e9finies. Un assistant de support technique peut ainsi envoyer les questions techniques vers une base de d\u00e9pannage et celles de facturation vers les informations de compte.<\/p>\n<p>Quelle que soit la m\u00e9thode, le retriever appel\u00e9 reste le m\u00eame objet. Seule change la mani\u00e8re de l&rsquo;atteindre.<\/p>\n<h2 id=\"trois-idees-recues\">Trois id\u00e9es re\u00e7ues<\/h2>\n<h3>\u00ab Un agent retriever est un agent autonome \u00bb<\/h3>\n<p>Le mot trompe. Dans cette architecture, un agent retriever peut n&rsquo;\u00eatre qu&rsquo;un gabarit de requ\u00eate cod\u00e9 en dur, qui prend des param\u00e8tres : la m\u00eame requ\u00eate, avec un autre nom ou un autre titre. Le point d&rsquo;entr\u00e9e du syst\u00e8me, lui, est le routeur, dont le r\u00f4le est de trouver les retrievers les mieux adapt\u00e9s \u00e0 la t\u00e2che en cours. L&rsquo;initiative est l\u00e0-haut ; les retrievers ex\u00e9cutent.<\/p>\n<h3>\u00ab Le mod\u00e8le \u00e9crira toujours la bonne requ\u00eate \u00bb<\/h3>\n<p>Un retriever text2cypher fait r\u00eaver : une question en langage courant, une requ\u00eate en sortie. Mais les mod\u00e8les ont tendance \u00e0 se tromper en g\u00e9n\u00e9rant du Cypher, surtout quand la question est complexe ou ambigu\u00eb, ou que les \u00e9l\u00e9ments du sch\u00e9ma ne sont pas nomm\u00e9s assez explicitement. Pour le fiabiliser, on soigne le prompt avec des <strong>exemples few-shot<\/strong>, le sch\u00e9ma du graphe, des correspondances de terminologie et des consignes de format. En ajoutant des exemples sur les types de questions qui posent probl\u00e8me, on voit la qualit\u00e9 des requ\u00eates s&rsquo;am\u00e9liorer au fil du temps. Des mod\u00e8les ajust\u00e9s \u00e0 cette seule t\u00e2che existent aussi et peuvent am\u00e9liorer les performances, notamment en production, l\u00e0 o\u00f9 la latence compte.<\/p>\n<h3>\u00ab Un retriever vectoriel renvoie le texte qu&rsquo;il a compar\u00e9 \u00bb<\/h3>\n<p>Dans sa version la plus simple, oui. Mais rien n&rsquo;oblige \u00e0 transformer en vecteur exactement le texte que l&rsquo;on veut renvoyer : on peut tout aussi bien le faire sur des sections plus pertinentes, des questions synth\u00e9tiques ou des reformulations.<\/p>\n<p>Le <strong>parent document retriever<\/strong> en est l&rsquo;exemple. Le document d&rsquo;origine, le parent, est d\u00e9coup\u00e9 en fragments plus petits, les enfants, chacun transform\u00e9 en vecteur s\u00e9par\u00e9ment. Quand un enfant correspond \u00e0 la question, c&rsquo;est le parent entier qui est renvoy\u00e9, pour conserver tout le contexte utile au mod\u00e8le. La raison : vectoriser un parent entier dilue ses id\u00e9es distinctes par un effet de moyenne, ce qui complique la correspondance avec une question pr\u00e9cise.<\/p>\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;6adef468e21f2&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"6adef468e21f2\" class=\"wp-block-image size-large wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1347\" 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\/10\/b1_ch03_graphe_parent_enfant-scaled.png\" alt=\"Un document PDF reli\u00e9 \u00e0 trois parents de 2 000 caract\u00e8res, dont le premier est reli\u00e9 \u00e0 des enfants de 500 caract\u00e8res, les seuls \u00e0 porter un vecteur\" class=\"wp-image-550\" srcset=\"https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch03_graphe_parent_enfant-scaled.png 2560w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch03_graphe_parent_enfant-300x158.png 300w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch03_graphe_parent_enfant-1024x539.png 1024w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch03_graphe_parent_enfant-768x404.png 768w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch03_graphe_parent_enfant-1536x808.png 1536w, https:\/\/www.ranksignal.fr\/wp-content\/uploads\/2026\/10\/b1_ch03_graphe_parent_enfant-2048x1078.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\">Seuls les enfants, en orange sur le sch\u00e9ma, portent un vecteur : ce sont eux que la recherche compare. La remont\u00e9e vers le parent se fait ensuite par le lien <code>HAS_CHILD<\/code>.<\/figcaption><\/figure>\n\n\n<pre><code>CALL db.index.vector.queryNodes(&#36;index_name, &#36;k * 4, &#36;question_embedding)\nYIELD node, score\nMATCH (node)&lt;-[:HAS_CHILD]-(parent)\nWITH parent, max(score) AS score\nRETURN parent.text AS text, score\nORDER BY score DESC\nLIMIT toInteger(&#36;k)\n<\/code><\/pre>\n<p><code><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.ranksignal.fr\/wp-content\/ql-cache\/quicklatex.com-647ac52d6b5fd7a39001567e0173e311_l3.png\" class=\"ql-img-inline-formula quicklatex-auto-format\" alt=\"&#105;&#110;&#100;&#101;&#120;&#95;&#110;&#97;&#109;&#101;&#96;&#32;&#101;&#115;&#116;&#32;&#108;&#101;&#32;&#110;&#111;&#109;&#32;&#100;&#101;&#32;&#108;&#39;&#105;&#110;&#100;&#101;&#120;&#32;&#118;&#101;&#99;&#116;&#111;&#114;&#105;&#101;&#108;&#32;&#112;&#111;&#115;&eacute;&#32;&#115;&#117;&#114;&#32;&#108;&#101;&#115;&#32;&#101;&#110;&#102;&#97;&#110;&#116;&#115;&#46;&#32;&#76;&#97;&#32;&#114;&#101;&#113;&#117;&ecirc;&#116;&#101;&#32;&#99;&#104;&#101;&#114;&#99;&#104;&#101;&#32;&#100;&#39;&#97;&#98;&#111;&#114;&#100;&#32;&#112;&#97;&#114;&#109;&#105;&#32;&#101;&#117;&#120;&#44;&#32;&#101;&#110;&#32;&#114;&eacute;&#99;&#108;&#97;&#109;&#97;&#110;&#116;&#32;&#101;&#120;&#112;&#114;&egrave;&#115;&#32;&#42;&#42;&#113;&#117;&#97;&#116;&#114;&#101;&#32;&#102;&#111;&#105;&#115;&#32;&#108;&#101;&#32;&#110;&#111;&#109;&#98;&#114;&#101;&#32;&#100;&#101;&#32;&#114;&eacute;&#115;&#117;&#108;&#116;&#97;&#116;&#115;&#32;&#118;&#111;&#117;&#108;&#117;&#42;&#42;&#32;&#40;&#96;\" title=\"Rendered by QuickLaTeX.com\" height=\"41\" width=\"899\" style=\"vertical-align: -5px;\"\/>k * 4<\/code>) : plusieurs enfants pertinents peuvent appartenir au m\u00eame parent, et il faut une marge avant de d\u00e9dupliquer. <code>MATCH (node)&lt;-[:HAS_CHILD]-(parent)<\/code> remonte \u00e0 chaque parent, <code>max(score)<\/code> retient le meilleur enfant de chacun, puis on garde les <code>&#36;k<\/code> premiers parents.<\/p>\n<blockquote>\n<p><strong>\ud83d\udccc \u00c0 retenir<\/strong> Une \u00e9tiquette lisible en haut, un corps libre en bas : cette s\u00e9paration permet de ranger c\u00f4te \u00e0 c\u00f4te un gabarit de requ\u00eate, une g\u00e9n\u00e9ration de requ\u00eate par mod\u00e8le et une recherche hybride. Le routeur compare des \u00e9tiquettes, jamais des corps.<\/p>\n<\/blockquote>","protected":false},"excerpt":{"rendered":"<p>Un agent retriever est une capacit\u00e9 de recherche mise sous \u00e9tiquette, que le syst\u00e8me choisit selon la question. D\u00e9finition, code lu pas \u00e0 pas, id\u00e9es re\u00e7ues.<\/p>\n","protected":false},"author":1,"featured_media":551,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-552","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-agentic"],"_links":{"self":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/552","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=552"}],"version-history":[{"count":3,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/552\/revisions"}],"predecessor-version":[{"id":787,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/posts\/552\/revisions\/787"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/media\/551"}],"wp:attachment":[{"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/media?parent=552"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/categories?post=552"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ranksignal.fr\/blog\/wp-json\/wp\/v2\/tags?post=552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}