<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[JD Armada - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[JD Armada - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/fr/search-labs/author/jd-armada</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/author/jd-armada</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/author/jd-armada.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 04:15:43 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Principaux projets d'Elastic Agent Builder et enseignements tirés de Cal Hacks 12.0]]></title>
    <description><![CDATA[Explorez les meilleurs projets Elastic Agent Builder de Cal Hacks 12.0 et plongez dans nos commentaires techniques sur Serverless, ES|QL et les architectures d'agents.]]></description>
    <content:encoded><![CDATA[<p>Il y a quelques semaines, nous avons eu l'incroyable opportunité de sponsoriser <a href="https://cal-hacks-12-0.devpost.com/">Cal Hacks 12.0</a>, l'un des plus grands hackathons en personne avec plus de 2000 participants venus du monde entier. Nous avons proposé une piste de prix dédiée à la meilleure utilisation d'Elastic Agent Builder sur Serverless, et la réponse a été phénoménale. En seulement 36 heures, nous avons reçu 29 soumissions qui utilisaient Agent Builder de manière créative, de la construction d'outils de renseignement sur les incendies de forêt aux validateurs StackOverflow.</p><p>Au-delà des projets impressionnants, l'expérience de Cal Hacks 12.0 nous a également apporté quelque chose de tout aussi précieux : un retour d'information rapide et non filtré de la part de développeurs qui découvrent notre pile pour la première fois. Les hackathons sont des tests de pression uniques, avec des délais serrés, une absence totale de connaissances préalables et des obstacles imprévisibles (comme les fameuses pannes de WiFi). Ils révèlent exactement les points forts de l'expérience du développeur et ceux sur lesquels il faut encore travailler. Cela est d'autant plus important aujourd'hui que les développeurs interagissent avec la pile Elastic de nouvelles façons, de plus en plus par le biais de flux de travail pilotés par LLM. Dans cet article de blog, nous allons approfondir ce que les participants ont construit avec Agent Builder et ce que nous avons appris au cours du processus.</p><h2>Les projets gagnants</h2><h3>Première place : AgentOverflow</h3><p>Stack Overflow reconstruit pour l'ère du LLM et de l'agent.</p><p>Pour en savoir plus sur AgentOverflow <a href="https://devpost.com/software/agentoverflow">, cliquez ici.</a></p><p>AgentOverflow s'attaque à un problème que rencontrent la plupart des développeurs d'IA : Les LLM hallucinent, les historiques de conversation disparaissent et les développeurs perdent du temps à résoudre les mêmes problèmes.</p><p>AgentOverflow capture, valide et fait réapparaître de véritables paires problème-solution, afin que les développeurs puissent sortir de la spirale de l'hallucination et livrer plus rapidement.</p><h4>Comment cela fonctionne-t-il ?</h4><p><strong>1. Partager JSON - le "schéma de solution".</strong></p><p>Un clic à partir d'un partage de Claude permet de récupérer, d'extraire et d'assembler une solution de partage JSON, qui est un format structuré contenant :</p><ul><li><p>Problème</p></li><li><p>Contexte</p></li><li><p>Code</p></li><li><p>Balises</p></li><li><p>Vérification des étapes de la solution.</p></li></ul><p>Un validateur (LAVA) vérifie et renforce la structure, l'utilisateur ajoute une ligne de contexte supplémentaire, puis le tout est stocké et indexé dans Elasticsearch.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte7bc35b6d54921e8/6a17f0176df73162760a0fe6/45a3e96f4474050a855419628c2a7338bb12c706-1600x877.png" alt="En cliquant sur &quot;Partager la solution&quot;, la session en cours sera récupérée avec les métadonnées correspondantes." /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9967f52007fff99e/6a17f019ec0f8987c45a6701/2d65cb154d8ee32fc96ff17dfa5b0bf2636e3777-1600x1002.png" alt="Les utilisateurs fournissent un contexte supplémentaire par l'intermédiaire de l'interface web, puis le JSON est indexé dans Elasticsearch." /><p><strong>2. Trouver la solution</strong></p><p>Lorsque vous êtes bloqué, cliquez sur <code>Find Solution</code> et AgentOverflow scrapera votre conversation actuelle, l'utilisera pour construire une requête, et lancera une recherche hybride Elasticsearch pour remonter à la surface :</p><ul><li><p>Corrections classées et validées par la communauté</p></li><li><p>Les invites exactes qui ont résolu le problème à l'origine</p></li></ul><p>Cela permet aux développeurs de copier, coller et débloquer rapidement leur session en cours.</p><p><strong>3. MCP - injection de contexte pour les LLM</strong></p><p>En se connectant aux solutions structurées stockées dans Elasticsearch via MCP (Model Context Protocol), les LLM sont alimentés en contexte à haut signal (code, journaux, configurations, corrections antérieures) au moment de l'exécution sans bruit supplémentaire.</p><p>AgentOverflow utilise Agent Builder avec Elasticsearch comme couche de mémoire structurée qui injecte un contexte pertinent dans les LLM. Ils passent ainsi du statut de chatbots passifs à celui de résolveurs de problèmes conscients du contexte.</p><h3>Deuxième prix : MarketMind</h3><p>Une vue interprétable en temps réel de l'énergie du marché, alimentée par six agents élastiques.</p><p>Pour en savoir plus sur MarketMind <a href="https://devpost.com/software/marketmind-b6cy2q">, cliquez ici.</a></p><p>MarketMind a gagné sa place en offrant aux traders débutants une plateforme qui convertit les données fragmentées du marché en signaux clairs et en temps réel. Au lieu de jongler avec l'évolution des prix, les fondamentaux, le sentiment et la volatilité sur différents outils, MarketMind consolide toutes ces informations sur une seule plateforme, aidant ainsi les traders à obtenir des informations exploitables. Ce projet a également utilisé des requêtes ES|QL complexes lors de la création de ses agents.</p><h4>Comment cela fonctionne-t-il ?</h4><p><strong>1. Collecter des données de marché en temps réel</strong></p><p>MarketMind extrait de Yahoo Finance des données sur l'évolution des cours, les fondamentaux, le sentiment, la volatilité et le risque. Ces données sont ingérées et organisées en plusieurs index Elasticsearch.</p><p><strong>2. Six agents spécialisés analysent le marché</strong></p><p>Chaque agent, créé avec Agent Builder, se concentre sur une couche différente du marché. Ils lisent un index Elasticsearch, calculent leurs propres mesures spécifiques au domaine et génèrent une sortie JSON standardisée avec des scores et un raisonnement.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4ba582f9872b65b/6a17f01b7f6f15c2d8c09c1c/7d9716cca06a047a2b3584378b5c7e592a785ba1-1284x878.png" alt="6 agents spécialisés GOOGL AI qui analysent le marché" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd86ed3bfe4b8bd2b/6a17f01c5ea30f868164b6ba/5aac6a833347c0d2e596c02049ec4b4d3aae5cd7-794x764.png" alt="Capacités d'analyse des anomalies de volume et de détection des catastrophes des agents spécialisés de GOOGL" /><p><strong>3. Agréger les signaux dans un modèle unifié d'"énergie de marché".</strong></p><p>Les résultats combinés apparaissent sous forme d'impulsions lumineuses autour de chaque action, indiquant si la dynamique se renforce, si le risque augmente ou si le sentiment change.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5af7c7c838308275/6a17f01e42022917b629f6ca/46b3da8e3d528c5dd4e2829416c5446098acb3aa-744x718.png" alt="Modèle unifié d'&quot;énergie de marché&quot; des agents spécialisés de GOOGL" /><p><strong>4. Visualiser les informations</strong></p><p>Le frontend a été construit avec React et <a href="https://github.com/vercel/next.js">Next.js</a>, en utilisant TypeScript, des visuels SVG basés sur la physique, et <a href="https://github.com/chartjs">Chart.js</a> pour les graphiques de chandeliers en direct. L'analyse brute est ainsi transformée en un retour d'information exploitable en temps réel.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt775e1880aa7afacc/6a17f01f1d1b83ce1f93e528/3f000c043117b77ed4127202be5a49c12e3682ba-1600x930.png" alt="Comment visualiser les résultats de l'analyse des agents spécialisés de GOOGL ?" /><h2>Autres projets intéressants :</h2><p>Voici d'autres concurrents de taille qui ont utilisé Elastic dans différentes parties de leur pile :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltffe292009e446a70/6a17f0216df731068c0a0fea/76c49a853426844f475cd6b2a74999e60af20e8c-926x1080.png" alt="" /><p>Vous trouverez <a href="https://cal-hacks-12-0.devpost.com/submissions/search?utf8=%E2%9C%93&amp;prize_filter%5Bprizes%5D%5B%5D=91882">ici la</a> liste complète des projets qui ont été soumis à notre circuit.</p><h2>Ce que nous ont appris les développeurs</h2><ul><li><p><strong>Agent Builder est convivial :</strong></p></li></ul><p>La plupart des équipes n'avaient jamais utilisé Elastic auparavant et étaient encore en mesure de créer des agents rapidement avec peu de soutien. Nous avons organisé un atelier pour ceux qui avaient besoin de plus de conseils, mais la plupart ont été en mesure d'ingérer leurs données et de créer un agent pour effectuer des actions sur ces données.</p><ul><li><p><strong>Les LLM excellent dans les </strong><strong> requêtes</strong><strong><code>kNN</code></strong>, mais ont encore besoin d'être guidés dans la création d'ES|QL :</p></li></ul><p>Demander à ChatGPT-5 de générer des requêtes ES|QL renvoyait des informations incorrectes, mélangeant souvent ES|QL et SQL. Alimenter le LLM avec les documents dans un fichier markdown semblait être une solution viable.</p><ul><li><p><strong>Les fonctions ES|QL en mode instantané ont fait l'objet d'une fuite dans la documentation :</strong></p></li></ul><p>Les fonctions d'agrégation <code>FIRST</code> et <code>LAST</code> ont été glissées involontairement dans nos documents ES|QL. Parce que nous avons fourni ces documents à ChatGPT, le modèle a consciencieusement utilisé ces fonctions, même si elles ne sont pas encore disponibles dans Serverless. Grâce au feedback du groupe, l'ingénierie a rapidement ouvert et fusionné un correctif pour supprimer les fonctions de la documentation publiée<a href="https://github.com/elastic/elasticsearch/pull/137341">(PR #137341</a>).</p><ul><li><p><strong>Absence d'orientations spécifiques à Serverless :</strong></p></li></ul><p>Une équipe a essayé d'activer <code>LOOKUP JOIN</code> sur un index qui n'a pas été créé en mode consultation. Le message d'erreur les a envoyés à la recherche de commandes qui n'existent pas sur Serverless. Nous avons relayé cette information à l'équipe produit, qui a immédiatement ouvert un correctif pour un message actionnable spécifique à Serverless. À plus long terme, l'objectif est de masquer entièrement la complexité de la réindexation<a href="https://github.com/elastic/elasticsearch-serverless/issues/4838">(problème n° 4838</a>).</p><ul><li><p><strong>Valeur des événements en personne :</strong></p></li></ul><p>Les hackathons en ligne sont formidables, mais rien n'égale la boucle de rétroaction rapide que vous obtenez lorsque vous déboguez épaule contre épaule avec des constructeurs. Nous avons vu des équipes intégrer Agent Builder dans différents cas d'utilisation, repérer où l'expérience des développeurs avec ES|QL pouvait être améliorée, et résoudre les problèmes beaucoup plus rapidement qu'en essayant de le faire sur des canaux asynchrones.</p><h2>Conclusion</h2><p>Cal Hacks 12.0 nous a offert plus qu'un week-end de démonstrations intéressantes ; il nous a également permis de comprendre comment les nouveaux développeurs interagissent avec la pile Elastic. En seulement 36 heures, nous avons vu des équipes prendre en main Agent Builder, ingérer des données dans Elasticsearch, concevoir des systèmes multi-agents et tester nos fonctionnalités de différentes manières. L'événement nous a également rappelé pourquoi les événements en personne sont importants. Les boucles de rétroaction rapides, les conversations réelles et le débogage pratique nous ont aidés à comprendre les besoins actuels des développeurs. Nous sommes ravis d'apporter ce que nous avons appris à l'équipe d'ingénieurs. Nous vous donnons rendez-vous au prochain hackathon.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agent-builder-projects-learnings-cal-hacks-12-0</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agent-builder-projects-learnings-cal-hacks-12-0</guid>
    <category><![CDATA[IA]]></category>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f079179be9832d4/6a17f023631730a69c585b6d/8ba034a6f19b50521f541b8131756a8acdb52975-1280x960.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 25 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Construire un agent de connaissance avec rappel sémantique en utilisant Mastra et Elasticsearch]]></title>
    <description><![CDATA[Apprenez à construire un agent de connaissance avec rappel sémantique en utilisant Mastra et Elasticsearch comme magasin vectoriel pour la mémoire et la recherche d'informations.]]></description>
    <content:encoded><![CDATA[<p>L'<a href="https://www.elastic.co/search-labs/blog/context-engineering-overview">ingénierie contextuelle</a> devient de plus en plus importante dans la construction d'agents et d'architectures d'IA fiables. Au fur et à mesure que les modèles s'améliorent, leur efficacité et leur fiabilité dépendent moins de leurs données d'entraînement que de leur ancrage dans le bon contexte. Les agents qui peuvent récupérer et appliquer les informations les plus pertinentes au bon moment sont beaucoup plus susceptibles de produire des résultats précis et fiables.</p><p>Dans ce blog, nous utiliserons <a href="https://mastra.ai/">Mastra</a> pour construire un agent de connaissance qui se souvient de ce que les utilisateurs disent et peut rappeler les informations pertinentes plus tard, en utilisant Elasticsearch comme mémoire et backend de récupération. Vous pouvez facilement étendre ce même concept à des cas d'utilisation réels, comme des agents d'assistance qui peuvent se souvenir de conversations et de résolutions antérieures, ce qui leur permet d'adapter les réponses à des utilisateurs spécifiques ou de trouver des solutions plus rapidement en fonction du contexte antérieur.</p><p>Suivez ici les étapes de sa construction. Si vous vous perdez ou si vous voulez simplement exécuter un exemple fini, consultez le repo <a href="https://github.com/jdarmada/getting-started-mastra-elastic/tree/main">ici.</a></p><h2>Qu'est-ce que Mastra ?</h2><p>Mastra est un framework TypeScript open-source pour la construction d'agents d'intelligence artificielle avec des parties interchangeables pour le raisonnement, la mémoire et les outils. Sa fonction de <a href="https://mastra.ai/docs/memory/semantic-recall">rappel sémantique</a> permet aux agents de se souvenir des interactions passées et de les retrouver en stockant les messages sous forme d'enchâssements dans une base de données vectorielle. Cela permet aux agents de conserver le contexte et la continuité de la conversation à long terme. Elasticsearch est un excellent magasin de vecteurs pour activer cette fonctionnalité, car il prend en charge la recherche vectorielle dense efficace. Lorsque le rappel sémantique est déclenché, l'agent introduit les messages antérieurs pertinents dans la fenêtre contextuelle du modèle, ce qui permet à ce dernier d'utiliser le contexte récupéré comme base de son raisonnement et de ses réponses.</p><h2>Ce qu'il faut pour commencer</h2><ul><li><p>Node v18+</p></li><li><p>Elasticsearch (version 8.15 ou plus récente)</p></li><li><p>Clé API Elasticsearch</p></li><li><p><a href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key">Clé API OpenAI</a></p></li></ul><p>Note : Vous en aurez besoin parce que la démo utilise le fournisseur OpenAI, mais Mastra prend en charge d'autres SDK d'IA et fournisseurs de modèles communautaires, vous pouvez donc facilement l'échanger en fonction de votre configuration.</p><h2>Construire un projet Mastra</h2><p>Nous utiliserons le CLI intégré de Mastra pour fournir l'échafaudage de notre projet. Exécutez la commande :</p>npm create mastra@latest<p>Vous obtiendrez une série d'invites, commençant par :</p><p>1. Donnez un nom à votre projet.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt87f941f654d03827/6a16f7af67045b214d45bfa1/2b9fe559e0276140dd539e24f916a73c60870405-620x84.png" alt="Nommer une invite dans l'application Mastra" /><p>2. Nous pouvons conserver cette valeur par défaut ; n'hésitez pas à la laisser vide.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7dbb3d4f27435cac/6a16f7b0cdacbf29497d27de/e04729eb03bce8499e973e18c28642402340d0e5-852x68.png" alt="Indiquer à mastra où conserver les fichiers d'invite" /><p>3. Pour ce projet, nous utiliserons un modèle fourni par OpenAI.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1f654f6cb9397e94/6a16f7b2964cea899a08b942/a86596a469a71bdf8bd99cbaf528d0f0cf7272c0-436x222.png" alt="Sélection d'un modèle fourni par OpenAI dans Mastra" /><p>4. Sélectionnez l'option "Skip for now" car nous allons stocker toutes nos variables d'environnement dans un fichier `.env` que nous configurerons plus tard.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltff106117521a3519/6a16f7b3c1e8a5031af880d8/02b19ccc34af0bdacf52fd94b519d036540ca2e6-426x114.png" alt="Sélectionner l'option &quot;ignorer pour l'instant&quot; pour la clé OpenAI" /><p>5. Nous pouvons également ignorer cette option.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcda7d9c51c3878d7/6a16f7b450916809dbe1b892/b3fe63d19d270bc2e0de1dd92033bf8b26750819-990x208.png" alt="" /><p>Une fois l'initialisation terminée, nous pouvons passer à l'étape suivante.</p><h3>Installation des dépendances</h3><p>Ensuite, nous devons installer quelques dépendances :</p>npm install ai @ai-sdk/openai @elastic/elasticsearch dotenv<ul><li><p><code>ai</code> - Ensemble de SDK d'IA de base qui fournit des outils pour gérer les modèles d'IA, les invites et les flux de travail en JavaScript/TypeScript. Mastra est construit sur le <a href="https://ai-sdk.dev/">SDK AI</a> de Vercel, nous avons donc besoin de cette dépendance pour permettre les interactions du modèle avec votre agent.</p></li><li><p><code>@ai-sdk/openai</code> - Plugin qui connecte le SDK AI aux modèles OpenAI (comme GPT-4, GPT-4o, etc.), permettant des appels API en utilisant votre clé API OpenAI.</p></li><li><p><code>@elastic/elasticsearch</code> - <a href="https://www.elastic.co/docs/reference/elasticsearch/clients/javascript">Client Elasticsearch officiel pour Node.js</a>, utilisé pour se connecter à votre Elastic Cloud ou à votre cluster local pour l'indexation, la recherche et les opérations vectorielles.</p></li><li><p><code>dotenv</code> - Charge les variables d'environnement à partir d'un fichier .env dans le fichier process.env, vous permettant d'injecter en toute sécurité des informations d'identification telles que des clés d'API et des points d'extrémité Elasticsearch.</p></li></ul><h3>Configuration des variables d'environnement</h3><p>Créez un fichier <code>.env</code> dans le répertoire racine de votre projet si vous n'en avez pas déjà un. Vous pouvez également copier et renommer l'exemple <code>.env</code> que j'ai fourni dans le <a href="https://github.com/jdarmada/getting-started-mastra-elastic/blob/main/.env.example">répertoire.</a> Dans ce fichier, nous pouvons ajouter les variables suivantes :</p>ELASTICSEARCH_ENDPOINT="your-endpoint-here"
ELASTICSEARCH_API_KEY="your-key-here"
OPENAI_API_KEY="your-key-here"<p>Voilà qui conclut la configuration de base. À partir de là, vous pouvez déjà commencer à construire et à orchestrer des agents. Nous allons aller plus loin et ajouter Elasticsearch en tant que couche de stockage et de recherche vectorielle.</p><h2>Ajouter Elasticsearch comme magasin de vecteurs</h2><p>Créez un nouveau dossier appelé <code>stores</code> et ajoutez-y ce <a href="https://github.com/jdarmada/getting-started-mastra-elastic/blob/main/src/mastra/stores/elastic-store.ts">fichier</a>. Avant que Mastra et Elastic ne proposent une intégration officielle de Elasticsearch vector store, <a href="https://github.com/abhiaiyer91">Abhi Aiyer</a>(Mastra CTO) a partagé ce prototype de classe appelé <code>ElasticVector</code>. Simplement, il relie l'abstraction mémoire de Mastra aux capacités vectorielles denses d'Elasticsearch, de sorte que les développeurs peuvent utiliser Elasticsearch comme base de données vectorielle pour leurs agents.</p><p>Examinons plus en détail les éléments importants de l'intégration :</p><h3>Ingestion du client Elasticsearch</h3><p>Cette section définit la classe <code>ElasticVector</code> et met en place la connexion du client Elasticsearch avec un support pour les déploiements standards et sans serveur.</p>export interface ElasticVectorConfig extends ClientOptions {
    /**
     * Explicitly specify if connecting to Elasticsearch Serverless.
     * If not provided, will be auto-detected on first use.
     */
    isServerless?: boolean;
    
    /**
     * Maximum documents to count accurately when describing indices.
     * Higher values provide accurate counts but may impact performance on large indices.
     * 
     * @default 10000
     */
    maxCountAccuracy?: number;
}

export class ElasticVector extends MastraVector {
    private client: Client;
    private isServerless: boolean | undefined;
    private deploymentChecked: boolean = false;
    private readonly maxCountAccuracy: number;

    constructor(config: ElasticVectorConfig) {
        super();
        this.client = new Client(config);
        this.isServerless = config.isServerless;
        this.maxCountAccuracy = config.maxCountAccuracy ?? 10000;
    }
}<ul><li><p><code>ElasticVectorConfig extends ClientOptions</code>: Ceci crée une nouvelle interface de configuration qui hérite de toutes les options du client Elasticsearch (comme <code>node</code>, <code>auth</code>, <code>requestTimeout</code>) et ajoute nos propriétés personnalisées. Cela signifie que les utilisateurs peuvent passer n'importe quelle configuration Elasticsearch valide avec nos options spécifiques au serveur.</p></li><li><p><code>extends MastraVector</code>: Cela permet à <code>ElasticVector</code> d'hériter de la classe de base <code>MastraVector</code> de Mastra, qui est une interface commune à laquelle se conforment toutes les intégrations de magasins vectoriels. Cela garantit qu'Elasticsearch se comporte comme n'importe quel autre backend vectoriel Mastra du point de vue de l'agent.</p></li><li><p><code>private client: Client</code>: Il s'agit d'une propriété privée qui contient une instance du client JavaScript Elasticsearch. Cela permet à la classe de s'adresser directement à votre cluster.</p></li><li><p><code>isServerless</code> et <code>deploymentChecked</code>: Ces propriétés fonctionnent ensemble pour détecter et mettre en cache si nous sommes connectés à un déploiement Elasticsearch standard ou sans serveur. Cette détection se fait automatiquement lors de la première utilisation ou peut être configurée explicitement.</p></li><li><p><code>constructor(config: ClientOptions)</code>: Ce constructeur prend un objet de configuration (contenant vos identifiants Elasticsearch et des paramètres serverless optionnels) et l'utilise pour initialiser le client dans la ligne <code>this.client = new Client(config)</code>.</p></li><li><p><code>super()</code>: Il appelle le constructeur de base de Mastra, ce qui lui permet d'hériter de la journalisation, des aides à la validation et d'autres crochets internes.</p></li></ul><p>À ce stade, Mastra sait qu'il existe un nouveau magasin de vecteurs appelé <code>ElasticVector</code></p><h3>Détection du type de déploiement</h3><p>Avant de créer des index, l'adaptateur détecte automatiquement si vous utilisez Elasticsearch standard ou Elasticsearch Serverless. C'est important car les déploiements sans serveur ne permettent pas la configuration manuelle des shards.</p>private async detectServerless(): Promise&lt;boolean&gt; {
    // Return cached result if already detected
    if (this.deploymentChecked) {
        return this.isServerless ?? false;
    }

    // Use explicit configuration if provided
    if (this.isServerless !== undefined) {
        this.deploymentChecked = true;
        this.logger?.info(
            `Using explicit deployment type: ${this.isServerless ? 'Serverless' : 'Standard'}`
        );
        return this.isServerless;
    }

    try {
        const info = await this.client.info();
        
        // Primary detection: build flavor (most reliable)
        const isBuildFlavorServerless = info.version?.build_flavor === 'serverless';
        
        // Secondary detection: tagline (fallback)
        const isTaglineServerless = info.tagline?.toLowerCase().includes('serverless') ?? false;
        
        this.isServerless = isBuildFlavorServerless || isTaglineServerless;
        this.deploymentChecked = true;
        
        this.logger?.info(
            `Auto-detected ${this.isServerless ? 'Serverless' : 'Standard'} Elasticsearch deployment`,
            { 
                buildFlavor: info.version?.build_flavor, 
                version: info.version?.number,
                detectionMethod: isBuildFlavorServerless ? 'build_flavor' : 'tagline'
            }
        );
        
        return this.isServerless;
    } catch (error) {
        this.logger?.warn(
            'Could not auto-detect deployment type, assuming Standard Elasticsearch. ' +
            'Set isServerless: true explicitly in config if using Serverless.',
            { error: error instanceof Error ? error.message : String(error) }
        );
        this.isServerless = false;
        this.deploymentChecked = true;
        return false;
    }
}<p>Ce qui se passe :</p><ul><li><p>Vérifie d'abord si vous avez explicitement défini <code>isServerless</code> dans la configuration (ignore l'autodétection).</p></li><li><p>Appelle l'API <code>info()</code> d'Elasticsearch pour obtenir des informations sur les clusters.</p></li><li><p>Vérifie le <code>build_flavor field</code> (les déploiements sans serveur renvoient <code>serverless</code>).</p></li><li><p>Renvoie à la vérification du slogan si la saveur de la construction n'est pas disponible</p></li><li><p>Met en cache le résultat afin d'éviter les appels répétés à l'API</p></li><li><p>Déploiement standard par défaut en cas d'échec de la détection</p></li></ul><p> Exemple d'utilisation :</p>// Option 1: Auto-detect (recommended)
const vector = new ElasticVector({
    node: 'https://your-cluster.es.cloud',
    auth: { apiKey: 'your-api-key' }
});
// Detection happens automatically on first index operation

// Option 2: Explicit configuration (faster startup)
const vector = new ElasticVector({
    node: 'https://your-serverless.es.cloud',
    auth: { apiKey: 'your-api-key' },
    isServerless: true  // Skips auto-detection
});<h3>Création du magasin "memory" dans Elasticsearch</h3><p>La fonction ci-dessous met en place un index Elasticsearch pour le stockage des embeddings. Il vérifie si l'index existe déjà. Si ce n'est pas le cas, il en crée un avec le mappage ci-dessous qui contient un champ <code>dense_vector</code> pour stocker les embeddings et les métriques de similarité personnalisées.</p><p>Quelques points à noter :</p><ul><li><p>Le paramètre <code>dimension</code> est la longueur de chaque vecteur d'intégration, qui dépend du modèle d'intégration utilisé. Dans notre cas, nous allons générer des embeddings en utilisant le modèle <code>text-embedding-3-small</code> d'OpenAI, qui produit des vecteurs de taille <code>1536</code>. Nous l'utiliserons comme valeur par défaut.</p></li><li><p>La variable <code>similarity</code> utilisée dans la correspondance ci-dessous est définie à partir de la fonction d'aide c<code>onst similarity = this.mapMetricToSimilarity(metric)</code>, qui prend la valeur du paramètre <code>metric</code> et la convertit en un mot-clé compatible avec Elasticsearch pour la métrique de distance choisie.</p><ul><li><p>Par exemple : Mastra utilise des termes généraux pour la similarité vectorielle comme <code>cosine</code>, <code>euclidean</code>, et <code>dotproduct</code>. Si nous devions passer la métrique <code>euclidean</code> directement dans le mappage Elasticsearch, une erreur se produirait car Elasticsearch s'attend à ce que le mot-clé <code>l2_norm</code> représente la distance euclidienne.</p></li></ul></li><li><p>Compatibilité sans serveur : Le code omet automatiquement les paramètres de shard et de réplique pour les déploiements sans serveur, car ils sont gérés automatiquement par Elasticsearch Serverless.</p></li></ul>async createIndex(params: CreateIndexParams): Promise&lt;void&gt; {
    const { indexName, dimension = 1536, metric = 'cosine' } = params;

    try {
        const exists = await this.client.indices.exists({ index: indexName });

        if (exists) {
            try {
                await this.validateExistingIndex(indexName, dimension, metric);
                this.logger?.info(`Index "${indexName}" already exists and is valid`);
                return;
            } catch (validationError) {
                throw new Error(
                    `Index "${indexName}" exists but does not match the required configuration: ${
                        validationError instanceof Error ? validationError.message : String(validationError)
                    }`
                );
            }
        }

        const isServerless = await this.detectServerless();
        const similarity = this.mapMetricToSimilarity(metric);

        const indexConfig: any = {
            index: indexName,
            mappings: {
                properties: {
                    vector: {
                        type: 'dense_vector',
                        dims: dimension,
                        index: true,
                        similarity: similarity,
                    },
                    metadata: {
                        type: 'object',
                        enabled: true,
                        dynamic: true, // Allows flexible metadata structures
                    },
                },
            },
        };

        // Only configure shards/replicas for non-serverless deployments
        // Serverless manages infrastructure automatically
        if (!isServerless) {
            indexConfig.settings = {
                number_of_shards: 1,
                number_of_replicas: 0, // Increase for production HA deployments
            };
        }

        await this.client.indices.create(indexConfig);

        this.logger?.info(
            `Created ${isServerless ? 'Serverless' : 'Standard'} Elasticsearch index "${indexName}"`,
            { dimension, metric, similarity }
        );
    } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        this.logger?.error(`Failed to create index "${indexName}": ${errorMessage}`);
        throw new Error(`Failed to create index "${indexName}": ${errorMessage}`);
    }
}<h3>Enregistrement d'un nouveau souvenir ou d'une nouvelle note après une interaction</h3><p>Cette fonction prend les nouveaux embeddings générés après chaque interaction, ainsi que les métadonnées, puis les insère ou les met à jour dans l'index à l'aide de l'API <code>bulk</code> d'Elastic. L'API <code>bulk</code> regroupe plusieurs opérations d'écriture en une seule demande ; cette amélioration de nos performances d'indexation garantit que les mises à jour restent efficaces alors que la mémoire de notre agent ne cesse de croître.</p>async upsert(params: UpsertVectorParams): Promise&lt;string[]&gt; {
    const { indexName, vectors, metadata = [], ids } = params;

    try {
        // Generate unique IDs if not provided
        const vectorIds = ids || vectors.map((_, i) =&gt; 
            `vec_${Date.now()}_${i}_${Math.random().toString(36).substr(2, 9)}`
        );

        const operations = vectors.flatMap((vec, index) =&gt; [
            { index: { _index: indexName, _id: vectorIds[index] } },
            {
                vector: vec,
                metadata: metadata[index] || {},
            },
        ]);

        const response = await this.client.bulk({
            refresh: true,
            operations,
        });

        if (response.errors) {
            const erroredItems = response.items.filter((item: any) =&gt; item.index?.error);
            const erroredIds = erroredItems.map((item: any) =&gt; item.index?._id);
            const errorDetails = erroredItems.slice(0, 3).map((item: any) =&gt; ({
                id: item.index?._id,
                error: item.index?.error?.reason || item.index?.error,
                type: item.index?.error?.type
            }));
            
            const errorMessage = `Failed to upsert ${erroredIds.length}/${vectors.length} vectors`;
            console.error(`${errorMessage}. Sample errors:`, JSON.stringify(errorDetails, null, 2));
            this.logger?.error(errorMessage, { 
                failedCount: erroredIds.length, 
                totalCount: vectors.length,
                sampleErrors: errorDetails 
            });
            
            // Still return successfully inserted IDs
            const successfulIds = vectorIds.filter((id, idx) =&gt; 
                !erroredIds.includes(id)
            );
            
            if (successfulIds.length === 0) {
                throw new Error(`${errorMessage}. All operations failed. See logs for details.`);
            }
            
            return successfulIds;
        }

        this.logger?.info(`Successfully upserted ${vectors.length} vectors to "${indexName}"`);
        return vectorIds;
    } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        this.logger?.error(`Failed to upsert vectors to "${indexName}": ${errorMessage}`);
        throw new Error(`Failed to upsert vectors to "${indexName}": ${errorMessage}`);
    }
}<h3>Interrogation des vecteurs similaires pour le rappel sémantique</h3><p>Cette fonction est au cœur de la fonction de rappel sémantique. L'agent utilise la recherche vectorielle pour trouver des enregistrements similaires dans notre index.</p>async query(params: QueryVectorParams&lt;any&gt;): Promise&lt;QueryResult[]&gt; {
    const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;

    try {
        const knnQuery: any = {
            field: 'vector',
            query_vector: queryVector,
            k: topK,
            num_candidates: Math.max(topK * 10, 100), // Search more candidates for better recall
        };

        // Apply metadata filters if provided
        if (filter) {
            knnQuery.filter = this.buildElasticFilter(filter);
        }

        const sourceFields = ['metadata'];
        if (includeVector) {
            sourceFields.push('vector');
        }

        const response = await this.client.search({
            index: indexName,
            knn: knnQuery,
            size: topK,
            _source: sourceFields,
        });

        const results = response.hits.hits.map((hit: any) =&gt; ({
            id: hit._id,
            score: hit._score || 0,
            metadata: hit._source?.metadata || {},
            vector: includeVector ? hit._source?.vector : undefined,
        }));

        this.logger?.debug(`Query returned ${results.length} results from "${indexName}"`);
        return results;
    } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        this.logger?.error(`Failed to query vectors from "${indexName}": ${errorMessage}`);
        throw new Error(`Failed to query vectors from "${indexName}": ${errorMessage}`);
    }
}<p>Sous le capot :</p><ul><li><p>Exécute une requête <a href="https://www.elastic.co/docs/solutions/search/vector/knn">kNN</a> (k-nearest neighbors) à l'aide de l'API <code>knn</code> dans Elasticsearch.</p></li><li><p>Récupère les K premiers vecteurs similaires au vecteur d'entrée de la requête.</p></li><li><p>Possibilité d'appliquer des filtres de métadonnées pour limiter les résultats (par exemple, recherche uniquement dans une catégorie ou une période spécifique).</p></li><li><p>Renvoie des résultats structurés comprenant l'identifiant du document, le score de similarité et les métadonnées stockées.</p></li></ul><h2>Création de l'agent de connaissance</h2><p>Maintenant que nous avons vu la connexion entre Mastra et Elasticsearch à travers l'intégration <code>ElasticVector</code>, créons l'agent de connaissance lui-même.</p><p>Dans le dossier <code>agents</code>, créez un fichier appelé <code>knowledge-agent.ts</code>. Nous pouvons commencer par connecter nos variables d'environnement et initialiser le client Elasticsearch.</p>import { Agent } from '@mastra/core/agent';
import { Memory } from '@mastra/memory';
import { openai } from '@ai-sdk/openai';
import { Client } from '@elastic/elasticsearch';
import { ElasticVector } from '../stores/elastic-store';
import dotenv from "dotenv";

dotenv.config();

const ELASTICSEARCH_ENDPOINT = process.env.ELASTICSEARCH_ENDPOINT;
const ELASTICSEARCH_API_KEY = process.env.ELASTICSEARCH_API_KEY;

//Error check for undefined credentials
if (!ELASTICSEARCH_ENDPOINT || !ELASTICSEARCH_API_KEY) {
  throw new Error('Missing Elasticsearch credentials');
}

//Check to see if a connection can be established
const testClient = new Client({
  node: ELASTICSEARCH_ENDPOINT,
  auth: { 
    apiKey: ELASTICSEARCH_API_KEY 
  },
});

try {
  await testClient.ping();
  console.log('Connected to Elasticsearch successfully');
} catch (error: unknown) {
  if (error instanceof Error) {
    console.error('Failed to connect to Elasticsearch:', error.message);
  } else {
    console.error('Failed to connect to Elasticsearch:', error);
  }
  process.exit(1);
}
//Initialize the Elasticsearch vector store
const vectorStore = new ElasticVector({
  node: ELASTICSEARCH_ENDPOINT,
  auth: {
    apiKey: ELASTICSEARCH_API_KEY,
  },
//Optional: Explicitly set to true if using Elasticsearch Serverless to skip auto-detection and improve startup time
//isServerless: true,
});<p>Ici, nous :</p><ul><li><p>Utilisez <code>dotenv</code> pour charger nos variables à partir de notre fichier <code>.env</code>.</p></li><li><p>Vérifiez que les informations d'identification Elasticsearch sont injectées correctement et que nous pouvons établir une connexion réussie avec le client.</p></li><li><p>Passez le point de terminaison Elasticsearch et la clé API dans le constructeur <code>ElasticVector</code> pour créer une instance de notre magasin vectoriel que nous avons défini plus tôt.</p></li><li><p>Spécifiez éventuellement <code>isServerless: true</code> si vous utilisez Elasticsearch Serverless. Cela permet d'éviter l'étape d'autodétection et d'améliorer le temps de démarrage. S'il est omis, l'adaptateur détectera automatiquement votre type de déploiement lors de la première utilisation.</p></li></ul><p>Ensuite, nous pouvons définir l'agent à l'aide de la classe <code>Agent</code> de Mastra.</p>export const knowledgeAgent = new Agent({
    name: 'KnowledgeAgent',
    instructions: 'You are a helpful knowledge assistant.',
    model: openai('gpt-4o'),
    memory: new Memory({

        vector: vectorStore,

        //embedder used to create embeddings for each message
        embedder: 'openai/text-embedding-3-small',

        //set semantic recall options
        options: {
            semanticRecall: {
                topK: 3, // retrieve 3 similar messages
                messageRange: 2, // include 2 messages before/after each match
                scope: 'resource',
            },
        },
    }),
});<p>Les champs que nous pouvons définir sont les suivants :</p><ul><li><p><code>name</code> et <code>instructions</code>: lui donner une identité et une fonction première.</p></li><li><p><code>model</code>: Nous utilisons <code>gpt-4o</code> d'OpenAI à travers le paquet <code>@ai-sdk/openai</code>.</p></li><li><p><code>memory</code>:</p><ul><li><p><code>vector</code>: Pointe vers notre magasin Elasticsearch, de sorte que les embeddings sont stockés et récupérés à partir de ce magasin.</p></li><li><p><code>embedder</code>: Quel modèle utiliser pour générer des embeddings ?</p></li><li><p><code>semanticRecall</code> décident de la manière dont le rappel fonctionne :</p><ul><li><p><code>topK</code>: Nombre de messages sémantiquement similaires à récupérer.</p></li><li><p><code>messageRange</code>: Quelle partie de la conversation doit être incluse dans chaque match.</p></li><li><p><code>scope</code>: Définit la limite de la mémoire.</p></li></ul></li></ul></li></ul><p>Presque terminé. Il ne nous reste plus qu'à ajouter cet agent nouvellement créé à notre configuration Mastra. Dans le fichier appelé <a href="http://index.ts/"><code>index.ts</code></a>, importez l'agent de connaissance et insérez-le dans le champ <code>agents</code>.</p>export const mastra = new Mastra({
  agents: { knowledgeAgent },
  storage: new LibSQLStore({
    // stores observability, scores, ... into memory storage, if it needs to persist, change to file:../mastra.db
    url: ":memory:",
  }),
  logger: new PinoLogger({
    name: 'Mastra',
    level: 'info',
  }),
  telemetry: {
    // Telemetry is deprecated and will be removed in the Nov 4th release
    enabled: false, 
  },
  observability: {
    // Enables DefaultExporter and CloudExporter for AI tracing
    default: { enabled: true }, 
  },
});<p>Les autres champs sont les suivants :</p><ul><li><p><code>storage</code>: Il s'agit du magasin de données interne de Mastra pour l'historique des exécutions, les mesures d'observabilité, les scores et les caches. Pour plus d'informations sur le stockage Mastra, <a href="https://mastra.ai/docs/server-db/storage">cliquez ici.</a></p></li><li><p><code>logger</code>: Mastra utilise <a href="https://github.com/pinojs/pino">Pino</a>, qui est un enregistreur JSON structuré et léger. Il capture des événements tels que le démarrage et l'arrêt de l'agent, les appels d'outils et les résultats, les erreurs et les temps de réponse du LLM.</p></li><li><p><code>observability</code>: Contrôle le suivi de l'IA et la visibilité de l'exécution pour les agents. Il suit :</p><ul><li><p>Début/fin de chaque étape du raisonnement.</p></li><li><p>Quel modèle ou outil a été utilisé.</p></li><li><p>Entrées et sorties.</p></li><li><p>Notes et évaluations</p></li></ul></li></ul><h3>Test de l'agent avec Mastra Studio</h3><p>Félicitations ! Si vous êtes arrivé jusqu'ici, vous êtes prêt à faire fonctionner cet agent et à tester ses capacités de rappel sémantique. Heureusement, Mastra fournit une interface de chat intégrée, ce qui nous évite d'avoir à créer notre propre interface.</p><p>Pour démarrer le serveur de développement Mastra, ouvrez un terminal et exécutez la commande suivante :</p>npm run dev<p>Après le regroupement initial et le démarrage du serveur, celui-ci devrait vous fournir une adresse pour le terrain de jeu.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5f857fddc74ffc9/6a16f7b6a6c2b995d5e794c0/8b045f70008d26aec4d2e6b59d61085555b9c5b2-686x116.png" alt="Adresse du serveur pour Playground" /><p>Collez cette adresse dans votre navigateur et vous serez accueilli par le Mastra Studio.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7fdda6ce46ce068/6a16f7b7b0367d4f7672bacf/69bc80fe8486edd9e0cf91d87b39f465aeb23111-1600x438.png" alt="Coller l'adresse du terrain de jeu pour accéder à Mastra Studio" /><p>Sélectionnez l'option <code>knowledgeAgent</code> et discutez.</p><p>Pour vérifier rapidement si tout est bien branché, donnez-lui des informations telles que : "L'équipe a annoncé que les ventes d'octobre ont augmenté de 12%, principalement grâce aux renouvellements de contrats d'entreprise. La prochaine étape consistera à élargir le champ d'action aux clients du marché intermédiaire". Ensuite, démarrez un nouveau chat et posez une question du type : "Sur quel segment de clientèle avons-nous dit que nous devions nous concentrer ensuite ?". L'agent de connaissance doit pouvoir se souvenir des informations que vous lui avez communiquées lors de la première conversation. Vous devriez obtenir une réponse du type</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfec3266e81a7213b/6a16f7b92b835f6f70f4afe2/da8ebddad89874023ed440a8f1ad2cb04ed043f4-1070x288.png" alt="Chat avec un agent de connaissance dans Mastra Studio- l'agent peut rappeler des informations" /><p>Une telle réponse signifie que l'agent a stocké avec succès notre message précédent sous forme d'éléments intégrés dans Elasticsearch et qu'il l'a récupéré ultérieurement à l'aide d'une recherche vectorielle.</p><h3>Inspection de la mémoire à long terme de l'agent</h3><p>Rendez-vous sur l'onglet <code>memory</code> dans la configuration de votre agent dans le Studio Mastra. Cela vous permet de voir ce que votre agent a appris au fil du temps. Chaque message, réponse et interaction qui est intégré et stocké dans Elasticsearch fait partie de cette mémoire à long terme. Vous pouvez effectuer une recherche sémantique dans les interactions passées pour retrouver rapidement les informations ou le contexte que l'agent a appris précédemment. Il s'agit essentiellement du même mécanisme que celui utilisé par l'agent lors du rappel sémantique, mais ici, vous pouvez l'inspecter directement. Dans l'exemple ci-dessous, nous recherchons le terme "ventes" et nous obtenons en retour toutes les interactions qui contiennent un élément relatif aux ventes.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte428134d7bf2a43a/6a16f7bbb0367d185872bad3/3decaa0c332d288c5ae0b11c25f592c7d50c2f0f-1104x1320.png" alt="Comment inspecter les agents de connaissance stockés dans la mémoire à long terme" /><h2>Conclusion</h2><p>En connectant Mastra et Elasticsearch, nous pouvons donner à nos agents de la mémoire, qui est une couche clé dans l'ingénierie contextuelle. Grâce au rappel sémantique, les agents peuvent construire un contexte au fil du temps, en fondant leurs réponses sur ce qu'ils ont appris. Cela signifie des interactions plus précises, plus fiables et plus naturelles.</p><p>Cette intégration précoce n'est que le point de départ. Le même modèle peut permettre aux agents d'assistance de se souvenir des tickets précédents, aux robots internes de retrouver la documentation pertinente ou aux assistants d'IA de se souvenir des détails d'un client au cours d'une conversation. Nous travaillons également à l'intégration officielle de Mastra, afin de rendre cette association encore plus transparente dans un avenir proche.</p><p>Nous sommes impatients de voir ce que vous allez construire. Essayez-le, explorez <a href="https://mastra.ai/">Mastra</a> et ses fonctions de mémoire, et n'hésitez pas à partager vos découvertes avec la communauté.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/knowledge-agent-semantic-recall-mastra-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/knowledge-agent-semantic-recall-mastra-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Expérience développeur]]></category>
    <category><![CDATA[Intégrations]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt09afdbff05603865/6a16f7bd839dfabbf2dcfcb5/b8d51c2726d5573385c9246a7821d12ade4f1b0e-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment afficher les champs d'un index Elasticsearch ?]]></title>
    <description><![CDATA[Apprenez à afficher les champs d'un index Elasticsearch à l'aide des API _mapping et _search, des sous-champs, de la _source synthétique et des champs d'exécution.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous verrons comment afficher les champs d'un index Elasticsearch. Cela peut être utile pour comprendre la structure de vos données, identifier des champs spécifiques et résoudre des problèmes. Nous aborderons les sujets suivants :</p><ol><li><p>Utilisation de l'API <code>_mapping</code> pour récupérer des informations sur les champs</p></li><li><p>Utilisation de l'API <code>_search</code> pour afficher les valeurs des champs</p></li><li><p>Affichage des sous-champs</p></li><li><p>Synthetic _source</p></li><li><p>Champs d'exécution</p></li></ol><h2>1. Utilisation de l'API _mapping pour récupérer des informations sur les champs</h2><p>L'API <code>_mapping</code> vous permet de récupérer la définition du mappage pour un ou plusieurs index. Il s'agit d'informations sur les champs, leurs types de données et d'autres propriétés. Pour récupérer le mappage d'un index spécifique, utilisez la requête suivante :</p>GET /&lt;index_name&gt;/_mapping<p>Par exemple, si vous avez un index nommé <code>my_index</code>, vous pouvez récupérer son mapping avec la requête suivante :</p>GET /my_index/_mapping<p>La réponse comprendra la définition du mappage pour l'index, qui contient des informations sur les champs et leurs propriétés.</p><p>Il est également possible de récupérer la cartographie d'un champ spécifique. Cela peut s'avérer utile si votre cartographie est assez vaste et que vous souhaitez vous concentrer sur un domaine spécifique. Pour récupérer la correspondance d'un champ spécifique, utilisez la requête suivante :</p>GET /my_index/_mapping/field/my_field<p>Vous pouvez également récupérer les correspondances de plusieurs champs en séparant leurs noms par des virgules, comme dans la requête suivante :</p>GET /my_index/_mapping/field/my_field_1,my_field_2,my_field_3<h2>2. Utilisation de l'API _search pour afficher les valeurs des champs</h2><p>Pour afficher les valeurs des champs d'un index Elasticsearch, vous pouvez utiliser l'API <code>_search</code>. L'API <code>_search</code> vous offre plusieurs moyens de contrôler les champs renvoyés ; les deux principaux sont les suivants :</p><ol><li><p><strong><code>_source</code></strong>: Le champ <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field"><code>_source</code></a> contient le corps du document JSON original tel qu'il a été indexé, y compris les modifications apportées par les pipelines d'ingestion ou les étapes de prétraitement. Pour afficher des champs spécifiques du document source, il faut mettre en œuvre le filtrage de la source, comme nous le verrons ci-dessous.</p></li><li><p><strong><code>fields</code></strong>: Le paramètre <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields"><code>fields</code></a> vous permet d'extraire des champs spécifiques de vos documents lors d'une recherche, sur la base du mappage de l'index. Contrairement à <code>_source</code>, <code>fields</code> peut également renvoyer des valeurs provenant de champs stockés, de valeurs documentaires ou de champs d'exécution sans faire référence à <code>_source</code>, bien que pour les champs standard sans valeurs documentaires ou paramètres stockés, il se réfère à <code>_source</code>. Cela peut apporter de nombreux avantages, notamment en termes de performances, comme nous le verrons ci-dessous.</p></li></ol><h3>Utilisation du champ _source</h3><p>Par défaut, l'API<code> _search</code> renvoie le champ <code>_source</code>, qui contient le document JSON original qui a été indexé. Pour afficher des champs spécifiques, vous pouvez ajouter des filtres dans le paramètre <code>_source </code>de la demande de recherche ; c'est ce qu'on appelle le filtrage à la source.</p><p>Voici un exemple de demande de recherche qui renvoie les valeurs des champs <code>title </code>et <code>author</code> pour les documents de l'index <code>my_index</code>:</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["title", "author"]
}<p>Dans cet exemple, le paramètre <code>_source</code> spécifie les champs à renvoyer.</p><p>Si vous avez besoin d'encore plus de contrôle, vous pouvez utiliser les propriétés <code>includes</code> et <code>excludes </code>de l'objet <code>_source</code>. Par exemple, la requête ci-dessous renvoie le champ de premier niveau <code>title</code> et tous les sous-champs de <code>author</code> à l'exception de <code>author.description</code>.</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "_source": {
     “includes”: [“title”, “author.*],
     “excludes”: [“author.description”]
  }
}<p>Dans cet exemple, nous utilisons le modèle <code>author.* </code>pour récupérer tous les sous-champs directs de l'objet <code>author </code>. Nous excluons ensuite explicitement <code>author.description </code>afin que seuls les autres champs relatifs à l'auteur soient renvoyés. Notez que cela n'améliore pas les performances, puisqu'il faut toujours charger et analyser la source JSON, mais cela permet de réduire la taille de la réponse envoyée sur le réseau.</p><h3>Utilisation du paramètre champs</h3><p>Vous pouvez utiliser le paramètre <code>fields</code> pour filtrer les champs renvoyés dans la réponse de recherche. L'utilisation de <code>fields</code> par rapport à <code>_source</code> présente plusieurs avantages, notamment</p><ul><li><p><strong>Amélioration des performances : </strong><code>fields </code>peut renvoyer des valeurs directement à partir de <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-store">champs stockés</a> ou de <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/doc-values">valeurs de documents</a> sans avoir à charger l'intégralité du site <code>_source</code>, ce qui réduit la taille de la charge utile de la réponse.</p></li><li><p><strong>Sortie formatée :</strong> Pour les champs standard,<code> fields</code> peut se référer à <code>_source</code> pour récupérer les valeurs, mais il s'appuie sur le mappage de l'index pour formater correctement la sortie, comme les dates formatées, afin de les rendre cohérentes avec ce qui est utilisé pour les agrégations et les tris.</p></li><li><p><strong>Accès aux champs d'exécution :</strong> <code>fields</code> peut renvoyer des champs d'exécution qui n'existent pas sur le site original <code>_source</code>.</p></li><li><p>D'autres avantages peuvent être trouvés <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields#search-fields-param">ici.</a></p></li></ul><p>Par exemple, pour obtenir uniquement les champs <code>title</code> et <code>author</code> dans l'index <code>my_index</code>, vous pouvez utiliser la requête de recherche suivante :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author"],
  "_source": false
}<p>Dans la requête ci-dessus, nous attribuons la valeur false au champ <code>_source </code>afin de ne pas renvoyer le document source. Cela peut réduire considérablement la taille de la charge utile de la réponse, mais n'oubliez pas que cela ne fonctionne que si les champs <code>title</code> et <code>author</code> sont de type <code>keyword </code>, pour lesquels <code>doc_values</code> est activé par défaut. Si le champ n'a pas été activé par <code>doc_values</code> et que <code>_source</code> a été défini sur false, Elasticsearch n'aura aucun moyen de les récupérer et ils seront ignorés dans la réponse.</p><p>Il est important de noter que la réponse <code>fields</code> renvoie toujours un tableau de valeurs pour chaque champ, même s'il n'y a qu'une seule valeur. Cela est dû au fait qu'Elasticsearch n'a pas de type de tableau dédié, et que tout champ peut avoir plusieurs valeurs. Pour plus d'informations sur les tableaux dans Elasticsearch, cliquez <a href="http://elastic.co/docs/reference/elasticsearch/mapping-reference/array">ici.</a></p><h3>Autres moyens d'extraire des champs</h3><p>Bien que l'extraction de champs à l'aide de <code>_source</code> ou <code>fields</code> soit la méthode recommandée, il existe d'autres méthodes pour des cas d'utilisation spécifiques, comme par exemple :</p><p><strong>Champs de valeur du document :</strong> Si vous souhaitez éviter <code>_source</code>, vous pouvez effectuer une recherche en utilisant le paramètre <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrieve-selected-fields#docvalue-fields"><code>docvalue_fields</code></a> . Doc values stocke les mêmes valeurs de champ que <code>_source</code> mais dans une structure de données sur disque, optimisée pour les tris et les agrégations.</p><p>Comme il s'agit d'une valeur distincte des valeurs stockées sur <code>_source</code>, vous pouvez demander des champs spécifiques sans avoir à charger l'ensemble du site <code>_source</code>. Cette option est utile si vous interrogez des documents volumineux, mais que vous n'avez besoin que de quelques petits champs prenant en charge des valeurs de documents. Un autre cas d'utilisation de <code>docvalue_fields </code>est celui où vous souhaitez utiliser un formatage personnalisé pour les champs <code>date</code> et <code>numeric</code>, comme nous le verrons dans l'exemple ci-dessous.</p><p>Notez que cela ne fonctionne que pour les champs pour lesquels vous avez activé <code>doc_values</code> ou pour les types de champs pour lesquels cette option est activée par défaut, tels que <code>keyword</code>, <code>date</code>, les types numériques et <code>boolean</code>, et non pour <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/text"><code>text</code></a> ou <a href="https://www.elastic.co/docs/reference/elasticsearch/plugins/mapper-annotated-text-usage"><code>annotated_text</code></a>.</p><p>Dans cet exemple, nous utilisons le paramètre <code>docvalue_fields</code> pour récupérer les champs <code>title</code>, <code>author</code> et <code>published</code> sans charger le document <code>_source</code> complet :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "docvalue_fields": [
    "title",
    "author",
    {
      "field": "published",
      "format": "epoch_millis"
    }
  ],
  "_source": false
}<p>Lorsque cette requête est exécutée, Elasticsearch récupère les valeurs directement à partir de son magasin en colonnes sur disque au lieu de référencer le site <code>_source </code>pour chaque document. Le champ <code>published</code> est retourné avec le format <code>epoch_millis</code> au lieu du format par défaut, grâce au paramètre <code>format</code> fourni dans la requête.</p><p><strong>Champs stockés :</strong> Si vous avez explicitement marqué des champs spécifiques comme étant <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-store">stockés</a> dans le mappage, vous pouvez utiliser le paramètre <code>stored_fields</code> pour filtrer ces champs. C'est utile si vous voulez des réponses légères avec seulement ces champs spécifiques ou pour les champs que vous avez délibérément stockés pour les retrouver plus tard. Il est stocké séparément de <code>_source</code>, de sorte que cette méthode est également utile pour éviter de devoir charger <code>_source</code>.</p><p>Il est important de noter que cette option est désactivée par défaut et qu'elle n'est généralement pas recommandée. Utilisez plutôt le filtrage des sources pour renvoyer certains sous-ensembles du document source original.</p><p>Dans l'exemple de requête ci-dessous, nous utilisons le paramètre <code>stored_fields</code> pour récupérer le champ <code>summary</code>, dont la configuration de mappage d'index est "<code>store”: true</code>.</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "stored_fields": ["summary"]
}<p>Lorsque cette requête est exécutée, Elasticsearch vérifie si ce champ a été marqué par <code>”store”: true</code>, s'il ne le trouve pas, il l'ignore complètement.</p><h2>3. Affichage des sous-champs</h2><p>Si votre index contient des sous-champs, vous pouvez utiliser la notation point pour spécifier le chemin d'accès au champ dans le paramètre <code>fields</code>. Notez que les sous-champs sont différents du <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/nested">type de champ imbriqué</a>. Par exemple, si vous avez un sous-champ nommé <code>address.city</code>, vous pouvez l'inclure dans la réponse de recherche comme suit :</p>GET /my_index/_search
{
  "query": {
    "match_all": {}
  },
  "fields": ["title", "author", "address.city"],
  "_source": false
}<p>Dans cet exemple, la réponse de la recherche comprendra les valeurs des champs <code>title</code>, <code>author</code> et <code>address.city</code>.</p><h2>4. Synthétique _source</h2><p>Si vous souhaitez conserver la fonctionnalité de<code> _source</code> tout en économisant de l'espace disque, vous avez la possibilité d'utiliser le site synthétique <code>_source</code> dans votre mappage d'index. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field#synthetic-source">Synthetic </a><a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-source-field#synthetic-source"><code>_source</code></a> est une fonctionnalité qui permet à Elasticsearch de reconstruire <code>_source</code> à partir de données existantes telles que des champs stockés et des valeurs de documents, même lorsque <code>_source</code> est désactivé. Cela vous permet d'économiser beaucoup d'espace de stockage au prix d'une vitesse légèrement inférieure au moment de l'interrogation, car la reconstruction se fait à la volée. Activez cette fonction en utilisant les valeurs ci-dessous dans vos paramètres d'index :</p>PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  }
}<p>Parmi les avantages de l'utilisation de la version synthétique de <code>_source </code>, citons : l'affichage complet du document lors de l'utilisation de l'API <code>_search</code>, le filtrage des sources et la compatibilité avec d'autres fonctionnalités et outils tels que Kibana qui s'attendent à ce que <code>_source</code> soit disponible, tout en évitant d'avoir à stocker le document <code>_source</code> dans son intégralité.</p><h2>5. Champs d'exécution</h2><p>Les champs <a href="https://www.elastic.co/docs/manage-data/data-store/mapping/runtime-fields">d'exécution</a> vous permettent de définir des champs scriptés au moment de la requête ou dans votre mappage d'index sous un bloc d'exécution. Ces champs ne sont jamais indexés, de sorte que l'ajout d'un champ d'exécution n'augmente pas la taille de l'index mais n'apparaîtra jamais dans <code>_source</code>. Les champs d'exécution définis dans le mappage sont persistants et disponibles pour toutes les requêtes, tandis que les champs d'exécution définis au moment de la requête sont temporaires et ne sont disponibles que dans cette requête de recherche.</p><p>Le principal avantage de l'utilisation des champs d'exécution est la possibilité d'ajouter des champs aux documents après les avoir ingérés, ce qui simplifie vos décisions en matière de mappage. Les champs d'exécution sont également très utiles pour enrichir vos documents avec des valeurs qui n'existent pas dans le document original mais qui sont générées à l'aide d'un script, comme le formatage d'une chaîne de caractères ou le calcul d'un score.</p><p>Il convient également de noter que les champs d'exécution peuvent nuire aux performances, car un script devra être exécuté pour chaque document de l'ensemble des résultats. Pour <a href="https://www.elastic.co/docs/manage-data/data-store/mapping/retrieve-runtime-field">récupérer un champ d'exécution</a>, vous pouvez également utiliser le paramètre <code>fields</code> de l'API <code>_search</code>.</p><h2>Conclusion</h2><p>L'affichage des champs d'un index Elasticsearch peut aller de la simple récupération des valeurs à l'aide du mappage d'index ou de <code>_source</code>, à des méthodes plus avancées utilisant <code>fields</code>, <code>docvalue_fields</code>, ou des champs d'exécution pour un meilleur contrôle et une plus grande efficacité. Il est essentiel de comprendre les compromis entre les différentes méthodes pour optimiser vos expériences de recherche. Qu'il s'agisse d'optimiser les charges utiles, d'enrichir des documents ou d'utiliser le site synthétique <code>_source</code> pour économiser de l'espace de stockage, Elasticsearch vous offre de nombreux outils et fonctionnalités pour trouver les données dont vous avez besoin, de la manière dont vous en avez besoin. Ces techniques peuvent vous aider à comprendre la structure de vos données, à identifier des champs spécifiques et à résoudre des problèmes.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-index-show-fields</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-index-show-fields</guid>
    <category><![CDATA[Indexer des données]]></category>
    <category><![CDATA[Mappings]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd041e871a8935448/6a17de320b0bedf404dd34ab/23b96aaa1a38b1f4747b4a87695d816f24c0cf70-720x421.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 06 Aug 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Construire un assistant agentique RAG avec JavaScript, Mastra et Elasticsearch]]></title>
    <description><![CDATA[Apprendre à construire des agents d'intelligence artificielle dans l'écosystème JavaScript]]></description>
    <content:encoded><![CDATA[<p>Cette idée m'est venue alors que je me trouvais au beau milieu d'une ligue de basket-ball fantastique passionnante et aux enjeux considérables. Je me suis posé la question : <em>Pourrais-je construire un agent IA qui m'aiderait à dominer mes matchs hebdomadaires ? Absolument !</em></p><p>Dans ce billet, nous allons voir comment construire un assistant RAG agentique en utilisant <a href="https://mastra.ai/en/docs">Mastra</a> et une application web JavaScript légère pour interagir avec lui. En connectant cet agent à Elasticsearch, nous lui donnons accès aux données structurées des joueurs et la possibilité d'exécuter des agrégations statistiques en temps réel, afin de vous donner des recommandations fondées sur les statistiques des joueurs. Rendez-vous sur le <a href="https://github.com/jdarmada/nba-ai-assistant-js.git">repo</a> GitHub pour suivre le processus ; le <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/README.md">README</a> fournit des instructions sur la manière de cloner et d'exécuter l'application par vos propres moyens. </p><p>Voici à quoi il devrait ressembler une fois assemblé :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt63ea3e7a09306fbf/6a17f1d97f6f150e22c09c50/1c73bd1dc1b5fe54f025c7a2b7c322acc9122f3a-1999x1393.png" alt="" /><p>Remarque : cet article de blog s'appuie sur "<a href="https://www.elastic.co/search-labs/blog/ai-agents-ai-sdk-elasticsearch">Building AI Agents with AI SDK and Elastic"</a> ( Créer des agents d'intelligence artificielle avec AI SDK et Elastic). Si vous ne connaissez pas encore les agents d'intelligence artificielle en général et leur utilité, commencez par là.
</p><h2><strong>Aperçu de l'architecture</strong></h2><p>Au cœur du système se trouve un grand modèle de langage (LLM), qui agit comme le moteur de raisonnement de l'agent (le cerveau). Il interprète les données de l'utilisateur, décide des outils à appeler et orchestre les étapes nécessaires pour générer une réponse pertinente.</p><p>L'agent lui-même est soutenu par Mastra, un cadre d'agent dans l'écosystème JavaScript. Mastra intègre le LLM à une infrastructure dorsale, l'expose en tant que point d'extrémité de l'API et fournit une interface pour définir les outils, les invites du système et le comportement de l'agent.</p><p>Sur le frontend, nous utilisons <a href="https://vite.dev/guide/">Vite</a> pour mettre en place rapidement une application web React qui fournit une interface de chat pour envoyer des requêtes à l'agent et recevoir ses réponses.</p><p>Enfin, nous avons Elasticsearch, qui stocke les statistiques des joueurs et les données de correspondance que l'agent peut interroger et agréger.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte13f09493f217047/6a17f1db1d1b83178d93e546/443bdc00d84ed1dd49e9f9e431e86ca4b0892563-1999x977.png" alt="" /><h2><strong>Arrière-plan</strong></h2><p>Passons en revue quelques concepts fondamentaux :</p><h3><strong>Qu'est-ce que le RAG agentique ?</strong></h3><p>Les agents d'intelligence artificielle peuvent interagir avec d'autres systèmes, fonctionner de manière indépendante et effectuer des actions en fonction de paramètres définis. Le RAG agentique combine l'autonomie d'un agent d'intelligence artificielle avec les principes de la génération augmentée par récupération, ce qui permet à un LLM de choisir les outils à utiliser et les données à utiliser comme contexte pour générer une réponse. Pour en savoir plus sur le RAG <a href="https://www.elastic.co/search-labs/blog/retrieval-augmented-generation-rag">, cliquez ici.</a></p><h3><strong>Pourquoi aller plus loin que AI-SDK dans le choix d'un framework ?</strong></h3><p>Il existe de nombreuses structures d'agents d'IA et vous avez probablement entendu parler des plus populaires comme <a href="https://www.elastic.co/search-labs/blog/using-crewai-with-elasticsearch">CrewAI</a>, <a href="https://www.elastic.co/search-labs/blog/using-autogen-with-elasticsearch">AutoGen</a> et <a href="https://www.elastic.co/search-labs/blog/build-rag-workflow-langgraph-elasticsearch">LangGraph</a>. La plupart de ces cadres partagent un ensemble commun de fonctionnalités, notamment la prise en charge de différents modèles, l'utilisation d'outils et la gestion de la mémoire.</p><p>Voici une <a href="https://docs.google.com/spreadsheets/d/1B37VxTBuGLeTSPVWtz7UMsCdtXrqV5hCjWkbHN8tfAo/edit?gid=0#gid=0">fiche comparative de</a> Harrison Chase (PDG de LangChain).</p><p>Ce qui a suscité mon intérêt pour Mastra, c'est qu'il s'agit d'un framework JavaScript conçu pour les développeurs full-stack afin d'intégrer facilement des agents dans leur écosystème. L'AI-SDK de Vercel permet également de réaliser la plupart de ces tâches, mais c'est lorsque vos projets incluent des flux de travail d'agents plus complexes que Mastra brille. Mastra améliore les modèles de base définis par l'AI-SDK et, dans ce projet, nous les utiliserons en tandem.</p><h3><strong>Cadres et considérations sur le choix du modèle</strong></h3><p>Si ces frameworks peuvent vous aider à créer rapidement des agents d'intelligence artificielle, ils présentent néanmoins certains inconvénients. Par exemple, l'utilisation d'autres cadres en dehors des agents d'IA ou de toute couche d'abstraction en général vous fait perdre un peu de contrôle. Si le LLM n'utilise pas les outils correctement ou fait quelque chose que vous ne voulez pas qu'il fasse, l'abstraction rend le débogage plus difficile. Cependant, à mon avis, ce compromis vaut la facilité et la rapidité que vous obtenez lors de la construction, en particulier parce que ces cadres gagnent du terrain et font l'objet d'itérations constantes.</p><p>Encore une fois, ces cadres sont agnostiques, ce qui signifie que vous pouvez brancher et utiliser différents modèles. N'oubliez pas que les modèles varient en fonction des ensembles de données sur lesquels ils ont été formés et qu'à leur tour, ils varient en fonction des réponses qu'ils donnent. Certains modèles ne prennent même pas en charge l'appel d'outils. Il est donc possible de changer et de tester différents modèles pour voir lequel vous donne les meilleures réponses, mais gardez à l'esprit que vous devrez probablement réécrire l'invite du système pour chacun d'entre eux. Par exemple, en utilisant Llama3.3 par rapport au GPT-4o, implique beaucoup plus d'invites et d'instructions spécifiques pour obtenir la réponse souhaitée.</p><h3><strong>Basket-ball fantaisie NBA</strong></h3><p>Le basket-ball fantaisie consiste à créer une ligue avec un groupe d'amis (attention, selon le degré de compétition de votre groupe, cela peut affecter le statut de vos amitiés), généralement avec de l'argent en jeu. Chacun d'entre vous constitue ensuite une équipe de 10 joueurs pour affronter les 10 joueurs d'un autre ami, en alternance chaque semaine. Les points qui contribuent à votre score global sont les résultats obtenus par chacun de vos joueurs contre leurs adversaires au cours d'une semaine donnée.</p><p>Si un joueur de votre équipe se blesse, est suspendu, etc., il y a une liste d'agents libres disponibles pour compléter votre équipe. C'est là qu'intervient une grande partie de la réflexion dans les sports fantastiques, car vous ne disposez que d'un nombre limité de choix et tout le monde est constamment à la recherche du meilleur joueur.</p><p>C'est là que notre assistant NBA AI va briller, en particulier dans les situations où vous devez rapidement décider quel joueur choisir. Au lieu de devoir rechercher manuellement les performances d'un joueur contre un adversaire spécifique, l'assistant peut trouver ces données rapidement et comparer les moyennes pour vous donner une recommandation éclairée.</p><p>Maintenant que vous connaissez les bases du RAG agentique et du basket-ball fantastique NBA, voyons ce qu'il en est dans la pratique.</p><h2><strong>Construire le projet</strong></h2><p>Si vous êtes bloqué à un moment ou à un autre ou si vous ne voulez pas le construire à partir de zéro, veuillez vous référer au <a href="https://github.com/jdarmada/nba-ai-assistant-js.git">repo</a>.</p><h3><strong>Ce que nous allons couvrir</strong></h3><ol><li><p><strong>L'échafaudage du projet :</strong></p><ol><li><p><strong>Backend (Mastra) :</strong> Utilisez npx create mastra@latest pour échafauder le backend et définir la logique de l'agent.</p></li><li><p><strong>Frontend (Vite + React) :</strong> Utilisez npm create vite@latest pour construire l'interface de chat frontale pour interagir avec l'agent.</p></li></ol></li><li><p><strong>Mise en place de variables d'environnement</strong></p><ol><li><p>Installer dotenv pour gérer les variables d'environnement.</p></li><li><p>Créer un fichier .env et fournir les variables nécessaires.</p></li></ol></li><li><p><strong>Configuration d'Elasticsearch</strong></p><ol><li><p>Mettre en place un cluster Elasticsearch (localement ou sur le cloud).</p></li><li><p>Installer le client Elasticsearch officiel.</p></li><li><p>S'assurer que les variables d'environnement sont accessibles.</p></li><li><p>Établir la connexion avec le client.</p></li></ol></li><li><p><strong>Acquisition en masse de données NBA dans Elasticsearch</strong></p><ol><li><p>Créez un index avec les mappings appropriés pour permettre les agrégations.</p></li><li><p>Intégrez en masse les statistiques de jeu des joueurs à partir d'un fichier CSV dans un index Elasticsearch.</p></li></ol></li><li><p><strong>Définir les agrégations Elasticsearch</strong></p><ol><li><p>Requête pour calculer les moyennes historiques contre un adversaire spécifique.</p></li><li><p>Requête pour calculer les moyennes de la saison contre un adversaire spécifique.</p></li></ol></li><li><p><strong>Fichier utilitaire de comparaison des joueurs</strong></p><ol><li><p>Consolidation des fonctions d'aide et des agrégations Elasticsearch.</p></li></ol></li><li><p><strong>Construction de l'agent</strong></p><ol><li><p>Ajouter la définition de l'agent et l'invite du système.</p></li><li><p>Installer les outils zod et define.</p></li><li><p>Ajout d'une configuration intermédiaire pour gérer CORS.</p></li></ol></li><li><p><strong>Intégration de l'interface utilisateur</strong></p><ol><li><p>Utilisation de la fonction useChat de l'AI-SDK pour interagir avec l'agent.</p></li><li><p>Créer l'interface utilisateur pour tenir des conversations correctement formatées.</p></li></ol></li><li><p><strong>Exécution de l'application</strong></p><ol><li><p>Démarrez le backend (serveur Mastra) et le frontend (application React).</p></li><li><p>Exemples de requêtes et d'utilisation.</p></li></ol></li><li><p><strong>Et maintenant ? Rendre l'agent plus intelligent</strong></p><ol><li><p>Ajout de capacités de recherche sémantique pour permettre des recommandations plus pertinentes.</p></li><li><p>Activer l'interrogation dynamique en déplaçant la logique de recherche vers le serveur Elasticsearch MCP (Model Context Protocol).</p></li></ol></li></ol><h3><strong>Produits requis</strong></h3><ul><li><p><strong>Node.js et npm</strong>: Le backend et le frontend fonctionnent tous deux sur Node. Assurez-vous d'avoir installé Node 18+ et npm v9+ (qui est fourni avec Node 18+).</p></li><li><p><strong>Cluster Elasticsearch :</strong> Un cluster Elasticsearch actif, soit localement, soit sur le cloud.</p></li><li><p><strong>Clé API OpenAI</strong>: Générez-en une sur la page des clés API du <a href="https://platform.openai.com/api-keys">portail des développeurs d'OpenAI</a>.</p></li></ul><p></p><h3><strong>Structure du projet</strong></h3><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt749baa120552e4ab/6a17f1dd1d1b83bfe993e54a/1c0bde11ad0eead523a95e03b9b905aa776e3fd1-1420x934.png" alt="" /><h4><strong>Étape 1 : Échafaudage du projet</strong></h4><ol><li><p>Tout d'abord, créez le répertoire nba-ai-assistant-js et naviguez à l'intérieur en utilisant : </p></li></ol>mkdir nba-ai-assistant-js &amp;&amp; cd nba-ai-assistant-js<p><strong>Backend :</strong></p><ol><li><p>Utilisez l'outil de création Mastra avec la commande : </p></li></ol>npx create-mastra@latest<p>2. Vous devriez obtenir quelques invites dans votre terminal, pour la première, nous nommerons le projet backend :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt65abf68fe588e968/6a17f1de63baff2814741d5b/de2725031ed6837db99a979efcdd0ece1e197dbb-608x84.png" alt="" /><p>3. Ensuite, nous conserverons la structure par défaut pour le stockage des fichiers Mastra, en saisissant <code>src/</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt89bd829fcf0ae6b9/6a17f1e04b055dd30e432302/88919d9ff1852126395e1fcd700ecb1b59aac63c-866x116.png" alt="" /><p>4. Ensuite, nous choisirons OpenAI comme fournisseur LLM par défaut.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfd167cc77a40b9a8/6a17f1e11480099e29b48863/2328761e769f3ded134e5a21e8a0bf8f41e88f68-404x210.png" alt="" /><p>5. Enfin, il vous demandera votre clé API OpenAI. Pour l'instant, nous choisirons d'ignorer l'option et nous la fournirons plus tard dans un fichier<code> .env</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt12654151ed495370/6a17f1e22f4a5c0f84fa89f9/0662de9bd28758e377e4c63df8d08b479068ce63-444x120.png" alt="" /><p><strong>Frontend :</strong></p><ol><li><p>Naviguez à nouveau vers le répertoire racine et exécutez l'<a href="https://vite.dev/guide/">outil de création Vite</a> à l'aide de cette commande : <code>npm create vite@latest frontend -- --template react</code></p></li></ol><p>Cela devrait créer une application React légère nommée <code>frontend</code> avec un modèle spécifique pour React.</p><p>Si tout se passe bien, à l'intérieur de votre répertoire de projet, vous devriez trouver un répertoire backend qui contient le code Mastra et un répertoire <code>frontend</code> avec votre application React.</p><p></p><h4><strong>Étape 2 : Configuration des variables d'environnement</strong></h4><ol><li><p>Pour gérer les clés sensibles, nous utiliserons le paquetage <code>dotenv</code> pour charger nos variables d'environnement à partir du fichier .env. fichier. Naviguez vers le répertoire backend et installez <code>dotenv</code>:</p></li></ol>cd backend
npm install dotenv --save<p>2. Dans le répertoire du backend, un fichier example.env est fourni avec les variables appropriées à remplir. Si vous créez le vôtre, veillez à inclure les variables suivantes :</p># OpenAI Configuration
OPENAI_API_KEY=your_openai_api_key_here

# Elasticsearch Configuration
ELASTIC_ENDPOINT=your_elasticsearch_endpoint_here
ELASTIC_API_KEY=your_elasticsearch_api_key_here
<p></p><p>Note : Assurez-vous que ce fichier est exclu de votre contrôle de version en ajoutant <code>.env</code> à <code>.gitignore</code>.</p><h4><strong>Étape 3 : Configuration d'Elasticsearch</strong></h4><p>Tout d'abord, vous devez disposer d'un cluster Elasticsearch actif. Deux options sont possibles :</p><ul><li><p><strong>Option A : utiliser Elasticsearch Cloud</strong></p><ul><li><p>S'inscrire à <a href="https://cloud.elastic.co/registration">Elastic Cloud</a></p></li><li><p>Créer un nouveau déploiement</p></li><li><p>Obtenez l'URL de votre point de terminaison et la clé API (encodée)</p></li></ul></li><li><p><strong>Option B : Exécuter Elasticsearch localement</strong></p><ul><li><p>Installer et exécuter Elasticsearch localement</p></li><li><p>Utilisez http://localhost:9200 comme point d'arrivée</p></li><li><p>Générer une clé API</p></li></ul></li></ul><p></p><p><strong>Installation du client Elasticsearch sur le backend :</strong></p><ol><li><p>Tout d'abord, installez le client Elasticsearch officiel dans votre répertoire backend :</p></li></ol>npm install @elastic/elasticsearch<p>2. Créez ensuite un répertoire lib pour contenir les fonctions réutilisables et naviguez-y :</p>mkdir lib &amp;&amp; cd lib<p>3. À l'intérieur, créez un nouveau fichier appelé <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/lib/elasticClient.js">elasticClient.js</a>. Ce fichier initialise le client Elasticsearch et l'expose pour qu'il soit utilisé dans votre projet.</p><p>4. Comme nous utilisons des modules ECMAScript (ESM), le nom de fichier __dirname and __n'est pas disponible. Pour vous assurer que vos variables d'environnement sont correctement chargées à partir du fichier .env dans le dossier backend, ajoutez cette configuration au début de votre fichier :</p>import { config } from 'dotenv';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { Client } from '@elastic/elasticsearch';

// Grab current directory and load .env from backend folder
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const envPath = join(__dirname, '../.env');

// Load environment variables from the correct path
config({ path: envPath });<p>5. Maintenant, initialisez le client Elasticsearch en utilisant vos variables d'environnement et vérifiez la connexion :</p>//Elastic client Initialization, make sure environment variables are being loaded in correctly
const config= {
    node: `${process.env.ELASTIC_ENDPOINT}`,
    auth: {
        apiKey: `${process.env.ELASTIC_API_KEY}`,
    },
};

export const elasticClient = new Client(config);

//Check if the client is connected
async function checkConnection() { 
    try {
        const info = await elasticClient.info();
        console.log('Elasticsearch is connected:', info);
    } catch (error) {
        console.error('Elasticsearch connection error:', error);
    }
}

checkConnection();
<p>Maintenant, nous pouvons importer cette instance client dans n'importe quel fichier qui doit interagir avec votre cluster Elasticsearch.</p><p></p><h4><strong>Étape 4 : Intégration en masse des données NBA dans Elasticsearch</strong></h4><p><strong>Ensemble de données :</strong></p><p>Pour ce projet, nous ferons référence aux ensembles de données disponibles dans le répertoire <a href="https://github.com/jdarmada/nba-ai-assistant-js/tree/main/backend">backend/data</a> de la base de données. Notre assistant NBA utilisera ces données comme base de connaissances pour effectuer des comparaisons statistiques et générer des recommandations.</p><ul><li><p><a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/data/sample_nba_data.csv">sample_player_game_stats.csv</a> - Exemple de statistiques de jeu d'un joueur (par exemple, points, rebonds, interceptions, etc.) par match et par joueur sur l'ensemble de sa carrière en NBA. Nous utiliserons cet ensemble de données pour effectuer des agrégations. (Remarque : il s'agit de données fictives, générées à des fins de démonstration et ne provenant pas de sources officielles de la NBA).</p></li><li><p><a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/data/playerAndTeamInfo.js">playerAndTeamInfo.js</a> - Remplace les métadonnées sur les joueurs et les équipes qui seraient normalement fournies par un appel à l'API afin que l'agent puisse faire correspondre les noms des joueurs et des équipes aux identifiants. Comme nous utilisons des données d'échantillon, nous ne voulons pas nous encombrer d'une API externe, c'est pourquoi nous avons codé en dur certaines valeurs auxquelles l'agent peut se référer.</p></li></ul><p></p><p><strong>Mise en œuvre :</strong></p><ol><li><p>Dans le répertoire <code>backend/lib</code>, créez un fichier nommé <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/lib/playerDataIngestion.js">playerDataIngestion.js</a>.</p></li><li><p>Configurer les importations, résoudre le chemin du fichier CSV et configurer l'analyse. Là encore, puisque nous utilisons ESM, nous devons reconstruire <code>__dirname</code> pour résoudre le chemin d'accès à l'échantillon CSV. Nous importerons également le module <a href="http://node.js/">Node.js</a> les modules intégrés, <code>fs</code> et <code>readline</code>, pour analyser le fichier CSV donné ligne par ligne.</p></li></ol>import fs from 'fs';
import readline from 'readline';
import path from 'path';
import { fileURLToPath } from 'url';
import { elasticClient } from './elasticClient.js';

const indexName = 'sample-nba-player-data'; //Replace with your preferred index name

//Since we are using ES modules __dirname and __filename don't exist, so this is a workaround that allows us to use the absolute file path for our sample data.
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const filePath = path.resolve(__dirname, '../data/sample_nba_data.csv');<p>Cela vous permet de lire et d'analyser efficacement le fichier CSV lorsque nous passons à l'étape de l'ingestion en masse.</p><p>3. Créez un index avec la correspondance appropriée. Bien qu'Elasticsearch puisse déduire automatiquement les types de champs avec le <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dynamic">mappage dynamique</a>, nous voulons être explicites ici pour que chaque statut soit traité comme un champ numérique. Ceci est important car nous utiliserons ces champs pour les agrégations par la suite. Nous voulons également utiliser le type <code>float </code>pour les statistiques telles que les points, les rebonds, etc., afin de nous assurer que nous incluons des valeurs décimales. Enfin, nous voulons ajouter la propriété de mappage <code>dynamic: 'strict'</code> afin qu'Elasticsearch ne mappe pas dynamiquement les champs non reconnus. 
</p>// Function to create an index with mappings
async function createIndex() {
    try {
        // Check if the index already exists
        const exists = await elasticClient.indices.exists({ index: indexName });

        if (exists) {
            console.log(`Index "${indexName}" already exists, deleting it now.`);
            await elasticClient.indices.delete({ index: indexName });
            console.log(`Deleted index "${indexName}".`);
        }
        // Create the index with mappings
        const response = await elasticClient.indices.create({
            index: indexName,
            body: {
                mappings: {
                    dynamic: 'strict', // Prevent dynamic mapping
                    properties: {
                        game_id: { type: 'integer' },
                        game_date: { type: 'date' },
                        player_id: { type: 'integer' },
                        player_full_name: { type: 'text' },
                        player_team_id: { type: 'integer' },
                        player_team_name: { type: 'text' },
                        home_team: { type: 'boolean' },
                        opponent_team_id: { type: 'integer' },
                        opponent_team_name: { type: 'text' },
                        points: { type: 'float' },
                        rebounds: { type: 'float' },
                        assists: { type: 'float' },
                        steals: { type: 'float' },
                        blocks: { type: 'float' },
                        fg_percentage: { type: 'float' },
                        minutes_played: { type: 'float' },
                    },
                },
            },
        });

        console.log('Index created:', response);
        return true;
    } catch (error) {
        console.error('Error creating index:', error);
        return false;
    }
}
<p>4. Ajoutez la fonction permettant d'intégrer en masse les données CSV dans votre index Elasticsearch. À l'intérieur du bloc de code, nous sautons la ligne d'en-tête. Ensuite, divisez chaque ligne par une virgule et insérez-les dans l'objet document. Cette étape permet également de les nettoyer et de s'assurer qu'ils sont du bon type. Ensuite, nous plaçons les documents dans le tableau bulkBody avec les informations d'index, qui serviront de charge utile pour l'ingestion en masse dans Elasticsearch.</p>async function bulkIngestCsv(filePath) {
    const readStream = fs.createReadStream(filePath);
    const rl = readline.createInterface({
        input: readStream,
        crlfDelay: Infinity,
    });

    const bulkBody = [];
    let lineNum = 0;

    //Skip the header line
    let headerLine = true;
    for await (const line of rl) {
        if (headerLine) {
            headerLine = false;
            continue;
        }
        lineNum++;

        // Split the line by comma and remove whitespace
        const [
            game_id,
            game_date,
            player_id,
            player_full_name,
            player_team_id,
            player_team_name,
            home_team,
            opponent_team_id,
            opponent_team_name,
            points,
            rebounds,
            assists,
            steals,
            blocks,
            fg_percentage,
            minutes_played,
        ] = line.split(',');

        // Create a document object
        const document = {
            game_id: parseInt(game_id),
            game_date: game_date.trim(),
            player_id: parseInt(player_id),
            player_full_name: player_full_name.trim(),
            player_team_id: parseInt(player_team_id),
            player_team_name: player_team_name.trim(),
            home_team: home_team.trim() === 'True', // Converts True/False into a boolean
            opponent_team_id: parseInt(opponent_team_id),
            opponent_team_name: opponent_team_name.trim(),
            points: parseFloat(points),
            rebounds: parseFloat(rebounds),
            assists: parseFloat(assists),
            steals: parseFloat(steals),
            blocks: parseFloat(blocks),
            fg_percentage: parseFloat(fg_percentage),
            minutes_played: parseFloat(minutes_played),
        };

        // Prepare the bulk operation format
        bulkBody.push({ index: { _index: indexName } });
        bulkBody.push(document);
    }

    console.log(`Parsed ${lineNum} lines from CSV`);
<p>5. Ensuite, nous pouvons utiliser l'<a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk">API Bulk</a> d'Elasticsearch avec <code>elasticClient.bulk()</code> pour ingérer plusieurs documents en une seule demande. La gestion des erreurs ci-dessous est structurée de manière à vous indiquer le nombre de documents qui n'ont pas été ingérés et le nombre de documents qui ont été ingérés avec succès.</p>try {
        // Perform the bulk request
        const response = await elasticClient.bulk({ body: bulkBody });

        if (response.errors) {
            console.log('Bulk Ingestion had some hiccups:');

            // Count successful vs failed operations
            let successCount = 0;
            let errorCount = 0;
            const errorDetails = [];

            response.items.forEach((item, index) =&gt; {
                const operation = item.index || item.create || item.update || item.delete;
                if (operation.error) {
                    errorCount++;
                    errorDetails.push({
                        document: index + 1,
                        error: operation.error,
                    });
                } else {
                    successCount++;
                }
            });

            console.log(`Successfully indexed: ${successCount} documents`);
            console.log(`Failed to index: ${errorCount} documents, here are the details`, errorDetails);

        } else {
            console.log(`Bulk Ingestion fully successful!`);
        }

    } catch (error) {
        console.error('Error performing bulk ingestion:', error);
    }
}
<p>6. Exécutez la fonction <code>main()</code> ci-dessous pour exécuter séquentiellement les fonctions <code>createIndex()</code> et <code>bulkIngestCsv()</code>.</p>// Run this function
async function main() {
    const result = await createIndex();
    if (!result) {
        console.error('Index setup failed. Aborting.');
        return;
    }

    await bulkIngestCsv(filePath);
    console.log('Bulk ingestion completed!');
}

main();
<p>Si vous voyez un journal de console indiquant que l'ingestion en masse a réussi, effectuez une vérification rapide de votre index Elasticsearch pour voir si les documents ont effectivement été ingérés avec succès.</p><h4><strong>Étape 5 : Définition des agrégations Elasticsearch et consolidation</strong></h4><p>Ce sont les principales fonctions qui seront utilisées lorsque nous définirons les outils de l'agent IA afin de comparer les statistiques des joueurs entre eux.</p><p>1. Naviguez jusqu'au répertoire <code>backend/lib</code> et créez un fichier appelé <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/lib/elasticAggs.js">elasticAggs.js</a>.</p><p>2. Ajoutez la requête ci-dessous pour calculer les moyennes historiques d'un joueur contre un adversaire spécifique. Cette requête utilise un <a href="https://www.elastic.co/search-labs/tutorials/search-tutorial/full-text-search/filters">filtre</a> <code>bool</code> avec 2 conditions : l'une correspondant à <code>player_id</code> et l'autre à <code>opponent_team_id</code>, afin de récupérer uniquement les jeux pertinents. Nous n'avons pas besoin de renvoyer de documents, nous ne nous intéressons qu'aux agrégations, c'est pourquoi nous définissons <code>size:0</code>. Sous le bloc <code>aggs</code>, nous exécutons plusieurs <a href="https://www.elastic.co/docs/explore-analyze/query-filter/aggregations">agrégations</a> métriques en parallèle sur des champs tels que <code>points, rebounds, assists, steals, blocks</code> et <code>fg_percentage</code> pour calculer leurs valeurs moyennes. Les LLM peuvent être aléatoires dans leurs calculs et ce processus est déchargé sur Elasticsearch, ce qui garantit à notre assistant NBA AI l'accès à des données exactes.</p>export async function getHistoricalAveragesAgainstOpponent(player_id, opponent_team_id) {
    try {
        //Query for Historical Averages
        const historicalQuery = await elasticClient.search({
            index: 'sample-nba-player-data', 
            size: 0,
            query: {
                bool: {
                    must: [
                        {
                            term: {
                                player_id: {
                                    value: player_id,
                                },
                            },
                        },
                        {
                            term: {
                                opponent_team_id: {
                                    value: opponent_team_id,
                                },
                            },
                        },
                    ],
                },
            },
            aggs: {
                avg_points: { avg: { field: 'points' } },
                avg_rebounds: { avg: { field: 'rebounds' } },
                avg_assists: { avg: { field: 'assists' } },
                avg_steals: { avg: { field: 'steals' } },
                avg_blocks: { avg: { field: 'blocks' } },
             avg_fg_percentage: { avg: { field: 'fg_percentage' } },
            },
        });

        return {
            points: historicalQuery.aggregations.avg_points.value || 0,
            rebounds: historicalQuery.aggregations.avg_rebounds.value || 0,
            assists: historicalQuery.aggregations.avg_assists.value || 0,
            steals: historicalQuery.aggregations.avg_steals.value || 0,
            blocks: historicalQuery.aggregations.avg_blocks.value || 0,
            fgPercentage: historicalQuery.aggregations.avg_fg_percentage.value || 0,
        };
    } catch (error) {
        console.error('Query error from getHistoricalAveragesAgainstOpponent function:', error);
        return { error: 'Queries failed in getting historical averages against opponent.' };
    }
}
<p>3. Pour calculer les moyennes saisonnières d'un joueur contre un adversaire spécifique, nous utiliserons pratiquement la même requête que la requête historique. La seule différence dans cette requête est que le filtre <code>bool</code> est assorti d'une condition supplémentaire pour <code>game_date</code>. Le champ <code>game_date</code> doit se situer dans la fourchette de la saison NBA en cours. Dans ce cas, la fourchette est comprise entre <code>2024-10-01</code> et <code>2025-06-30</code>. Cette condition supplémentaire ci-dessous garantit que les agrégations qui suivent n'isoleront que les matchs de cette saison.
</p>        {
                            range: {
                    //Range for this season, change to match current season
                                game_date: {
                                    gte: '2024-10-01',
                                    lte: '2025-06-30',
                                },
                            },
<h4><strong>Étape 6 : Utilitaire de comparaison des joueurs</strong></h4><p>Pour que notre code reste modulaire et facile à maintenir, nous allons créer un fichier utilitaire qui consolide les fonctions d'aide aux métadonnées et les agrégations Elasticsearch. Il s'agit de l'outil principal utilisé par l'agent. Nous y reviendrons plus tard :</p><p>1. Créez un nouveau fichier <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/lib/comparePlayers.js">comparePlayers.js</a> dans le répertoire <code>backend/lib</code>.</p><p>2. Ajoutez la fonction ci-dessous pour consolider les aides aux métadonnées et la logique d'agrégation Elasticsearch en une seule fonction qui alimente l'outil principal utilisé par l'agent.
</p>import { playersByName } from '../data/playerAndTeamInfo.js';
import { teamsByName } from '../data/playerAndTeamInfo.js';
import { upcomingMatchups } from '../data/playerAndTeamInfo.js';
import { getHistoricalAveragesAgainstOpponent } from './elasticAggs.js';
import { getSeasonAveragesAgainstOpponent } from './elasticAggs.js';

//Simple helper functions to simulate API calls for player and team metadata. These reference the hardcoded values from playerAndTeamInfo.js in the data directory
export function getPlayerInfo(playerFullName) {
    return playersByName[playerFullName];
}

export function getTeamID(teamFullName) {
    return teamsByName[teamFullName];
}

export function getUpcomingMatchups(teamId) {
    return upcomingMatchups[teamId];
}

//Main function used by the 'playerComparisonTool' agent tool
export async function comparePlayersForNextMatchup(player1Name, player2Name) {
    //Get Player Info
    const player1Info = getPlayerInfo(player1Name);
    const player2Info = getPlayerInfo(player2Name);

    //Get upcoming matchups
    const player1NextGame = getUpcomingMatchups(player1Info.team_id)[0];
    const player2NextGame = getUpcomingMatchups(player2Info.team_id)[0];

    //Get season and historical averages against next opponent for player 1
    const player1SeasonAverages = await getSeasonAveragesAgainstOpponent(
        player1Info.player_id,
        player1NextGame.opponent_team_id
    );
    const player1HistoricalAverages = await getHistoricalAveragesAgainstOpponent(
        player1Info.player_id,
        player1NextGame.opponent_team_id
    );

    //Get season and historical averages against next opponent for player 2
    const player2SeasonAverages = await getSeasonAveragesAgainstOpponent(
        player2Info.player_id,
        player2NextGame.opponent_team_id
    );
    const player2HistoricalAverages = await getHistoricalAveragesAgainstOpponent(
        player2Info.player_id,
        player2NextGame.opponent_team_id
    );

    const player1 = {
        name: player1Name,
        playerId: player1Info.player_id,
        teamId: player1Info.team_id,
        nextOpponent: {
            teamId: player1NextGame.opponent_team_id,
            teamName: player1NextGame.opponent_team_name,
            home: player1NextGame.home,
        },
        stats: {
            seasonAverages: player1SeasonAverages,
            historicalAverages: player1HistoricalAverages,
        },
    };

    const player2 = {
        name: player2Name,
        playerId: player2Info.player_id,
        teamId: player2Info.team_id,
        nextOpponent: {
            teamId: player2NextGame.opponent_team_id,
            teamName: player2NextGame.opponent_team_name,
            home: player2NextGame.home,
        },
        stats: {
            seasonAverages: player2SeasonAverages,
            historicalAverages: player2HistoricalAverages,
        },
    };

    return [player1, player2];
}
<h4><strong>Étape 7 : Création de l'agent</strong></h4><p>Maintenant que vous avez créé les échafaudages frontend et backend, ingéré les données du jeu NBA et établi une connexion à Elasticsearch, nous pouvons commencer à assembler toutes les pièces pour construire l'agent.</p><p><strong>Définition de l'agent</strong></p><p>1. Accédez au fichier <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/src/mastra/agents/index.ts">index.ts</a> dans le répertoire <code>backend/src/mastra/agents</code> et ajoutez la définition de l'agent. Vous pouvez spécifier des champs tels que :</p><ul><li><p><strong>Nom :</strong> Donnez à votre agent un nom qui sera utilisé comme référence lorsqu'il sera appelé sur le frontend.</p></li><li><p><strong>Instructions/Instructions du système : </strong>Une invite système donne au MLD le contexte initial et les règles à suivre pendant l'interaction. Il s'agit d'une invite similaire à celle que les utilisateurs envoient par l'intermédiaire de la boîte de dialogue, mais celle-ci est donnée avant toute entrée de l'utilisateur. Là encore, cela varie en fonction du modèle que vous choisissez.</p></li><li><p><strong>Modèle :</strong> Quel LLM utiliser (Mastra soutient OpenAI, Anthropic, les modèles locaux, etc.)</p></li><li><p><strong>Outils :</strong> Une liste de fonctions d'outils que l'agent peut appeler.</p></li><li><p><strong>Mémoire :</strong> (Facultatif) si nous voulons que l'agent se souvienne de l'historique des conversations, etc. Pour des raisons de simplicité, nous pouvons commencer sans mémoire persistante, bien que Mastra la prenne en charge.</p></li></ul><p></p>import { openai } from '@ai-sdk/openai';
import { Agent } from '@mastra/core/agent';
import { playerComparisonTool } from '../tools';

export const basketballAgent = new Agent({
    name: 'Basketball Agent',
    instructions: `
      You are a NBA Basketball expert.
      Your primary function is to compare two NBA players and recommend which one is the better fantasy pickup.

      Only compare players from the following list:
      - LeBron James
      - Stephen Curry
      - Jayson Tatum
      - Jaylen Brown
      - Nikola Jokic
      - Luka Doncic
      - Kyrie Irving
      - Anthony Davis
      - Kawhi Leonard
      - Russell Westbrook

      Input Handling Rules:
      - If the user asks about a player that is not on this list, respond with the list of available players for comparison.
      - If the user only inputs one player, ask the user to add another player from the list provided.
      - If the user inputs a player with the wrong spelling or capitalizations, infer from the list of available players provided.
      - IMPORTANT: If the user asks a question or asks you to generate a response about anything outside of basketball or the scope of this project, DO NOT answer and affirm you can only talk about basketball.

      Tool Usage:
      - Extract and standardize player names to match the list exactly.
      - Use the playerComparisonTool, passing both names as strings.
      - The tool will return an object with game information, stats, and analysis.

      Format your response using Markdown syntax. Use:

        Example output format:

       
        #### Next Game Info
        - ***LeBron James** vs Warriors, May 24 (Home)  
        - ***Stephen Curry** vs Lakers, May 24 (Away)


        #### Stats Comparison  
        \`\`\`  
        Stat                  LeBron James (vs Warriors)    Stephen Curry (vs Lakers)  
        --------------------  -----------------------------  ----------------------------  
        Historical Points     28.3                          30.3  
        Historical Assists    6.7                           8.7  
        Season Points         28.8                          23.3  
        Season Assists        6.2                           4.7  
        \`\`\`

        #### Fantasy Recommendation  
        Explain which player is the better fantasy pickup and why.
      
    `,
    model: openai('gpt-4o'),
    tools: { playerComparisonTool },
});
<p><strong>
Définition des outils</strong></p><ol><li><p>Naviguez jusqu'au fichier <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/src/mastra/tools/index.ts">index.ts</a> dans le répertoire <code>backend/src/mastra/tools</code>.</p></li><li><p>Installez Zod à l'aide de la commande :</p></li></ol>npm install zod<p>3. Ajouter des définitions d'outils. Notez que nous importons la fonction dans le fichier <code>comparePlayers.js</code> en tant que fonction principale que l'agent utilisera lorsqu'il appellera cet outil. En utilisant la fonction <code>createTool()</code> de Mastra, nous enregistrerons notre <code>playerComparisonTool</code>. Les domaines concernés sont les suivants :</p><ul><li><p><code>id</code>: Il s'agit d'une description en langage naturel qui aide l'agent à comprendre ce que fait l'outil.</p></li><li><p><code>input schema</code>: Pour définir la forme de l'entrée de l'outil, Mastra utilise le schéma <a href="https://zod.dev/">Zod</a>, qui est une bibliothèque de validation de schéma TypeScript. Zod s'assure que l'agent saisit des données correctement structurées et empêche l'outil de s'exécuter si la structure de l'entrée ne correspond pas.</p></li><li><p><code>description</code>: Il s'agit d'une description en langage naturel qui aide l'agent à comprendre quand il doit appeler et utiliser l'outil.</p></li><li><p><code>execute</code>: La logique qui s'exécute lorsque l'outil est appelé. Dans notre cas, nous utilisons une fonction d'aide importée pour renvoyer des statistiques de performance.</p></li></ul>import { comparePlayersForNextMatchup } from '../../../lib/comparePlayers.js'
import { createTool } from "@mastra/core/tools";
import { z } from "zod";

export const playerComparisonTool = createTool({
    id: "Compare two NBA players",
    inputSchema: z.object({
        player1:z.string(),
        player2:z.string()
    }),
    description: "Use this tool to compare two players given in the user prompt.",
    execute: async ({ context: { player1, player2 } }) =&gt; {
        return await comparePlayersForNextMatchup(player1, player2);
      },
})<p><strong>Ajout d'un logiciel intermédiaire pour gérer CORS</strong></p><p>Ajouter un middleware dans le serveur Mastra pour gérer <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS">CORS</a>. On dit qu'il y a trois choses dans la vie qu'on ne peut pas éviter : la mort, les impôts, et pour les développeurs web, c'est CORS. En bref, le partage des ressources inter-origines est une fonction de sécurité du navigateur qui empêche le front-end d'envoyer des requêtes à un back-end fonctionnant sur un domaine ou un port différent. Même si nous exécutons le backend et le frontend sur localhost, ils utilisent des ports différents, ce qui déclenche la politique CORS. Nous devons ajouter l'intergiciel spécifié dans la <a href="https://mastra.ai/en/docs/server-db/middleware">documentation de Mastra</a> afin que notre backend autorise ces requêtes depuis le frontend.</p><p>1. Naviguez jusqu'au fichier <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/backend/src/mastra/index.ts">index.ts</a> dans le répertoire <code>backend/src/mastra</code> et ajoutez la configuration pour CORS :</p><ul><li><p><code>origin: ['http://localhost:5173']</code></p><ul><li><p>Autorise les demandes provenant uniquement de cette adresse (adresse par défaut de Vite)</p></li></ul></li><li><p><code>allowMethods: ["GET", "POST"]</code></p><ul><li><p>Méthodes HTTP autorisées. La plupart du temps, il utilisera POST.</p></li></ul></li><li><p><code>allowHeaders: ["Content-Type", "Authorization", "x-mastra-client-type, "x-highlight-request", "traceparent"],</code></p><ul><li><p>Ils déterminent quels en-têtes personnalisés peuvent être utilisés dans les requêtes</p></li></ul></li></ul><p></p>import { Mastra } from '@mastra/core/mastra';
import { basketballAgent } from './agents';

console.log('Starting Mastra server...');

export const mastra = new Mastra({
  agents: { basketballAgent },
  server:{
    timeout: 10 * 60 * 1000, // 10 minutes
    cors: {
      origin: ['http://localhost:5173'],
      allowMethods: ["GET", "POST"],
      allowHeaders: [
        "Content-Type",
        "Authorization",
        "x-mastra-client-type",
        "x-highlight-request",
        "traceparent",
      ],
      exposeHeaders: ["Content-Length", "X-Requested-With"],
      credentials: false,
    },
  },

});

console.log('Mastra server configured.'); // Log after server configuration
<h4><strong>Étape 8 : Intégration de l'interface utilisateur</strong></h4><p>Ce composant React fournit une interface de chat simple qui se connecte à l'agent IA Mastra en utilisant le hook <a href="https://mastra.ai/en/docs/frameworks/agentic-uis/ai-sdk#using-the-usechat-hook">useChat()</a> de <code>@ai-sdk/react</code>. Nous allons également utiliser ce crochet pour afficher l'utilisation des jetons, les appels d'outils et pour rendre la conversation. Dans l'invite système ci-dessus, nous demandons également à l'agent de produire la réponse en format markdown, nous utiliserons donc <code>react-markdown</code> pour formater correctement la réponse.</p><p></p><p>1. Dans le répertoire frontend, installez le paquetage @ai-sdk/react pour utiliser le hook useChat().</p>npm install @ai-sdk/react<p>2. Dans le même répertoire, installez React Markdown pour que nous puissions formater correctement la réponse générée par l'agent.</p>npm install react-markdown<p>3. Mettre en œuvre <code>useChat()</code>. Ce hook va gérer l'interaction entre votre frontend et votre agent IA backend. Il gère l'état des messages, les entrées de l'utilisateur, l'état et vous donne des crochets de cycle de vie à des fins d'observabilité. Les options que nous transmettons sont les suivantes :</p><ul><li><p><code>api:</code> Ceci définit le point final de votre agent Mastra AI. Le port par défaut est le port 4111 et nous voulons également ajouter la route qui prend en charge les réponses en continu.</p></li><li><p><code>onToolCall</code>: Cette fonction s'exécute chaque fois que l'agent appelle un outil ; nous l'utilisons pour savoir quels outils notre agent appelle.</p></li><li><p><code>onFinish</code>: Cette opération s'exécute après que l'agent a fourni une réponse complète. Même si nous avons activé le streaming, <code>onFinish</code> sera toujours exécuté après la réception du message complet et non après chaque morceau. Ici, nous l'utilisons pour suivre l'utilisation de nos jetons. Cela peut s'avérer utile pour contrôler et optimiser les coûts de la gestion du cycle d'apprentissage tout au long de la vie.</p></li></ul><p>4. Enfin, nous nous rendons au composant <a href="https://github.com/jdarmada/nba-ai-assistant-js/blob/main/frontend/components/ChatUI.jsx">ChatUI.jsx</a> dans le répertoire <code>frontend/components</code> pour créer l'interface utilisateur de notre conversation. Ensuite, la réponse est enveloppée dans un composant <code>ReactMarkdown</code> afin de formater correctement la réponse de l'agent.</p>import React, { useState } from 'react';
import { useChat } from '@ai-sdk/react';
import ReactMarkdown from 'react-markdown';

export default function ChatUI() {
    const [totalTokenUsage, setTotalTokenUsage] = useState(0);
    const [promptTokenUsage, setPromptTokenUsage] = useState(0);
    const [completionTokenUsage, setCompletionTokenUsage] = useState(0);
    const [toolsCalled, setToolsCalled] = useState([]);

    const { messages, input, handleInputChange, handleSubmit, status } = useChat({
        api: 'http://localhost:4111/api/agents/basketballAgent/stream', //Replace with your own endpoint for your agent
        id: 'my-chat-session',

        //Optional parameter to check agent tool calls
        onToolCall: ({ toolCall }) =&gt; {
            setToolsCalled((prev) =&gt; [...prev, toolCall.toolName]);
        },

        //Optional parameter to check token usages
        onFinish: (message, { usage }) =&gt; {
            setTotalTokenUsage((prev) =&gt; prev + usage.totalTokens);
            setPromptTokenUsage((prev) =&gt; prev + usage.promptTokens);
            setCompletionTokenUsage((prev) =&gt; prev + usage.completionTokens);
        },

        //Optional parameter for error handling
        onError: (error) =&gt; {
            console.error('Agent error:', error);
        },
    });

    return (
        &lt;div&gt;
            &lt;div className="agent-info"&gt;
                &lt;h4 className="stats-title"&gt;What's My Agent Doing?&lt;/h4&gt;

                &lt;div className="stats-box"&gt;
                    &lt;strong className="stats-sub-title"&gt;Tools Called:&lt;/strong&gt;
                    &lt;ul className="tool-list"&gt;
                        {toolsCalled.map((tool, idx) =&gt; (
                            &lt;li key={idx}&gt;{tool}&lt;/li&gt;
                        ))}
                        {toolsCalled.length === 0 &amp;&amp; &lt;li&gt;No tools called yet.&lt;/li&gt;}
                    &lt;/ul&gt;

                    &lt;div className="usage-stats"&gt;
                        &lt;p&gt;Prompt Token Usage: {promptTokenUsage}&lt;/p&gt;
                        &lt;p&gt;Completion Token Usage: {completionTokenUsage}&lt;/p&gt;
                        &lt;p&gt;Total Token Usage: {totalTokenUsage}&lt;/p&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;

            &lt;strong&gt;Conversation:&lt;/strong&gt;
            &lt;div className="convo-box"&gt;
                {messages.map((msg) =&gt; (
                    &lt;div key={msg.id} className="message-item"&gt;
                        &lt;strong className="message-role"&gt;{msg.role === 'assistant' ? 'Basketbot' : 'You'}:&lt;/strong&gt;
                        &lt;ReactMarkdown&gt;{msg.content}&lt;/ReactMarkdown&gt;
                    &lt;/div&gt;
                ))}
            &lt;/div&gt;

            &lt;form onSubmit={handleSubmit}&gt;
                &lt;input
                    type="text"
                    value={input}
                    onChange={handleInputChange}
                    placeholder="Input two players you want to compare."
                    className="input-box"
                /&gt;
                &lt;button type="submit" disabled={status === 'streaming'}&gt;
                    {status === 'streaming' ? 'Thinking...' : 'Send'}
                &lt;/button&gt;
            &lt;/form&gt;
        &lt;/div&gt;
    );
}<h4><strong>Étape 9 : Exécution de l'application</strong></h4><p>Félicitations ! Vous êtes maintenant prêt à exécuter l'application. Suivez ces étapes pour démarrer le backend et le frontend.</p><ol><li><p>Dans une fenêtre de terminal, à partir du répertoire racine, naviguez jusqu'au répertoire backend et démarrez le serveur Mastra :</p></li></ol>cd backend

npm run dev<p>2. Dans une autre fenêtre de terminal, à partir du répertoire racine, naviguez jusqu'au répertoire frontend et démarrez l'application React :</p><p></p>cd frontend

npm run dev<p></p><p>3. Allez dans votre navigateur et naviguez jusqu'à :</p><p></p><p><a href="http://localhost:5173/">http://localhost:5173</a></p><p></p><p>Vous devriez voir l'interface de chat. Essayez les exemples suivants :</p><ul><li><p>"Comparer LeBron James et Stephen Curry"</p></li><li><p>"Qui choisir entre Jayson Tatum et Luka Doncic ?"</p></li></ul><p></p><h3><strong>Et maintenant ? Rendre l'agent plus intelligent</strong></h3><p>Pour rendre l'assistant plus agentive et les recommandations plus perspicaces, j'ajouterai quelques améliorations clés dans la prochaine itération.</p><p></p><p><strong>Recherche sémantique pour les nouvelles de la NBA</strong></p><p>Il y a une tonne de facteurs qui peuvent affecter les performances des joueurs, dont beaucoup n'apparaissent pas dans les statistiques brutes. Des choses comme les rapports sur les blessures, les changements de composition, ou même une analyse d'après-match, vous ne pouvez les trouver que dans des articles de presse. Pour saisir ce contexte supplémentaire, j'ajouterai des capacités de recherche sémantique afin que l'agent puisse retrouver des articles pertinents de la NBA et tenir compte de ce récit dans ses recommandations.</p><p></p><p><strong>Recherche dynamique avec le serveur Elasticsearch MCP</strong></p><p>Le protocole MCP (Model Context Protocol) devient rapidement la norme pour la connexion des agents aux sources de données. Je vais migrer la logique de recherche dans le serveur Elasticsearch MCP, qui permet à l'agent de construire dynamiquement des requêtes plutôt que de s'appuyer sur les fonctions de recherche prédéfinies que nous fournissons. Cela nous permet d'utiliser davantage de flux de travail en langage naturel et de réduire la nécessité de rédiger manuellement chaque requête de recherche. Pour en savoir plus sur le serveur Elasticsearch MCP et l'état actuel de l'écosystème <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">, cliquez ici.</a></p><p></p><p>Ces changements sont déjà en cours, restez à l'écoute !</p><h3><strong>Conclusion</strong></h3><p></p><p>Dans ce blog, nous avons construit un assistant RAG agentique qui fournit des recommandations personnalisées pour votre équipe de basket-ball fantasy en utilisant JavaScript, Mastra et Elasticsearch. Nous avons couvert :</p><ul><li><p><strong>Les principes fondamentaux de la RAG agentique</strong> et la manière dont la combinaison de l'autonomie d'un agent d'intelligence artificielle avec les outils permettant d'utiliser efficacement la RAG peut déboucher sur des agents plus nuancés et plus dynamiques.</p></li><li><p><strong>Elasticsearch </strong>et comment ses capacités de stockage de données et ses puissantes agrégations natives en font un partenaire idéal en tant que base de connaissances pour un LLM.</p></li><li><p><strong>Le </strong>cadre Mastra et la manière dont il simplifie la construction de ces agents pour les développeurs de l'écosystème JavaScript.</p></li></ul><p>Que vous soyez fanatique de basket-ball, que vous cherchiez à construire des agents d'intelligence artificielle, ou les deux comme moi, j'espère que ce blog vous a donné quelques éléments de base pour commencer. Le repo complet est disponible sur <a href="https://github.com/jdarmada/nba-ai-assistant-js">GitHub</a>, n'hésitez pas à le cloner et à le modifier. Maintenant, allez gagner cette ligue de fantasy !</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agentic-rag</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agentic-rag</guid>
    <category><![CDATA[IA]]></category>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[JavaScript]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ffd561836a4cb20/6a17f1e47b54f978588b39e4/8132ed781c1ea5d46ca244182f421ed5c721f23b-1200x628.png" length="0" type="image/png"/>
    <pubDate>Tue, 01 Jul 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[L'état actuel du MCP (Model Context Protocol)]]></title>
    <description><![CDATA[Découvrez MCP, les mises à jour du projet, les fonctionnalités, les défis de sécurité, les cas d'utilisation émergents, et comment bricoler avec le serveur Elasticsearch MCP d'Elastic.]]></description>
    <content:encoded><![CDATA[<p>J'ai récemment assisté au <a href="https://mcpdevsummit.ai/">sommet des développeurs MCP</a> à San Francisco et il est clair que le protocole MCP (Model Context Protocol) devient rapidement un élément fondamental pour les agents d'intelligence artificielle et les applications d'intelligence artificielle riches en contexte. Chez Elastic, nous nous orientons dans cette direction en exposant les serveurs MCP directement à partir d'<a href="https://www.elastic.co/fr/elasticsearch/agent-builder">Agent Builder</a>, faisant d'Elasticsearch un contexte de premier ordre et un fournisseur d'outils pour tout agent compatible MCP. Dans ce billet, je vais passer en revue les principales mises à jour de l'événement, les cas d'utilisation émergents, ce qui se profile à l'horizon pour MCP, et comment vous pouvez utiliser Agent Builder pour rendre Elasticsearch disponible aux agents via MCP.</p><h2>Qu'est-ce que le protocole de contexte de modèle (MCP) ?</h2><p>Pour ceux qui ne connaissent pas, <a href="https://modelcontextprotocol.io/introduction">Model Context Protocol</a> est une norme ouverte qui offre un moyen structuré et bidirectionnel de connecter les modèles d'IA à diverses sources de données et à divers outils, ce qui leur permet de générer des réponses plus pertinentes et mieux informées. Il est communément appelé "<a href="https://modelcontextprotocol.io/introduction">port USB-C pour les applications d'intelligence artificielle</a>".</p><p>Voici un schéma architectural qui met en évidence son caractère bidirectionnel :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5ff0e141b5dfda29/6a17e7ffe8fbcee5263a1946/5eba1e59514eb58a5220bb92bb49e6328ee83cd7-674x466.png" alt="Architecture du protocole de contexte de modèle (MCP)" /><p>Il s'agit d'un changement important pour les praticiens de l'IA, car l'un des principaux défis de la mise à l'échelle des applications d'IA est de devoir créer des intégrations personnalisées pour chaque nouvelle source de données. MCP offre une architecture durable et réutilisable pour la gestion et la fourniture de contexte aux modèles. Il est indépendant des modèles et des serveurs et est entièrement open source.</p><p>MCP est la dernière itération d'une lignée de spécifications d'API visant à normaliser l'intégration entre les applications. Dans le passé, nous avions OpenAPI pour les services RESTful, GraphQL pour l'interrogation des données et gRPC pour la communication des microservices. MCP ne partage pas seulement la rigueur structurée de ces anciennes spécifications, mais l'intègre également dans un cadre d'IA générative, ce qui facilite l'intégration des agents dans différents systèmes sans avoir recours à des connecteurs personnalisés. À bien des égards, MCP vise à faire pour les agents d'intelligence artificielle ce que HTTP a fait pour le web. Tout comme HTTP a normalisé la communication entre les navigateurs et les sites web, MCP cherche à normaliser la façon dont les agents d'intelligence artificielle interagissent avec le monde des données qui les entoure.</p><h2>MCP par rapport à d'autres protocoles d'agents</h2><p>Le paysage des protocoles d'agents se développe rapidement, avec plus d'une douzaine de normes émergentes en concurrence pour définir la manière dont les agents interagissent. <a href="https://x.com/seldo">Laurie Voss</a> de LlamaIndex décrit comment la plupart peuvent être catégorisés en 2 types : les protocoles inter-agents qui se concentrent sur les agents qui parlent entre eux et les protocoles orientés vers le contexte comme MCP qui se concentrent sur la fourniture d'un contexte structuré aux LLMs.</p><p>D'autres protocoles populaires comme <a href="https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/">A2A</a> (Agent to Agent) de Google, <a href="https://agentcommunicationprotocol.dev/introduction/welcome">ACP</a> (Agent Communication Protocol) de Cisco et IBM, et <a href="https://agoraprotocol.org/">Agora</a>, visent à permettre les négociations entre agents, la création de coalitions et même des systèmes d'identité décentralisés. MCP adopte une approche un peu plus pragmatique en ce sens qu'il se concentre sur la manière dont les agents accèdent aux outils et aux données et pas nécessairement sur la manière dont ils communiquent entre eux (bien que MCP puisse également permettre cela à l'avenir de différentes manières).</p><p>Actuellement, ce qui distingue MCP, c'est sa traction et son élan. Comme React dans les premiers jours des frameworks frontaux, MCP a commencé avec un problème de niche et est maintenant l'un des protocoles d'agent les plus adoptés et les plus extensibles dans la pratique.</p><h2>Récapitulation du sommet : Évolution des priorités pour le MCP</h2><p>Le sommet a accueilli des intervenants de Anthropic, Okta, OpenAI, AWS, GitHub et bien d'autres. Les discussions ont porté sur l'amélioration des protocoles de base et sur leur mise en œuvre dans le monde réel, et ont mis en évidence les priorités immédiates et à long terme. Ces exposés ont montré que l'on s'éloignait de l'expérimentation précoce et de l'appel à de simples outils pour passer à la construction de systèmes d'IA fiables, évolutifs et modulaires en utilisant le MCP comme base.</p><p>Plusieurs orateurs ont évoqué un avenir où le MCP est plus qu'un simple protocole, il peut devenir le fondement d'un web orienté vers l'intelligence artificielle. Tout comme JavaScript permet aux utilisateurs de cliquer et d'interagir avec les pages web, MCP pourrait permettre aux agents d'effectuer ces mêmes actions en notre nom. Par exemple, dans le domaine du commerce électronique, au lieu de naviguer manuellement sur un site web pour faire des achats, les utilisateurs pourraient simplement demander à un agent de se connecter, de trouver un produit spécifique, de l'ajouter à leur panier et de passer à la caisse.</p><p>Il ne s'agit pas non plus d'une pure spéculation ou d'un battage médiatique : PayPal a présenté sa nouvelle boîte à outils pour agents et son serveur MCP lors du sommet, qui permet exactement cette expérience de commerce agentique. Grâce à MCP qui fournit un accès sécurisé et fiable aux outils et aux sources de données, les agents ne se contenteront pas de lire le web, ils pourront agir en conséquence. Aujourd'hui, MCP est déjà une norme puissante qui a le vent en poupe et, à terme, elle pourrait devenir la norme des interactions utilisateur améliorées par l'IA sur l'ensemble du web.</p><h2>Mise à jour du projet MCP : Transport, élicitation et outils structurés</h2><p><a href="https://x.com/JeromeSwannack">Jerome Swannack</a>, l'un des principaux contributeurs à MCP, a fait part de quelques mises à jour de la spécification du protocole au cours des six derniers mois. Les principaux objectifs de ces changements sont les suivants</p><ol><li><p>Pour activer le MCP à distance avec l'ajout du HTTP en continu</p></li><li><p>Permettre des modèles d'interaction entre agents plus riches grâce à l'ajout de schémas d'élicitation et de sortie d'outils.</p></li></ol><p>MCP étant un logiciel libre, les développeurs peuvent déjà mettre en œuvre des modifications telles que le protocole HTTP fluide. Les schémas d'élicitation et de sortie de l'outil ne sont pas encore publiés ; ils sont à l'état de projet et peuvent évoluer.</p><p><strong>Streamable HTTP </strong><a href="https://modelcontextprotocol.io/specification/2025-03-26/basic/transports">(publié le 26 mars 2025</a>)<strong>:</strong> Une mise à jour technique importante a été l'introduction du protocole HTTP en flux continu en tant que nouveau mécanisme de transport. Il remplace les événements envoyés par le serveur (SSE) par un modèle bidirectionnel plus évolutif qui prend en charge le codage de transfert par morceaux et la transmission progressive de messages sur une seule connexion HTTP. Cela vous permet de déployer des serveurs MCP sur une infrastructure cloud comme AWS Lambda et de prendre en charge les contraintes du réseau d'entreprise sans connexions à longue durée de vie ni nécessité de polling.</p><p><strong>Elicitation </strong><a href="https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation">(publié le 18 juin 2025</a>)<strong>:</strong> L'élicitation permet aux serveurs de définir un schéma sur la façon dont ils veulent que le contexte soit structuré à partir d'un client. Essentiellement, le serveur peut décrire ce dont il a besoin et le type d'entrée qu'il attend. Cela a plusieurs implications : Les constructeurs de serveurs peuvent créer des interactions agentiques plus complexes. Les concepteurs de clients peuvent mettre en œuvre des interfaces utilisateur dynamiques qui s'adaptent à ces schémas. Cependant, l'élicitation ne doit pas être utilisée pour extraire des informations sensibles ou personnellement identifiables des utilisateurs. Les développeurs doivent suivre les <a href="https://modelcontextprotocol.io/specification/draft/client/elicitation#security-considerations">meilleures pratiques</a> pour s'assurer que les messages d'élicitation restent sûrs et appropriés, en particulier au fur et à mesure que le MCP évolue. Ceci est lié à des problèmes de sécurité plus larges que nous aborderons plus loin dans ce billet.</p><p><strong>Schémas de sortie d'outil </strong><a href="https://modelcontextprotocol.io/specification/draft/server/tools#output-schema">(publié le 18 juin 2025</a>)<strong>: </strong>Ce concept permet au client et au LLM de connaître à l'avance les formes de sortie de l'outil. Les schémas de sortie des outils permettent aux développeurs de décrire les résultats attendus d'un outil. Ces schémas répondent à l'une des principales limites de l'appel direct d'outils, à savoir l'utilisation inefficace de la fenêtre contextuelle. La fenêtre contextuelle est considérée comme l'une des ressources les plus importantes lorsque vous travaillez avec des LLM. Lorsque vous appelez directement un outil, celui-ci renvoie un contenu brut qui est entièrement transféré dans le contexte du LLM. Les schémas de sortie des outils peuvent vous aider à mieux utiliser vos jetons et la fenêtre contextuelle en permettant au serveur MCP de fournir des données structurées. Voici quelques <a href="https://modelcontextprotocol.io/specification/draft/server/tools#security-considerations">bonnes pratiques</a> concernant les outils en général.</p><p>Ensemble, ces nouvelles mises à jour et les ajouts futurs aideront le MCP à devenir un protocole d'agent plus modulaire, typé et prêt pour la production.</p><h2>Caractéristiques de puissance sous-utilisées : Échantillonnage et racines</h2><p>Bien qu'ils ne soient pas nouveaux dans la spécification MCP, l'échantillonnage et les racines ont été mis en évidence lors de la présentation. Ces deux primitives sont actuellement négligées et sous-explorées, mais elles peuvent contribuer de manière significative à des interactions plus riches et plus sûres entre les agents.</p><p><strong>Échantillonnage - Les serveurs peuvent demander des compléments au client : </strong>L'<a href="https://modelcontextprotocol.io/docs/concepts/sampling">échantillonnage</a> permet aux serveurs MCP de demander des compléments au LLM côté client. Cela ajoute à la nature bidirectionnelle du protocole, où le serveur ne se contente pas de répondre aux demandes ; il peut inciter et demander au modèle du client de générer une réponse. Cela permet au client de garder un contrôle total sur le coût, la sécurité et le modèle utilisé par le serveur MCP. Ainsi, dans le cas de l'utilisation d'un serveur MCP externe avec un modèle préconfiguré, vous n'aurez pas besoin de fournir vos propres clés API ou de configurer votre propre abonnement à ce modèle, car le serveur peut simplement demander le modèle déjà connecté au client. Cela permet d'obtenir des comportements d'agents plus complexes et plus interactifs.</p><p><strong>Racines - Accès limité aux ressources : </strong>Les<a href="https://modelcontextprotocol.io/docs/concepts/roots">racines</a> ont été conçues pour permettre aux clients d'informer les serveurs des ressources et des espaces de travail pertinents sur lesquels ils doivent se concentrer. Il s'agit d'un outil puissant pour définir le champ d'action des serveurs. Il est important de noter que les racines sont "<a href="https://modelcontextprotocol.io/docs/concepts/roots#how-roots-work">informatives et non strictement exécutoires</a>", ce qui signifie qu'elles ne définissent pas de droits ou de permissions pour les serveurs ou les agents MCP. En d'autres termes, vous ne pouvez pas vous fier uniquement aux racines pour empêcher un serveur ou un agent d'exécuter certains outils ou d'effectuer des actions d'écriture. En ce qui concerne les racines, les autorisations doivent toujours être gérées du côté du client, avec des mécanismes d'approbation par l'utilisateur. Par ailleurs, les développeurs doivent toujours veiller à utiliser des serveurs conçus pour respecter les limites fixées par les racines et utiliser les <a href="https://modelcontextprotocol.io/docs/concepts/roots#best-practices">meilleures pratiques.</a></p><h2>Authentification des agents : OAuth 2.1 et métadonnées protégées</h2><p>Cette section se concentre sur OAuth 2.1, la dernière itération d'OAuth 2.0, qui supprime les flux non sécurisés et consolide les meilleures pratiques.</p><p>La prise en charge d'OAuth était un sujet très attendu, d'autant plus que la sécurité et l'évolutivité sont considérées comme les principaux obstacles qui empêchent MCP de devenir la norme pour la connexion des agents aux outils. <a href="https://x.com/aaronpk">Aaron Parecki</a> (éditeur d'OAuth 2.1 et expert en normes d'identité chez Okta) a expliqué comment MCP peut adopter un flux OAuth propre et évolutif qui décharge les développeurs de serveurs de la majeure partie de la complexité. La spécification d'autorisation officielle OAuth 2.1 a été récemment publiée dans la dernière révision du protocole le <a href="https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization">18 juin 2025</a>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4d53e7bb091b4f43/6a17e80163baff80dc741c56/2ea159116fe5e03ff800f077adf16d6ca9f1c1d1-1594x1280.png" alt="Authentification MCP pour les agents" /><p>Dans cette implémentation, les responsabilités OAuth peuvent être réparties entre le client MCP et le serveur. La majeure partie du flux d'authentification est initiée et gérée par le client MCP, le serveur n'intervenant qu'à la fin pour recevoir et vérifier le jeton sécurisé. Cette scission permet de résoudre un problème critique de mise à l'échelle, à savoir comment s'authentifier à travers de nombreux outils sans exiger des développeurs qu'ils configurent chaque connexion, et garantit que les développeurs de serveurs MCP n'ont pas à devenir des experts OAuth.</p><p>Deux points saillants de l'exposé :</p><ol><li><p><a href="https://datatracker.ietf.org/doc/rfc9728/"><strong>Métadonnées des ressources protégées</strong></a>: Les serveurs MCP peuvent publier un fichier JSON décrivant leur objectif, leurs points d'accès et leurs méthodes d'authentification. Cela permet aux clients de démarrer des flux OAuth avec seulement l'URL du serveur, ce qui simplifie le processus de connexion. En savoir plus : <a href="https://aaronparecki.com/2025/04/03/15/oauth-for-model-context-protocol">Corrigeons OAuth dans MCP</a></p></li><li><p><a href="https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-13"><strong>Prise en charge des IDP et du SSO</strong></a>: les entreprises peuvent intégrer des fournisseurs d'identité pour gérer l'accès de manière centralisée. C'est une victoire pour l'expérience de l'utilisateur et la sécurité. Les utilisateurs n'auraient pas besoin de cliquer sur dix écrans de consentement différents et les équipes de sécurité pourraient observer chaque connexion.</p></li></ol><p>En transférant la logique OAuth au client et en s'appuyant sur les métadonnées des serveurs, l'écosystème MCP évite un goulot d'étranglement majeur. Le MCP s'aligne ainsi plus étroitement sur la manière dont les API modernes sont sécurisées dans les environnements de production d'aujourd'hui.</p><p>Lecture complémentaire : <a href="https://aaronparecki.com/oauth-2-simplified/">OAuth 2 simplifié</a>.</p><h2>Défis de sécurité dans un écosystème composable</h2><p>Les nouveaux développements s'accompagnent également de nouvelles surfaces d'attaque. Arjun Sambamoorthy, de Cisco, énumère les principales menaces qui pèsent sur le paysage MCP :</p><p>Profils</p><p>Description</p><p>Remédiation &amp; meilleures pratiques</p><p>Injection rapide &amp; Empoisonnement des outils</p><p>Un moyen d'injecter une invite malveillante dans le contexte du système LLM ou dans la description de l'outil, amenant le LLM à effectuer des actions involontaires telles que la lecture de fichiers ou la fuite de données.</p><p>Utilisez des outils tels que MCP Scan pour vérifier les métadonnées des outils. Validez les descriptions et les paramètres avant de les inclure dans les invites. Enfin, envisagez de mettre en place des approbations d'utilisateurs pour les outils à haut risque. Pour plus de détails, voir le guide OWASP Prompt Injection dans la liste de lectures complémentaires sous le tableau.</p><p>Attaques par échantillonnage</p><p>Dans le contexte de MCP, l'échantillonnage ouvre la porte au serveur MCP pour effectuer des attaques d'injection rapide sur le LLM.</p><p>Désactiver l'échantillonnage pour les serveurs non fiables et envisager d'ajouter des approbations humaines en boucle pour les demandes d'échantillonnage.</p><p>Serveurs MCP malveillants</p><p>Dans les collections actuelles de serveurs MCP, il est difficile de contrôler chacun d'entre eux pour garantir la sécurité. Des serveurs malveillants peuvent discrètement collecter vos données et les exposer à des acteurs malveillants.</p><p>Ne vous connectez qu'à des serveurs MCP provenant de registres de confiance ou de listes internes. Exécuter des serveurs tiers dans des conteneurs avec sandboxing.</p><p>Outils d'installation MCP malveillants</p><p>Les installateurs de ligne de commande et les scripts sont pratiques pour mettre en œuvre rapidement des serveurs ou des outils MCP, mais vous risquez d'installer du code non vérifié et compromis.</p><p>Installer dans des environnements "sandbox" et valider les signatures des paquets. Ne jamais effectuer de mise à jour automatique à partir de sources non vérifiées.</p><p>Pour lutter contre ce problème, Arjun suggère d'utiliser un registre MCP de confiance pour gérer toutes les vérifications (un sujet qui était au cœur de l'actualité - pour plus de détails, voir les deux premiers éléments de la liste de lecture ci-dessous), ainsi que d'utiliser cette <a href="https://github.com/slowmist/MCP-Security-Checklist">liste de contrôle de la sécurité</a>.</p><p>Lecture complémentaire :</p><ul><li><p><a href="https://modelcontextprotocol.io/specification/2025-06-18/basic/security_best_practices">Meilleures pratiques officielles de sécurité MCP</a></p></li><li><p><a href="https://owasp.org/www-project-top-10-for-large-language-model-applications/">Top 10 des candidatures au LLM de l'OWASP</a></p></li><li><p><a href="https://hiddenlayer.com/innovation-hub/">Recherche sur les menaces HiddenLayer</a></p></li><li><p><a href="https://github.com/invariantlabs-ai/mcp-scan">Scan MCP</a></p></li><li><p><a href="https://genai.owasp.org/llmrisk/llm01-prompt-injection/">Guide OWASP sur l'injection d'invites</a></p></li></ul><h2>Prochaines étapes : Registres, gouvernance et écosystème</h2><p>Un registre centralisé des MCP est en cours d'élaboration et a été l'un des sujets les plus discutés lors du sommet. L'écosystème actuel des serveurs souffre de fragmentation, d'un manque de confiance et d'accessibilité. Il est difficile pour les développeurs de trouver des serveurs MCP, de vérifier ce qu'ils font et de les installer en toute sécurité, en particulier dans un écosystème décentralisé où les métadonnées peuvent être incomplètes ou usurpées.</p><p>Un registre centralisé répond directement à ces problèmes en agissant comme une source de vérité fiable, en améliorant la découvrabilité, en garantissant l'intégrité des métadonnées du serveur et en réduisant le risque d'installation d'outils malveillants.</p><p>Les objectifs du registre MCP sont les suivants :</p><ul><li><p>Offrir une source unique de vérité pour les métadonnées des serveurs (ce que fait un serveur, comment s'authentifier, l'installer et l'appeler)</p></li><li><p>Se débarrasser des registres tiers incomplets et de la fragmentation, de sorte que lorsqu'un serveur veut être enregistré, il n'a pas à mettre à jour tous les autres registres sur l'internet.</p></li><li><p>Fournir un flux d'enregistrement de serveur qui comprend un outil CLI et un fichier server.json qui contient les métadonnées mentionnées précédemment.</p></li></ul><p>L'espoir le plus large est qu'un registre fiable aidera à développer l'écosystème en toute sécurité, en permettant aux développeurs de créer et de partager de nouveaux outils en toute confiance.</p><p>La gouvernance est une autre question prioritaire pour Anthropic. Ils ont clairement indiqué que le projet MCP devait rester ouvert et dirigé par la communauté, mais la mise à l'échelle de ce modèle de gouvernance est encore un travail en cours. Ils recherchent actuellement de l'aide dans ce domaine et demandent à toute personne ayant de l'expérience en matière de gouvernance dans les protocoles à source ouverte de les contacter. Cela nous amène à l'autre sujet que je voulais aborder. Tout au long de l'événement, les intervenants ont insisté sur le fait que l'écosystème ne peut se développer qu'avec les contributions des développeurs. Un effort concentré est nécessaire pour faire de MCP la nouvelle norme web et se démarquer des autres protocoles d'agents populaires.</p><h2>MCP dans le monde réel : Études de cas et démonstrations</h2><p>Plusieurs organisations ont expliqué comment le MCP est déjà utilisé dans des applications pratiques :</p><ul><li><p><strong>PayPal - Serveur MCP pour le commerce agentique : </strong>PayPal a présenté son nouvel <a href="https://github.com/paypal/agent-toolkit/">agent-toolkit</a> et son serveur MCP, qui peuvent changer fondamentalement l'expérience d'achat d'un utilisateur. Au lieu de parcourir les médias sociaux pour trouver des articles, comparer les prix et passer à la caisse, les utilisateurs peuvent discuter avec un agent qui se connecte au serveur MCP de PayPal pour gérer toutes ces actions.
</p></li><li><p><strong>EpicAI.pro - Jarvis :</strong> Les développements de MCP nous rapprochent de plus en plus d'un véritable assistant de type Jarvis. Pour ceux qui ne connaissent pas les films d'Iron Man, Jarvis est un assistant IA qui utilise le langage naturel, répond aux entrées multimodales, n'a aucune latence lorsqu'il répond, est proactif en anticipant les besoins de l'utilisateur, gère automatiquement les intégrations et peut passer d'un appareil à l'autre et d'un lieu à l'autre en fonction du contexte. Si nous imaginons Jarvis comme un assistant robotique physique, MCP lui donne des "mains" ou la capacité de gérer des tâches complexes.
</p></li><li><p><strong>Postman - </strong><a href="https://www.postman.com/explore/mcp-generator"><strong>Générateur de serveur MCP</strong></a><strong>: </strong>Fournit une expérience de panier pour les demandes d'API où vous pouvez choisir différentes demandes d'API, les mettre dans un panier et télécharger l'ensemble du panier en tant que serveur MCP.
</p></li><li><p>Bloomberg <strong>- </strong>Bloomberg a résolu un goulot d'étranglement important dans le développement de la GenAI en entreprise. Avec près de 10 000 ingénieurs, la société avait besoin d'un moyen standardisé pour intégrer les outils et les agents au sein des équipes. Avec MCP, ils ont transformé leurs outils internes en composants modulaires à distance que les agents peuvent facilement appeler sur une interface unifiée. Cela a permis à leurs ingénieurs de fournir des outils à l'ensemble de l'organisation, tandis que les équipes d'intelligence artificielle se sont concentrées sur la création d'agents plutôt que sur des intégrations personnalisées. Bloomberg prend désormais en charge des flux de travail d'agents évolutifs et sécurisés qui débloquent une interopérabilité totale avec l'écosystème MCP. Bloomberg n'a lié aucune ressource publique, mais c'est ce qu'ils ont présenté en public lors du sommet.
</p></li><li><p><strong>Block - </strong>Block utilise MCP pour alimenter <a href="https://github.com/block/goose?tab=readme-ov-file">Goose</a>, un agent d'intelligence artificielle interne qui permet aux employés d'automatiser des tâches dans les domaines de l'ingénierie, des ventes, du marketing, etc. Ils ont construit plus de 60 serveurs MCP pour des outils tels que Git, Snowflake, Jira et Google Workspace afin de permettre une interaction en langage naturel avec les systèmes qu'ils utilisent tous les jours. Les employés de Block utilisent désormais Goose pour interroger les données, détecter les fraudes, gérer les incidents, naviguer dans les processus internes et bien plus encore, le tout sans avoir à écrire de code. MCP a aidé Block à adopter l'IA dans de nombreuses fonctions en seulement 2 mois.
</p></li><li><p><strong>AWS - </strong><a href="https://github.com/awslabs/mcp"><strong>Serveurs MCP AWS</strong></a><strong>: </strong>AWS a présenté un serveur MCP amusant sur le thème de Donjons et Dragons qui simule un lancer de dés, suit les lancers passés et renvoie les résultats à l'aide de HTTP en continu. Cet exemple léger a mis en évidence la facilité avec laquelle il est possible de construire et de déployer des serveurs MCP à l'aide d'outils et d'infrastructures AWS comme Lambda et Fargate. Ils ont également présenté <a href="https://aws.amazon.com/blogs/opensource/introducing-strands-agents-an-open-source-ai-agents-sdk/">Strands SDK</a>, un kit d'outils open-source pour la création d'agents multimodaux qui interagissent avec les serveurs MCP.</p></li></ul><h2>Support MCP dans Elastic Agent Builder</h2><p>Vous pouvez commencer à expérimenter MCP dès aujourd'hui en utilisant <a href="https://www.elastic.co/fr/search-labs/blog/elastic-ai-agent-builder-context-engineering-introduction">Elastic Agent Builder,</a> qui est le moyen le plus simple de créer des agents directement à partir de vos données. Agent Builder vous permet d'exposer des outils basés sur Elasticsearch à des agents compatibles avec MCP et il est déjà livré avec quelques outils intégrés puissants, notamment :</p><ul><li><p><code>platform.core.search</code> - Exécute des recherches à l'aide du DSL Elasticsearch Query complet.</p></li><li><p><code>platform.core.list_indices</code> - Liste de tous les index disponibles dans Elasticsearch (aide les agents à découvrir les données existantes)</p></li><li><p><code>platform.core.get_index_mapping</code> - Récupère les correspondances de champs pour un index spécifique (aide les agents à comprendre la forme et les types de vos données).</p></li><li><p><code>platform.core.get_document_by_id</code> - Recherche d'un document spécifique par son numéro d'identification (pour une recherche précise)</p></li></ul><p>Grâce à ces outils, vous pouvez doter votre agent d'une fonction de recherche et de pertinence au niveau de l'entreprise, ce qui est essentiel pour créer des agents d'intelligence artificielle fiables.</p><p>Ce qui rend Agent Builder encore plus puissant, c'est la possibilité de définir et d'exposer vos propres outils personnalisés, adaptés aux besoins de votre application. Ceci est particulièrement utile pour les flux de travail basés sur l'opinion ou répétables lorsque vous souhaitez que l'agent effectue un type de recherche spécifique sur un index spécifique sans avoir à redécouvrir cette logique à chaque fois. Au lieu de dépenser des jetons en planification et en raisonnement pour arriver à la même conclusion, vous pouvez encoder cette intention directement dans un outil, ce qui rend vos agents plus rapides, plus fiables et plus rentables.</p><p>Dans l'interface utilisateur de l'Agent Builder, voici un exemple de définition d'outil personnalisé qui utilise ES|QL :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca9e3d0a4e7031c0/6a17e803faa913d8c393c897/c1f6405a374b707e8e6fa36b9e21db5f3c7cd127-1376x864.png" alt="Interface utilisateur de l'Agent Builder" /><p>Une fois que vous avez défini vos outils personnalisés, vous pouvez les exposer (ainsi que les outils natifs intégrés) à l'aide de MCP en cliquant sur la liste déroulante <code>Manage MCP</code> et en copiant l'URL du serveur MCP.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf7d8b29b06c08f94/6a17e805033c8d07f06bb1b6/9f39588525ca2643475de557ea54a6bcf5c150f6-1282x616.png" alt="Outils MCP" /><p>Vous pouvez maintenant importer ce point de terminaison MCP dans n'importe quel client qui consomme MCP pour le connecter à Agent Builder et lui donner accès à tous les outils disponibles. Pour plus d'informations, lisez cette introduction à <a href="https://www.elastic.co/fr/search-labs/blog/elastic-ai-agent-builder-context-engineering-introduction">Agent Builder</a>.</p><h2>Conclusion</h2><p>Le MCP Dev Summit a clairement montré que le MCP façonne la manière dont ces agents d'intelligence artificielle interagissent entre eux et avec le monde des données qui les entoure. Qu'il s'agisse de connecter un agent aux données de l'entreprise ou de concevoir des agents entièrement autonomes, MCP offre une méthode d'intégration normalisée et composable qui devient rapidement utile à grande échelle. Des protocoles de transport et des modèles de sécurité aux registres et à la gouvernance, l'écosystème MCP mûrit rapidement. Le programme MCP restera ouvert et axé sur la communauté, de sorte que les développeurs d'aujourd'hui ont la possibilité de façonner son évolution.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/mcp-current-state</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/mcp-current-state</guid>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2f63f23bbecd2a18/6a17e8066317302039585aa7/02b8c8672ffa129e0ed91a92d6cab612a01d27f2-1200x628.png" length="0" type="image/png"/>
    <pubDate>Thu, 12 Jun 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>