<?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[IA agentique - 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[IA agentique - 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/blog/category/agentic-ai</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/blog/category/agentic-ai</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/category/agentic-ai.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 00:42:03 GMT</lastBuildDate>
  <item>
    <title><![CDATA[137 000 personnes, zéro décision humaine : réponse agentique aux catastrophes avec Elasticsearch]]></title>
    <description><![CDATA[Découvrez comment une règle de détection Kibana, un workflow et un agent IA ont automatiquement relocalisé 137 000 militaires sur sept sites lors du passage d'un ouragan, sans aucune intervention de régulateur.]]></description>
    <content:encoded><![CDATA[<p>Elastic vient de coordonner l'évacuation automatisée de 137 000 militaires répartis sur sept sites, sans aucune intervention humaine. Un ouragan de catégorie 4 frappe le littoral de Hampton Roads. La fonctionnalité d'enrichissement géospatial d'Elasticsearch identifie, dès l'indexation, toutes les installations situées dans la zone d'impact. Une règle de détection Kibana se déclenche. Un workflow initie une conversation avec un agent IA. L'agent évalue les capacités d'accueil, les distances et la compatibilité des unités, puis diffuse 16 notifications d'évacuation et de prise en charge en une seule opération. Le tout automatiquement, en passant de l'événement brut (issu du GDACS) à une action coordonnée.</p><p>Chaque année, les catastrophes naturelles contraignent les responsables de la gestion des urgences, les commandants militaires et les autorités de sécurité publique à prendre des décisions aux enjeux considérables dans des délais très courts. Ces décisions reposent traditionnellement sur des chaînes d'appel, des feuilles de calcul et des connaissances institutionnelles réparties entre des dizaines de personnes. À elle seule, la surcharge liée à la coordination fait perdre un temps précieux.</p><p>Cet article montre comment Elastic permet de disposer d'un système de coordination agentique réactif et autonome pour la réponse aux catastrophes. Ce système détecte une menace, analyse les aspects logistiques et prend des mesures automatiquement. Pour illustrer ce concept, nous avons créé une simulation : un ouragan fictif de catégorie 4 menaçant le littoral de Hampton Roads déclenche le déplacement automatisé de plus de 137 000 personnes réparties sur sept installations militaires.</p><p><strong>Avertissement</strong> : <strong>ceci est un scénario entièrement fictif élaboré à des fins de démonstration. </strong>L’ouragan ELARA-26 n’existe pas. Les emplacements des installations reposent sur des données géographiques réelles et accessibles au public issues de l'ensemble de données MIRTA (Military Installations, Ranges and Training Areas) du département de la Défense des États-Unis. Toutes les données opérationnelles, telles que les effectifs, la capacité de logement, les ressources, les adresses e-mail de contact et les profils de mission, sont entièrement fictives. Rien dans cette démonstration ne reflète la préparation opérationnelle, les capacités ou les procédures opérationnelles militaires réelles.</p><h2>Pourquoi la réponse automatisée aux catastrophes nécessite une coordination géospatiale et agentique</h2><p>Lorsqu'une catastrophe naturelle menace les infrastructures critiques, le défi de la coordination est immédiat :</p><ul><li><p>Quelles installations se trouvent dans la zone d'impact ?</p></li><li><p>Combien de membres du personnel doivent être déplacés ?</p></li><li><p>Où peuvent-ils aller, et ces installations ont-elles la capacité nécessaire ?</p></li><li><p>Qui doit être informé immédiatement ?</p></li></ul><p>Ces questions n'attendent pas. Les réponses non plus.</p><h2>Déploiement du pipeline : prérequis et configuration</h2><p>Suivez les instructions <a href="https://github.com/tehbooom/elastic_natural_disaster/blob/main/README.md">ici dans le dépôt d'exemples</a> pour déployer un cluster Elastic local avec Elastic Inference Service (EIS) via <a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/connect-self-managed-cluster-to-eis#set-up-eis-with-cloud-connect">Cloud Connect</a>.</p><h2>Fonctionnement du pipeline agentique de réponse aux catastrophes d'Elasticsearch</h2><p>Le pipeline comporte sept couches qui fonctionnent ensemble de bout en bout :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf09bfae87ab35bec/6a4693ef31bdbbe3ef8b33ae/61814cddea0409162fb057c2113e0a496c105238-1999x275.png" alt="Pipeline flowchart Alt text: Horizontal flowchart with seven labeled boxes connected by arrows: GDACS feed, ingest pipeline, enrich (geo_shape), detection rule, workflow, AI agent, and email." /><ol><li><p><strong>Ingestion de données</strong> : les événements de catastrophe du Système mondial d'alerte et de coordination en cas de catastrophe (GDACS) sont envoyés à Elasticsearch.</p></li><li><p><strong>Pipeline d'ingestion</strong> : les données GeoJSON sont ingérées et normalisées selon Elastic Common Schema (ECS).</p></li><li><p><strong>Enrichissement géospatial</strong> : le polygone de la zone touchée par l'événement est confronté aux limites indexées des installations militaires.</p></li><li><p><strong>Alerting</strong> : une règle de détection Kibana se déclenche lorsqu'une catastrophe recoupe une installation.</p></li><li><p><strong>Automatisation du workflow</strong> : l'alerte déclenche un workflow Kibana qui lance une conversation avec un agent IA.</p></li><li><p><strong>Raisonnement de l'IA</strong> : l'agent analyse les installations concernées, leurs actifs et les installations de soutien les plus proches afin de déterminer la relocalisation de l'ensemble des actifs et du personnel.</p></li><li><p><strong>Notifications par e-mail</strong>: l'agent envoie des e-mails à tous les destinataires concernant le personnel et/ou les actifs entrants et sortants.</p></li></ol><p>Passons en revue chaque couche.</p><h2>Étape 1 : Indexation des installations militaires avec limites géographiques</h2><p>La base repose sur l'ensemble de données DoD MIRTA provenant de <a href="https://source.coop/seerai/hifld/military-installations-ranges-and-training-areas-mirta-dod-sites---boundaries">source.coop/seerai/hifld</a>. Cet ensemble fournit une géométrie de type Point pour chaque installation, à savoir des coordonnées de centroïde plutôt que de polygones délimitant l'intégralité du périmètre.</p><p>Chaque document d'installation dans l'index 'mitra-facilities' est enrichi de données de profil opérationnel (toutes fictives), au-delà de ce que fournit MIRTA :</p>{
  "entity_name": "Naval Station Norfolk",
  "branch_of_service": "Navy",
  "mission_function_type": "fleet_support",
  "personnel_count": 50000,
  "housing_capacity": 55000,
  "temporary_housing_capacity": 10000,
  "logistics_capabilities": ["fuel", "airlift", "sealift", "medical"],
  "available_assets": [
    { "type": "helicopters", "count": 24 },
    { "type": "transport_vehicles", "count": 150 }
  ],
  "contact_email": "norfolk.ops@navy.mil.gov.fake",
  "operational_status": "act",
  "is_joint_base": false,
  "entity_geo_location": { "type": "polygon", "coordinates": [...] }
}<p>C'est cet index riche qui permet à l'agent IA de prendre des décisions d'affectation intelligentes. Il ne s'agit pas simplement d'identifier des bases à proximité, mais de repérer celles qui disposent de capacités de logement disponibles, de types de missions compatibles et de la logistique nécessaire pour accueillir les ressources entrantes.</p><h2>Étape 2 : Ingestion et normalisation des événements GDACS</h2><p>GDACS publie des données GeoJSON en temps réel concernant les séismes, les cyclones tropicaux, les inondations, les feux de forêt, les volcans et les sécheresses. Nous intégrons ce flux dans un flux de données (logs-gdacs.events-*) à l'aide d'un pipeline d'ingestion personnalisé qui normalise les données GeoJSON brutes au format de champs ECS.</p><p>À noter que le pipeline d'ingestion GDACS effectue plusieurs opérations :</p><p><strong>Extraction de la géométrie</strong> : le centroïde est stocké sous forme de 'geo_point' pour l'affichage cartographique, et le polygone d'impact est stocké sous forme de 'geo_shape' dans 'gdacs.affected_area', un champ qui sera utilisé ultérieurement pour les requêtes de recoupement.</p><p><strong>Normalisation de la gravité</strong> : chaque type de catastrophe présente une échelle de gravité différente. Un cyclone tropical se mesure par la vitesse du vent en km/h, tandis qu'un séisme s'évalue selon la magnitude de Richter. Le pipeline convertit toutes ces mesures en un score normalisé allant de 0 à 100 :</p>// Painless snippet from the ingest pipeline
if (type == 'TC') {
  norm = Math.min(100.0, Math.max(0.0, (val - 40.0) / 2.6));
} else if (type == 'EQ') {
  norm = Math.min(100.0, Math.max(0.0, (val - 4.0) * 20.0));
}<p>Le score de gravité normalisé est ensuite associé à une étiquette de niveau de gravité (faible, moyen, élevé, critique) utilisée pour la correspondance du niveau de gravité de l'alerte dans la règle de détection.</p><p><strong>Alignement ECS</strong> : event.kind : alerte, event.category : menace, horodatages mappés sur event.start/event.end et un _id stable basé sur une empreinte pour la déduplication.</p><h2>Étape 3 : Enrichissement géospatial - identifier les installations affectées au moment de l'indexation</h2><p>La politique d'enrichissement 'geo_match' d'Elasticsearch fait correspondre le polygone de la zone sinistrée à chaque périmètre d'installation lors de l'indexation, sans nécessiter de jointure au moment de la requête. Au lieu d'effectuer une requête lors de la recherche, nous utilisons un <strong>processeur d'enrichissement</strong> dans le pipeline d'ingestion pour faire correspondre le polygone d'impact de la catastrophe avec chaque limite d'installation <em>au moment où le document est indexé</em>.</p><p>La politique d'enrichissement est une politique 'geo_match' :</p>{
  "geo_match": {
    "indices": "mitra-facilities",
    "match_field": "entity_geo_location",
    "enrich_fields": [
      "entity_name",
      "entity_type",
      "entity_station_number",
      "entity_geo_city_name",
      "entity_geo_region_name"
    ]
  }
}<p>Le processeur s'exécute à la fin du pipeline d'ingestion :</p>{
  "enrich": {
    "policy_name": "facilities-geo",
    "field": "gdacs.affected_area",
    "target_field": "affected_facilities",
    "shape_relation": "INTERSECTS",
    "max_matches": 128
  }
}<p>INTERSECTS permet de détecter toute installation dont la limite touche ou chevauche le polygone de la catastrophe, y compris en cas d'intersection partielle. Par conséquent, chaque document d'événement GDACS est enregistré avec un tableau imbriqué 'affected_facilities' indiquant précisément quelles installations se trouvent dans la zone d'impact. Aucune requête de jointure n'est nécessaire.</p><h2>Étape 4 : Règle de détection – alerting en cas d'impact sur les installations</h2><p>Une règle de détection Kibana surveille le flux de données logs-gdacs.events-* et se déclenche lorsqu'un événement GDACS a été enrichi avec au moins une infrastructure affectée :</p>Requête : affected_facilities : { entity_name: * }<p>La règle s'exécute selon une planification horaire (couvrant une fenêtre allant de 'now-1h' à 'now') et utilise une correspondance dynamique de la gravité ; le champ 'gdacs.severity_level', calculé par le pipeline d'ingestion, détermine automatiquement la gravité de l'alerte.</p><p>La gravité de l'alerte détermine également le score de risque via le mapping de champs :</p>"risk_score_mapping": [
  {
    "field": "gdacs.normalized_severity",
    "operator": "equals",
    "value": ""
  }
]<p>Lorsque la règle se déclenche, elle transmet à un workflow Kibana l'intégralité du contexte de l'alerte, y compris le tableau 'affected_facilities' enrichi contenant les noms, types et emplacements des installations.</p><h2>Étape 5 : Automatisation des workflows – relier l'alerte à l'agent</h2><p>Les workflows Kibana gèrent la transition entre la détection et la réponse. Le workflow de réponse aux catastrophes naturelles est déclenché par l'alerte :</p>triggers:
  - type: alert
steps:
  - name: start_convo
    type: kibana.request
    with:
      method: "POST"
      path: "/api/agent_builder/converse"
      body:
        agent_id: "mitra.response"
        input: "New Natural Disaster Alert: {{ event.alerts | json }}"<p>L'intégralité de la charge utile de l'alerte (type de catastrophe, gravité, zone touchée et liste des installations impactées) est transmise à l'agent IA en tant que contexte initial. L'agent prend ensuite le relais.</p><h2>Étape 6 : L'agent IA – des données à l'action coordonnée</h2><p>L'agent mitra.response utilise l'intégralité de la charge utile d'alerte et, au cours d'une seule boucle agentique, évalue le périmètre, trouve les établissements d'accueil, affecte le personnel et envoie des notifications d'évacuation et de prise en charge, le tout sans intervention humaine.</p><p>L'agent dispose de deux outils :</p><ul><li><p><strong>mitra.nearest_facility</strong>interroge l'index mitra-facilities à l'aide d'une requête geo_shape, triée par distance par rapport à une coordonnée donnée, et renvoie jusqu'à 50 installations actives à proximité disposant de capacités d'accueil.</p></li><li><p><strong>mitra.send_email</strong> itère sur un tableau JSON d'objets d'installation et transmet des notifications formatées d'évacuation ou de réception.</p></li></ul><p>L'ensemble d'instructions de l'agent définit un workflow clair :</p><ol><li><p><strong>Évaluer la situation.</strong> Analyser l'alerte, identifier les installations touchées et déterminer l'ampleur de la catastrophe.</p></li><li><p><strong>Faire l'inventaire de ce qui doit être déplacé.</strong> Effectifs, ressources critiques, besoins en hébergement par établissement.</p></li><li><p><strong>Rechercher les installations de destination.</strong> Appeler mitra.nearest_facility pour chaque installation concernée, en excluant celles qui se trouvent encore dans la zone de danger.</p></li><li><p><strong>Prendre des décisions d'allocation.</strong> Raisonner sur les solutions monosite par rapport aux solutions multisites, la compatibilité des branches, la capacité d'hébergement, le support technique des actifs.</p></li><li><p><strong>Envoyer les e-mails de coordination.</strong> Transmettre les ordres d'évacuation aux établissements d'origine et les notifications d'admission aux établissements d'accueil.</p></li><li><p><strong>Générer un rapport récapitulatif. </strong>Produire un court résumé, à transmettre dans le chat pour examen, de toutes les installations concernées, de l'effectif total, des actifs déplacés, des installations de destination et de toute préoccupation.</p></li></ol><p>La logique d'affectation de l'agent respecte des contraintes réelles : ne pas dépasser la capacité d'hébergement, privilégier les réaffectations au sein d'une même branche lorsque c'est possible, utiliser des bases interarmées pour les excédents multibranches et prioriser la distance afin de minimiser le temps de trajet.</p><h3>L'outil d'installation la plus proche</h3><p>La requête de workflow sous-jacente utilise geo_shape avec un filtre de cercle et un tri _geo_distance :</p>"query": {
  "bool": {
    "filter": [
      {
        "geo_shape": {
          "entity_geo_location": {
            "shape": {
              "type": "circle",
              "coordinates": [{{ inputs.lon }}, {{ inputs.lat }}],
              "radius": "5000km"
            },
            "relation": "intersects"
          }
        }
      },
      { "term": { "operational_status.keyword": "act" } }
    ]
  }
},
"sort": [
  {
    "_geo_distance": {
      "entity_geo_point": { "lat": {{ inputs.lat }}, "lon": {{ inputs.lon }} },
      "order": "asc",
      "unit": "km"
    }
  }
],
"script_fields": {
  "available_capacity": {
    "script": {
      "source": "Math.max(0, doc['housing_capacity'].value - doc['personnel_count'].value)"
    }
  }
}<p>La capacité disponible est calculée au moment de la requête via un champ de script qui soustrait l'effectif actuel de la capacité d'hébergement. L'agent utilise cette information pour répartir le personnel entre les différentes destinations sans dépasser les limites.</p><h2>Ouragan ELARA-26 : coordination agentique de 137 000 personnes, de bout en bout</h2><p>L'ouragan ELARA-26 est une tempête de catégorie 4 (vitesse maximale de 213 km/h) dont l'arrivée sur les côtes est prévue dans la région de Hampton Roads, en Virginie. Lors de l'intégration de l'événement GDACS, le polygone de la zone touchée recoupe sept installations militaires majeures de la région. La règle de détection se déclenche. Le workflow initie une conversation entre agents.</p><p>Au sein d'une seule boucle agentique, l'agent :</p><ul><li><p>a identifié sept installations dans la zone d'impact pour un total de 137 372 membres du personnel ;</p></li><li><p>a appelé mitra.nearest_facility pour trouver des établissements d'accueil situés en dehors de la trajectoire de la tempête ;</p></li><li><p>a réparti le personnel entre neuf établissements d'accueil en fonction de la capacité d'hébergement disponible et de la distance ;</p></li><li><p>a généré et envoyé des ordres d'évacuation aux sept installations concernées ;</p></li><li><p>a généré et envoyé des notifications d'admission aux neuf installations destinataires ;</p></li><li><p>a généré un récapitulatif complet de coordination, semblable à ce qui suit :</p></li></ul><p><strong>Sites évacués :</strong></p><p>Installation</p><p>Personnel</p><p>Base navale de Norfolk</p><p>50 000</p><p>Base expéditionnaire interarmées Little Creek-Fort Story</p><p>18 000</p><p>Base aéronavale Oceana</p><p>15 355</p><p>Annexe Dam Neck de la base aéronavale d'Oceana</p><p>17 509</p><p>Réserve militaire d'État de la Garde nationale Camp Pendleton</p><p>9 707</p><p>Base interarmées Langley-Eustis</p><p>15 000</p><p>Base d'armement naval de Yorktown</p><p>11 801</p><p><strong>Installations d'accueil :</strong></p><p>Installation</p><p>Distance</p><p>Personnel entrant</p><p>Fort Gregg-Adams</p><p>97 km</p><p>~40 000</p><p>Base du Corps des Marines de Quantico</p><p>148 km</p><p>~30 000</p><p>Installation de soutien naval d'Indian Head</p><p>151 km</p><p>~30 000</p><p>Base interarmées Andrews</p><p>180 km</p><p>~30 000</p><p>Base aéronavale de Patuxent River</p><p>141 km</p><p>~10 000</p><p>Camp Butner de la Garde nationale</p><p>174 km</p><p>~5 000</p><p>Site d'entraînement de la Garde nationale Bethany Beach</p><p>209 km</p><p>~4 707</p><p>Base de Rivanna</p><p>140 km</p><p>~7 500</p><p>Centre d'approvisionnement général de la Défense</p><p>22 km</p><p>~6 000</p><p>Les moyens redéployés comprennent des véhicules de transport, des hélicoptères, des patrouilleurs, des unités médicales, des engins du génie, des groupes électrogènes, des remorques-citernes, des kits d'hébergement et des systèmes de communication.</p><h3>Notifications par e-mail automatisées</h3><p>Une fois son plan d'affectation finalisé, l'agent a appelé mitra.send_email et a envoyé 16 e-mails en une seule opération : des ordres d'évacuation destinés aux sept installations concernées et des avis d'admission adressés aux neuf établissements d'accueil. Chaque message précisait l'établissement de destination, le nombre de personnes transférées, les ressources à déplacer ainsi qu'un contact de coordination. Ce qui aurait nécessité des heures de chaînes d'appels téléphoniques a été accompli automatiquement dès que l'agent a achevé son raisonnement.</p><h3>Extension de la réponse agentique aux catastrophes avec la RAG et l'ancrage des politiques</h3><p>Cette démo repose uniquement sur des données structurées, telles que les capacités, les distances et l'état opérationnel. Les fonctionnalités de recherche sémantique et de génération augmentée par récupération (RAG) d'Elastic contribuent à rendre l'agent nettement plus intelligent, grâce à deux ajouts :</p><p><strong>Récupération des réponses historiques</strong> : indexation des anciens rapports post-intervention, des résumés d'incidents de l'Agence fédérale de gestion des urgences (FEMA) et des archives de réponse aux catastrophes sous forme d'embeddings vectoriels. Lorsqu'un nouvel événement se déclenche, l'agent peut effectuer une recherche sémantique sur la manière dont des événements similaires ont été traités, afin d'éclairer les décisions d'allocation grâce aux connaissances institutionnelles plutôt qu'aux seuls calculs de capacité.</p><p><strong>Ancrage dans les politiques et la doctrine</strong> : indexation des directives de gestion des urgences du DoD, des plans de continuité des opérations des installations et des orientations du commandement. L'agent peut récupérer et citer les politiques réelles régissant une réponse, garantissant ainsi que chaque décision est fondée sur la doctrine plutôt que sur une inférence.</p><p>Ces deux fonctionnalités suivent la même approche Elastic native : un pipeline d'inférence génère des embeddings au moment de l'indexation, et un outil de recherche sémantique est exposé à l'agent. Le pipeline de coordination reste le même. L'agent devient simplement plus intelligent.</p><h2>Pourquoi Elasticsearch est la plateforme idéale pour la réponse agentique dans le secteur public</h2><p>Ce n'est pas un chatbot. Ce n'est pas un tableau de bord. C'est un système de workflow agentique réactif, lequel a détecté une menace, analysé un problème logistique complexe et coordonné le déplacement de 137 000 personnes sans intervention humaine. Ce type de résultat n'est possible que parce que chaque fonctionnalité dont il dépend repose sur une plateforme unique et unifiée.</p><p>La prise en charge géospatiale d'Elasticsearch (geo_point, geo_shape, stratégies d'enrichissement et tri basé sur la distance) gère le raisonnement spatial qui rend possibles la détection des recoupements et la recherche d'installations à grande échelle. La recherche sémantique et les embeddings vectoriels ancrent les agents dans la réalité, garantissant que le raisonnement de l'IA repose sur ce qui se trouve réellement dans vos données plutôt que sur des hypothèses hallucinées. Le moteur de détection de Kibana, Workflows, Agent Builder et les outils d'Agent Builder connectent l'ensemble au sein d'un pipeline allant de l'événement brut à l'action coordonnée, sans nécessiter le moindre code de liaison externe.</p><p>Aucune autre plateforme ne réunit ces capacités comme le fait Elastic. L'alliance de l'indexation en temps réel, de la précision géospatiale, de la recherche sémantique et de l'orchestration par agents, le tout au sein d'une même pile technologique intégrant sécurité et observabilité de niveau entreprise, distingue Elastic des outils qui excellent dans un seul de ces domaines tout en vous obligeant à assembler vous-même les autres éléments.</p><h2>Réponse géospatiale agentique pour la gestion des urgences, les services d'incendie, les forces de l'ordre et la santé publique</h2><p>La même architecture s'applique partout où les personnes, les installations, et les événements en temps réel se recoupent. Les données spécifiques changent. Le pipeline ne change pas.</p><p><strong>Gestion des urgences</strong> : la FEMA et les services de gestion des urgences des États peuvent cartographier l'emplacement des abris, les zones de déploiement et les populations vulnérables en regard des polygones de conditions météorologiques extrêmes émis par le National Weather Service (NWS), déclenchant ainsi le prépositionnement automatisé des ressources avant qu'une tempête ne touche terre.</p><p><strong>Services d'incendie et de secours d'urgence</strong> : les services d'incendie peuvent superposer l'emplacement des unités et les zones d'intervention aux périmètres des feux de forêt ou aux clusters d'incendies de structures, en acheminant automatiquement les demandes d'entraide vers les unités disponibles les plus proches dotées de l'équipement adapté.</p><p><strong>Forces de l'ordre</strong> : les organismes peuvent corréler les lieux d'incidents en cours avec les zones scolaires, les infrastructures critiques et la position des agents, déclenchant ainsi des notifications de confinement géolocalisées ou le déploiement de ressources sans attendre un tri manuel.</p><p><strong>Sécurité des établissements scolaires</strong> : les districts scolaires peuvent monitorer les flux de menaces en temps réel par rapport au périmètre des campus. Lorsqu'une menace franchit le périmètre d'une école, un agent peut immédiatement avertir l'administration, déclencher les communications de confinement et coordonner la réponse des forces de l'ordre, avant même qu'un coordinateur ne décroche son téléphone.</p><p><strong>Santé publique</strong> : les services de santé peuvent comparer les données de surveillance des maladies ou les zones de risques environnementaux avec les emplacements des établissements de soin, les couches de densité de population et les inventaires des dépôts de fournitures afin d'acheminer les ressources là où elles sont le plus nécessaires.</p><p>Secteur</p><p>Cas d'utilisation</p><p>Capacité Elastic</p><p>Gestion des urgences</p><p>Croiser les emplacements des abris aux polygones de phénomènes météorologiques violents du NWS</p><p>Enrichissement geo_shape + workflows Kibana</p><p>Incendie et SMU</p><p>Superposer les emplacements des unités aux périmètres des feux de forêt</p><p>Routage géospatial + requête de recherche de l'installation la plus proche</p><p>Application de la loi</p><p>Corréler les incidents avec les zones scolaires et les positions des agents</p><p>Règles d'alerte tenant compte de la géolocalisation + répartition des agents</p><p>Sécurité des établissements scolaires</p><p>Monitorer les flux de menaces par rapport aux périmètres de campus</p><p>Règles de détection + notification automatisée</p><p>Santé publique</p><p>Croiser les zones de danger avec les emplacements des établissements de soin et les dépôts de ravitaillement</p><p>Recherche sémantique + enrichissement géospatial</p><p>Les données varient selon les scénarios, mais le schéma sous-jacent reste identique : ingestion, enrichissement lors de l'indexation, détection des recoupements, déclenchement d'une réponse agentique et exécution de l'action. Elastic fournit aux organismes du secteur public une plateforme permettant de concevoir cette solution une seule fois et de l'adapter partout.</p><p><em>La publication et la date de publication des fonctionnalités ou fonctions décrites dans le présent article restent à la seule discrétion d'Elastic. Toute fonctionnalité ou fonction qui n'est actuellement pas disponible peut ne pas être livrée à temps ou ne pas être livrée du tout.</em></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-agentic-disaster-response</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-agentic-disaster-response</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Kibana]]></category>
    <dc:creator><![CDATA[Alec Carpenter]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt969cad2694920de4/6a4693f37746672ad42675b5/cb292a501835472598dee30bef25c77afc54db6c-720x420.png" length="0" type="image/png"/>
    <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment créer des applications d'IA agentique avec Mastra et Elasticsearch]]></title>
    <description><![CDATA[Découvrez comment créer des applications d'IA agentiques avec Mastra et Elasticsearch à travers un exemple pratique.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous allons voir comment utiliser le framework <a href="https://mastra.ai/">Mastra</a> TypeScript pour créer des applications agentiques qui interagissent avec <a href="https://www.elastic.co/elasticsearch">Elasticsearch</a>.</p><p>Nous avons récemment contribué au projet open source <a href="https://github.com/mastra-ai/mastra">mastra-ai/mastra</a> en ajoutant la prise en charge d'Elasticsearch en tant que base de données vectorielle. Avec cette nouvelle option, vous avez la possibilité d’utiliser Elasticsearch de manière native au sein de Mastra pour le stockage de vos plongements sémantiques. En plus des vecteurs, Elasticsearch propose une suite de fonctionnalités avancées pour répondre à toutes vos exigences en matière d’ingénierie de contexte. (par exemple, <a href="https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai">recherche hybride et reclassement</a>).</p><p>Cet article détaille la création d'un agent chargé de mettre en œuvre une architecture RAG (Retrieval Augmented Generation) à l'aide d'Elasticsearch. Nous présenterons un projet de démonstration dans lequel une approche agentique est utilisée pour interagir avec un corpus de données de films de science-fiction stockées dans Elasticsearch. Le projet est disponible à l’adresse <a href="https://github.com/elastic/mastra-elasticsearch-example">elastic/mastra-elasticsearch-example</a>.</p><h2>Mastra</h2><p>Mastra est un framework TypeScript qui permet de créer des applications d'IA agentiques.</p><p>La structure du projet dans Mastra se présente comme suit :</p>src/
├── mastra/
│   ├── agents/
│   │   └── weather-agent.ts
│   ├── tools/
│   │   └── weather-tool.ts
│   ├── workflows/
│   │   └── weather-workflow.ts
│   ├── scorers/
│   │   └── weather-scorer.ts
│   └── index.ts
├── .env.example
├── package.json
└── tsconfig.json<p>Dans Mastra, vous pouvez créer des <a href="https://mastra.ai/docs/agents/overview">agents</a>, <a href="https://mastra.ai/docs/agents/using-tools">outils</a>, <a href="https://mastra.ai/docs/workflows/overview">workflows</a> et <a href="https://mastra.ai/docs/evals/overview">scores</a>.</p><p>Un <strong>agent</strong> est une classe qui accepte un message en entrée et produit une réponse en sortie. Un agent peut utiliser des outils, de grands modèles de langage (LLM) et une mémoire (figure 1).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f7484f7501997dc/6a170417cdacbffb5a7d28f6/f6aca2dcc7fcc45d25e06681649be1b2b7eb6781-706x721.png" alt="Un schéma montrant comment fonctionne un agent à Mastra." /><p>Les <strong>outils</strong> d’un agent lui permettent d’interagir avec le « monde extérieur », par exemple en communiquant avec une API Web ou en effectuant une opération interne, comme l’interrogation d’Elasticsearch. Le composant <strong>mémoire</strong> est crucial pour stocker l'historique des conversations, y compris les entrées et sorties passées. Ce contexte stocké permet à l’agent de fournir des réponses plus éclairées et pertinentes aux questions futures en utilisant ses interactions passées.</p><p>Les <strong>workflows</strong> permettent de définir des séquences complexes de tâches en utilisant des étapes claires et structurées, plutôt que de se fier au raisonnement d’un seul agent (figure 2). Ils vous donnent un contrôle total sur la manière dont les tâches sont décomposées, comment les données circulent entre elles et ce qui est exécuté à chaque fois. Les workflows s'exécutent en utilisant le moteur d'exécution intégré par défaut ou peuvent être déployés sur des <a href="https://mastra.ai/docs/deployment/workflow-runners">workflow runners</a>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd82ea661569e1018/6a170419dc55de3adde00cc9/0dce161cf7891207015dc87532b5b90df1822432-880x252.png" alt="Un exemple de workflow dans Mastra." /><p>Dans Mastra, vous pouvez également définir des scores : des tests automatisés qui évaluent les sorties des agents à l'aide de méthodes basées sur des modèles, des règles et des statistiques. Les scoreurs renvoient <em>des scores</em> : des valeurs numériques (généralement entre 0 et 1) qui quantifient dans quelle mesure une sortie répond à vos critères d'évaluation. Ces scores vous permettent de suivre objectivement les performances, de comparer différentes approches et d'identifier les domaines à améliorer dans vos systèmes d'IA. Les évaluateurs peuvent être personnalisés avec vos propres invites et fonctions de notation.</p><h2>Elasticsearch</h2><p>Pour exécuter le projet de démonstration, nous devons avoir une instance Elasticsearch en cours d'exécution. Vous pouvez activer un essai gratuit sur <a href="https://www.elastic.co/cloud">Elastic Cloud</a> ou l’installer localement en utilisant le script <a href="https://github.com/elastic/start-local"><code>start-local</code></a> :</p>curl -fsSL https://elastic.co/start-local | sh<p>Cela installera Elasticsearch et Kibana sur votre ordinateur et générera une clé API à utiliser pour configurer l’intégration Mastra.</p><p>La clé API sera affichée comme sortie de la commande précédente et stockée dans un fichier <strong>.env</strong> dans le dossier elastic-start-local.</p><h2>Installation et configuration de la démo</h2><p>Nous avons créé un dépôt <a href="https://github.com/elastic/mastra-elasticsearch-example">elastic/mastra-elasticsearch-example</a> contenant le code source du projet de démonstration. L'exemple rapporté dans le référentiel illustre comment créer un agent dans Mastra qui implémente une architecture RAG pour récupérer des documents depuis Elasticsearch.</p><p>Nous avons fourni un ensemble de données pour la démo sur les films de science-fiction. Nous avons extrait 500 films de l'ensemble de données IMDb sur <a href="https://www.kaggle.com/datasets/rajugc/imdb-movies-dataset-based-on-genre/versions/2?select=scifi.csv">Kaggle</a>.</p><p>La première étape consiste à installer les dépendances du projet avec npm, en utilisant la commande suivante :</p>npm install<p>Ensuite, nous devons configurer le fichier <strong>.env</strong> qui contiendra les paramètres. Nous pouvons générer ce fichier en copiant la structure du fichier <strong>.env.example</strong>, à l'aide de la commande suivante :</p>cp .env.example .env<p>Nous pouvons maintenant modifier le fichier .env, en ajoutant les informations manquantes :</p>OPENAI_API_KEY=
ELASTICSEARCH_URL=
ELASTICSEARCH_API_KEY=
ELASTICSEARCH_INDEX_NAME=scifi-movies<p>Le nom de l’index Elasticsearch est <strong><code>scifi-movies</code></strong>. Si vous le souhaitez, vous pouvez le modifier en utilisant la variable env <code>ELASTICSEARCH_INDEX_NAME</code>.</p><p>Nous avons utilisé OpenAI comme service d’intégration, ce qui signifie que vous devez fournir une clé API pour OpenAI dans la variable <code>OPENAI_API_KEY</code> environnement.</p><p>Le modèle de plongement utilisé dans l'exemple est <a href="https://developers.openai.com/api/docs/models/text-embedding-3-small">openai/text-embedding-3-small</a>, avec une dimension de plongement de 1536.</p><p>Pour obtenir la réponse finale, nous avons utilisé le modèle <a href="https://developers.openai.com/api/docs/models/gpt-5-nano">openai/gpt-5-nano</a> afin de réduire les coûts.</p><p>La structure RAG autorise l’usage d’un LLM moins sophistiqué en bout de chaîne, puisque la mission critique d’ancrage de la réponse dans des données fiables est assurée en amont par le moteur de recherche (Elasticsearch).</p><p>Le LLM plus petit n'est responsable que de deux tâches principales :</p><ul><li><p><strong>Reformuler/intégrer la requête :</strong> conversion de la question en langage naturel de l'utilisateur en une question vectorielle intégrée pour la recherche sémantique.</p></li><li><p><strong>Synthétiser la réponse :</strong> prendre les éléments contextuels (documents/films) les plus pertinents récupérés et les synthétiser pour obtenir une réponse cohérente, finale et lisible par l'homme, en suivant les instructions rapides fournies.</p></li></ul><p>Puisque le processus RAG <strong>fournit le contexte factuel précis</strong> nécessaire à la réponse, le LLM final n’a pas besoin d’être massif ou extrêmement complexe, et il n’est pas nécessaire qu’il possède toutes les connaissances requises au sein de ses propres paramètres (domaine où excellent les modèles volumineux et coûteux). Il agit essentiellement comme un outil sophistiqué de résumé et de formatage de texte pour le contexte fourni par Elasticsearch, plutôt que comme une base de connaissances à part entière. Cela permet l’utilisation de modèles comme <code>gpt-5-nano</code> pour l’optimisation des coûts et de la latence.</p><p>Après la configuration du fichier .env , vous pouvez ingérer les films dans Elasticsearch à l'aide de la commande suivante :</p>npx tsx src/utility/store.ts<p>Vous devriez obtenir la sortie suivante :</p>🚀 Starting ingestion of 500 movies from 500_scifi_movies.jsonl...
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 1/500 (0%) | ok:1 | fail:0 | chunks:1 | eta:19m 33s | current:Capricorn One
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 2/500 (0%) | ok:2 | fail:0 | chunks:2 | eta:10m 32s | current:Doghouse
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 3/500 (1%) | ok:3 | fail:0 | chunks:3 | eta:7m 33s | current:Dinocroc
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 4/500 (1%) | ok:4 | fail:0 | chunks:7 | eta:6m 10s | current:Back to the Future           
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 5/500 (1%) | ok:5 | fail:0 | chunks:9 | eta:5m 14s | current:The Projected Man            
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 6/500 (1%) | ok:6 | fail:0 | chunks:11 | eta:4m 41s | current:I, Robot
...
✅ Ingestion complete in 1m 46s. Success: 500, Failed: 0, Chunks: 693.<p>Le mapping de l’index des films de science-fiction contient les champs suivants :</p><ul><li><p><strong>plongement</strong>, vecteur dense de dimension 1536, similarité cosinus.</p></li><li><p><strong>description</strong>, texte contenant la description du film.</p></li><li><p><strong>réalisateur</strong>, texte contenant le nom du réalisateur.</p></li><li><p><strong>titre</strong>, texte contenant le titre du film.</p></li></ul><p>Nous avons généré les vecteurs d'inclusion en utilisant le titre et la description. Puisque le titre et la description sont deux champs distincts, la concaténation des deux garantit que le vecteur d’inclusion résultant capture à la fois l’identité spécifique et unique (titre) et le contexte descriptif riche (description) du film, conduisant à des résultats de recherche sémantiques plus précis et complets. Cette entrée combinée donne au modèle d'intégration une meilleure représentation unique du contenu du document pour le rapprochement par similarité.</p><h2>Exécutez la démo</h2><p>Vous pouvez exécuter la démo avec la commande suivante :</p>npm run dev<p>Cette commande lancera une application web à <strong>localhost :4111</strong> pour accéder à Mastra Studio (figure 3).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8a539df677a33b36/6a17041a47d49c36842d88a0/1567e309df21a12bcf1dfef4429f82342549956c-1705x1079.png" alt="Capture d'écran de Mastra Studio avec l'exemple d'Elasticsearch Agent." /><p><a href="https://mastra.ai/docs/getting-started/studio">Mastra Studio</a> offre une interface utilisateur interactive pour construire et tester vos agents, ainsi qu'une API REST qui expose votre application Mastra en tant que service local. Cela vous permet de commencer à construire immédiatement sans vous soucier de l'intégration.</p><p>Nous avons fourni un <strong>agent Elasticsearch</strong> qui utilise l'<a href="https://mastra.ai/reference/tools/vector-query-tool">outil createVectorQueryTool</a> de Mastra comme outil pour exécuter une recherche sémantique à l'aide d'Elasticsearch. Cet agent utilise l'approche RAG pour rechercher des documents pertinents (c'est-à-dire des films) pour répondre à la question de l'utilisateur.</p><p>Cet agent utilise la consigne suivante :</p>You are a helpful assistant that answers questions based on the provided context.
Follow these steps for each response:

1. First, carefully analyze the retrieved context chunks and identify key information.
2. Break down your thinking process about how the retrieved information relates to the query.
3. Draw conclusions based only on the evidence in the retrieved context.
4. If the retrieved chunks don't contain enough information, explicitly state what's missing.

Format your response as:
THOUGHT PROCESS:
- Step 1: [Initial analysis of retrieved chunks]
- Step 2: [Reasoning based on chunks]

FINAL ANSWER:
[Your concise answer based on the retrieved context]

Important: When asked to answer a question, please base your answer only on the context provided in the tool. 
If the context doesn't contain enough information to fully answer the question, please state that explicitly and stop it.
Do not add more information than what is present in the retrieved chunks.
Remember: Explain how you're using the retrieved information to reach your conclusions.<p>Si vous cliquez sur le menu <code>Mastra Studio &gt; Agents</code> et sélectionnez <strong>Agent Elasticsearch</strong>, vous pouvez tester l’agent via un système de chat. Par exemple, vous pouvez demander des informations sur les films de science-fiction en posant la question suivante :</p><p><em>Trouvez 5 films ou séries télévisées sur les OVNI</em>.</p><p>Vous remarquerez que l’agent exécutera le vectorQueryTool. Vous pouvez cliquer sur l'outil invoqué pour voir l'entrée et la sortie. À la fin de l’exécution, le LLM répondra à votre question, compte tenu du contexte issu de l’index des films de science-fiction d’Elasticsearch (figure 4).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda92a9b6e56528d3/6a17041c2b835f9724f4b0d6/d9998d4f687984de98845dae52d1288166abf448-1344x1071.png" alt=" Réponse de LLM à l'aide de l'agent Elasticsearch." /><p>Mastra exécute les étapes suivantes en interne :</p><ol><li><p><strong>Conversion vectorielle :</strong> La question de l'utilisateur, <em>trouvez 5 films ou séries télévisées sur les OVNI,</em> est convertie en une intégration vectorielle à l'aide du modèle <code>openai/text-embedding-3-small</code> d'OpenAI.</p></li><li><p><strong>Recherche vectorielle :</strong> ce plongement sémantique sert alors à effectuer une requête au sein d’Elasticsearch par le biais d’une recherche vectorielle.</p></li><li><p><strong>Récupération des résultats :</strong> Elasticsearch renvoie un ensemble de 10 films très pertinents par rapport à la requête (c'est-à-dire ceux dont les vecteurs sont les plus proches du vecteur de la requête de l'utilisateur).</p></li><li><p><strong>Génération de réponses :</strong> Les films récupérés et la question originale de l'utilisateur sont envoyés au LLM, en particulier à <code>openai/gpt-5-nano</code>. Le LLM traite ces informations et génère une réponse finale, en s'assurant que la demande de l'utilisateur pour cinq résultats est satisfaite.</p></li></ol><h2>L'agent Elasticsearch</h2><p>Ici, nous avons rapporté le code source d'Elasticsearch Agent.</p>import { Agent } from "@mastra/core/agent";
import { ElasticSearchVector } from '@mastra/elasticsearch';
import { createVectorQueryTool } from '@mastra/rag';
import { ModelRouterEmbeddingModel } from "@mastra/core/llm";
import { Memory } from "@mastra/memory";

const es_url = process.env.ELASTICSEARCH_URL;
const es_apikey = process.env.ELASTICSEARCH_API_KEY;
const es_index_name = process.env.ELASTICSEARCH_INDEX_NAME;
const prompt = 'insert here the previous prompt';

const esVector = new ElasticSearchVector({
  id: 'elasticsearch-vector',
  url: es_url,
  auth: {
    apiKey : es_apikey
  }
});

const vectorQueryTool = createVectorQueryTool({
  vectorStore: esVector,
  indexName: es_index_name,
  model: new ModelRouterEmbeddingModel("openai/text-embedding-3-small")
});

export const elasticsearchAgent = new Agent({
  id: "elasticsearch-agent",
  name: "Elasticsearch Agent",
  instructions: prompt,
  model: 'openai/gpt-5-nano',
  tools: { vectorQueryTool },
  memory: new Memory(),
});<p>L'<strong>outil vectorQueryTool</strong> est l'outil invoqué pour mettre en œuvre la partie extraction de l'exemple RAG. Il utilise l’implémentation <a href="https://mastra.ai/reference/vectors/elasticsearch">ElasticSearchVector</a> qu’Elastic a apportée à Mastra.</p><p>L’agent est une instance de la classe agent qui utilise le vectorQueryTool, l’invite et un composant de mémoire. On remarque que le code nécessaire pour l’interconnexion entre Elasticsearch et un agent est extrêmement réduit.</p><h2>Conclusion</h2><p>Cet article a mis en lumière la facilité et l'efficacité de l'association entre Elasticsearch et la structure Mastra pour développer des solutions d'IA agentiques avancées. Nous avons plus spécifiquement exploré la conception d’un agent RAG pouvant mener des recherches sémantiques sur un ensemble de données relatives à des films de science-fiction indexés sous Elasticsearch.</p><p>L’un des enseignements majeurs réside dans la contribution directe d’Elastic à la communauté Mastra, permettant d’intégrer nativement Elasticsearch comme magasin de vecteurs. Cette intégration réduit considérablement la barrière à l'entrée, comme le montre le code source de l'<strong>agent Elasticsearch</strong>. En utilisant <code>ElasticSearchVector</code> et <code>createVectorQueryTool</code>, la configuration complète pour connecter Elasticsearch à votre agent ne nécessite qu'un nombre minimal de lignes de code de configuration.</p><p>Elasticsearch propose plusieurs fonctionnalités avancées pour améliorer la pertinence des résultats. Par exemple, la <a href="https://www.elastic.co/elasticsearch/hybrid-search">recherche hybride</a> améliore considérablement la précision en combinant la recherche lexicale et la recherche vectorielle. Une autre fonctionnalité intéressante est le reranking utilisant les derniers <a href="https://www.elastic.co/search-labs/tutorials/jina-tutorial/jina-reranker-v3">modèles Jina</a> qui peuvent être appliqués à la fin de la recherche hybride. Pour en savoir plus sur ces techniques, consultez les articles suivants d'Elasticsearch Labs :</p><ul><li><p><a href="https://www.elastic.co/search-labs/blog/hybrid-search-elasticsearch">Recherche hybride Elasticsearch</a> par Valentin Crettaz</p></li><li><p><a href="https://www.elastic.co/search-labs/blog/jina-models-elasticsearch-guide">Présentation des modèles Jina, de leurs fonctionnalités et de leurs cas d'usage dans Elasticsearch</a> par Scott Martens</p></li></ul><p>Nous vous encourageons également à explorer l’exemple fourni et à commencer à créer vos propres agents alimentés par les données avec Mastra et Elasticsearch. Pour plus d'informations sur Mastra, vous pouvez consulter la documentation officielle <a href="https://mastra.ai/docs">ici</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/build-agentic-ai-applications-mastra-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/build-agentic-ai-applications-mastra-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Enrico Zimuel]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt083181bab7c0e2d0/6a17041eacf0880b70be99f5/ab30baf2f908534840c5d71a46705773807baf54-1280x720.png" length="0" type="image/png"/>
    <pubDate>Wed, 08 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Création d'un serveur Elasticsearch MCP avec TypeScript]]></title>
    <description><![CDATA[Apprenez à créer un serveur MCP Elasticsearch avec TypeScript et Claude Desktop.]]></description>
    <content:encoded><![CDATA[<p>Lorsque vous travaillez avec de grandes bases de connaissances dans Elasticsearch, trouver des informations n’est que la moitié du travail. Les ingénieurs ont souvent besoin de synthétiser des résultats issus de plusieurs documents, de générer des résumés et de faire remonter les réponses à leur source. Model Context Protocol (MCP) fournit un moyen standardisé de connecter Elasticsearch à des applications alimentées par des grands modèles de langage (LLM) afin d’y parvenir. Bien qu’Elastic propose des solutions officielles, comme Elastic Agent Builder (qui inclut un <a href="https://www.elastic.co/docs/solutions/search/agent-builder/mcp-server">point de terminaison MCP</a> parmi ses fonctionnalités), la création d’un serveur MCP personnalisé vous offre un contrôle total sur la logique de recherche, la mise en forme des résultats et la manière dont le contenu récupéré est transmis à un LLM pour la synthèse, les résumés et les citations.</p><p>Dans cet article, nous examinerons les avantages de la création d’un serveur MCP Elasticsearch personnalisé et expliquerons comment en créer un en TypeScript pour connecter Elasticsearch aux applications alimentées par des modèles LLM.</p><h2>Pourquoi créer un serveur Elasticsearch MCP personnalisé ?</h2><p>Elastic propose quelques alternatives pour <a href="https://www.elastic.co/docs/solutions/search/mcp">les serveurs MCP</a> :</p><ul><li><p><a href="https://www.elastic.co/docs/solutions/search/agent-builder/mcp-server">Serveur MCP Elastic Agent Builder pour Elasticsearch 9.2+</a></p></li><li><p><a href="https://github.com/elastic/mcp-server-elasticsearch?tab=readme-ov-file#elasticsearch-mcp-server">Serveur MCP Elasticsearch pour les anciennes versions (Python)</a></p></li></ul><p>Si vous avez besoin de plus de contrôle sur la façon dont votre serveur MCP interagit avec Elasticsearch, la création de votre propre serveur personnalisé vous donne la flexibilité de l'adapter exactement à vos besoins. Par exemple, le point de terminaison MCP d'Agent Builder est limité aux requêtes du langage de requête Elasticsearch (ES|QL), tandis qu'un serveur personnalisé vous permet d'utiliser le langage de requête DSL complet. Vous gagnez également le contrôle sur la façon dont les résultats sont formatés avant d'être transmis au LLM et pouvez intégrer des étapes de traitement supplémentaires, comme la summarisation alimentée par OpenAI que nous mettrons en œuvre dans ce tutoriel.</p><p>À la fin de cet article, vous aurez un serveur MCP dans TypeScript qui recherche les informations stockées dans un index Elasticsearch, les résume et fournit des citations. Nous utiliserons Elasticsearch pour la récupération, le modèle <code>gpt-4o-mini</code> d'OpenAI pour résumer et générer des citations, et Claude Desktop comme client MCP et interface utilisateur pour recevoir les requêtes des utilisateurs et fournir des réponses. Le résultat final est un assistant de connaissances interne qui aide les ingénieurs à découvrir et à synthétiser les bonnes pratiques dans l'ensemble de la documentation technique de leur organisation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltad9133cb083ad352/6a170c19b0367d411e72bd5b/ec5771a874cf9740d4cac6888622cbe8cd6aede7-1999x1133.png" alt="Création d’un serveur MCP Elastic avec TypeScript et Claude Desktop." /><h2>Produits requis</h2><ul><li><p>Node.js 20 +</p></li><li><p>Elasticsearch</p></li><li><p>Clé API OpenAI</p></li><li><p>Claude Desktop</p></li></ul><h3>Qu'est-ce que le MCP ?</h3><p><a href="https://www.elastic.co/what-is/mcp">MCP</a> est une norme ouverte, créée par <a href="https://www.anthropic.com/news/model-context-protocol">Anthropic</a>, qui fournit des connexions bidirectionnelles sécurisées entre les LLM et les systèmes externes, comme Elasticsearch. Vous pouvez en savoir plus sur l'état actuel du MCP dans <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">cet article</a>.</p><p>Le paysage des MCP <a href="https://www.elastic.co/search-labs/blog/mcp-current-state#mcp-project-updates:-transport,-elicitation,-and-structured-tooling">évolue chaque jour</a>, avec des serveurs disponibles pour un large éventail de cas d'utilisation. De plus, il est facile de créer votre propre serveur MCP personnalisé, comme nous le montrerons dans cet article.</p><h3>Clients MCP</h3><p>Il existe une longue <a href="https://modelcontextprotocol.io/clients">liste de clients MCP disponibles</a>, chacun ayant ses propres caractéristiques et limitations. Par souci de simplicité et de popularité, nous utiliserons <a href="https://claude.ai/download">Claude Desktop</a> comme client MCP. Il servira d'interface de chat où les utilisateurs pourront poser des questions en langage naturel, et il invoquera automatiquement les outils exposés par notre serveur MCP pour rechercher des documents et générer des résumés.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt06fd7a02042094e1/6a170c1b14b2700024e3c651/66eb0b11473347b6cf2d85718251eeac38d6249d-1999x1491.png" alt="Page de Claude 4.5 du Sonnet, avec la note : « Café avec Claude ? » Comment puis-je vous aider aujourd'hui ?" /><h2>Créer un serveur Elasticsearch MCP</h2><p>Grâce au <a href="https://github.com/modelcontextprotocol/typescript-sdk">SDK TypeScript</a>, nous pouvons facilement créer un serveur qui comprend comment interroger nos données Elasticsearch à partir d'une requête utilisateur.</p><p>Voici les étapes dans cet article pour intégrer le serveur Elasticsearch MCP avec le client Claude Desktop :</p><ol><li><p><a href="https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude#configure-mcp-server-for-elasticsearch">Configurer le serveur MCP pour Elasticsearch.</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude#load-the-mcp-server-into-claude-desktop">Chargez le serveur MCP dans Claude Desktop.</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude#test-it-out">Testez-le.</a></p></li></ol><h3>Configurez le serveur MCP pour Elasticsearch</h3><p>Pour commencer, initialisons une application Node :</p>npm init -y<p>Cela créera un fichier <code>package.json</code>, et avec lui, nous pourrons commencer à installer les dépendances nécessaires pour cette application.</p>npm install @elastic/elasticsearch @modelcontextprotocol/sdk openai zod &amp;&amp; npm install --save-dev ts-node @types/node typescript<ul><li><p><strong>@elastic/elasticsearch</strong> nous donnera accès à la bibliothèque de Node.js Elasticsearch.</p></li><li><p><strong>@modelcontextprotocol/sdk</strong> fournit les outils du noyau pour créer et gérer un serveur MCP, enregistrer les outils et gérer la communication avec les clients MCP.</p></li><li><p><strong>OpenAI</strong> permet d'interagir avec les modèles OpenAI pour générer des résumés ou des réponses en langage naturel.</p></li><li><p><a href="https://zod.dev/"><strong>ZOD</strong></a>aide à définir et valider des schémas structurés pour les données d’entrée et de sortie dans chaque outil.</p></li></ul><p><code>ts-node</code>, <code>@types/node</code> et <code>typescript</code> seront utilisés pendant le développement pour écrire le code et compiler les scripts.</p><h4>Configurer l’ensemble de données</h4><p>Pour fournir les données que Claude Desktop peut interroger via notre serveur MCP, nous utiliserons un <a href="https://github.com/Delacrobix/typescript-elasticsearch-mcp/blob/main/dataset.json">ensemble de données simulé de base de connaissances interne</a>. Voici à quoi ressemblera un document issu de cet ensemble de données :</p>{
    "id": 5,
    "title": "Logging Standards for Microservices",
    "content": "Consistent logging across microservices helps with debugging and tracing. Use structured JSON logs and include request IDs and timestamps. Avoid logging sensitive information. Centralize logs in Elasticsearch or a similar system. Configure log rotation to prevent storage issues and ensure logs are searchable for at least 30 days.",
    "tags": ["logging", "microservices", "standards"]
}<p>Pour ingérer les données, nous avons préparé un script qui crée un index dans Elasticsearch et y charge l’ensemble de données. Vous pouvez le trouver <a href="https://github.com/Delacrobix/typescript-elasticsearch-mcp/blob/main/setup.ts">ici</a>.</p><h4>Serveur MCP</h4><p>Créez un fichier nommé <a href="https://github.com/Delacrobix/typescript-elasticsearch-mcp/blob/main/index.ts"><code>index.ts</code></a> et ajoutez le code suivant pour importer les dépendances et gérer les variables d’environnement :</p>// index.ts
import { z } from "zod";
import { Client } from "@elastic/elasticsearch";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import OpenAI from "openai";

const ELASTICSEARCH_ENDPOINT =
  process.env.ELASTICSEARCH_ENDPOINT ?? "http://localhost:9200";
const ELASTICSEARCH_API_KEY = process.env.ELASTICSEARCH_API_KEY ?? "";
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "";
const INDEX = "documents";<p>Aussi, initialisons les clients pour gérer les appels Elasticsearch et OpenAI :</p>const openai = new OpenAI({
  apiKey: OPENAI_API_KEY,
});

const _client = new Client({
  node: ELASTICSEARCH_ENDPOINT,
  auth: {
    apiKey: ELASTICSEARCH_API_KEY,
  },
});<p>Pour rendre notre implémentation plus robuste et garantir des entrées et des sorties structurées, nous définirons des schémas en utilisant <a href="https://zod.dev/"><code>zod</code></a>. Cela nous permet de valider les données au moment de l'exécution, de détecter les erreurs tôt et de rendre les réponses des outils plus faciles à traiter de manière programmatique :</p>const DocumentSchema = z.object({
  id: z.number(),
  title: z.string(),
  content: z.string(),
  tags: z.array(z.string()),
});

const SearchResultSchema = z.object({
  id: z.number(),
  title: z.string(),
  content: z.string(),
  tags: z.array(z.string()),
  score: z.number(),
});

type Document = z.infer&lt;typeof DocumentSchema&gt;;
type SearchResult = z.infer&lt;typeof SearchResultSchema&gt;;<p>Pour en savoir plus sur les sorties structurées, cliquez <a href="https://www.elastic.co/search-labs/blog/structured-outputs-elasticsearch-guide">ici</a>.</p><p>Maintenant, initialisons le serveur MCP :</p>const server = new McpServer({
  name: "Elasticsearch RAG MCP",
  description:
    "A RAG server using Elasticsearch. Provides tools for document search, result summarization, and source citation.",
  version: "1.0.0",
});<h4>Définition des outils MCP</h4><p>Une fois que tout est configuré, nous pouvons commencer à écrire les outils qui seront exposés par notre serveur MCP. Ce serveur expose deux outils :</p><ul><li><p><strong><code>search_docs</code></strong><strong>: </strong>Recherche des documents dans Elasticsearch à l'aide de la recherche full-text.</p></li><li><p><strong><code>summarize_and_cite</code></strong><strong>:</strong> Résume et synthétise les informations provenant de documents précédemment récupérés pour répondre à la question d'un utilisateur. Cet outil ajoute également des citations faisant référence aux documents sources.</p></li></ul><p>Ensemble, ces outils forment un workflow simple de « récupération puis synthèse », où un outil extrait les documents pertinents et l'autre utilise ces documents pour générer une réponse synthétisée et citée.</p><h4>Format de réponse de l'outil</h4><p>Chaque outil peut accepter des paramètres d'entrée arbitraires, mais il doit répondre avec la structure suivante :</p><ul><li><p><strong>Contenu :</strong> il s'agit de la réponse de l'outil dans un format non structuré. Ce champ est généralement utilisé pour renvoyer du texte, des images, de l’audio, des liens ou des plongements. Pour cette application, il sera utilisé pour renvoyer un texte formaté contenant les informations générées par les outils.</p></li><li><p><strong>structuredContent : </strong>il s'agit d'un retour facultatif utilisé pour fournir les résultats de chaque outil dans un format structuré. Ceci est utile à des fins de programmation. Bien qu'il ne soit pas utilisé dans ce serveur MCP, il peut être utile si vous souhaitez développer d'autres outils ou traiter les résultats de manière programmée.</p></li></ul><p>En gardant cette structure à l’esprit, entrons dans le vif du sujet en examinant chaque outil en détail.</p><h4>Outil de recherche</h4><p>Cet outil effectue une <a href="https://www.elastic.co/docs/solutions/search/full-text">recherche full-text</a> dans l’index Elasticsearch pour récupérer les documents les plus pertinents selon la requête de l’utilisateur. Il met en évidence les correspondances clés et offre un aperçu rapide avec des scores de pertinence.</p>server.registerTool(
  "search_docs",
  {
    title: "Search Documents",
    description:
      "Search for documents in Elasticsearch using full-text search. Returns the most relevant documents with their content, title, tags, and relevance score.",
    inputSchema: {
      query: z
        .string()
        .describe("The search query terms to find relevant documents"),
      max_results: z
        .number()
        .optional()
        .default(5)
        .describe("Maximum number of results to return"),
    },
    outputSchema: {
      results: z.array(SearchResultSchema),
      total: z.number(),
    },
  },
  async ({ query, max_results }) =&gt; {
    if (!query) {
      return {
        content: [
          {
            type: "text",
            text: "Query parameter is required",
          },
        ],
        isError: true,
      };
    }

    try {
      const response = await _client.search({
        index: INDEX,
        size: max_results,
        query: {
          bool: {
            must: [
              {
                multi_match: {
                  query: query,
                  fields: ["title^2", "content", "tags"],
                  fuzziness: "AUTO",
                },
              },
            ],
            should: [
              {
                match_phrase: {
                  title: {
                    query: query,
                    boost: 2,
                  },
                },
              },
            ],
          },
        },
        highlight: {
          fields: {
            title: {},
            content: {},
          },
        },
      });

      const results: SearchResult[] = response.hits.hits.map((hit: any) =&gt; {
        const source = hit._source as Document;

        return {
          id: source.id,
          title: source.title,
          content: source.content,
          tags: source.tags,
          score: hit._score ?? 0,
        };
      });

      const contentText = results
        .map(
          (r, i) =&gt;
            `[${i + 1}] ${r.title} (score: ${r.score.toFixed(
              2,
            )})\n${r.content.substring(0, 200)}...`,
        )
        .join("\n\n");

      const totalHits =
        typeof response.hits.total === "number"
          ? response.hits.total
          : (response.hits.total?.value ?? 0);

      return {
        content: [
          {
            type: "text",
            text: `Found ${results.length} relevant documents:\n\n${contentText}`,
          },
        ],
        structuredContent: {
          results: results,
          total: totalHits,
        },
      };
    } catch (error: any) {
      console.log("Error during search:", error);

      return {
        content: [
          {
            type: "text",
            text: `Error searching documents: ${error.message}`,
          },
        ],
        isError: true,
      };
    }
  }
);<p><em>Nous configurons </em><a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-fuzzy-query"><em><code>fuzziness</code></em></a><em><code>: “AUTO”</code></em><em> pour que la tolérance aux fautes de frappe soit variable en fonction de la longueur du jeton analysé. Nous configurons également </em><em><code>title^2</code></em><em> pour qu'il augmente le score des documents dont la correspondance se fait sur le champ du titre.</em></p><h4>outil summarize_and_cite</h4><p>Cet outil génère un résumé basé sur les documents récupérés lors de la recherche précédente. Il utilise le modèle <code>gpt-4o-mini</code> d’OpenAI pour synthétiser les informations les plus pertinentes afin de répondre à la question de l’utilisateur, en fournissant des réponses dérivées directement des résultats de recherche. Outre le résumé, il renvoie également les métadonnées de citation des documents sources utilisés.</p>server.registerTool(
  "summarize_and_cite",
  {
    title: "Summarize and Cite",
    description:
      "Summarize the provided search results to answer a question and return citation metadata for the sources used.",
    inputSchema: {
      results: z
        .array(SearchResultSchema)
        .describe("Array of search results from search_docs"),
      question: z.string().describe("The question to answer"),
      max_length: z
        .number()
        .optional()
        .default(500)
        .describe("Maximum length of the summary in characters"),
      max_docs: z
        .number()
        .optional()
        .default(5)
        .describe("Maximum number of documents to include in the context"),
    },
    outputSchema: {
      summary: z.string(),
      sources_used: z.number(),
      citations: z.array(
        z.object({
          id: z.number(),
          title: z.string(),
          tags: z.array(z.string()),
          relevance_score: z.number(),
        })
      ),
    },
  },
  async ({ results, question, max_length, max_docs }) =&gt; {
    if (!results || results.length === 0 || !question) {
      return {
        content: [
          {
            type: "text",
            text: "Both results and question parameters are required, and results must not be empty",
          },
        ],
        isError: true,
      };
    }

    try {
      const used = results.slice(0, max_docs);

      const context = used
        .map(
          (r: SearchResult, i: number) =&gt;
            `[Document ${i + 1}: ${r.title}]\\n${r.content}`
        )
        .join("\n\n---\n\n");

      // Generate summary with OpenAI
      const completion = await openai.chat.completions.create({
        model: "gpt-4o-mini",
        messages: [
          {
            role: "system",
            content:
              "You are a helpful assistant that answers questions based on provided documents. Synthesize information from the documents to answer the user's question accurately and concisely. If the documents don't contain relevant information, say so.",
          },
          {
            role: "user",
            content: `Question: ${question}\\n\\nRelevant Documents:\\n${context}`,
          },
        ],
        max_tokens: Math.min(Math.ceil(max_length / 4), 1000),
        temperature: 0.3,
      });

      const summaryText =
        completion.choices[0]?.message?.content ?? "No summary generated.";

      const citations = used.map((r: SearchResult) =&gt; ({
        id: r.id,
        title: r.title,
        tags: r.tags,
        relevance_score: r.score,
      }));

      const citationText = citations
        .map(
          (c: any, i: number) =&gt;
            `[${i + 1}] ID: ${c.id}, Title: "${c.title}", Tags: ${c.tags.join(
              ", ",
            )}, Score: ${c.relevance_score.toFixed(2)}`,
        )
        .join("\n");

      const combinedText = `Summary:\\n\\n${summaryText}\\n\\nSources used (${citations.length}):\\n\\n${citationText}`;

      return {
        content: [
          {
            type: "text",
            text: combinedText,
          },
        ],
        structuredContent: {
          summary: summaryText,
          sources_used: citations.length,
          citations: citations,
        },
      };
    } catch (error: any) {
      return {
        content: [
          {
            type: "text",
            text: `Error generating summary and citations: ${error.message}`,
          },
        ],
        isError: true,
      };
    }
  }
);<p>Enfin, il faut démarrer le serveur avec <a href="https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#stdio">stdio</a>. Cela signifie que le client MCP communiquera avec notre serveur en lisant et en écrivant dans ses flux d'entrée et de sortie standard. StDIO est l’option de transport la plus simple et fonctionne bien pour les serveurs MCP locaux lancés en sous-processus par le client. Ajoutez le code suivant à la fin du fichier :</p>const transport = new StdioServerTransport();
server.connect(transport);<p>Compilez le projet en utilisant la commande suivante :</p>npx tsc index.ts --target ES2022 --module node16 --moduleResolution node16 --outDir ./dist --strict --esModuleInterop<p>Cela créera un dossier <code>dist</code>, dans lequel se trouvera un fichier <code>index.js</code>.</p><h3>Chargez le serveur MCP dans Claude Desktop.</h3><p>Suivez <a href="https://modelcontextprotocol.io/docs/develop/connect-local-servers">ce guide</a> pour configurer le serveur MCP avec Claude Desktop. Dans le fichier de configuration Claude, nous devons définir les valeurs suivantes :</p>{
  "mcpServers": {
    "elasticsearch-rag-mcp": {
      "command": "node",
      "args": [   "/Users/user-name/app-dir/dist/index.js"
      ],
      "env": {
        "ELASTICSEARCH_ENDPOINT": "your-endpoint-here",
        "ELASTICSEARCH_API_KEY": "your-api-key-here",
        "OPENAI_API_KEY": "your-openai-key-here"
      }
    }
  }
}<p>La valeur <code>args</code> doit pointer vers le fichier compilé dans le dossier <code>dist</code> . Vous devez également définir les variables d'environnement dans le fichier de configuration avec les noms exacts définis dans le code.</p><h3>Testez-le</h3><p>Avant d’exécuter chaque outil, cliquez sur <strong>Recherche et Outils</strong> pour vous assurer que les outils sont activés. Vous pouvez également activer ou désactiver chaque option ici :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt395a7337021f9820/6a170c1c67045bb74d45c228/172981c2a54adabc70d5819013c3007670935605-1999x1002.png" alt="Claude 4.5 Page de sonnet, avec la note : « Bonjour, Jeff. » Comment puis-je vous aider aujourd'hui ?" /><p>Enfin, testons le serveur MCP depuis le chat Claude Desktop et commençons à poser des questions :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf4ac458dc0206271/6a170c1e66c4f91328f8c072/03654c0f8c53c714f801fba8b25747071179209b-1999x1353.png" alt="Requête de recherche d'utilisateur dans le chat de Claude Desktop pour des documents sur les méthodes d'authentification et le contrôle d'accès basé sur les rôles, ainsi que sur les réponses de Claude." /><p>Pour la question « <strong>Recherche de documents sur les méthodes d’authentification et le contrôle d’accès basé sur les rôles</strong> », l’outil <code>search_docs</code> est exécuté et renvoie les résultats suivants :</p>Most Relevant Documents:
Access Control and Role Management (highest relevance) - This document covers role-based access control (RBAC) principles, including ensuring users only have necessary permissions, regular auditing of user roles, revoking inactive accounts, and implementing just-in-time access for sensitive operations.
User Authentication with OAuth 2.0 - This document explains OAuth 2.0 authentication, which enables secure delegated access without credential sharing. It covers configuring identity providers, token management with limited scope and lifetime, and secure storage of refresh tokens.
Container Security Guidelines - While primarily about container security, this document touches on access control aspects like running containers as non-root users and avoiding embedded credentials.
Incident Response Playbook - This mentions role assignment during incidents (incident commander, communications lead, etc.), which relates to access control in emergency scenarios.
Logging Standards for Microservices - This document includes guidance on avoiding logging sensitive information, which is relevant to authentication security.<p>La réponse est : « Super ! J'ai trouvé 5 documents pertinents sur les méthodes d'authentification et le contrôle d'accès basé sur les rôles. Voici ce qui a été découvert : »</p><p>L'appel d'outil renvoie les documents sources dans le cadre de sa charge utile de réponse, qui sont ensuite utilisés pour générer des citations.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbaf48a9468770ce2/6a170c21509168bffee1bb14/25ff4c7e9563d99752f95540dafdc7fd211a66e3-800x530.gif" alt="Page Claude 4.5 Sonnet, avec des réponses qui défilent et incluent les cinq documents pertinents sur les méthodes d'authentification et le contrôle d'accès basé sur les rôles." /><p>Il est également possible d'enchaîner plusieurs outils dans une même interaction. Dans ce cas, Claude Desktop analyse la question de l’utilisateur et détermine qu’il doit d’abord appeler <code>search_docs</code> pour récupérer les documents pertinents, puis transmettre ces résultats à <code>summarize_and_cite</code> pour générer la réponse finale, le tout sans nécessiter d’invites séparées de la part de l’utilisateur :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta46ff45274e64192/6a170c230c4857a91501aac1/e6a8a46acb4236e77058f18bcd2f0737b5882c05-1999x1101.png" alt="Chat de bureau Claude, avec la note « Jeff revient », plus une nouvelle question d'utilisateur : « Quelles sont les principales recommandations pour améliorer l'authentification et le contrôle d'accès à travers nos systèmes ? » Incluez des références. »" /><p>Dans ce cas, pour la requête « <strong>Quelles sont les principales recommandations pour améliorer l’authentification et le contrôle d’accès dans l’ensemble de nos systèmes ? Veuillez inclure des références.</strong> », Nous avons obtenu les résultats suivants :</p>Based on the documentation, here are the main recommendations to improve authentication and access control across your systems:

Key Recommendations

1. Implement Role-Based Access Control (RBAC)
Ensure users have only the permissions necessary for their job functions. This principle of least privilege minimizes security risks by limiting access to what's truly needed. [1]

2. Regular Access Audits
Conduct regular audits of user roles and promptly revoke access for inactive accounts. This helps prevent unauthorized access from dormant or compromised accounts. [1]

3. Just-in-Time (JIT) Access
Implement just-in-time access for sensitive operations, where permissions are granted only when needed and for a limited duration. This reduces the attack surface by minimizing standing privileges. [1]

4. OAuth 2.0 for Secure Authentication
Use OAuth 2.0 to enable secure delegated access without sharing user credentials. This protocol allows third-party applications to access resources on behalf of users without exposing passwords. [2]

5. Token Security and Management
Configure your identity provider to issue tokens with limited scope and lifetime

Store refresh tokens securely
Validate access tokens consistently to maintain security [2]
References

Access Control and Role Management (Tags: security, access-control)
User Authentication with OAuth 2.0 (Tags: authentication, oauth)
These recommendations work together to create a defense-in-depth approach, where multiple security layers protect your systems from unauthorized access.<p>Comme à l’étape précédente, nous pouvons voir la réponse de chaque outil à cette question :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8f633c518e708a99/6a170c25ab7f082991db9ed6/cb606d356b2f7d5e4878a5eff71bc881869ac0ee-800x585.gif" alt="Page de chat de Claude Desktop, avec un texte défilant qui inclut la réponse de chaque outil à la question, « Quelles sont les principales recommandations pour améliorer l'authentification et le contrôle d'accès à travers nos systèmes ? » Incluez des références. »" /><p><em>Note : Si un sous-menu apparaît demandant si vous approuvez l’utilisation de chaque outil, sélectionnez </em><em><strong>Toujours autoriser</strong></em><em> ou </em><em><strong>Permettre une fois</strong></em><em>.</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6627ee0bff1862df/6a170c266f7f040f6f91488c/aea942ba9b0037526ea215bec65690f1a5c3099c-1522x250.png" alt="Claude Desktop propose à l’utilisateur les options « Toujours autoriser » et « Autoriser une seule fois »." /><h2>Conclusion</h2><p>Les serveurs MCP représentent une étape importante vers la standardisation des outils LLM pour les applications locales et distantes. Bien que la compatibilité totale soit encore en cours de développement, nous avançons rapidement dans cette direction.</p><p>Dans cet article, nous avons appris à créer un serveur MCP personnalisé en TypeScript qui connecte Elasticsearch aux applications basées sur LLM. Notre serveur propose deux outils : <code>search_docs</code> pour récupérer les documents pertinents à l'aide de Query DSL ; et <code>summarize_and_cite</code> pour générer des résumés avec des citations via des modèles OpenAI et Claude Desktop comme interface utilisateur client.</p><p>L'avenir de la compatibilité entre les différents fournisseurs côté client et côté serveur semble prometteur. Les prochaines étapes consistent à ajouter davantage de fonctionnalités et de flexibilité à votre agent. Vous trouverez un <a href="https://www.elastic.co/search-labs/blog/llm-functions-elasticsearch-intelligent-query">article</a> pratique expliquant comment paramétrer vos requêtes à l'aide de modèles de rechercher pour gagner en précision et en flexibilité.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Intégrations]]></category>
    <dc:creator><![CDATA[Jeffrey Rengifo]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5600198cb47666a5/6a170c28509168ce3ae1bb18/0bb24c05fff391f42070c2883182ea6fe9cb9680-1280x720.png" length="0" type="image/png"/>
    <pubDate>Fri, 27 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[L'outil shell n'est pas une solution miracle pour l'ingénierie du contexte]]></title>
    <description><![CDATA[Découvrez quels outils de récupération de contexte existent pour l'ingénierie contextuelle, comment ils fonctionnent et leurs compromis.]]></description>
    <content:encoded><![CDATA[<p>Les outils les plus importants dont dispose un agent sont les outils de rechercher qu’il peut utiliser pour construire son propre contexte. Les récents articles de <a href="https://www.llamaindex.ai/blog/files-are-all-you-need">LlamaIndex</a> et <a href="https://x.com/hwchase17/status/2011814697889316930">LangChain</a> ont suscité une discussion : <em>un outil shell et un système de fichiers sont-ils tout ce dont un agent a besoin pour l’ingénierie du contexte ? </em>Malheureusement, la discussion a rapidement dévié sur un sujet inapproprié : système de fichiers contre base de données.</p><p>Ce billet se concentre sur la question <em>suivante : quelles sont les bonnes interfaces de recherche dont un agent a besoin pour construire son propre contexte ?</em> Il couvre d'abord les compromis entre les outils de shell et les outils de base de données dédiés. Il propose ensuite un framework pratique pour trouver les interfaces adaptées aux besoins de votre agent.</p><h2>Que signifie concrètement pour un agent le terme « contexte de construction » ?</h2><p>Dans les premiers <a href="https://www.elastic.co/what-is/retrieval-augmented-generation">pipelines de Retrieval-Augmented Generation (RAG)</a>, le développeur concevait un pipeline de recherche fixe, et le grand modèle de langage (LLM) était un récepteur passif du contexte. C'était une limitation fondamentale : le contexte était récupéré à chaque requête, qu'il soit nécessaire ou non, sans vérification qu'il aidait réellement.</p><p>Avec le passage au RAG agentique, les agents ont désormais accès à un ensemble d’outils de recherche pour construire leur propre contexte. Par exemple, Claude Code [1] et Cursor [2] permettent tous deux à l’agent de choisir entre différents outils de recherche et même de les combiner pour des requêtes chaînées, en fonction de ce que la tâche exige réellement.</p><h2>Quelles interfaces de recherche existent pour l'ingénierie contextuelle ?</h2><p>Le contexte peut se trouver à différents endroits, par exemple sur le Web, dans un système de fichiers local ou dans une base de données. Un agent peut interagir avec chacune de ces sources de données hors contexte à l'aide de différents outils :</p><ul><li><p><strong>Les outils Shell</strong> peuvent exécuter des commandes shell et accéder au système de fichiers local. Quelques exemples d’outils shell intégrés sont <a href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/bash-tool">l’outil bash de Claude API</a>, <a href="https://docs.openclaw.ai/tools/exec">l’outil exécutif d’OpenClaw</a>, et <a href="https://docs.langchain.com/oss/python/integrations/tools/bash">l’outil shell de LangChain</a>.</p></li><li><p><strong>Les outils de base de données dédiés,</strong> tels que les outils d’un serveur Model Context Protocol (MCP) (par exemple, le <a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/mcp-server">serveur MCP Elastic Agent Builder)</a> ou les outils personnalisés (par exemple, <code>run_esql(query)</code> ou <code>db_list_index()</code>), peuvent interroger les bases de données.</p></li><li><p><strong>Les outils de recherche de fichiers dédiés</strong> peuvent rechercher et lire des fichiers locaux (ou téléchargés) (sans accès complet au shell). Quelques exemples d'outils de recherche de fichiers intégrés sont <a href="https://ai.google.dev/gemini-api/docs/file-search">l'outil de recherche de fichiers de Gemini API</a> ou <a href="https://developers.openai.com/api/docs/guides/tools-file-search">l'outil de recherche de fichiers d'OpenAI</a>.</p></li><li><p><strong>Les outils de recherche Web</strong> peuvent extraire des informations du web.</p></li><li><p><strong>Les outils de mémoire</strong> stockent et rappellent la mémoire à long terme (quelle que soit la manière dont elle est stockée).</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2c5d083815149773/6a170acb964cea61a108bb80/115f20c8ded259e508f51524b2c06bdc702d70ab-1999x1050.png" alt="Diagramme montrant comment un agent utilise différents outils de recherche contextuelle pour accéder aux fichiers locaux, aux données propriétaires, au web et à la mémoire à long terme." /><p>Comme vous pouvez le voir, l’outil shell est polyvalent et peut être utilisé pour récupérer du contexte à partir de différentes sources de données, notamment :</p><ul><li><p><strong>Système de fichiers :</strong> l'agent explore la structure des répertoires (ls, find), recherche le contenu pertinent (grep, cat) et répète l'opération jusqu'à ce qu'il ait construit un contexte suffisant.</p></li><li><p><strong>Base de données :</strong> l’agent peut utiliser des outils d’interface en ligne de commande (CLI) de base de données (par exemple, <a href="https://www.elastic.co/docs/reference/query-languages/sql/sql-cli"><code>elasticsearch-sql-cli</code></a>), appeler des API HTTP via curl, ou exécuter des scripts, ce qui est particulièrement utile en combinaison avec les compétences de l’agent, qui sont des exemples réutilisables et documentés injectés dans le contexte de l’agent pour guider l’utilisation correcte des outils (par exemple, <a href="https://github.com/elastic/agent-skills">Elastic Agent Skills pour Elasticsearch</a>).</p></li><li><p><strong>Web : </strong>l’agent peut exécuter des recherches web via une commande curl à travers l’API d’un fournisseur de recherche.</p></li></ul><p>Cependant, l'outil shell fournit un accès système direct et nécessite donc des mesures de sécurité, telles que l'exécution dans un environnement sandbox isolé et le logging de toutes les commandes exécutées.</p><h2>Quand utiliser quelles interfaces de recherche</h2><p>L'interface de recherche appropriée dépend de vos données, de vos modèles de requête et de votre cas d'utilisation. Cette section constitue un point de départ pratique.</p><h3>Les systèmes de fichiers ne rendent pas les bases de données obsolètes</h3><p>Le débat entre systèmes de fichiers et bases de données ne porte pas sur la couche de stockage. Par exemple, LangChain explique que <a href="https://x.com/hwchase17/status/2011814697889316930">son système de mémoire</a> ne stocke pas réellement la mémoire dans un véritable système de fichiers. Au lieu de cela, il stocke la mémoire dans une base de données et la <em>représente</em> sous la forme d'un ensemble de fichiers pour l'agent [3].</p><p>Les systèmes de fichiers sont particulièrement adaptés aux cas d'utilisation natifs basés sur les fichiers, tels que les agents de codage. Ils fonctionnent également bien comme bloc-notes temporaire ou mémoire de travail pour les scénarios à utilisateur unique ou à agent unique où la concurrence n'est pas une préoccupation. Dans ces cas, un système de fichiers physique ou la représentation des données sous forme de système de fichiers vous offre une certaine flexibilité avant de vous engager dans une interface dédiée.</p><p>Mais le stockage par système de fichiers présente de réels inconvénients, tels qu'une faible concurrence, l'application manuelle du schéma et les transactions atomiques. Ces problèmes deviennent plus évidents lorsque votre application doit scaler ou passer à un scénario multi-agents. Quiconque ignore ces inconvénients est condamné à <a href="https://dx.tips/oops-database">réinventer péniblement des bases de données de moindre qualité</a>, sans bénéficier des décennies d'ingénierie qui sous-tendent la sécurité des transactions ou le contrôle d'accès que les bases de données de production offrent déjà. De plus, dans la plupart des contextes d'entreprise, on ne choisit pas d'utiliser ou non une base de données puisqu'elle est déjà en place et stocke des données essentielles à l'activité.</p><h3>Outil shell + système de fichiers</h3><p>Un outil shell est le point de départ naturel pour la recherche dans le système de fichiers. Actuellement, les agents de codage sont à l'origine de nombreux progrès dans le champ. Parce qu'ils travaillent avec du code dans des fichiers locaux, ce sont naturellement des cas d'utilisation gourmands en fichiers. Par conséquent, les LLM sont affinés lors de la phase de post-entraînement pour les tâches de codage. C'est pourquoi de nombreux LLM savent non seulement écrire du code, mais aussi utiliser des commandes shell et naviguer dans les systèmes de fichiers.</p><p>L'utilisation d'un outil shell avec des CLI intégrées, comme <code>ls</code> et <code>grep</code>, pour rechercher des fichiers est efficace. Avec grep, une requête comme « Trouver tous les fichiers qui importent <code>matplotlib</code>» est rapide, précise et peu coûteuse. Mais lorsque l'agent doit gérer des requêtes conceptuelles, comme « Comment notre application gère-t-elle une authentification défaillante ? », La correspondance de motifs avec grep peut rapidement atteindre ses limites. Plusieurs alternatives qui apportent des capacités de recherche sémantique à la ligne de commande ont émergé pour combler ce manque, notamment <a href="https://github.com/jina-ai/jina-grep-cli"><code>jina-grep</code></a>.</p><p>Cependant, grep et plusieurs de ses alternatives de recherche sémantique fonctionnent en O(n) sur le corpus. Pour les cas d'utilisation sur des bases de code, cela peut convenir. Cependant, si vos données s'accumulent, la latence deviendra perceptible. Dans ce cas, un datastore indexé devient nécessaire pour assurer la maintenance des performances.</p><h3>Outil shell + base de données</h3><p>Une autre façon d'ajouter des capacités de recherche, telles que la recherche sémantique ou hybride, à vos données est de les stocker dans une base de données, comme le fait Cursor, par exemple. De plus, lorsque les données nécessitent des jointures relationnelles complexes ou des agrégations, une interface de base de données est non négociable.</p><p>Lorsque les données se trouvent dans une base de données plutôt que dans le système de fichiers, un outil shell peut servir d'interface de base de données légère pour certains cas d'utilisation. Si vos requêtes sont assez simples pour une interface de ligne de commande ou un appel curl, un outil de base de données dédié peut ajouter de la complexité inutile.</p><p>Cette approche est également adaptée aux premières étapes de l’exploration, lorsque vous ne savez pas encore quels modèles de requête votre agent développera réellement. Dans ce cas, les compétences des agents peuvent donner à l’agent suffisamment de structure pour effectuer des requêtes correctement sans avoir recours à un outil spécialement conçu. Cependant, lorsque l'agent doit effectuer de nombreuses itérations pour déterminer la meilleure façon d'interroger la base de données pour des tâches répétitives, la surcharge de jetons associée à l'utilisation d'un outil shell comme interface ne justifie plus l'avantage de simplicité qu'offre l'évitement d'un outil supplémentaire.</p><h3>Outil de base de données dédié</h3><p>Des outils de base de données spécialisés deviennent nécessaires, surtout lorsque les modèles de requêtes répétées sont structurés ou analytiques. Un <a href="https://vercel.com/blog/testing-if-bash-is-all-you-need">article de blog de Vercel et Braintrust</a> a comparé des agents utilisant différents ensembles d'outils de recherche pour des tâches de récupération réelles sur des données semi-structurées, telles que les tickets de service client et les transcriptions d'appels de vente (par exemple : « Combien de problèmes ouverts mentionnent la « sécurité » ? » ou « Trouver les problèmes où quelqu'un a signalé un bug et où quelqu'un a ensuite soumis une PR prétendant le corriger ? »). [4].</p><p>Les agents utilisant des outils de base de données dédiés consommaient moins de jetons, étaient plus rapides et faisaient moins d'erreurs que ceux utilisant uniquement un outil shell et un système de fichiers. La leçon à retenir est que les outils de base de données directs constituent le meilleur choix lorsque la requête exige un raisonnement analytique sur des données semi-structurées.</p><h3>Combinaison d'interfaces de recherche</h3><p>Aucune interface de recherche unique ne traite correctement toutes les requêtes. Par exemple, Cursor combine des outils shell (pour les recherches via grep) et des outils de recherche sémantique, et permet à l'agent de sélectionner l'outil approprié en fonction de la requête de l'utilisateur. Ils indiquent que l'agent choisit grep pour faire correspondre des symboles ou des chaînes spécifiques, la recherche sémantique pour les questions conceptuelles ou liées au comportement, et les deux pour les tâches exploratoires.</p><p>L'expérience Vercel rapporte la même chose : son agent hybride, ayant accès à la fois à un outil en ligne de commande (shell) et à un outil de base de données dédié, a obtenu les meilleures performances parmi tous les agents testés, en utilisant d'abord les outils de base de données dédiés, puis en vérifiant les résultats en parcourant le système de fichiers avec la commande « grep ». Cependant, cette approche utilise plus de tokens et de temps pour le choix et la vérification des outils.</p><p>Le schéma est identique dans les deux exemples : la composition Beats toute interface unique, mais elle implique un compromis en termes de coût et de latence supplémentaires.</p><h2>Recommandations pratiques pour trouver les bons outils</h2><p>Le bon ensemble d'interfaces de recherche est restreint, ciblé et spécifique aux schémas de requêtes réels de votre agent. La bonne pratique actuelle est d'avoir un agent avec le moins d'outils possible au lieu d'avoir un agent avec des centaines d'outils MCP. En effet, le fait d'exposer d'emblée tous les outils possibles a pour inconvénient de gonfler la fenêtre contextuelle et d'embrouiller l'agent quant à l'outil à utiliser. Par exemple, Claude Code ne disposerait que d'une vingtaine d'outils.</p><p>L'idée de la divulgation progressive est plutôt de commencer avec un ensemble minimal d'outils et de laisser l'agent découvrir des capacités supplémentaires uniquement lorsqu'il en a besoin. Les recherches menées par Anthropic [5] et Cursor [6] ont montré que cette approche permet de réaliser une économie de tokens de 47%–85%. Claude Code, par exemple, implémente cela directement, permettant à l'agent de découvrir progressivement comment interroger une API ou une base de données, sans que cette connaissance ne consomme du contexte à chaque appel de LLM.</p><p>Une fois que vous vous êtes familiarisé avec les modèles de requête de l’agent, vous pouvez revoir l’ensemble des outils de recherche auxquels l’agent a accès par défaut. Une façon utile d'envisager ce compromis est le <a href="https://www.elastic.co/search-labs/blog/database-retrieval-tools-context-engineering#building-the-right-database-retrieval-tools-%5C(%E2%80%9Clow-floor,-high-ceiling%E2%80%9D%5C">principe « plancher bas, plafond haut » </a> pour décider quels outils doivent être retenus. Les outils à haut plafond ne limitent pas le potentiel de l’agent. Par exemple, un outil shell polyvalent permet à l’agent d’écrire des requêtes de base de données complètes, y compris celles ambiguës, mais au prix d’une surcharge de raisonnement, d’une latence plus élevée et d’une fiabilité moindre.</p><p>Les outils à plancher surbaissé sont à l'opposé. Ce sont des outils spécialisés qui répondent à des requêtes spécifiques et sont immédiatement accessibles à l'agent avec un minimum de frais de raisonnement, ce qui permet de réduire les coûts et d'accroître la fiabilité. Mais ils nécessitent un travail d’ingénierie préalable, ne peuvent pas couvrir toutes les requêtes possibles, et peuvent compliquer le choix du bon outil pour l’agent.</p><p>Pensez à chaque outil sur un spectre : les outils à seuil bas sont faciles à utiliser correctement par l'agent mais sont limités en portée. Les outils à haut potentiel sont polyvalents, mais nécessitent davantage de réflexion pour être utilisés efficacement.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72deecc6781e3499/6a170acd5091682f4fe1baba/e6d1b973be4b0a0a25c99c74f02a47e98395a3f7-1200x630.png" alt="Diagramme comparant trois approches de conception d’agents (plancher élevé/plafond haut, plancher bas/plafond bas, et plancher bas/plafond haut), montrant comment différentes stratégies d’outils influencent la manière dont les agents traitent les requêtes ambiguës, polyvalentes et prévisibles." /><p>La plupart des agents ont besoin d'une combinaison de différents outils de recherche. Mais chaque outil doit mériter son ajout. Nous recommandons de commencer par un outil de recherche polyvalent (par exemple un outil <code>search_database()</code> ou un outil shell). Réutilisez ensuite les logs de commandes que vous conservez déjà à des fins de sécurité pour suivre ce que votre agent fait réellement, y compris les appels d’outils, les nouvelles tentatives et le nombre d’appels par requête utilisateur. Et, lorsque vous voyez un modèle de requête se répéter ou échouer, c'est le signal pour créer un outil spécialement conçu à cet effet.</p><h2>Résumé</h2><p>Le débat système de fichiers contre base de données détourne l'attention de la véritable question que les ingénieurs doivent se poser : <em>quelles sont les bonnes interfaces de recherche dont un agent a besoin pour construire son propre contexte ?</em> La réponse est, selon toute vraisemblance, <em>pas une seule</em>.</p><p>Un outil shell est un outil polyvalent pour interagir avec différentes sources hors contexte et constitue ainsi un bon point de départ. Mais il est moins efficace et précis pour les cas d'utilisation avec des requêtes analytiques structurées que les outils de base de données dédiés.</p><p>L'objectif est de trouver l'ensemble minimal d'outils de recherche qui gère bien les modèles de requêtes réels de votre agent. Commencez avec un outil shell, et consignez ce que fait réellement votre agent dans les logs. Lorsque vous constatez qu'un schéma de requête se répète et échoue, il est temps de concevoir des outils spécialisés.</p><h2>Références</h2><p>1. Thariq (Anthropic). <a href="https://x.com/trq212/status/2027463795355095314">Leçons tirées de la construction du code Claude : voir comme un agent</a> (2026).</p><p>2. Cursor : Documentation. <a href="https://cursor.com/docs/agent/tools/search">Recherche sémantique et agentique</a> (2026).</p><p>3. Harrison Chase (LangChain). <a href="https://x.com/hwchase17/status/2011814697889316930">Comment nous avons construit le système de mémoire d'Agent Builder</a> (2026).</p><p>4. Ankur Goyal (Braintrust) et Andrew Qu (Vercel). <a href="https://vercel.com/blog/testing-if-bash-is-all-you-need">Tester si « bash est tout ce dont vous avez besoin »</a> (2026).</p><p>5. Anthropic. <a href="https://www.anthropic.com/engineering/advanced-tool-use">Présentation de l'utilisation d'outils avancés sur la plateforme de développement Claude</a> (2025).</p><p>6. Cursor. <a href="https://cursor.com/blog/dynamic-context-discovery">Découverte dynamique du contexte</a> (2026).</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/search-tools-context-engineering</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/search-tools-context-engineering</guid>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Leonie Monigatti]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b9bbbff55c09fa4/6a170acecdacbff1167d29fd/f91e4d07915ba7bf3b7abf15fac8fab3350f7df2-1280x720.png" length="0" type="image/png"/>
    <pubDate>Wed, 25 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Utilisation de l'API d'inférence Elasticsearch avec les modèles Hugging Face]]></title>
    <description><![CDATA[Découvrez comment connecter Elasticsearch aux modèles Hugging Face à l'aide de points de terminaison d'inférence, et comment créer un système de recommandation de blogs multilingue avec recherche sémantique et complétion de chat.]]></description>
    <content:encoded><![CDATA[<p>Dans ses dernières mises à jour, Elasticsearch a introduit une intégration native permettant de se connecter aux modèles hébergés sur le <a href="https://endpoints.huggingface.co/">service d'inférence Hugging Face</a>. Dans cet article, nous verrons comment configurer cette intégration et effectuer des inférences via de simples appels d'API à l'aide d'un grand modèle de langage (LLM). Nous utiliserons <a href="https://huggingface.co/HuggingFaceTB/SmolLM3-3B">SmolLM3-3B</a>, un modèle léger et polyvalent offrant un bon compromis entre consommation de ressources et qualité des réponses.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9094997548bd70f8/6a170d6a839dfa0ad6dcff54/7ddadf1976421a860a7d62087239adb9150d808b-1999x1388.png" alt="Diagramme de dispersion présentant plusieurs petits modèles de langage, classés selon leur taille (en milliards de paramètres) en abscisse et leur taux de réussite (en pourcentage) en ordonnée. Le modèle SmolLM3-3B se distingue par une efficacité supérieure, avec un taux de réussite plus élevé que les autres modèles de taille similaire." /><h2>Produits requis</h2><ul><li><p><strong>Elasticsearch 9.3 ou Elastic Cloud Serverless</strong> : vous pouvez créer un déploiement dans le cloud en suivant <a href="https://www.elastic.co/search-labs/tutorials/install-elasticsearch/elastic-cloud">ces instructions</a>, ou utiliser le démarrage rapide <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart#local-dev-quick-start"><code>start-local</code></a> à la place.</p></li><li><p><strong>Python 3.12</strong> : téléchargez <a href="https://www.python.org/">Python ici</a>.</p></li><li><p><strong>Jeton d'accès Hugging Face</strong><a href="https://huggingface.co/docs/hub/en/security-tokens"></a>.</p></li></ul><h2>Complétions de chat utilisant un point de terminaison d'inférence Hugging Face</h2><p>Nous allons d'abord créer un exemple pratique connectant Elasticsearch à un <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put">point de terminaison d'inférence</a> Hugging Face afin de générer des recommandations alimentées par l'IA à partir d'une collection d'articles de blog. Pour la base de connaissances de l'application, nous utiliserons un ensemble de données d'articles de blogs d'entreprise, qui contiennent des informations précieuses mais souvent difficiles à consulter.</p><p>Avec ce point de terminaison, la <a href="https://www.elastic.co/docs/solutions/search/semantic-search">recherche sémantique</a> extrait les articles les plus pertinents pour une requête donnée, et un LLM Hugging Face génère de courtes recommandations contextuelles sur la base de ces résultats.</p><p>Examinons d'abord les grandes lignes du flux d'informations que nous allons mettre en place :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf217b7b7db4e1e6c/6a170d6ca929cf8022ae0a3b/1dfbc2323438feaaa42e13ab242dd1f7166f74aa-1200x676.png" alt="Diagramme de flux montrant un index Elasticsearch alimentant un point de terminaison d'inférence avec les résultats de recherche sémantique, lequel renvoie des recommandations d'articles." /><p>Dans cet article, nous allons tester la capacité de <strong>SmolLM3-3B </strong>àà allier sa taille compacte à de puissantes fonctionnalités de raisonnement multilingue et d'appel d'outils. À partir d'une requête de recherche, nous enverrons tous les contenus correspondants (en anglais et en espagnol) au LLM afin de générer une liste d'articles recommandés, accompagnés d'une description personnalisée basée sur la requête et les résultats de recherche.</p><p>Voici à quoi pourrait ressembler l'interface utilisateur d'un site d'articles doté d'un système de génération de recommandations par IA.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt20e69b9a06fecd65/6a170d6e839dfa6f97dcff58/8d3b86b212f28ff279f2da67a33e6134039f0e4e-1999x949.png" alt="Interface utilisateur d'un site d'articles doté d'un système de génération de recommandations par IA, présentant trois exemples, avec un texte en anglais et des titres en anglais ou en espagnol." /><p>Vous trouverez la mise en œuvre complète de cette application dans le <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/elasticsearch-inference-api-and-hugging-face/notebook.ipynb">notebook</a> associé.</p><h3>Configuration des points de terminaison d’inférence Elasticsearch</h3><p>Pour utiliser le <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-hugging-face">point de terminaison d'inférence Hugging Face d'Elasticsearch</a>, nous avons besoin de deux éléments importants : une clé API Hugging Face et une URL de point de terminaison Hugging Face en cours d'exécution. Cela devrait ressembler à ceci :</p>PUT _inference/chat_completions/hugging-face-smollm3-3b
{
    "service": "hugging_face",
    "service_settings": {
        "api_key": "hugging-face-access-token", 
        "url": "url-endpoint" 
    }
}<p>Le point de terminaison d'inférence Hugging Face dans Elasticsearch prend en charge différents types de tâches : <code>text_embedding</code>, <code>completion</code>, <code>chat_completion</code> et <code>rerank</code>. Dans cet article de blog, nous utilisons <code>chat_completion</code>, car nous avons besoin que le modèle génère des recommandations conversationnelles basées sur les résultats de recherche et un prompt système. Ce point de terminaison nous permet d'effectuer des complétions de chat directement depuis Elasticsearch de manière simple grâce à l'API Elasticsearch :</p>POST _inference/chat_completion/hugging-face-smollm3-3b/_stream
{
  "messages": [
      { "role": "user", "content": "&lt;user prompt&gt;" }
  ]
}<p>Ceci va constituer le cœur de l'application, recevant la requête et les résultats de recherche qui seront ensuite traités par le modèle. La théorie étant posée, passons à la mise en œuvre de l'application.</p><h4>Configuration du point de terminaison d'inférence sur Hugging Face</h4><p>Pour déployer le modèle Hugging Face, nous allons utiliser le <a href="https://huggingface.co/inference-endpoints/dedicated">service de déploiement en un clic de Hugging Face</a>, une solution simple et rapide pour déployer des points de terminaison de modèles. Notez qu'il s'agit d'un service payant et que son utilisation peut engendrer des coûts supplémentaires. Cette étape créera l'instance du modèle qui servira à générer les recommandations d'articles.</p><p>Vous pouvez choisir un modèle dans le catalogue accessible en un clic :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta7bdfa43d6766324/6a170d6fb339d59e5476a039/b816e9fba1fe172687bf58f5143fb1f838c1077f-549x331.png" alt="Vue d'interface d'un catalogue de modèles filtré sur &quot;smoll3&quot;, montrant un modèle nommé &quot;smollm3‑3b&quot; avec génération de texte, vLLM, GPU 1× Nvidia L4 et un prix indiqué de 0,8 $, ainsi qu'une note suggérant d'étendre la recherche à tous les modèles Hugging Face." /><p>Sélectionnons le modèle <strong>SmolLM3-3B</strong> :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb0a2e6ffd7deb20/6a170d710c48574b7401aafc/610d3aba0429f3666c2df3616d513eb6a4397c0c-502x478.png" alt="Interface permettant de créer un point de terminaison pour le modèle SmolLM3‑3B, affichant le nom du modèle, une note &quot;vérifié par Hugging Face&quot;, un champ de nom de point de terminaison, un coût de 0,80 $ par heure et par réplique en cours d'exécution, une option cURL et un bouton &quot;Créer un point de terminaison&quot;." /><p>À partir d'ici, veuillez récupérer l'URL du point de terminaison Hugging Face :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt25714021711ed6ff/6a170d72c1e8a54853f88336/025094ddb2cfbd1f0f216a5ec4e119b0f4fa2c42-646x328.png" alt="Vue du tableau de bord d'un point de terminaison d'inférence Hugging Face nommé &quot;smollm3‑3b‑pnz&quot;, affichant un statut d'exécution vert, une réplique active, zéro requête au cours de la dernière heure, des onglets de navigation et l'URL du point de terminaison affiché." /><p>Comme indiqué dans la <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-hugging-face">documentation Elasticsearch relative aux points de terminaison d'inférence Hugging Face</a>, la génération de texte nécessite un modèle compatible avec l'API OpenAI. Pour cette raison, nous devons ajouter le sous-chemin <code>/v1/chat/completions</code> à à l'URL de point de terminaison Hugging Face. Le résultat final ressemblera à ceci :</p>https://j2g31h0futopfkli.us-east-1.aws.endpoints.huggingface.cloud/v1/chat/completions<p>Une fois ces éléments en place, nous pouvons commencer à coder dans un notebook Python.</p><h4>Génération de la clé API Hugging Face</h4><p>Créez un <a href="https://huggingface.co/join">compte Hugging Face</a> et obtenez un jeton API en suivant <a href="https://huggingface.co/docs/hub/en/security-tokens#user-access-tokens">ces instructions</a>. Vous avez le choix entre trois types de jetons : un jeton <em>granulaire</em> (recommandé pour la production, car il ne donne accès qu'à des ressources spécifiques), un jeton de <em>lecture</em> (pour un accès en lecture seule) ou un jeton d'<em>écriture</em> (pour un accès en lecture et en écriture). Pour ce tutoriel, un jeton de lecture suffit, car nous n'avons besoin d'appeler que le point de terminaison d'inférence. Enregistrez cette clé pour la prochaine étape.</p><h4>Configuration du point de terminaison d'inférence Elasticsearch</h4><p>Tout d'abord, déclarons un client Elasticsearch Python :</p>os.environ["ELASTICSEARCH_API_KEY"] = "your-elasticsearch-api-key"
os.environ["ELASTICSEARCH_URL"] = "https://xxxx.us-central1.gcp.cloud.es.io:443"

es_client = Elasticsearch(
    os.environ["ELASTICSEARCH_URL"], api_key=os.environ["ELASTICSEARCH_API_KEY"]
)<p>Ensuite, nous allons créer un point de terminaison d'inférence Elasticsearch qui utilise le modèle Hugging Face. Ce point de terminaison nous permettra de générer des réponses en fonction des articles de blog et du prompt transmis au modèle.</p>INFERENCE_ENDPOINT_ID = "smollm3-3b-pnz"

os.environ["HUGGING_FACE_INFERENCE_ENDPOINT_URL"] = (
 "https://j2g31h0futopfkli.us-east-1.aws.endpoints.huggingface.cloud/v1/chat/completions"
)
os.environ["HUGGING_FACE_API_KEY"] = "hf_xxxxx"

resp = es_client.inference.put(
        task_type="chat_completion",
        inference_id=INFERENCE_ENDPOINT_ID,
        body={
            "service": "hugging_face",
            "service_settings": {
                "api_key": os.environ["HUGGING_FACE_API_KEY"],
                "url": os.environ["HUGGING_FACE_INFERENCE_ENDPOINT_URL"],
            },
        },
    )<h3>Ensemble de données</h3><p>L'ensemble de données contient les <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/elasticsearch-inference-api-and-hugging-face/dataset.json">articles de blog</a> sur lesquels des requêtes seront exécutées ; il s'agit d'un ensemble de contenus multilingues utilisé tout au long du workflow :</p>// Articles dataset document example: 
{
    "id": "6",
    "title": "Complete guide to the new API: Endpoints and examples",
    "author": "Tomas Hernandez",
    "date": "2025-11-06",
    "category": "tutorial",
    "content": "This guide describes in detail all endpoints of the new API v2. It includes code examples in Python, JavaScript, and cURL for each endpoint. We cover authentication, resource creation, queries, updates, and deletion. We also explain error handling, rate limiting, and best practices. Complete documentation is available on our developer portal."
  }<h4>Mappings Elasticsearch</h4><p>Une fois l'ensemble de données défini, nous devons créer un schéma de données adapté à la structure des articles de blog. Les <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">mappings d'index</a> suivants seront utilisés pour stocker les données dans Elasticsearch :</p>INDEX_NAME = "blog-posts"

mapping = {
    "mappings": {
        "properties": {
            "id": {"type": "keyword"},
            "title": {
                "type": "object",
                "properties": {
                    "original": {
                        "type": "text",
                        "copy_to": "semantic_field",
                        "fields": {"keyword": {"type": "keyword"}},
                    },
                    "translated_title": {
                        "type": "text",
                        "fields": {"keyword": {"type": "keyword"}},
                    },
                },
            },
            "author": {"type": "keyword", "copy_to": "semantic_field"},
            "category": {"type": "keyword", "copy_to": "semantic_field"},
            "content": {"type": "text", "copy_to": "semantic_field"},
            "date": {"type": "date"},
            "semantic_field": {"type": "semantic_text"},
        }
    }
}


es_client.indices.create(index=INDEX_NAME, body=mapping)<p>Ici, nous pouvons voir plus clairement comment les données sont structurées. Nous utiliserons la recherche sémantique pour récupérer les résultats basés sur le langage naturel, ainsi que la propriété <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/copy-to"><code>copy_to</code></a> pour copier le contenu du champ dans le champ <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text"><code>semantic_text</code></a>. De plus, le champ <code>title</code> contient deux sous-champs : le sous-champ <code>original</code> stocke le titre en anglais ou en espagnol, selon la langue d'origine de l'article, et le sous-champ <code>translated_title</code> n'est présent que pour les articles en espagnol et contient la traduction anglaise du titre original.</p><h3>Ingestion des données</h3><p>L'extrait de code suivant ingère l'ensemble de données des articles de blog dans Elasticsearch à l'aide de l'<a href="https://www.elastic.co/docs/reference/elasticsearch/clients/javascript/bulk_examples">API Bulk</a> :</p>def build_data(json_file, index_name):
    with open(json_file, "r") as f:
        data = json.load(f)

    for doc in data:
        action = {"_index": index_name, "_source": doc}
        yield action


try:
    success, failed = helpers.bulk(
        es_client,
        build_data("dataset.json", INDEX_NAME),
    )
    print(f"{success} documents indexed successfully")

    if failed:
        print(f"Errors: {failed}")
except Exception as e:
    print(f"Error: {str(e)}")<p>Maintenant que nous avons intégré les articles dans Elasticsearch, nous devons créer une fonction capable de rechercher dans le champ <code>semantic_text</code> :</p>def perform_semantic_search(query_text, index_name=INDEX_NAME, size=5):
    try:
        query = {
            "query": {
                "match": {
                    "semantic_field": {
                        "query": query_text,
                    }
                }
            },
            "size": size,
        }

        response = es_client.search(index=index_name, body=query)
        hits = response["hits"]["hits"]

        return hits
    except Exception as e:
        print(f"Semantic search error: {str(e)}")
        return []<p>Nous avons également besoin d'une fonction qui appelle le point de terminaison d'inférence. Dans ce cas, nous appellerons le point de terminaison en utilisant le type de tâche <strong><code>chat_completion</code></strong>pour obtenir des réponses en streaming :</p>def stream_chat_completion(messages: list, inference_id: str = INFERENCE_ENDPOINT_ID):
    url = f"{ELASTICSEARCH_URL}/_inference/chat_completion/{inference_id}/_stream"
    payload = {"messages": messages}
    headers = {
        "Authorization": f"ApiKey {ELASTICSEARCH_API_KEY}",
        "Content-Type": "application/json",
    }

    try:
        response = requests.post(url, json=payload, headers=headers, stream=True)
        response.raise_for_status()

        for line in response.iter_lines(decode_unicode=True):
            if line:
                line = line.strip()

                if line.startswith("event:"):
                    continue

                if line.startswith("data: "):
                    data_content = line[6:]

                    if not data_content.strip() or data_content.strip() == "[DONE]":
                        continue

                    try:
                        chunk_data = json.loads(data_content)

                        if "choices" in chunk_data and len(chunk_data["choices"]) &gt; 0:
                            choice = chunk_data["choices"][0]
                            if "delta" in choice and "content" in choice["delta"]:
                                content = choice["delta"]["content"]
                                if content:
                                    yield content

                    except json.JSONDecodeError as json_err:
                        print(f"\nJSON decode error: {json_err}")
                        print(f"Problematic data: {data_content}")
                        continue

    except requests.exceptions.RequestException as e:
        yield f"Error: {str(e)}"<p>Nous pouvons maintenant écrire une fonction qui appelle la fonction de recherche sémantique, ainsi que le point de terminaison d'inférence <code>chat_completions</code> et le point de terminaison de recommandations, afin de générer les données qui seront allouées dans les fiches :</p>def recommend_articles(search_query, index_name=INDEX_NAME, max_articles=5):
    print(f"\n{'='*80}")
    print(f"🔍 Search Query: {search_query}")
    print(f"{'='*80}\n")

    articles = perform_semantic_search(search_query, index_name, size=max_articles)

    if not articles:
        print("❌ No relevant articles found.")
        return None, None

    print(f"✅ Found {len(articles)} relevant articles\n")

    # Build context with found articles
    context = "Available blog articles:\n\n"
    for i, article in enumerate(articles, 1):
        source = article.get("_source", article)
        context += f"Article {i}:\n"
        context += f"- Title: {source.get('title', 'N/A')}\n"
        context += f"- Author: {source.get('author', 'N/A')}\n"
        context += f"- Category: {source.get('category', 'N/A')}\n"
        context += f"- Date: {source.get('date', 'N/A')}\n"
        context += f"- Content: {source.get('content', 'N/A')}\n\n"

    system_prompt = """You are an expert content curator that recommends blog articles.

    Write recommendations in a conversational style starting with phrases like:
    - "If you're interested in [topic], this article..."
    - "This post complements your search with..."
    - "For those looking into [topic], this article provides..."


    FORMAT REQUIREMENTS:
    - Return ONLY a JSON array
    - Each element must have EXACTLY these three fields: "article_number", "title", "recommendation"
    - If the original title is in spanish, use the "translated_title" subfield in the "title" field

    Keep each recommendation concise (2-3 sentences max) and focused on VALUE to the reader.

    EXAMPLE OF CORRECT FORMAT:
    [
        {"article_number": 1, "title": "Article title in english", "recommendation": "If you are interested in [topic], this article provides..."},
        {"article_number": 2, "title": "Article title in english", "recommendation": " for those looking into [topic], this article provides..."}
    ]

    Return ONLY the JSON array following this exact structure."""

    user_prompt = f"""Search query: "{search_query}"

    Generate recommendations for the following articles: {context}
    """

    messages = [
        {"role": "system", "content": "/no_think"},
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": user_prompt},
    ]

    # LLM generation
    print(f"{'='*80}")
    print("🤖 Generating personalized recommendations...\n")

    full_response = ""

    for chunk in stream_chat_completion(messages):
        print(chunk, end="", flush=True)
        full_response += chunk

    return context, articles, full_response<p>Enfin, nous devons extraire les informations et les mettre en forme pour l'impression :</p>def display_recommendation_cards(articles, recommendations_text):
    print("\n" + "=" * 100)
    print("📇 RECOMMENDED ARTICLES".center(100))
    print("=" * 100 + "\n")

    # Parse JSON recommendations - clean tags and extract JSON
    recommendations_list = []
    try:

        # Clean up &lt;think&gt; tags
        cleaned_text = re.sub(
            r"&lt;think&gt;.*?&lt;/think&gt;", "", recommendations_text, flags=re.DOTALL
        )
        # Remove markdown code blocks ( ... ``` or ``` ... ```)
        cleaned_text = re.sub(r"```(?:json)?", "", cleaned_text)
        cleaned_text = cleaned_text.strip()

        parsed = json.loads(cleaned_text)

        # Extract recommendations from list format
        for item in parsed:
            article_number = item.get("article_number")
            title = item.get("title", "")
            rec_text = item.get("recommendation", "")

            if article_number and rec_text:
                recommendations_list.append(
                    {
                        "article_number": article_number,
                        "title": title,
                        "recommendation": rec_text,
                    }
                )
    except json.JSONDecodeError as e:
        print(f"⚠️  Could not parse recommendations as JSON: {e}")
        return

    for i, article in enumerate(articles, 1):
        source = article.get("_source", article)

        # Card border
        print("┌" + "─" * 98 + "┐")

        # Find recommendation and title for this article number
        recommendation = None
        title = None
        for rec in recommendations_list:
            if rec.get("article_number") == i:
                recommendation = rec.get("recommendation")
                title = rec.get("title")
                break

        # Print title
        title_lines = textwrap.wrap(f"📌 {title}", width=94)
        for line in title_lines:
            print(f"│  {line}".ljust(99) + "│")

        # Card border
        print("├" + "─" * 98 + "┤")

        # Print recommendation
        if recommendation:
            recommendation_lines = textwrap.wrap(recommendation, width=94)
            for line in recommendation_lines:
                print(f"│  {line}".ljust(99) + "│")

        # Card bottom
        print("└" + "─" * 98 + "┘")<p>Faisons un test en posant une question sur les articles de blog relatifs à la sécurité :</p>search_query = "Security and vulnerabilities"

context, articles, recommendations = recommend_articles(search_query)

print("\nElasticsearch context:\n", context)

# Display visual cards
display_recommendation_cards(articles, recommendations)<p>Nous pouvons voir ici les fiches générées par le workflow dans la console :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4aa221a08a51aeb3/6a170d7460084be1413c45d6/730d35212594bb3db30447c3ea7e2a92857287b7-1999x1515.png" alt="Section intitulée &quot;Articles recommandés&quot; présentant cinq résumés d'articles en encadré, portant sur une vulnérabilité du système d'authentification, les risques de migration, les améliorations des performances et de l'authentification de l'API REST v2, les modifications du système de notification et un guide complet de la nouvelle API." /><p>Vous trouverez les résultats complets, y compris tous les résultats et la réponse du LLM dans <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/elasticsearch-inference-api-and-hugging-face/results.md">ce fichier</a>.</p><p>Nous recherchons des articles portant sur le thème "Security et vulnérabilités". Cette question est utilisée comme requête de recherche sur les documents stockés dans Elasticsearch. Les résultats récupérés sont ensuite transmis au modèle, qui génère des recommandations basées sur leur contenu. Comme nous pouvons le constater, le modèle a parfaitement réussi à générer des textes courts et attrayants qui incitent le lecteur à cliquer dessus.</p><h2>Conclusion</h2><p>Cet exemple illustre comment combiner Elasticsearch et Hugging Face pour créer un système centralisé, rapide et performant pour les applications d'IA. Cette approche réduit les interventions manuelles et offre une grande flexibilité grâce au vaste catalogue de modèles de Hugging Face. L'utilisation de SmolLM3-3B, en particulier, montre comment des modèles multilingues compacts peuvent fournir un raisonnement pertinent et une génération de contenu efficace lorsqu'ils sont associés à la recherche sémantique. Ensemble, ces outils constituent une base scalable et performante pour le développement d'applications d'analyse de contenu intelligentes et multilingues.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hugging-face-elasticsearch-inference-api</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hugging-face-elasticsearch-inference-api</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Intégrations]]></category>
    <dc:creator><![CDATA[Jeffrey Rengifo]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5f961af4cb26ec97/6a170d767d8d6790c770e790/1417d6ff033712206c9bd4bcc22074ee3437ce96-1999x1125.png" length="0" type="image/png"/>
    <pubDate>Mon, 23 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[L'extension Gemini CLI pour Elasticsearch avec des outils et des fonctionnalités]]></title>
    <description><![CDATA[Présentation de l’extension Elastic pour le CLI Gemini de Google, afin de rechercher, récupérer et analyser les données Elasticsearch dans les workflows des développeurs et des agents.
]]></description>
    <content:encoded><![CDATA[<p>Nous sommes heureux d'annoncer la sortie de notre extension Elastic pour l'interface de ligne de commande Gemini de Google, qui apporte toute la puissance de <a href="https://www.elastic.co/elasticsearch">Elasticsearch</a> et <a href="https://www.elastic.co/elasticsearch/agent-builder">Elastic Agent Builder</a> directement dans votre workflow de développement d'IA. Cette extension propose également plusieurs compétences d’agent récemment développées pour interagir avec Elasticsearch.</p><p>L'extension est disponible en tant que projet open source <a href="https://github.com/elastic/gemini-cli-elasticsearch">ici</a>.</p><h2>Qu'est-ce que Gemini CLI et comment l'installer ?</h2><p><a href="https://geminicli.com/">Gemini CLI</a> est un agent d’IA open source qui intègre les modèles Gemini de Google directement dans la ligne de commande. Il permet aux développeurs d’interagir avec l’IA depuis le terminal pour effectuer des tâches telles que générer du code, éditer des fichiers, exécuter des commandes shell et récupérer des informations sur le web.</p><p>Contrairement aux interfaces de chat classiques, Gemini CLI s'intègre à votre environnement de développement local, ce qui signifie qu'il peut comprendre le contexte du projet, modifier des fichiers, assurer l'exécution des compilations ou des tests et automatiser les workflows directement dans le terminal. Il est donc utile aux développeurs, aux ingénieurs de fiabilité des sites (SRE) et aux ingénieurs qui souhaitent un codage assisté par l'IA et une automatisation sans quitter leur workflow en ligne de commande.</p><p>Le CLI Gemini s’installe à l’aide de plusieurs gestionnaires de paquets. La méthode la plus courante passe par npm :</p>npm install -g @google/gemini-cli<p>Si vous souhaitez connaître d’autres options d’installation, consultez la <a href="https://geminicli.com/docs/get-started/installation/">page officielle d’installation</a>.</p><p>Après l’installation, lancez la CLI en exécutant :</p>gemini<p>Vous voyez un écran, comme illustré sur la figure 1 :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4ff43abe550941b4/6a17072ba29299fc2ad00fa4/6dfcec4a77b3dc83bf0d974417bf2e211abb1f4f-876x468.png" alt="Une capture d'écran de Gemini CLI." /><h2>Configurer Elasticsearch</h2><p>Nous avons besoin d'une instance Elasticsearch en cours d'exécution. Si vous souhaitez utiliser le serveur Model Context Protocol (MCP), vous devez également installer Kibana 9.3+. Pour utiliser le langage de requête Elasticsearch (ES|QL) (<code>esql</code>) décrit ci-dessous, Kibana n’est pas requise.</p><p>Vous pouvez activer un essai gratuit sur <a href="https://www.elastic.co/cloud">Elastic Cloud</a> ou l’installer localement en utilisant le script <a href="https://github.com/elastic/start-local"><code>start-local</code></a> :</p>curl -fsSL https://elastic.co/start-local | sh<p>Cela installera Elasticsearch et Kibana sur votre ordinateur et générera une clé API à utiliser pour configurer Gemini CLI.</p><p>La clé API sera affichée comme sortie de la commande précédente et stockée dans un fichier <strong>.env</strong> fichier dans le dossier <strong><code>elastic-start-local</code></strong>.</p><p>Si vous utilisez Elasticsearch sur site (par exemple, en utilisant <code>start-local</code>), et que vous souhaitez utiliser Elastic Agent Builder avec MCP, vous devez aussi connecter un grand modèle de langage (LLM). Vous pouvez consulter <a href="https://www.elastic.co/docs/explore-analyze/ai-features/llm-guides/llm-connectors">cette page de documentation</a> pour comprendre les différentes options.</p><p>Si vous utilisez Elastic Cloud (ou Elastic Cloud Serverless), vous disposez déjà d’une connexion LLM préconfigurée.</p><h2>Installez l'extension Elasticsearch</h2><p>Vous pouvez installer l'extension Elasticsearch pour Gemini CLI avec la commande suivante :</p>gemini extensions install https://github.com/elastic/gemini-cli-elasticsearch<p>Vous pouvez vérifier que les extensions ont été installées avec succès en ouvrant Gemini et en exécutant la commande suivante :</p>/extensions list<p>L'extension Elasticsearch devrait être disponible.</p><p>Si vous souhaitez utiliser l'intégration MCP, vous devez avoir une version d'Elasticsearch 9.3+ installée. Vous avez besoin de l’URL de votre serveur MCP depuis <a href="https://www.elastic.co/kibana">Kibana</a> :</p><ul><li><p>Obtenez l'URL de votre serveur MCP dans Agents &gt; Voir tous les outils &gt; Gérer MCP &gt; Copier l'URL du serveur MCP.</p></li><li><p>L'URL se présentera comme suit : https://your-kibana-instance/api/agent_builder/mcp</p></li></ul><p>Vous avez besoin de l’URL de l'endpoint Elasticsearch. Ce message apparaît généralement en haut de la page Elasticsearch de Kibana. Si vous utilisez Elasticsearch avec <code>start-local</code>, vous avez déjà l'endpoint dans la clé <code>ES_LOCAL_URL</code> dans le fichier<code>start-local</code> .env.</p><p>Vous avez également besoin d’une clé API. Si vous exécutez Elasticsearch avec <code>start-local</code>, vous avez déjà le <code>ES_LOCAL_API_KEY</code> dans le fichier <code>start-local</code> .env. Sinon, vous pouvez créer une clé API en utilisant l’interface Kibana, comme indiqué <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">ici</a> :</p><ul><li><p>Dans Kibana : Stack Management &gt; Security &gt; Clés API &gt; Créer une clé API.</p></li><li><p>Nous suggérons de définir uniquement les privilèges de lecture pour la clé API, en activant le privilège <code>feature_agentBuilder.read</code> comme indiqué <a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/permissions#grant-access-with-roles">ici</a>.</p></li><li><p>Copiez la valeur de la clé API encodée.</p></li></ul><p>Définissez les variables d'environnement requises dans votre shell :</p>export ELASTIC_URL="your-elasticsearch-url"
export ELASTIC_MCP_URL="your-elasticsearch-mcp-url"
export ELASTIC_API_KEY="your-encoded-api-key"<h2>Installer l'ensemble de données d'exemple</h2><p>Vous pouvez installer l'ensemble de données <strong>eCommerce orders </strong>disponible dans Kibana. Il comprend un seul index nommé <strong><code>kibana_sample_data_ecommerce</code></strong>, contenant des informations sur 4 675 commandes provenant d'un site web. Pour chaque commande, nous disposons des informations suivantes :</p><ul><li><p>Informations client (nom, identifiant, date de naissance, e-mail, etc.).</p></li><li><p>Date de la commande.</p></li><li><p>ID de commande.</p></li><li><p>Produits (liste de tous les produits avec prix, quantité, identification, catégorie, réduction et autres détails).</p></li><li><p>SKU.</p></li><li><p>Prix total (hors taxes, taxes incluses).</p></li><li><p>Quantité totale.</p></li><li><p>Informations géographiques (ville, pays, continent, localisation, région).</p></li></ul><p>Pour installer les données d'exemple, ouvrez la page <strong>Intégrations</strong> dans Kibana (recherchez « Intégrations » dans la barre de recherche supérieure) et installez l'<strong>ensemble de données</strong> « Échantillons de données ». Pour plus de détails, consultez la documentation <a href="https://www.elastic.co/docs/explore-analyze/#gs-get-data-into-kibana">ici</a>.</p><p>Le but de cet article est de montrer à quel point il est facile de configurer la CLI Gemini pour se connecter à Elasticsearch et interagir avec l'index <strong><code>kibana_sample_data_ecommerce</code></strong>.</p><h2>Comment utiliser le MCP d’Elasticsearch</h2><p>Vous pouvez vérifier la connexion à l'aide de la commande suivante dans Gemini :</p>/mcp list<p>Le <strong><code>elastic-agent-builder</code></strong> devrait être activé, comme le montre la figure 2 :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt52b85e7255360f3b/6a17072da929cf33d3ae08f5/1508423bc1d1bc3c04a1cb01e2d59495a3516ed1-1465x844.png" alt="Le serveur MCP « elastic-agent-builder » avec la liste des outils." /><p>Elasticsearch fournit un ensemble d'outils par défaut. Voir la description <a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/tools/builtin-tools-reference">ici</a>.</p><p>Grâce à ces outils, vous pouvez interagir avec Elasticsearch, en posant des questions telles que :</p><ul><li><p><code>Give me the list of all the indexes available in Elasticsearch.</code></p></li><li><p><code>How many customers are based in the USA in the kibana_sample_data_ecommerce index of Elasticsearch?</code></p></li></ul><p>En fonction de la question, Gemini utilisera un ou plusieurs des outils disponibles pour tenter d'y répondre.</p><h2>Les commandes /elastic</h2><p>Dans l’extension Elasticsearch pour Gemini CLI, nous avons également ajouté<strong><code>/elastic</code></strong> commandes.</p><p>Si vous exécutez la commande <strong><code>/help</code></strong>, vous verrez toutes les options <code>/elastic</code> disponibles (Figure 3) :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt741c7451ecab10d2/6a17072ea6c2b9ccd6e79643/5b2a0727ce7a04354878dd048253d3f4d062324b-1983x230.png" alt="Commandes /elastic disponibles." /><p>Ces commandes peuvent être utiles si vous souhaitez exécuter directement un outil spécifique du serveur MCP <code>elastic-agent-builder</code>. Par exemple, en utilisant la commande suivante, vous pouvez obtenir le mapping de <code>kibana_sample_data_ecommerce</code> :</p>/elastic:get-mapping kibana_sample_data_ecommerce<p>Ces commandes sont essentiellement des raccourcis permettant d’exécuter des outils spécifiques, plutôt que de s’en remettre au modèle Gemini pour déterminer l’outil à invoquer.</p><h2>Comment utiliser les compétences Elasticsearch</h2><p>Cette extension inclut également une <a href="https://github.com/elastic/gemini-cli-elasticsearch/tree/main/skills/esql">compétence d’agent pour ES|QL</a>, le <a href="https://www.elastic.co/docs/explore-analyze/discover/try-esql">langage de requête canalisé d’Elasticsearch (ES|QL)</a> disponible dans Elasticsearch. <a href="https://agentskills.io/home">Agent Skills</a> est un format ouvert qui fournit aux agents IA de codage, comme Gemini CLI, des instructions personnalisées pour des tâches spécifiques. Ils utilisent un concept appelé <em>divulgation progressive</em>, ce qui signifie que seule une brève description de la compétence est ajoutée au prompt système initial. Lorsque vous demandez à l’agent d’effectuer une tâche, comme interroger Elasticsearch, il fait correspondre la requête à la compétence pertinente et charge dynamiquement les instructions détaillées. Il s’agit d’un moyen efficace de gérer les budgets de tokens tout en fournissant à l’IA exactement le contexte dont elle a besoin.</p><p>La<strong> compétence</strong> <strong><code>esql</code></strong>est conçue pour permettre à Gemini CLI d’écrire et d’exécuter des requêtes ES|QL directement sur votre cluster. ES|QL est un langage de requête puissant qui rend l'exploration des données, l'analyse des logs et les agrégations très intuitives. Avec cette compétence activée, vous n'avez pas besoin de rechercher la syntaxe ES|QL ; vous pouvez simplement poser des questions en langage naturel à l'interface en ligne de commande Gemini sur vos données, et l'agent se chargera du reste.</p><p>Les exécutions sont réalisées à l'aide de simples commandes <a href="https://curl.se/">curl</a> lancées dans un terminal. L’intégration d’Elasticsearch à n’importe quelle architecture est simplifiée par la richesse de ses API REST.</p><p><strong>Ce que la </strong>compétence<strong><code>esql</code></strong><strong> offre :</strong></p><ul><li><p><strong>Recherche d'index et de schémas :</strong> L'agent peut utiliser les outils intégrés de la compétence pour dresser la liste des index disponibles et récupérer le mapping des champs. Par exemple, avant d’écrire une requête pour l’ensemble de données eCommerce, l’agent peut effectuer une exécution de vérification de schéma sur <strong><code>kibana_sample_data_ecommerce</code></strong> afin de comprendre les champs disponibles, comme <strong><code>taxful_total_price</code></strong> ou <strong><code>category</code></strong>.</p></li><li><p><strong>Traduction transparente en langage naturel :</strong> La compétence donne à l'agent plus qu'un simple manuel de référence ; elle lui fournit un guide spécifique pour interpréter l'intention de l'utilisateur. Dès que vous tapez une demande en langage naturel, par exemple « Afficher le temps de réponse moyen groupé par service », l’agent s’appuie sur les modèles intégrés de la compétence pour convertir vos mots en commandes, filtres et agrégations ES|QL appropriés.</p></li><li><p><strong>Autocorrection :</strong> en cas d’échec d’une requête (erreur de syntaxe ou de type, par exemple), la compétence transmet la requête ainsi que l’erreur Elasticsearch précise. L’agent peut alors la rectifier immédiatement et retenter l’opération sans que vous ayez à intervenir.</p></li></ul><p>Comme la compétence <code>esql</code> est également disponible sous forme d'outil sur le serveur MCP <code>elastic-agent-builder</code>, nous devons désactiver ce serveur temporairement. Vous pouvez utiliser la commande suivante pour le désactiver :</p>/mcp disable elastic-agent-builder<p>Ensuite, vous pouvez simplement taper une invite comme celle-ci dans votre interface de ligne de commande Gemini :</p>Find the top 5 product categories by total sales revenue in the kibana_sample_data_ecommerce index<p>L’agent devra :</p><ul><li><p>Reconnaissez la nécessité de la compétence <code>esql</code>.</p></li><li><p>Consultez le schéma de <strong><code>kibana_sample_data_ecommerce</code></strong>.</p></li><li><p>Construisez une requête ES|QL, comme : <code>FROM kibana_sample_data_ecommerce | STATS total_revenue = SUM(taxful_total_price) BY category.keyword | SORT total_revenue DESC | LIMIT 5</code>.</p></li><li><p>Exécutez la requête auprès de l’API Elasticsearch.</p></li><li><p>Présentez la réponse finale directement dans le terminal.</p></li></ul><p>Nous avons cité ici un exemple de réponse de Gemini à la question précédente :</p>───────────────────────────────────────────────────────────
&gt; Find the top 5 product categories by total sales revenue in the kibana_sample_data_ecommerce index   ───────────────────────────────────────────────────────────
✓  Activate Skill "esql": Interact with Elasticsearch using ES|QL and curl. Use when querying, managing indices,  …
Skill esql activated. Resources loaded from /home/user/.gemini/extensions/elasticsearch/skills/esql: 
Showing up to 200 items (files + folders).                                                                     /home/user/.gemini/extensions/elasticsearch/skills/esql/                                                            ├───SKILL.md 
└───references/
├───esql-reference.md 
├───generation-tips.md 
└───query-patterns.md

✦ I will start by exploring the mapping of the kibana_sample_data_ecommerce index to identify the fields for product category and sales revenue. Then, I will construct and execute an ES|QL query to determine the top 5 product categories by total sales revenue.

✓  Shell curl -s "${ELASTIC_URL%/}/kibana_sample_data_ecommerce/_mapping" -H "Authorization: ApiKey $(printenv ELAS…                                                                                                                       {  
   "kibana_sample_data_ecommerce": { 
     "mappings": { 
       "properties": {
         "category": { 
           "type": "text", 
           "fields": {
             "keyword": {
               "type": "keyword"
             }
           }
         }, 
         "currency": {
           "type": "keyword"
         }, 

✦ Okay, I have the mapping. The category is products.category.keyword and sales revenue is taxful_total_price. I'll now execute the ES|QL query to get the top 5 categories by revenue.

✓  Shell curl -s -X POST "${ELASTIC_URL%/}/_query" \  -H "Authorization: ApiKey $(printenv ELASTIC_API_KEY)" \  -H …
{ 
   "took": 62,
   "is_partial": false, 
   "completion_time_in_millis": 1772805644164,
   "documents_found": 4675,
   "values_loaded": 12084, 
   "start_time_in_millis": 1772805644102, 
   "expiration_time_in_millis": 1773237644087,  
   "columns": [ 
     { 
       "name": "total_revenue",    
       "type": "double"  
     }, 
     {   
       "name": "products.category.keyword",

✦ The query for top 5 product categories by revenue was successful. I'll format the returned JSON values into a   user-friendly list.

 ✓  Shell 
                             
 Top 5 product categories by total sales revenue: 
 1. Men's Clothing: 149393.91
 2. Women's Clothing: 135099.91
 3. Women's Shoes: 105479.17
 4. Men's Shoes: 91797.92
 5. Women's Accessories: 60830.31 

✦ I've found the answer; now I'll format it for clarity.

 ✓  Shell 

 Here are the top 5 product categories by total sales revenue:                                                        
                                                                      
 | Rank | Category              | Total Revenue | 
 |------|-----------------------|---------------| 
 | 1    | Men's Clothing        | 149,393.91    |
 | 2    | Women's Clothing      | 135,099.91    |
 | 3    | Women's Shoes         | 105,479.17    |
 | 4    | Men's Shoes           | 91,797.92     | 
 | 5    | Women's Accessories   | 60,830.31     | 

✦ I've formatted and presented the answer. I'm finished.
 ───────────────────────────────────────────────────────────<p>Il est intéressant de noter comment le modèle Gemini génère la réponse finale en montrant toutes les étapes qu’il suit. On peut voir ici l’influence de la compétence sur la démarche de réflexion du modèle. Dès que le modèle identifie la nécessité d’utiliser une compétence ou d’exécuter une commande shell, il sollicite une autorisation via l’approche supervision humaine dans la boucle.</p><p>Grâce à la gestion automatisée de la découverte de schéma, de la génération de requêtes et de leur exécution, la compétence <code>esql</code> vous libère des contraintes techniques pour vous focaliser uniquement sur l’analyse des résultats. Vous obtiendrez les données dont vous avez besoin, correctement formatées et directement dans votre terminal, sans jamais écrire une seule ligne de code ni basculer vers une autre application.</p><h2>Conclusion</h2><p>Dans cet article, nous avons présenté l'extension Elasticsearch pour Gemini CLI que nous avons récemment publiée. Cette extension vous permet d'interagir avec votre instance Elasticsearch en utilisant Gemini et le serveur Elasticsearch MCP fourni par Elastic Agent Builder, disponible à partir de la version 9.3.0, ainsi que la commande <code>/elastic</code>.</p><p>De plus, l'extension comprend également une compétence <code>esql</code> qui convertit la demande d'un utilisateur en langage naturel en une requête ES|QL. Cette compétence est très pratique quand l’usage du serveur MCP est impossible, puisque les échanges s’appuient sur l’exécution de commandes curl basiques dans le terminal. L’intégration d’Elasticsearch à tous vos projets est simplifiée par la richesse de ses API REST. C’est particulièrement utile lors du développement d’applications d’IA agentique.</p><p>Pour plus d’informations sur notre extension Gemini CLI, visitez le dépôt de projets <a href="https://github.com/elastic/gemini-cli-elasticsearch">ici</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/gemini-cli-extension-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/gemini-cli-extension-elasticsearch</guid>
    <category><![CDATA[Intégrations]]></category>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Walter Rafelsberger,Enrico Zimuel]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4ff43abe550941b4/6a17072ba29299fc2ad00fa4/6dfcec4a77b3dc83bf0d974417bf2e211abb1f4f-876x468.png" length="0" type="image/png"/>
    <pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Compétences d'agent pour Elastic : transformez votre agent IA en un expert Elastic]]></title>
    <description><![CDATA[Donnez à votre agent de codage IA les connaissances nécessaires pour interroger, visualiser, sécuriser et automatiser avec les compétences Elastic Agent.]]></description>
    <content:encoded><![CDATA[<p>Chaque développeur, ingénieur SRE ou analyste qui a essayé d'utiliser un agent IA de programmation avec une plateforme spécialisée s'est heurté au même obstacle. Vous demandez à l'agent de rédiger une requête, de configurer une alerte ou d'enquêter sur un point, et il s'en sort presque, mais pas tout à fait. Elastic a un avantage ici : le fait qu'il existe plus d'une décennie de documentation, d'articles de blog et de réponses de la communauté fait que les agents IA connaissent déjà Elastic mieux que la plupart des plateformes de données. Mais cette richesse s'accompagne d'un certain désordre. Les API obsolètes coexistent avec les API actuelles. Les modèles obsolètes sont classés au même niveau que les bonnes pratiques. L'agent reproduit avec confiance une approche qui fonctionnait il y a trois versions, car dans ses données d'entraînement, c'était le cas. Il en résulte un fardeau de correction : les utilisateurs alimentent manuellement la documentation dans le contexte, corrigent la syntaxe hallucinée et contournent l'agent au lieu de travailler avec lui. Pire encore, les fonctionnalités avancées restent totalement inutilisées, non pas parce que les utilisateurs n’en ont pas besoin, mais parce que l’agent ignore leur existence.</p><p>C'est pourquoi nous mettons en open source les <a href="https://github.com/elastic/agent-skills">compétences Elastic Agent</a> : une expertise native de la plateforme pour Elasticsearch, Kibana, Elastic Observability et Elastic Security. Ajoutez-les dans l'environnement d'exécution de l'agent que vous utilisez déjà, et améliorez votre agent en le faisant passer d'un statut de "généraliste" qui devine un grand nombre de syntaxes à un statut d'expert, capable par exemple d'utiliser un grand nombre de normes architecturales comme le font les équipes d'ingénieurs d'Elastic. Cette première version technique se concentre sur les compétences avec une compatibilité maximale pour <a href="https://www.elastic.co/cloud/serverless">Elastic Cloud Serverless</a>, mais évoluera rapidement pour inclure une meilleure prise en charge des anciennes versions de la pile.</p><p>De plus, Elastic résout ce problème sur les deux fronts. Pour les agents sur la plateforme Elastic, <a href="https://www.elastic.co/search-labs/blog/agent-builder-elastic-ga">Elastic Agent Builder</a> (désormais disponible en version générale) vous permet de créer et de discuter avec des agents IA qui héritent des contrôles d'accès de vos données, utilisent des outils de recherche et d'analyse intégrés, et travaillent en contexte aux côtés de vos tableaux de bord, alertes et investigations. Nous travaillons dur pour garantir des expériences exceptionnelles d’agent sur la plateforme Elastic. Mais tous les agents ne se trouvent pas au sein d’Elastic. Votre équipe utilise déjà Cursor, Claude Code ou d'autres environnements d'exécution, et ces agents doivent également maîtriser Elastic. C'est là que les compétences des agents entrent en jeu.</p><h2>Pourquoi les agents rencontrent-ils des difficultés avec les plateformes spécialisées</h2><p>Les grands modèles de langage (LLM) sont des généralistes remarquablement compétents. Ils peuvent écrire en Python, expliquer les manifestes Kubernetes et restructurer les composants React car leurs données d'entraînement sont riches en exemples. Mais lorsqu’il s’agit de travaux spécifiques à la plateforme, ceux qui impliquent des langages de requête propriétaires, des interfaces API complexes et des bonnes pratiques spécifiques à un domaine, ils échouent de manière prévisible.</p><p>Pour Elasticsearch, l'écart se manifeste concrètement :</p><ul><li><p><strong>Le langage de requête Elasticsearch (ES|QL) est un nouveau domaine.</strong> Les LLM sont fortement entraînés au SQL, mais ES|QL est un langage de requête canalisé avec une syntaxe différente, des fonctions différentes et une sémantique différente. Les agents écrivent fréquemment des requêtes qui semblent plausibles mais ne s'analysent pas. Ils confondent <code>WHERE</code> et <code>| WHERE</code>, inventent des fonctions qui n'existent pas et passent complètement à côté du modèle de composition canalisé.</p></li><li><p>Les <strong>surfaces API sont larges et profondes.</strong> Elasticsearch, Kibana et Elastic Security exposent des centaines d'API dans les domaines de la recherche, de l'ingestion, de l'alerting, des règles de détection, de la gestion des cas, des tableaux de bord et plus encore. Un agent ne disposant que de données d'entraînement générales doit deviner quel point de terminaison appeler, à quoi ressemble le corps de la requête et comment gérer la réponse. Il se trompe suffisamment souvent pour éroder la confiance.</p></li><li><p><strong>Les bonnes pratiques ne figurent pas dans les données d'entraînement.</strong> Quand devez-vous utiliser <code>semantic_text</code> plutôt qu'un pipeline de plongement personnalisé ? Comment structurer un pipeline d'ingestion pour un CSV de 10 Go ? Quelle est la bonne syntaxe de règle de détection pour une technique <a href="https://www.elastic.co/docs/solutions/security/detect-and-alert/mitre-attandckr-coverage">MITRE ATT&amp;CK</a> ? Les agents polyvalents ne disposent pas de connaissances spécifiques à Elastic organisées et structurées de manière fiable et chargées par défaut. Ils devraient aller les chercher, et même s'ils le faisaient, les documents bruts ne reflètent pas toujours les jugements et les bonnes pratiques que les praticiens qualifiés appliquent.</p></li></ul><p>Résultat : les développeurs passent plus de temps à corriger les sorties des agents qu'à écrire le code eux-mêmes. Ce n'est pas l'expérience pour laquelle ils se sont engagés.</p><h2>Compétences des agents : connaissances de la plateforme, destinées aux agents</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2099e0ccdf446fee/6a17074bd7c022e3e1de63d4/8d16ec00d16e70a916c5eef0aaa23fcc735b7186-1067x1280.png" alt="npx skills add elastic/agent-skills" /><p>Les compétences des agents sont des répertoires autonomes d'instructions, de scripts et de matériel de référence que les environnements d'exécution des agents peuvent charger de manière dynamique. Lorsqu’une compétence est active, l’agent a accès au bon contexte au bon moment : syntaxe de requête, modèles d’API, logique de validation, exemples pratiques, afin de pouvoir exécuter correctement les tâches du premier coup.</p><p>Chaque compétence suit la spécification ouverte <a href="https://agentskills.io">agentskills.io</a> : un dossier avec un fichier <code>SKILL.md</code> contenant des métadonnées et des instructions structurées. Aucun format propriétaire, pas de dépendance. Les compétences fonctionnent à travers les environnements d'exécution des agents, notamment Cursor, Claude Code, GitHub Copilot, Windsurf, Gemini CLI, Cline, Codex, et <a href="https://agentskills.io">bien d’autres</a>.</p><h3>Contenu de la version initiale v0.1.0</h3><p>Le premier ensemble de compétences couvre cinq domaines de l’Elastic Stack :</p><ul><li><p>Interagir avec les API Elasticsearch (recherche, indexation, clustering)</p></li><li><p>Création et gestion de contenu Kibana tels que les tableaux de bord, les alertes, les connecteurs et plus encore.</p></li><li><p>Expertise de domaine pour Elastic Observability</p></li><li><p>Expertise de domaine pour Elastic Security</p></li><li><p>Créer des agents efficaces dans Agent Builder</p></li></ul><h3>Les compétences sont composables</h3><p>Les compétences ne sont pas monolithiques. Elles sont modulaires de par leur conception. Votre agent charge uniquement les compétences pertinentes pour la tâche en cours. Vous travaillez sur une requête ES|QL ? La compétence ES|QL est activée. Vous souhaitez créer un tableau de bord à partir de ces résultats ? La compétence tableaux de bord se lance. Évaluer la santé de votre application ? La compétence de santé des services entre en jeu. Enquêter sur une alerte de sécurité ? Les compétences de triage s'enchaînent avec celles de gestion de cas et de réponse au fur et à mesure que l'enquête progresse.</p><p>Cette composabilité signifie que vous n'avez pas besoin d'une invite unique et massive qui tente de tout couvrir. Chaque compétence comporte exactement le contexte requis par son domaine, ni plus ni moins.</p><h2>Pour les développeurs d'applications de recherche et d'IA</h2><p>Si vous chargez des données dans Elasticsearch, que vous rédigez des requêtes ou que vous migrez des index, les compétences réduisent le cycle de génération de code, de détection d'erreurs et de recherche dans la documentation pour trouver ce qui n'a pas fonctionné.</p><p>Demandez à votre agent de charger un fichier CSV ; celui-ci utilisera un outil d’ingestion en continu qui gérera la contre-pression et déduira les mapping à partir des données. Il ne s'agit pas d'une boucle _bulk exécutée à la main qui épuise la mémoire dès le premier fichier volumineux. Demandez-lui de faire une requête auprès d’ES|QL, et il découvre vos véritables noms d’index et schémas de champs, puis écrit des requêtes valides canalisées avec la bonne syntaxe, les agrégations appropriées et la sélection de fonctionnalités adaptée à la version, et non une supposition SQL nécessitant trois tours de débogage. Demandez-lui de réindexer sur plusieurs clusters, et il suit le workflow complet : il crée la destination avec des mappings explicites, ajuste les paramètres de débit, effectue l'exécution de la tâche de manière asynchrone et restaure les paramètres de production une fois celle-ci terminée, et non pas un simple appel _reindex qui saute la moitié des étapes qu’un opérateur expérimenté suivrait.</p><p>Au lieu d'un agent qui vous donne un point de départ plausible à corriger, vous en obtenez un qui encode la discipline opérationnelle qui permet à la sortie de fonctionner réellement.</p><p><strong>Exemples d'impacts de l'utilisation des compétences d'Elastic Agent</strong></p><p>Eval</p><p>Ce que la compétence a changé</p><p>es-requêtes-d'audit-échecs-de-connexion</p><p>Utilisation des modèles de requête du log d'audit à partir de la compétence au lieu d'une recherche générique</p><p>es-autorisation-mapping-de-rôle-ldap</p><p>Émission de la structure correcte de l'appel d'API de mapping des rôles</p><p>esql-requête-de-base</p><p>Écriture de la syntaxe canalisée d'ES|QL via Query DSL</p><p>esql-gestion-des-erreurs</p><p>Priorité au schéma au lieu de deviner les noms des champs</p><p>esql-découverte de schéma</p><p>Ne devinez jamais le nom d'un index</p><p>es-ingestion-csv-avec-inférence</p><p>Utilisation de --infer-mapping uniquement, évitant de le combiner avec --source-format CSV qui crée un index vide</p><p>es-ingestion-fichier-json</p><p>Utilisation d'une approche d'ingestion robuste capable de traiter des fichiers volumineux</p><p>es-réindexer-local-asynchrone</p><p>Création de l’index de destination avec les répliques : 0 et refresh_interval : « -1 », puis réindexation asynchrone. Base : pas de préparation</p><p>es-sécurité-403-privilèges</p><p>Suivi d'un workflow de diagnostic de la compétence pour les erreurs de privilège au lieu de conseils génériques.</p><h2>Pour les équipes de sécurité</h2><p>Security répète quotidiennement les mêmes workflows opérationnels : trier les alertes, ajuster les règles de détection, gérer les dossiers. Les compétences de l'agent encodent ces connaissances procédurales afin que votre agent IA puisse exécuter correctement ces workflows, en appelant les bonnes API dans le bon ordre et avec les bons noms de champ. Pour une présentation pratique qui vous permettra de passer de zéro à un environnement Elastic Security complet sans quitter votre IDE, consultez la section <a href="https://www.elastic.co/security-labs/agent-skills-elastic-security">Prise en main d'Elastic Security depuis votre agent d'IA</a>.</p><h2>Pour les équipes d'observabilité et d'opérations</h2><p>Les nouvelles compétences des agents pour Elastic Observability réduisent les tâches opérationnelles liées à l'instrumentation de systèmes complexes, à la gestion des SLO, au tri des données complexes et à l'évaluation de l'état des services. L'intégration de l'expertise native d'Elastic directement dans les agents IA permet aux équipes d'exécuter des workflows d'observabilité complexes en utilisant un langage naturel simple. Cela permet aux équipes SRE et chargées des opérations de résoudre les incidents plus rapidement et d'assurer la maintenance de systèmes fiables plus facilement. Pour en savoir plus, consultez <a href="https://www.elastic.co/observability-labs/blog/elastic-agent-skills-observability-workflows">cet article de blog</a>.</p><h2>Open source, spécifications ouvertes, piloté par la communauté</h2><p>Nous publions les compétences d'agent sous la licence Apache 2.0, car nous pensons que les connaissances des agents doivent être ouvertes. La spécification <a href="https://agentskills.io">agentskills.io</a> que suivent les compétences est un standard ouvert, et non un format propriétaire d'Elastic. Nous voulons que les compétences soient le fruit d'un effort communautaire, et non d'un lieu clos.</p><h2>Une partie d'un tableau plus vaste</h2><p>Agent Skills fait partie d'une initiative plus vaste visant à faire d'Elasticsearch la plateforme de données la plus adaptée aux agents disponible sur le marché. Pour les agents hébergés sur la plateforme Elasticsearch, <a href="https://www.elastic.co/search-labs/blog/agent-builder-elastic-ga">Agent Builder</a> va plus loin en reprenant les contrôles d'accès et les autorisations de vos données, en fournissant des outils intégrés et personnalisés pour la recherche et l'analyse, et en permettant aux utilisateurs d'interagir avec les agents en contexte, au sein de leurs tableaux de bord, alertes et enquêtes. Enfin, la prise en charge des compétences sera bientôt disponible dans Agent Builder, offrant aux développeurs la flexibilité nécessaire pour tirer parti des compétences Elastic Agent ainsi que de celles provenant de toute autre source, afin de permettre un chat sécurisé et enrichi par le contexte, ainsi qu'une automatisation sur la plateforme Elasticsearch.</p><p>Pour les agents qui vivent ailleurs, nous investissons dans l'écosystème ouvert :</p><ul><li><p><strong>Extension du serveur Model Context Protocol (MCP) :</strong> Extension du <a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/mcp-server">point de terminaison MCP</a> dans Agent Builder avec davantage d'outils au-delà des opérations actuelles de recherche, ES|QL et d'index.</p></li><li><p><strong>Améliorations de l'authentification :</strong> faciliter la connexion sécurisée des agents, dans le but d'éliminer le copier-coller manuel des clés API.</p></li><li><p><strong>Documentation lisible par LLM :</strong> publication des fichiers <code>llms.txt</code> et <code>AGENTS.md</code> afin que les agents puissent découvrir et comprendre les API Elastic par eux-mêmes.</p></li><li><p><strong>Une interface de ligne de commande (CLI) pour les flux de travail des agents :</strong> Un outil de ligne de commande qui facilite la gestion des connexions et les opérations courantes pour les agents.</p></li></ul><p>Les compétences sont la partie que vous pouvez utiliser aujourd'hui. Le reste est à venir.</p><h2>Lancez-vous</h2><p><strong>Avant de commencer : </strong>Les agents de codage d’IA fonctionnent avec de vraies informations d’identification, un véritable accès au shell et, souvent, avec toutes les autorisations de l’utilisateur qui les exécute. Lorsque ces agents sont orientés vers des workflows de sécurité, les enjeux sont plus élevés : vous confiez à un système automatisé l’accès à la logique de détection, aux actions de réponse et aux télémétries sensibles. Le profil de risque de chaque organisation est différent. Avant d’activer les workflow de sécurité pilotés par l’IA, <strong>évaluez les données auxquelles l’agent peut accéder, les actions qu’il peut entreprendre et ce qui se passe s’il se comporte de manière inattendue</strong>.</p><p>Installez les compétences Elastic Agent dans votre environnement d'exécution de l'agent :</p><p><code>npx skills add elastic/agent-skills</code></p><p>Cela détecte automatiquement vos agents d'exécution installés et place les compétences dans le répertoire de configuration approprié. A partir de là, votre agent les récupère automatiquement.</p><p>Vous pouvez également consulter directement le <a href="https://github.com/elastic/agent-skills">catalogue de compétences</a> et installer manuellement des compétences individuelles en copiant le dossier de compétences dans le répertoire de configuration de votre agent.</p><p>Vous n'avez pas encore de cluster Elasticsearch ? Démarrer un <a href="https://cloud.elastic.co/registration">essai gratuit d'Elastic Cloud</a>. Il faut environ une minute pour obtenir un environnement entièrement configuré.</p><p><strong>Explorez le projet :</strong></p><ul><li><p><a href="https://github.com/elastic/agent-skills">Répertoire des compétences des agents</a></p></li><li><p><a href="https://agentskills.io">Spécifications d'agentskills.io</a></p></li><li><p><a href="https://www.elastic.co/docs">Documentation Elasticsearch</a></p></li><li><p><a href="https://cloud.elastic.co/registration">Essai gratuit d'Elastic Cloud</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agent-skills-elastic</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agent-skills-elastic</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Outils d'IA ]]></category>
    <dc:creator><![CDATA[Graham Hudgins,Matt Ryan]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbd233e8cf5c66c88/6a17074dc1e8a59502f8822a/09e64953819083168a9ecef0888c7f8bde1a43bd-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 16 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Langage d'expression commun (CEL) : comment l'entrée CEL améliore la collecte de données dans les intégrations Elastic Agent]]></title>
    <description><![CDATA[Découvrez en quoi le Common Expression Language se distingue des autres langages de programmation, comment nous l’avons étendu pour l’entrée CEL de Filebeat, et la flexibilité qu’il vous offre pour exprimer la logique de collecte de données dans les intégrations Elastic Agent.]]></description>
    <content:encoded><![CDATA[<p>Les <a href="https://www.elastic.co/integrations">intégrations</a> Elastic Agent permettent d’ingérer des données dans Elasticsearch à partir d’un large éventail de sources. Elles regroupent la logique de collecte, les pipelines d’ingestion, les tableaux de bord et d’autres artefacts au sein d’un package installable et administrable depuis l’interface web Kibana.</p><p>Les intégrations configurent une ou plusieurs <a href="https://www.elastic.co/docs/reference/beats/filebeat/configuration-filebeat-options">entrées Filebeat</a> pour assurer la collecte des données. Pour collecter des données via des API HTTP, nous avons souvent utilisé l’entrée <a href="https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-httpjson">HTTP JSON</a>. Cependant, même les API de type listing les plus simples peuvent varier considérablement dans leurs détails. Le modèle de transformations configurées en YAML de l’entrée HTTP JSON peut alors devenir contraignant, voire parfois insuffisant pour exprimer la logique de collecte requise.</p><p>L’<a href="https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-cel">entrée Common Expression Language (CEL)</a> a été introduite afin de permettre une interaction plus souple avec les API HTTP. <a href="https://cel.dev/">CEL</a> est un langage conçu pour être intégré dans des applications nécessitant un moyen rapide, sûr et extensible d’exprimer des conditions et des transformations de données. L’entrée CEL permet au créateur d’intégration d’écrire une expression unique capable de lire les paramètres, de suivre son propre état, d’effectuer des requêtes, de traiter les réponses et, au final, de renvoyer des événements prêts à être ingérés.</p><p>Dans cet article, nous examinons les différences entre CEL et d’autres langages de programmation, les extensions apportées pour l’entrée CEL, ainsi que la puissance et la souplesse qu’il apporte à l’expression de votre logique de collecte de données.</p><h2>CEL et son fonctionnement dans l’entrée</h2><p>CEL est un langage d’expressions. Il ne comporte pas d’instructions. Lorsque vous écrivez en CEL, vous ne décrivez pas une suite d’actions à exécuter à l’aide d’instructions. Vous indiquez plutôt la valeur à produire en rédigeant une expression. Chaque expression CEL renvoie une valeur. De petites expressions peuvent être combinées pour former une expression plus large, capable de produire un résultat selon des règles plus complexes. Nous verrons plus loin comment utiliser des expressions pour des usages généralement exprimés à l’aide d’instructions dans d’autres langages.</p><p>CEL est volontairement un langage non Turing-complet. Il n’autorise pas les boucles non bornées. Nous verrons également comment traiter des listes et des maps à l’aide de macros. En évitant les boucles non bornées, le langage garantit un temps d’exécution prévisible et limité pour chaque expression.</p><p>L’entrée CEL est configurée avec un programme CEL (une expression) et un état initial. L’état est fourni en entrée au programme. Le programme est évalué afin de produire un état de sortie. Si l’état de sortie comprend une liste d’événements, ceux-ci sont extraits puis publiés. Le reste de l’état de sortie est utilisé comme entrée pour l’évaluation suivante. Si l’état de sortie contient un ou plusieurs événements et que l’indicateur <code>want_more: true</code>, l’évaluation suivante est effectuée immédiatement ; sinon, l’entrée attend la fin de l’intervalle configuré avant de poursuivre. Voici un schéma simplifié du flux de contrôle de l’entrée :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0ec4ea57bfc2a2ff/6a17059f2b835f7d58f4b115/42671541f97e2dba808fd53969fe12f517917f9a-1600x529.png" alt="Flux de contrôle de l’entrée Common Expression Language (CEL)" /><p>La sortie de chaque évaluation est transmise comme entrée à l’évaluation suivante, tant que l’entrée s’exécute. Les données de sortie sous la clé « <code>cursor</code>» sont persistées sur disque et rechargées après le redémarrage de l’entrée, mais le reste de l’état n’est pas conservé entre les redémarrages.</p><p>Le langage CEL lui-même offre des fonctionnalités limitées et évite les effets de bord, mais il est extensible. L’implémentation <a href="https://github.com/google/cel-go">cel-go</a> ajoute certaines fonctionnalités, comme la prise en charge des syntaxes et des types optionnels. La bibliothèque <a href="https://github.com/elastic/mito">Mito</a> s’appuie sur cel-go et enrichit ses capacités, notamment en permettant l’exécution de requêtes HTTP. L’entrée CEL utilise la version de CEL fournie par Mito.</p><h2>Travailler avec Mito</h2><p>Pour créer ou déboguer une intégration à l’aide de l’entrée CEL, il est essentiel de comprendre l’état de sortie que votre programme CEL produira à partir d’un état d’entrée donné. Pendant le développement, il peut être contraignant d’exécuter votre programme CEL via l’entrée, au sein de l’ensemble de la Suite Elastic. Pour accélérer la boucle de rétroaction, vous pouvez utiliser l’outil de commande en ligne de Mito. Il vous permet d’exécuter un programme CEL directement et d’observer la sortie générée pour une entrée donnée.</p><p>Mito est écrit en Go et peut être installé comme suit :</p>go install github.com/elastic/mito/cmd/mito@latest<p>Lorsque vous exécutez un programme CEL avec Mito, vous lui fournissez généralement deux fichiers : un fichier JSON contenant l’état d’entrée initial, et un autre fichier avec le code source de votre programme CEL :</p>mito -data state.json src.cel<p>Pour faciliter le copier-coller, les exemples de cet article sont écrits sous forme de commandes uniques qui permettent au shell de créer des fichiers temporaires à la volée, en enveloppant le contenu de chaque fichier dans <code>&lt;(echo '...content...')</code>. Dans votre propre développement, travailler avec des fichiers réels sera plus facile.</p><h2>Récupération des tickets depuis GitHub</h2><p>L'exemple suivant inclut un programme CEL complet qui récupérera des données sur les problèmes depuis l'<a href="https://docs.github.com/en/rest/issues/issues?apiVersion=2022-11-28#list-repository-issues">API GitHub</a>. Son état d'entrée initial contient l'URL du point de terminaison de l'API et quelques informations sur la manière dont il doit gérer la pagination. Le programme CEL utilise les données dans l’état d’entrée pour générer une requête. Il va décoder la réponse, produire des événements à partir de celle-ci, et les renvoyer en tant que partie de son état de sortie.</p>mito -data &lt;(echo '
  {
    "url": "https://api.github.com/repos/elastic/integrations/issues",
    "per_page": 3,
    "max_pages": 3
  }
') &lt;(echo '
  int(state.?cursor.page.orValue(1)).as(page,
    (
      state.url + "?" + {
        "state": ["all"],
        "sort": ["created"],
        "direction": ["asc"],
        "per_page": [string(state.per_page)],
        "page": [string(page)],
      }.format_query()
    ).as(full_url,
      request("GET", full_url).with({
        "Header": {
          "Accept": ["application/vnd.github+json"],
          "X-GitHub-Api-Version": ["2022-11-28"],
        }
      }).do_request().as(resp,
        resp.Body.decode_json().as(data,
          state.with({
            "events": data.map(i, {
              "html_url": i.html_url,
              "title": i.title,
              "created_at": i.created_at,
            }),
            "cursor": { "page": page + 1 },
            "want_more": size(data) == state.per_page &amp;&amp; page &lt; state.max_pages,
          })
        )
      )
    )
  )
')<p>Sa première évaluation produit la sortie suivante :</p>{
  "cursor": {
    "page": 2
  },
  "events": [
    {
      "created_at": "2018-09-14T09:47:35Z",
      "html_url": "https://github.com/elastic/integrations/issues/3250",
      "title": "Increase support of log formats in haproxy filebeat module"
    },
    {
      "created_at": "2019-02-06T12:37:37Z",
      "html_url": "https://github.com/elastic/integrations/issues/487",
      "title": "ETCD Metricbeat module needs polishing and grooming"
    },
    {
      "created_at": "2019-08-13T11:33:11Z",
      "html_url": "https://github.com/elastic/integrations/pull/1",
      "title": "Initial structure"
    }
  ],
  "max_pages": 3,
  "per_page": 3,
  "url": "https://api.github.com/repos/elastic/integrations/issues",
  "want_more": true
}<p>Les événements seront supprimés et, lorsqu’ils seront exécutés dans l’entrée CEL, ils seront publiés pour ingestion. Le reste de la sortie sera transmis à l’évaluation suivante du programme CEL en tant qu’état d’entrée.</p><p></p><p>Pour comprendre le fonctionnement de ce programme CEL, nous allons examiner quelques exemples CEL plus simples et détailler davantage le fonctionnement de l’entrée CEL.</p><h2>Les bases de CEL</h2><p>Dans le langage CEL, il n’y a pas d’instructions ; uniquement des expressions. Toute expression CEL valide est évaluée pour produire une valeur finale. Voici l’une des plus petites expressions CEL que vous puissiez écrire, ainsi que sa sortie :</p>mito &lt;(echo '
  "hello" + " " + "world"
')"hello world"<p>De nombreuses expressions simples sont intuitives. Les opérations mathématiques ne sont prises en charge que sur des valeurs de même type (par exemple, <code>int</code> avec <code>int</code>), convertissez donc les types selon vos besoins (ici de <code>int</code> à <code>double</code>) :</p>mito &lt;(echo '
  double((1 + 2) * (3 + 4)) / 2.0
')10.5<p>Il n’y a pas de variables dans le langage CEL, mais une expression peut recevoir un nom et être utilisée dans une expression plus large grâce à la macro <a href="https://pkg.go.dev/github.com/elastic/mito/lib#hdr-As__Macro_-Collections"><code>as</code></a> de Mito. Dans cet exemple, l’expression <code>(1 + 1)</code> évalue la valeur <code>2</code>, et <code>.as(n, ...)</code> donne à cette valeur le nom <code>n</code> pour l’utilisation dans l’expression <code>"one plus one is "+string(n)</code>:</p>mito &lt;(echo '
  (1 + 1).as(n, "one plus one is "+string(n))
')"one plus one is 2"<p>Il est également possible d’accumuler des informations dans une carte et de les utiliser plus tard dans l’expression, comme démontré ici avec <a href="https://pkg.go.dev/github.com/elastic/mito/lib#hdr-With-Collections"><code>with</code></a>:</p>mito &lt;(echo '
  { "key": "value" }.with({ "key2": "value2" }).as(data,
    {
      "data": data,
      "size": size(data),
    }
  )
'){
  "data": {
    "key": "value",
    "key2": "value2"
  },
  "size": 2
}<p>Regardez à nouveau cet exemple. Remarquez que la partie imbriquée, <code>({ "data": data, "size": size(data), })</code>, nous donne la forme de la valeur finale. C'est une carte avec les clés <code>"data"</code> et <code>"size"</code>. Les valeurs de ces clés dépendent de <code>data</code>, qui est défini par la partie extérieure de l’expression. Lire les expressions CEL de l'intérieur vers l'extérieur peut aider à voir rapidement ce qu'elles renverront.</p><p>CEL ne possède pas d’instructions de flux de contrôle, comme <code>if</code>, mais le branchement conditionnel peut être réalisé avec l’opérateur ternaire :</p>mito &lt;(echo '
  1 + 1 &lt; 12 ? "few" : "many"
')"few"<p>Les boucles non bornées et la récursion ne sont pas prises en charge, car CEL n’est pas un langage Turing-complet. Le temps d’exécution est donc prévisible et proportionnel à la taille des données d’entrée et à la complexité de l’expression.</p><p>Bien que les boucles non bornées ne soient pas possibles dans des expressions CEL individuelles, vous pouvez traiter des listes et des cartes à l’aide de macros comme <a href="https://github.com/google/cel-spec/blob/master/doc/langdef.md#macros"><code>map</code></a> :</p>mito &lt;(echo '
  [1, 2, 3].map(x, x * 2)
')[2, 4, 6]<p>Dans cette section, nous avons abordé les points suivants :</p><ul><li><p>Les chaînes de caractères, les nombres, les listes et les maps.</p></li><li><p>La concaténation de chaînes.</p></li><li><p>Les opérations mathématiques.</p></li><li><p>Le transtypage.</p></li><li><p>Les conditions.</p></li><li><p>La nomination des sous-expressions.</p></li><li><p>Le traitement des collections.</p></li></ul><p>Ensuite, nous verrons comment effectuer des requêtes HTTP.</p><h2>Requêtes</h2><p>Mito étend CEL en lui donnant la possibilité d'effectuer des <a href="https://pkg.go.dev/github.com/elastic/mito/lib#HTTP">requêtes HTTP</a> :</p>mito &lt;(echo '
  get("https://example.com").as(resp, string(resp.Body))
')"&lt;!doctype html&gt;&lt;html lang=\"en\"&gt;&lt;head&gt;&lt;title&gt;Example Domain&lt;/title&gt;..."<p>Les requêtes peuvent être construites explicitement avant leur exécution. Cela permet d’utiliser différentes méthodes HTTP et d’ajouter des en-têtes ainsi qu’un corps de requête.</p><p>Dans cet exemple, nous construisons une URL avec l’aide de <a href="https://pkg.go.dev/github.com/elastic/mito/lib#hdr-Format_Query-HTTP"><code>format_query</code></a>, ajoutons un en-tête à la requête, et analysons le corps de la réponse avec <a href="https://pkg.go.dev/github.com/elastic/mito/lib#hdr-Decode_JSON-JSON"><code>decode_json</code></a>. Lorsque l'option <code>-log_requests</code> est sélectionnée, Mito log des informations détaillées au format JSON sur chaque demande et réponse.</p>mito -log_requests &lt;(echo '
  request("GET",
    "https://postman-echo.com/get?" + {
        "q": ["query value"]
     }.format_query()
  ).with({
    "Header": { "Accept": ["application/json"] }
  }).do_request().as(resp, {
    "status": resp.StatusCode,
    "data": resp.Body.decode_json(),
  })
'){"time":"...","level":"INFO","msg":"HTTP request",...}
{"time":"...","level":"INFO","msg":"HTTP response",...}
{
  "data": {
    "args": {
      "q": "query value"
    },
    "headers": {
      "accept": "application/json",
      "accept-encoding": "gzip, br",
      "host": "postman-echo.com",
      "user-agent": "Go-http-client/2.0",
      "x-forwarded-proto": "https"
    },
    "url": "https://postman-echo.com/get?q=query+value"
  },
  "status": 200
}<h2>Gestion de l’état et des évaluations</h2><p>Maintenant que nous avons vu comment effectuer des requêtes et passé en revue les bases de CEL nécessaires pour produire l’état de sortie souhaité, examinons de plus près ce que nous devons placer dans l’état de sortie et comment cela nous permet d’orienter les traitements ultérieurs.</p><p>Le programme CEL d'une intégration doit s'assurer que son état de sortie peut être utilisé comme entrée de l'évaluation suivante. La configuration définit l'état initial, qui doit être répété dans la sortie avec toutes les modifications appropriées. Une façon simple de le faire est d’utiliser <code>state.with({ ... })</code>, pour répéter la carte d’état avec quelques dérogations. Un modèle courant pour les petits programmes consiste à envelopper l'ensemble du programme dans <code>state.with()</code>, de sorte que la propagation de l'état ne doive pas être répétée dans chaque branche qui génère des données de sortie (par exemple, succès, erreurs).</p><p>Lorsque des valeurs d’état sont initialisées par une évaluation plutôt que codées en dur dans l’état d’entrée initial, le programme devra vérifier la présence d’une valeur existante avant de définir la valeur initiale. La prise en charge de la <a href="https://pkg.go.dev/github.com/google/cel-go/cel#OptionalTypes">syntaxe et des types optionnels</a> peut aider à résoudre ce problème. En utilisant un point d'interrogation avant le nom du champ dans une clé de carte, l'accès devient facultatif : il peut ou non aboutir à une valeur, mais d'autres accès facultatifs sont possibles et il est facile de fournir une valeur par défaut si aucune valeur n'est présente :
</p>mito -data &lt;(echo '{}') &lt;(echo '
  int(state.?counter.orValue(0)).as(counter,
    state.with({
      "counter": counter + 1,
      "want_more": counter + 1 &lt; 3,
    })
  )
'){ "counter": 1, "want_more": true }
{ "counter": 2, "want_more": true }
{ "counter": 3, "want_more": false }<p>Dans cet exemple, la valeur du compteur lue à partir de l'état est convertie en <code>int</code> car tous les nombres sont sérialisés dans l'état sous forme de nombres à virgule flottante, conformément aux conventions établies par JSON et le type <code>Number</code> de JavaScript. Il convient également de noter que <code>"want_more": true</code> est respecté ici par Mito, mais lorsqu’elle est exécutée dans l’entrée CEL, l’évaluation ne sera répétée que si la sortie contient également des événements.</p><p>C’est une exigence des programmes CEL exécutés par l’entrée CEL de retourner une clé <code>"events"</code> dans leur carte de sortie. Sa valeur peut être une liste de cartes d’événements, une liste vide ou une carte d’événement unique. Le cas d’événement unique est généralement utilisé pour les erreurs. L’événement sera publié par l’entrée, mais sa valeur sera également journalisée, et s’il définit une valeur <code>error.message</code>, celle-ci sera utilisée pour mettre à jour l’état de santé de la Fleet de l’intégration. Si votre programme ne produit qu’un seul événement sans erreur, il est préférable de l’inclure dans une liste.</p><p>Reprenons la sortie de notre programme de récupération des tickets GitHub présenté précédemment :</p>{
  "url": "https://api.github.com/repos/elastic/integrations/issues",
  "per_page": 3,
  "max_pages": 3,
  "cursor": {
    "page": 2
  },
  "events": [
    { ... },
    { ... },
    { ... }
  ],
  "want_more": true
}<p>Le programme gérait effectivement son état de la manière suivante :</p><ul><li><p>Répétition des valeurs d’état initiales dans <code>url</code>, <code>per_page</code>, et <code>max_pages</code>.</p></li><li><p>Ajout d’état qui devrait être maintenu lors des redémarrages dans <code>cursor.page</code>.</p></li><li><p>Les événements prêts à être publiés dans la liste <code>events</code>.</p></li><li><p>Demande de réévaluation immédiate avec <code>want_more: true</code>.</p></li></ul><p>Maintenant que vous maîtrisez l’accès optionnel, la gestion de l’état, les bases de CEL et les requêtes HTTP, le programme complet de récupération des tickets GitHub devrait être plus clair. Essayez de l’exécuter avec Mito et d’expérimenter quelques modifications.</p><h2>Conclusion et ressources</h2><p>Dans cet article, nous avons expliqué ce qu’est le langage CEL et comment il a été étendu dans la bibliothèque Mito pour une utilisation dans l’entrée CEL. Nous avons illustré la flexibilité de CEL à travers un programme exemple qui récupère des informations sur des tickets via l’API GitHub, et détaillé les éléments nécessaires à sa compréhension : accès aux paramètres dans l’état initial, interaction avec les API HTTP, renvoi d’événements destinés à l’ingestion et gestion de l’état pour les exécutions ultérieures du programme.</p><p>Pour aller plus loin et créer des intégrations à l’aide de l’entrée CEL, plusieurs ressources méritent votre attention :</p><ul><li><p><a href="https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-cel">Entrée CEL - Documentation Filebeat</a></p></li><li><p><a href="https://pkg.go.dev/github.com/elastic/mito">Documentation Mito</a></p></li><li><p><a href="https://cel.dev/">Langage d'expression commun - site web cel.dev</a></p></li><li><p><a href="https://www.elastic.co/docs/extend/integrations">Créer une intégration - Documentation Elastic</a></p></li></ul><p>Et sans doute la ressource la plus précieuse pour créer des intégrations avec l’entrée CEL reste le code CEL des intégrations Elastic existantes, disponible sur GitHub :</p><p><a href="https://github.com/search?q=repo%3Aelastic%2Fintegrations+path%3A**%2Fcel.yml.hbs&amp;type=code"><code>cel.yml.hbs</code></a><a href="https://github.com/search?q=repo%3Aelastic%2Fintegrations+path%3A**%2Fcel.yml.hbs&amp;type=code"> fichiers du dépôt des intégrations Elastic – GitHub</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/common-expression-language-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/common-expression-language-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Chris Berkhout]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt330db607ffb818f9/6a1705a08b73cb8502189f4c/985c50bfabee3348494eb4307f0b3375a97a0644-1280x720.png" length="0" type="image/png"/>
    <pubDate>Fri, 27 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Agent Builder, bien plus qu’une interface de discussion : vers une infrastructure augmentée]]></title>
    <description><![CDATA[Découvrez Elastic Agent Builder avec l’infrastructure augmentée, un agent d’IA qui permet des opérations, du développement et des tests Synthetic augmentés.]]></description>
    <content:encoded><![CDATA[<p><strong>Nous ne nous contentons pas d’en parler. Nous passons à l’action.</strong></p><p>Nous avons tous été témoins de l’essor des agents d’IA. Ils se révèlent particulièrement performants pour le résumé de textes, l’écriture de scripts et l’extraction de réponses issues de bases documentaires. Pourtant, dans les domaines du DevOps et de la fiabilité système (SRE), nous faisions face à un obstacle particulièrement frustrant. L’immense majorité des agents reste confinée au modèle du support client. S’ils analysent et échangent, ils demeurent incapables d’intervenir directement sur les couches d’infrastructure dont ils ont la charge.</p><p>Lors de notre récent hackathon, nous avons pris le parti de briser définitivement cette contrainte.</p><p>Nous avons conçu l’<strong>Infrastructure augmentée</strong> : un copilote d’infrastructure qui ne se contente pas de vous conseiller, mais qui crée, déploie, surveille et répare également votre environnement de production.</p><h2><strong>Le problème : copier, reformater, coller</strong></h2><p>Les agents standards fonctionnent en vase clos. Face à une panne majeure représentant une perte de 5 millions de dollars, l’assistance d’un agent standard se limite à la simple lecture du protocole de remise en service. Mais c’est toujours à <em>vous</em> d’effectuer le travail. Il vous reste encore à extraire le code, à en assurer la compatibilité avec votre environnement, puis à procéder manuellement à sa saisie dans la console.</p><p>Nous recherchions un agent capable de faire la part des choses entre le <em>discours</em> sur Kubernetes et l’<em>exécution technique</em> sur Kubernetes.</p><h2><strong>Au cœur du système : présentation d’Elastic Agent Builder.</strong></h2><p>Pour concevoir cette solution, nous ne sommes pas partis d’une page blanche. Nous l’avons conçue sur la base d’<a href="https://www.elastic.co/fr/elasticsearch/agent-builder"><strong>Elastic Agent Builder</strong></a>. À titre de rappel, Elastic Agent Builder est une architecture logicielle dédiée au développement rapide d’agents, agissant comme interface entre un modèle de langage (LLM), tel que Google Gemini, et les données propriétaires hébergées dans Elasticsearch.</p><p>Agent Builder peut être utilisé pour l’IA conversationnelle en l’ancrant sur des données internes, comme des documents ou des logs. Mais sa fonctionnalité la plus puissante est la possibilité d’assigner des <strong>outils</strong>. Ces outils permettent au LLM de sortir de l’interface de discussion pour accomplir des tâches spécifiques. Nous avons compris qu’en exploitant tout le potentiel de cette fonction, l’Agent Builder pourrait devenir un véritable pilier de l’automatisation.</p><h2><strong>Mise en œuvre : création de la première version</strong></h2><p>Dès le début du projet, notre ambition était de permettre aux agents d’exercer une action concrète sur leur environnement externe. Une idée a germé : pourquoi ne pas créer un « runner », un logiciel chargé d’exécuter sur la machine hôte toutes les instructions générées par l’agent ? Puis, nous avons envisagé ceci : et si les « runners », Elastic Agent Builder et l’utilisateur communiquaient en temps réel, comme lors d’une conférence téléphonique ?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltec9d20da8c41a898/6a170704dc55debd4ce00d43/8dc8317c1301b8eb7b89438529e8d8d17411c95a-1024x559.png" alt="Agent Builder with Augmented Infrastructure architecture" /><p>Nous avons commencé par concevoir un projet Python, Augmented Infrastructure Runners, qui consistait essentiellement en une boucle while(true) qui interrogeait chaque seconde l’API des conversations d’Elastic Agent Builder pour y détecter une syntaxe spécifique que nous avions créée :</p>{
	"tool_name": "my_tool",
       "tool_arguments": "\{stringified json arguments\}"
}<p>Nous avons ensuite mis à jour l’invite pour l’enseigner sur notre nouvelle syntaxe d’appel d’outil. Bill contribue à la maintenance de <a href="https://gofastmcp.com/getting-started/welcome">FastMCP</a>, la solution de référence en Python pour le développement de serveurs conformes au Model Context Protocol (MCP). Il a entrepris d’utiliser le client FastMCP conjointement avec ce nouveau runner afin de coupler les serveurs MCP et d’exposer leurs outils au sein de l’environnement d’exécution. Lorsque l’agent voyait cela, il exécutait l’appel de l’outil et publiait les résultats dans la conversation, comme si l’utilisateur lui-même les avait envoyés. Cela incitait le LLM à répondre au résultat, et c’est ainsi que tout a commencé !</p><p>C’était génial mais cela posait deux problèmes principaux :</p><ol><li><p>L’agent se contenterait de projeter l’intégralité des données JSON au beau milieu de l’échange avec l’utilisateur.</p></li><li><p>Dans l’API des conversations, les messages n’étaient accessibles qu’une fois le tour de parole terminé, soit après l’émission de la réponse par le LLM.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0596217e962f8464/6a17070647d49c3fef2d890c/7b3755aeae17722ff1bb9677712293e9195f96a0-1058x1034.png" alt="Issue when building agent with augment infrastructure" /><p>Nous nous sommes alors attachés à trouver comment déporter cette tâche en tâche de fond.</p><p>Nous avons ensuite choisi de donner à l’agent un outil appelé call_external_tool avec deux arguments : le tool_name et les arguments JSON sous forme de chaîne de caractères. Cet appel d’outil externe ne renvoie rien, mais il est important de noter qu’il est visible dans la requête GET envoyée à l’API des conversations. Nous avons ensuite donné aux runners l’autorisation d’écrire des documents directement dans Elasticsearch, que l’agent Elastic Agent Builder pouvait récupérer si nécessaire. L’agent fonctionne toujours en réponse à un message d’utilisateur. Nous devons donc démarrer l’agent avec un message d’utilisateur afin qu’il recherche des résultats et poursuive le traitement. Aussi, nous avons demandé aux agents d’insérer un court message dans le chat pour reprendre la conversation :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta22be3c67ad2ff1f/6a170708cdacbf0ae87d295b/61ff59a57c68ed5fad492d19c0580644113a507d-1600x1321.png" alt="Agent Builder with Augmented Infrastructure demostration" /><p>Ainsi, nous avions désormais des appels d’outils externes. Cependant, en raison du deuxième problème mentionné ci-dessus, nous avons dû supprimer cette dernière partie de démarrage. Sinon, chaque appel à un outil externe nécessitait un cycle complet de conversation pour récupérer les résultats !</p><h2><strong>Pour aller plus loin : présentation des workflows</strong></h2><p>En plus des appels d’outils via ES|QL et la recherche d’index, les agents d’Agent Builder peuvent solliciter des outils Elastic basés sur des workflows. Les workflows Elastic offrent une méthode flexible et simple à gérer pour exécuter une séquence arbitraire d’actions et de logiques. Dans notre cas, le rôle du workflow se limite à l’enregistrement d’une demande d’outil externe dans Elasticsearch et à la transmission d’un identifiant (ID) pour le suivi des résultats. Le résultat est une définition de workflow simple, articulée comme suit :</p>nom : ai-tool-call
activé : true
déclencheurs :
  - type : manuel
entrées :
  - nom : runner_id
    type : string
  - nom : tool_calls
    type : string

étapes :
  - nom : store_request
    type : elasticsearch.create
    avec :
      index : distributed-tool-requests
      id : "{{inputs.runner_id}}_{{ execution.id }}"
      document :
        request_id : "{{ execution.id }}"
        runner_id : "{{inputs.runner_id}}"
        tool_call : "{{inputs.tool_calls}}"
        status : "unhandled"

  - nom : output_result
    type : console
    avec :
      message : « Outil appelé, avec l’identifiant d’exécution : {{ execution.id }}. Utilisez cet identifiant pour consulter les résultats. »<p>Ainsi, au lieu de compter sur l’écriture de la requête d’appel d’outil dans la conversation, les runners peuvent simplement interroger l’index Elasticsearch distributed-tool-requests pour de nouvelles requêtes d’outils externes et faire un rapport des résultats dans un autre index Elasticsearch avec l’execution.id fourni.</p><p>Cela élimine les deux principaux problèmes mentionnés ci-dessus :</p><ol><li><p>L’historique de la conversation n’est plus encombré par les données de transfert des appels d’outils externes.</p></li><li><p>Comme les runners interrogent l’index Elasticsearch au lieu de l’historique de conversation, ils ne sont plus bloqués par l’achèvement du cycle d’échange pour que les requêtes d’outils externes deviennent visibles.</p></li></ol><p>L’intérêt principal de ce deuxième point est que l’exécution des requêtes vers les outils externes débute pendant que l’agent « réfléchit », sans attendre que le tour de parole soit terminé. Cela nous permet d’instruire le LLM, via le prompt système, d’interroger les résultats de l’outil externe jusqu’à ce qu’ils soient disponibles, éliminant ainsi le besoin d’un message de relance. Dans l’ensemble, cette approche fluidifie l’interaction : le LLM est désormais capable de gérer simultanément plusieurs appels d’outils externes lors d’une seule itération. Cela lui permet de traiter des requêtes utilisateur complexes de manière groupée, plutôt que de fragmenter le processus.</p><h2><strong>Mise en place</strong></h2><p>Pour rapprocher le LLM et la baie de serveurs, nous avons développé une architecture spécifique en exploitant les fonctionnalités des outils d’Agent Builder :</p><ol><li><p><strong>Les runners de l’infrastructure augmentée :</strong> Nous avons déployé des runners légers à l’intérieur des environnements cibles (serveurs, clusters Kubernetes, comptes cloud). Ces runners sont connectés directement à Elastic, en utilisant des endpoints sécurisés et des secrets accessibles uniquement à chacun des runners.</p></li><li><p><strong>Récupération ES|QL :</strong> Le copilote utilise <strong>ES|QL</strong> d’Elastic pour effectuer des recherches hybrides. Il ne se contente pas de rechercher des connaissances, il recherche des <em>capacités</em>. Il interroge les exécuteurs connectés pour voir quels outils sont disponibles (par exemple, list_ec2_instances, install_helm_chart).</p></li><li><p><strong>Exécution du workflow :</strong> Une fois que l’agent a décidé d’un plan d’action, il crée un workflow structuré.</p></li><li><p><strong>Boucle de rétroaction :</strong> Les runners exécutent la commande localement et rapportent les résultats dans Elasticsearch. Le copilote lit le résultat de l’index et décide de l’étape suivante.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9726199693a10c5c/6a17070ae8fbced43a39fb9a/76be256da722c1965971fc506502768bd890f0c4-1290x1076.png" alt="Architecture using Agent Builder’s tool capabilities with Augmented Infrastructure" /><h2><strong>Démonstration : transformer un incident critique en levier d’observabilité</strong></h2><p>Dans la vidéo, nous avons présenté deux scénarios distincts démontrant la puissance de cette architecture.</p><h3><strong>Scénario 1 : DevOps à la rescousse</strong></h3><p>Le point de départ est un incident critique : un utilisateur confronté à une perte de 5 millions de dollars due à un défaut de visibilité dans son cluster Kubernetes.</p><ul><li><p><strong>La demande :</strong> « Comment m’assurer que cela ne se reproduise plus ? »</p></li><li><p><strong>Action :</strong> L’agent ne s’est pas contenté de fournir un tutoriel. Il a identifié le cluster, créé les espaces de nom nécessaires, généré des secrets Kubernetes, installé l’opérateur OpenTelemetry et a immédiatement fourni un lien vers un tableau de bord APM en direct.</p></li><li><p><strong>Le résultat :</strong> Une observabilité complète de Kubernetes et des informations sur les applications sans que l’utilisateur n’écrive une seule ligne de YAML.</p></li></ul><h3><strong>Scénario 2 : Transfert de Security</strong></h3><p>En sécurité des infrastructures, un principe de base prévaut : l’impossibilité de protéger ce qui échappe à notre visibilité. En pleine intervention de secours DevOps, l’agent identifie une occasion d’optimiser la sécurité globale de l’infrastructure.</p><p>En s’appuyant sur une alerte générée lors d’une analyse Elastic Observability, nous illustrons la capacité d’un analyste sécurité à interagir en langage naturel avec son infrastructure. L’objectif est double : recenser précisément les ressources cloud existantes et mettre en œuvre les solutions de protection indispensables.</p><ul><li><p><strong>Découverte :</strong> Le copilote a énuméré les ressources AWS pour le spécialiste de la sécurité et a identifié une lacune critique : une instance Amazon Elastic Compute Cloud (EC2) et un cluster Amazon Elastic Kubernetes Service (EKS) avec des points de terminaison publics dépourvus de protection des points de terminaison.</p></li><li><p><strong>Remédiation :</strong> Avec une simple approbation, le copilote a déployé <strong>Elastic Security</strong> <strong>détection et réponse étendues (XDR) et détection et réponse cloud (CDR)</strong> sur les ressources vulnérables, assurant la sécurité de l’environnement en temps réel.</p></li><li><p><strong>Le résultat :</strong> Protection des ressources AWS déployées avec une sécurité totale à l’exécution.</p></li></ul><h2><strong>Perspectives : Vers une infrastructure intégralement augmentée</strong></h2><p>Ce projet démontre la capacité d’Elastic Agent Builder à agir comme le centre de pilotage de vos opérations distribuées. Notre champ d’action dépasse désormais le cadre strict de l’infrastructure. Les capacités de notre technologie de runner s’étendent à :</p><ul><li><p><strong>Synthetics augmenté :</strong> Diagnostiquer les erreurs TLS chez les runners du monde entier.</p></li><li><p><strong>Développement augmenté :</strong> Création de requêtes d’extraction et implémentation de CAPTCHA sur les services frontend.</p></li><li><p><strong>Opérations augmentées :</strong> reconfiguration automatique des résolveurs DNS en cas de panne.</p></li></ul><h2><strong>Essayez par vous-même</strong></h2><p>Nous pensons que l’avenir de l’IA ne se limite pas à l’assistance par chat, mais aussi à une <strong>infrastructure augmentée</strong>. Il s’agit d’avoir un partenaire qui peut déployer, réparer, observer et protéger à vos côtés.</p><p>Consultez le code et essayez-le par vous-même avec des runners distribués (<a href="https://github.com/strawgate/augmented-infrastructure">GitHub</a>) et Elastic Agent Builder sur <a href="https://cloud.elastic.co/">Elastic Cloud Serverless</a> dès aujourd'hui !</p><ul><li><p>Créez un projet sans serveur sur Elastic Cloud.</p></li><li><p>Déployez le code vers un runner.</p></li><li><p>Configurez le runner.</p></li><li><p>Configurez votre fichier mcp.json.</p></li><li><p>Démarrez l’agent, qui créera automatiquement votre agent et ses outils.</p></li><li><p>Dialoguez avec un agent capable de raisonner, de planifier et d’exécuter des actions sur vos runners distribués !</p></li></ul><p><strong>L’équipe : </strong><em>Alex, Bill, Gil, Graham et Norrie</em></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agent-builder-augmented-infrastructure</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agent-builder-augmented-infrastructure</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Outils d'IA ]]></category>
    <dc:creator><![CDATA[Alexander Wert,Bill Easton,Gil Raphaelli,Graham Hudgins,Norrie Taylor]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6de9245ad57ccc00/6a17070cdc55deaa39e00d48/e08daf78f328e826f39d06329f6a5487f75d178d-1272x700.png" length="0" type="image/png"/>
    <pubDate>Thu, 22 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Agent Builder est maintenant en disponibilité générale : créez des agents contextuels en quelques minutes]]></title>
    <description><![CDATA[Agent Builder est maintenant en disponibilité générale. Découvrez comment il vous permet de développer rapidement des agents d'IA contextuels.]]></description>
    <content:encoded><![CDATA[<p>Nous sommes ravis d'annoncer la disponibilité générale d'Agent Builder dans Elastic Cloud Serverless et dans la prochaine version 9.3. Agent Builder exploite la puissance d'Elasticsearch comme plateforme d'ingénierie du contexte pour développer rapidement des agents d'IA contextuels et axés sur les données.</p><p>Les agents gagnent du terrain en raison de leur potentiel d'amélioration de l'efficacité et de l'expérience client. Mais dans la pratique, il est difficile de fournir aux agents le bon contexte, en particulier lorsqu'ils travaillent sur des données d'entreprise hétérogènes et non structurées. Les développeurs doivent gérer les outils, les prompts, l'état, la logique de raisonnement, les modèles, et surtout récupérer un contexte pertinent à partir des sources métier pour garantir des résultats et des actions précis. Elastic Agent Builder fournit ces composants essentiels pour développer des agents sécurisés, fiables et contextuels.</p><h2>Fonctionnalités principales d'Agent Builder</h2><p>Agent Builder est le résultat des investissements à long terme d'Elastic dans la pertinence de la recherche et la génération augmentée par récupération, et contribue à faire d'Elasticsearch la meilleure base de données vectorielle pour simplifier le développement d'agents d'IA contextuels et axés sur les données.</p><p>Agent Builder vous permet de :</p><ul><li><p>Commencer immédiatement avec un agent conversationnel intégré capable de répondre aux questions, d'effectuer des analyses et de mener des investigations sur n'importe quelles données dans Elasticsearch.</p></li><li><p>Passer rapidement des données non structurées complexes à un agent personnalisé grâce à une expérience de développement basée sur la configuration.</p></li><li><p>Bénéficier de la pertinence d'une recherche hybride de pointe grâce à ES|QL intégré ou à des outils personnalisés pour améliorer la qualité du contexte et la fiabilité des agents.</p></li><li><p>Exécuter des workflows complexes (préversion) sous forme d'outils réutilisables pour enrichir les données, mettre à jour les enregistrements, envoyer des messages et plus encore pour l'automatisation basée sur des règles.</p></li><li><p>Vous connecter à des sources de données externes à Elasticsearch à l'aide de workflows et de MCP pour corréler et combiner le contexte pour les agents.</p></li><li><p>Intégrer à n'importe quel framework agentique ou d'application à l'aide d'outils intégrés et personnalisés exposés via MCP, et possibilité de se connecter à un MCP externe (préversion), prise en charge d'A2A et support technique API complet.</p></li><li><p>Étendre les capacités d'Agent Builder avec l'intégration de solutions tierces comme LlamaIndex pour le traitement complexe de documents ou Arcade.dev pour un accès sécurisé et structuré aux outils.</p></li></ul><p>Pour étendre les fonctionnalités d'Agent Builder, nous lançons Elastic Workflows, notre nouvelle solution d'automatisation basée sur des règles, actuellement disponible en préversion technique. Pour les tâches organisationnelles, les agents ont parfois besoin de la certitude et de la fiabilité des actions basées sur des règles, qui sont souvent nécessaires pour mettre en œuvre une logique métier spécifique. Elastic Workflows offre aux agents une méthode simple et déclarative pour orchestrer des systèmes internes et externes afin d'effectuer des actions, de collecter des données et du contexte, et de les transformer. Entièrement composables, pilotés par les événements et flexibles, les workflows peuvent être exposés comme outils à un agent via MCP.</p><h2>Passez des données à l'agent en quelques minutes</h2><p>Le développement d'agents peut prendre des semaines de travail préparatoire pour consolider des datastores distincts, construire des pipelines manuels, optimiser les requêtes et gérer une orchestration complexe. Agent Builder réduit le temps de développement des agents en supprimant le besoin de datastores séparés, de bases vectorielles, de pipelines RAG, de couches de recherche, de traducteurs de requêtes et d'orchestrateurs d'outils, vous permettant ainsi de vous concentrer sur la logique de l'agent et la livraison de l'application.</p><p>Agent Builder intègre nativement les primitives de la plateforme Elasticsearch pour accélérer le développement d'agents.</p><ul><li><p>Commencez avec un agent conversationnel intégré qui peut immédiatement discuter et raisonner avec vos données indexées.</p></li><li><p>Intégrez des agents dans des applications, des tableaux de bord ou des systèmes CI/CD avec un accès interactif via Kibana, des API, ou MCP et A2A.</p></li><li><p>Utilisez des outils par défaut pour comprendre la structure de vos données, sélectionner l'index approprié, générer des requêtes hybrides, sémantiques et structurées optimisées, et créer des visualisations configurables à l'aide d'ES|QL basées sur des prompts en langage naturel.</p></li></ul><p>Pour aller plus loin, essayez une <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">procédure pas à pas</a> complète.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd8def92028138672/6a17e086af47b60cd8cdde96/b55b63eae40f72952967cc8f3ea4df4cd62d7d70-1080x608.gif" alt="Guide pratique Elastic Agent Builder" /><h2>Développez sur Elasticsearch, une plateforme de données complète pour l'ingénierie du contexte</h2><p>En matière d'agents d'IA, la qualité du contexte est essentielle pour un raisonnement efficace et pour limiter les risques d'hallucinations. Dans de nombreux cas, les données métier nécessaires à l'exécution d'une tâche constituent l'élément de contexte le plus crucial. Elasticsearch, base de données vectorielle hautement scalable et leader en matière de pertinence, offre déjà de nombreuses primitives performantes d'ingénierie du contexte. L'ingénierie du contexte va au-delà de la simple génération augmentée par récupération : elle permet de personnaliser et de dimensionner la manière dont les données sont extraites, classées, filtrées et présentées aux agents, contribuant ainsi à réduire le bruit et l'ambiguïté.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc4c10c1d09e9f81e/6a17e087577262feb31bcb4b/419b9b6f13739e0a8983249d8ac31478e73dac89-1600x901.png" alt="Schéma Agent Builder" /><p>Elasticsearch fournit un moteur de contexte qui combine la recherche lexicale, la recherche vectorielle et le filtrage structuré pour la récupération, ce qui <a href="https://www.elastic.co/search-labs/blog/context-engineering-relevance-ai-agents-elasticsearch">améliore considérablement les performances des LLM</a> en garantissant que le modèle opère sur un contexte pertinent et précis. Cette fonctionnalité est prise en charge par la récupération agentique, ainsi que par des outils intégrés et une logique de recherche qui sélectionnent automatiquement les index appropriés et transforment le langage naturel en requêtes optimisées pour le contexte.</p><p>Avec Agent Builder, vous avez l'assurance que les agents reçoivent en priorité le contexte le plus pertinent grâce à des options de contrôle de la pertinence et du classement afin d'affiner la logique de notation, de classement et de filtrage. Elasticsearch vous permet de contrôler ce qui est important, pourquoi c'est important et comment l'ordre de priorité est établi, au lieu de vous fier à un comportement de récupération opaque. L'ensemble repose sur Elasticsearch, une plateforme de données scalable qui permet de stocker et de gérer toutes vos données (texte, vecteurs, métadonnées, logs, etc.) sur une seule et même plateforme, simplifiant ainsi la gestion du contexte pour les agents.</p><h2>Exécutez des workflows complexes en tant qu'outils réutilisables</h2><p>Si les agents d'IA permettent de raisonner sur des tâches complexes, l'automatisation repose en grande partie sur l'exécution fiable d'actions basées sur des règles qui appliquent une logique métier spécifique. Elastic Workflows offre une méthode simple et déclarative pour orchestrer les systèmes internes et externes afin d'effectuer des actions, collecter du contexte ou des données et les intégrer aux agents. Définis en YAML, les workflows sont entièrement composables de manière à les rendre aussi simples ou complexes que l'exige la tâche à accomplir. Les agents disposent ainsi d'un moyen efficace d'interagir avec la plateforme et les solutions Elasticsearch, de même qu'avec des applications tierces.</p><p>L'intégration d'un workflow avec Agent Builder peut se faire en trois étapes (prérequis : activez les workflows avec les détails fournis <a href="https://github.com/elastic/workflows">ici</a>)</p><p>1. Créez et enregistrez un nouveau workflow à l'aide de l'éditeur simple basé sur YAML avec autocomplétion et tests intégrés.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt00585158429a3395/6a17e089e317916b122d5740/308888bf3d2fa013f9391a55be6a6fbd458b6dac-1600x998.png" alt="Workflow Agent Builder" /><p>2. Créez un nouvel outil dans Agent Builder avec le type "Workflow" et fournissez une description pour aider l'agent à déterminer quand utiliser l'outil de workflow.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt874b6a1ce3a2ac34/6a17e08be9ea87b1dea9c4d9/c04810d30d226112c3610bd58e208607b213fc3d-1600x945.png" alt="Créer un nouvel outil dans Agent Builder" /><p>3. Ajoutez l'outil de workflow à votre agent personnalisé.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt94a31cb60ef11ce6/6a17e08daf47b61f0dcdde9a/724cd4ac93c46efb0d339fd140e5caf138f8150f-1600x948.png" alt="Ajoutez l'outil de workflow à votre agent personnalisé." /><p>4. Et voilà ! L'agent peut maintenant déclencher le workflow directement depuis une conversation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5143f401a06e8ba2/6a17e08fdbb4ffcfc6fb55de/8dfdd726ab89e31c48b79372650ce33946713dca-1600x929.png" alt="Un agent IA a été créé avec Elastic Agent Builder" /><h2>Votre agent, vos règles</h2><p>Agent Builder ne vous enferme pas dans un seul paradigme de développement. Au contraire, il est conçu pour permettre des approches de développement ouvertes et flexibles pour les agents avec un contrôle total des données, de la pertinence, des modèles, de l'interopérabilité, de la sécurité et de la conception des agents.</p><p>Les définitions d'agents personnalisés vous permettent de choisir précisément les outils auxquels un agent peut accéder, d'intégrer des prompts système personnalisés, d'adapter ses instructions et de définir des limites de sécurité. Les agents restent indépendants du modèle, ce qui vous permet de configurer avec flexibilité un LLM de votre choix, qu'il soit natif ou issu de l'écosystème étendu, sans être lié à un fournisseur unique.</p><p>Créez des outils extensibles qui encapsulent la logique spécifique au domaine (par exemple, des filtres d'index spécifiques, des jointures ES|QL, des pipelines analytiques) et sécurisez leur utilisation en production. La prise en charge API complète assure l'interopérabilité avec d'autres frameworks d'agents, grâce à une compatibilité native avec le protocole MCP (Model Context Protocol). L'intégration A2A vous permet d'exposer vos agents Elastic à d'autres frameworks, services et applications clientes, en réutilisant la même logique d'ingénierie des données et du contexte.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt309a0b3dd4cc367b/6a17e090ec0f8932045a6550/5e903ba24ffb3f40231e901f63bd494c89cb7757-1600x1004.png" alt="Configuration de l'agent IA avec Elastic Agent Builder" /><p>Agent Builder permet un développement flexible et ouvert, et il est conçu pour s'intégrer facilement aux frameworks et plateformes d'agents les plus populaires. Ces intégrations peuvent être essentielles pour fournir des agents efficaces. Comme l'explique <strong>Sam Partee, cofondateur d'Arcade.dev</strong>,</p><p><em>"Les systèmes agentiques échouent aujourd'hui, car la connexion de l'IA aux outils et aux données est complexe. Elastic Agent Builder avec Arcade.dev offre aux développeurs un moyen structuré et sécurisé de gérer la manière dont les agents récupèrent le contexte, raisonnent et agissent, permettant ainsi de passer de la démo à la phase de production."</em></p><p>Agent Builder tire également parti de l'extensibilité d'Elasticsearch pour gérer des données complexes. Comme le décrit <strong>Jerry Liu, PDG de LlamaIndex </strong>,</p><p><em>"L'extraction du contexte d'entreprise à partir de sources de données non structurées est essentielle à la création d'agents performants. Elastic Agent Builder, associé au traitement de documents complexes de LlamaIndex, renforce la couche de contexte critique, aidant les équipes à récupérer, traiter et préparer les données afin que les agents puissent raisonner avec plus de précision et obtenir de meilleurs résultats."</em></p><h2>Que pouvez-vous construire ?</h2><p>Agent Builder est déjà exploité dans de nombreux cas d'utilisation. Vous trouverez ci-dessous quelques exemples et architectures de référence pour vous familiariser avec les agents :</p><ul><li><p><strong>Automatiser l'infrastructure</strong> : dans les scénarios de support, les agents sont utilisés pour lire, analyser et dialoguer, mais jusqu'à présent, ils ne peuvent pas interagir directement avec l'infrastructure qu'ils sont appelés à gérer. L'équipe d'ingénierie d'Elastic a développé un agent pour la <a href="https://www.elastic.co/search-labs/blog/agent-builder-augmented-infrastructure">gestion automatisée de l'infrastructure</a> dans le cadre d'un hackathon. L'agent enquête activement sur les problèmes liés à l'infrastructure des applications et prend des mesures automatisées. Il utilise des workflows pour optimiser les configurations, répondre aux problèmes et scaler les ressources, le tout basé sur une compréhension intelligente des logs d'infrastructure.</p></li><li><p><strong>Analyse des menaces de sécurité</strong> : un agent de vulnérabilité de sécurité a été développé avec Elastic Agent Builder, MCP et Elasticsearch. Il automatise l'analyse des menaces en corrélant les données de sécurité internes avec les renseignements sur les menaces externes. L'agent effectue une recherche sémantique sur les incidents et configurations historiques, enrichit les résultats avec des données Internet en temps réel et applique un raisonnement LLM pour évaluer la pertinence environnementale, hiérarchiser les risques et proposer des mesures correctives concrètes. Voir l'<a href="https://www.elastic.co/search-labs/blog/agent-builder-mcp-reference-architecture-elasticsearch">architecture de référence</a><strong>.</strong></p></li><li><p><strong>Support technique client</strong> : les agents peuvent effectuer de nombreuses tâches de support, notamment la synthèse des cas, la déduplication et la création de tickets, ainsi que des investigations techniques approfondies. Agent Builder facilite ces opérations grâce à une recherche hybride en plusieurs étapes permettant de trouver uniquement les problèmes, solutions et procédures les plus pertinents, de formuler des hypothèses sur les causes profondes et de proposer des plans de remédiation. Agent Builder peut simplifier l'architecture des <a href="https://www.elastic.co/blog/generative-ai-customer-support-elastic-support-assistant">systèmes de support</a> complexes et accélérer les délais de livraison.</p></li><li><p><strong>Découverte de produits et de contenus</strong> : Agent Builder simplifie le processus d'<a href="https://www.elastic.co/search-labs/blog/build-voice-agents-elastic-agent-builder">exposition de catalogues produits complexes pour des expériences conversationnelles</a>, tout en permettant aux organisations de conserver la flexibilité nécessaire pour inclure leur propre logique métier et leurs propres exigences.</p></li><li><p><strong>Créez le vôtre</strong> : participez au <a href="https://elasticsearch.devpost.com/">hackathon Agent Builder,</a> qui se déroulera du 22 janvier au 27 février 2026. Collaborez avec la communauté pour créer des agents d'IA contextuels à plusieurs étapes qui combinent la recherche, les workflows, les outils et le raisonnement pour automatiser des tâches concrètes*</p></li></ul><h2>Commencez à créer des agents personnalisés dès maintenant</h2><p>Commencez avec un <a href="https://cloud.elastic.co/registration?onboarding_token=search&amp;pg=en-enterprise-search-page">essai Elastic Cloud</a>, et consultez la documentation <a href="https://www.elastic.co/docs/solutions/search/elastic-agent-builder">ici</a>. Pour les clients existants, Agent Builder est disponible dans Cloud Serverless et avec le niveau Enterprise dans Elastic Cloud Hosted et autogéré.</p><p>* <a href="https://elasticsearch.devpost.com/rules">Cliquez ici</a> pour connaître les modalités, conditions et critères d'éligibilité pour le hackathon</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agent-builder-elastic-ga</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agent-builder-elastic-ga</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Elastic Cloud Serverless]]></category>
    <dc:creator><![CDATA[Anish Mathur,Evan Castle]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta5ffa581514d8b8c/6a17e092dbb4fff61afb55e2/6840eb7dbb884055ab0e965dcfd614fec54936af-2210x1440.png" length="0" type="image/png"/>
    <pubDate>Thu, 22 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Création d'agents vocaux avec Elastic Agent Builder]]></title>
    <description><![CDATA[Découverte du fonctionnement des agents vocaux et création d’un agent vocal avec Elastic Agent Builder et LiveKit.]]></description>
    <content:encoded><![CDATA[<p>L’IA est restée enfermée dans une boîte en verre. Vous tapez des commandes, elle répond par du texte. Et c’est tout. C’est utile, mais distant. Comme observer quelqu’un derrière un écran. Cette année, 2026, marquera un tournant : les entreprises briseront cette vitre pour intégrer des agents d’IA dans leurs produits – là où ils apportent une vraie valeur.</p><p>L’un des moyens de briser la vitre : adopter des <em>agents vocaux</em>, autrement dit des agents IA capables de comprendre la voix humaine et de produire un son de synthèse. Grâce à l’essor des transcriptions à faible latence, des modèles de langage de grande taille (LLM) rapides et des systèmes de synthèse vocale au rendu naturel, cette vision devient réalité.</p><p>Pour réellement créer de la valeur, les agents vocaux doivent aussi avoir accès aux données métier. Dans ce billet, nous verrons comment fonctionnent les agents vocaux et comment en créer un pour ElasticSport, une boutique fictive d’équipements de sport de plein air, à l’aide de <a href="https://livekit.io/">LiveKit</a> et <a href="https://www.elastic.co/elasticsearch/agent-builder">Elastic Agent Builder</a>. Notre agent vocal sera sensible au contexte et s’appuiera sur nos données.</p><h2>Fonctionnement</h2><p>Le monde des agents vocaux repose sur deux grands paradigmes : le premier s’appuie sur des modèles de conversion vocale directe (speech-to-speech), le second sur une chaîne vocale composée de reconnaissance vocale, de LLM et de synthèse vocale. Les modèles speech-to-speech ont leurs avantages, mais les chaînes vocales permettent une personnalisation bien plus poussée des technologies employées et de la gestion du contexte, ainsi qu’un contrôle plus fin du comportement de l’agent. Nous allons nous concentrer sur le modèle basé sur la chaîne vocale.</p><h3>Composants clés</h3><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7dbeb09a3743f38d/6a17de9caf47b67330cdde7d/b237501903f9c3a71fe1b7755c3990e40c5495c8-1600x653.png" alt="Architecture de création d’un agent vocal IA ​ avec Elastic Agent Builder" /><h4>Transcription (reconnaissance vocale)</h4><p>La transcription est le point d’entrée de la chaîne vocale. Le composant de transcription reçoit des trames audio brutes en entrée, convertit la voix en texte, puis restitue ce texte en sortie. Le texte transcrit est mis en mémoire tampon jusqu’à ce que le système détecte la fin de la prise de parole de l’utilisateur – c’est alors que la génération par le LLM démarre. Plusieurs prestataires tiers proposent des transcriptions à faible latence. Lors de votre sélection, tenez compte de la latence et de la précision de transcription, et vérifiez que le fournisseur prend en charge les transcriptions en flux continu.</p><p></p><p>Exemples d’API tierces : <a href="https://www.assemblyai.com/">AssemblyAI</a>, <a href="https://deepgram.com/product/speech-to-text">Deepgram</a>, <a href="https://platform.openai.com/docs/guides/realtime-transcription">OpenAI</a>, <a href="https://elevenlabs.io/speech-to-text">ElevenLabs</a></p><h4>Détection de prise de parole</h4><p>La détection de prise de parole est le composant de la chaîne qui identifie la fin de l’intervention de l’utilisateur, déclenchant ainsi la génération. Une méthode courante consiste à utiliser un modèle de détection d’activité vocale (VAD), comme <a href="https://github.com/snakers4/silero-vad">Silero VAD</a>. Le VAD s’appuie sur le niveau d’énergie du signal audio pour détecter la présence de parole et identifier la fin de l’intervention. Cependant, un VAD seul ne peut pas distinguer une pause de la fin d’une prise de parole. C’est pourquoi on l’associe souvent à un modèle de fin d’énoncé, capable de prédire si l’utilisateur a terminé de parler, en se basant sur la transcription provisoire ou l’audio brut.</p><p>Exemples (Hugging Face) : <a href="https://huggingface.co/livekit/turn-detector">livekit/turn-detector</a>, <a href="https://huggingface.co/pipecat-ai/smart-turn-v3">pipecat-ai/smart-turn-v3</a></p><h4>Agent</h4><p>L’agent constitue le cœur de la chaîne vocale. Il est chargé de comprendre l’intention, de récupérer le bon contexte et de formuler une réponse sous forme de texte. <a href="https://www.elastic.co/elasticsearch/agent-builder">Elastic Agent Builder</a>, avec ses fonctions de raisonnement intégrées, sa bibliothèque d’outils et son intégration aux workflows, permet de créer un agent capable d’exploiter vos données et d’interagir avec des services externes.</p><h4>LLM (texte à texte)</h4><p>Pour choisir un LLM dans Elastic Agent Builder, deux critères principaux sont à prendre en compte : les benchmarks de raisonnement du LLM et le temps jusqu’au premier jeton (TTFT).</p><p>Les benchmarks de raisonnement mesurent la capacité du LLM à produire des réponses pertinentes. Les benchmarks à privilégier sont ceux qui évaluent la cohérence des conversations à plusieurs tours et les capacités cognitives, comme MT-Bench et le jeu de données Humanity’s Last Exam, respectivement.</p><p>Les benchmarks TTFT évaluent la rapidité avec laquelle le modèle génère son premier jeton en sortie. Il existe d’autres types de benchmarks de latence, mais le TTFT est particulièrement crucial pour les agents vocaux, car la synthèse vocale peut démarrer dès réception du premier jeton. Résultat : une latence réduite entre les prises de parole et une conversation plus naturelle.</p><p>Il faut souvent faire un compromis entre ces deux critères, car les modèles plus rapides obtiennent généralement de moins bons résultats aux tests de raisonnement.</p><p>Exemples (Hugging Face) : <a href="https://huggingface.co/openai/gpt-oss-20b">openai/gpt-oss-20b</a>, <a href="https://huggingface.co/openai/gpt-oss-120b">openai/gpt-oss-120b</a></p><h4>Synthèse (texte à la parole)</h4><p>La dernière étape de la chaîne consiste à convertir le texte en parole grâce à un modèle de synthèse vocale. Ce composant est chargé de convertir le texte généré par le LLM en parole audible. Comme pour les LLM, la latence est un critère important lors du choix d’un fournisseur de synthèse vocale. La latence de la synthèse vocale se mesure au temps jusqu’au premier octet (TTFB). C’est le délai nécessaire pour recevoir le tout premier octet audio. Un TTFB plus court permet aussi de réduire la latence entre les prises de parole.</p><p>Exemples : <a href="https://elevenlabs.io/text-to-speech-api">ElevenLabs</a>, <a href="https://cartesia.ai/sonic">Cartesia</a>, <a href="https://www.rime.ai/">Rime</a></p><h4>Construction du pipeline vocal</h4><p>Elastic Agent Builder peut s’intégrer dans une chaîne vocale à différents niveaux :</p><ol><li><p>Outils Agent Builder uniquement : reconnaissance vocale → LLM (avec outils Agent Builder) → synthèse vocale</p></li><li><p>Agent Builder en tant que MCP : reconnaissance vocale → LLM (avec accès Agent Builder via MCP) → synthèse vocale</p></li><li><p>Agent Builder comme noyau central : reconnaissance vocale → Agent Builder → synthèse vocale</p></li></ol><p>Pour ce projet, j’ai choisi d’utiliser Agent Builder comme solution centrale. Cette approche permet de tirer pleinement parti des fonctionnalités d’Agent Builder et des workflows. Le projet s’appuie sur LiveKit pour orchestrer la reconnaissance vocale, la détection de prise de parole et la synthèse vocale. Il implémente également un nœud LLM personnalisé, directement intégré à Agent Builder.</p><h2>Agent vocal de support technique Elastic</h2><p>Nous allons créer un agent vocal de support personnalisé pour une boutique de sport fictive, appelée ElasticSport. Les clients pourront appeler la ligne d’assistance, demander des recommandations de produits, consulter les fiches produit, vérifier le statut de leurs commandes, et recevoir les informations par message texte. Pour cela, nous devons commencer par configurer un agent personnalisé et créer des outils permettant d’exécuter des requêtes Elasticsearch Query Language (ES|QL) ainsi que des workflows.</p><h3>Configuration de l'agent</h3><h4>Invite</h4><p>L’invite détermine la personnalité que doit adopter l’agent et la façon dont il doit répondre. Il existe également quelques invites spécifiques à la voix, qui garantissent une synthèse vocale fluide et permettent de gérer élégamment les incompréhensions.</p>You are a Sales Assistant at ElasticSport, an outdoor sport shop specialized in hiking and winter equipment. 

[Profile]
- name: Iva
- company: ElasticSport
- role: Sales Assistant
- language: en-GB
- description: ElasticSport virtual sales assistant

[Context]
- Ask clarifying questions to understand the context.
- Use available tools to answer the user's question.
- Use the knowledge base to retrieve general information

[Style]
- Be informative and comprehensive.
- Maintain a professional, friendly and polite tone.
- Mimic human behavior and speech patterns.
- Be concise. Do not over explain initially

[Response Guideline]
- Present dates in spelled-out month date format (e.g., January fifteenth, two thousand and twenty-four).
- Avoid the use of unpronounceable punctuation such as bullet points, tables, emojis.
- Respond in plain text, avoid any formatting.
- Spell out numbers as words for more natural-sounding speech.
- Respond in short and concise sentences. Responses should be 1 or 2 sentences long.

[ERROR RECOVERY]
### Misunderstanding Protocol
1. Acknowledge potential misunderstanding
2. Request specific clarification<h4>Workflows</h4><p>Nous allons ajouter un petit workflow permettant d’envoyer un SMS via l’API de messagerie de Twilio. Ce workflow sera exposé à l’agent personnalisé sous forme d’outil, afin que l’agent puisse envoyer un SMS à l’appelant pendant l’appel. Cela permet à l’appelant, par exemple, de demander : « Pouvez-vous m’envoyer plus de détails sur <em>X</em> par SMS ? »</p>name: send sms
enabled: true
triggers:
  - type: manual
inputs:
  - name: message
    type: string
    description: The message to send to the phone number.

  - name: phone_number
    type: string
    description: The phone number to send the message to.

consts:
  TWILIO_ACCOUNT: "****"
  BASIC_AUTH: "****"
  FROM_PHONE_NNUMBER: "****"
steps:
  - name: http_step
    type: http
    with:
      url: https://api.twilio.com/2010-04-01/Accounts/{{consts.TWILIO_ACCOUNT}}/Messages.json
      method: POST
      headers:
        Content-Type: application/x-www-form-urlencoded
        Authorization: Basic {{consts.BASIC_AUTH | base64_encode}}
      body: From={{consts.FROM_PHONE_NNUMBER}}&amp;To={{inputs.phone_number}}&amp;Body={{inputs.message}}
      timeout: 30s<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt960a9395fb0985bf/6a17de9e4b055d1dff4320f0/b057e71b0a7c50eb3da47cd4f95e77ec7b4c6126-1600x1245.png" alt="Créer un nouvel outil pour agent vocal IA avec Elastic Agent Builder" /><h4>Outils ES|QL</h4><p>Les outils suivants permettent à l’agent de fournir des réponses pertinentes, basées sur des données réelles. Le dépôt d’exemple contient un script d’initialisation de Kibana avec des jeux de données produits, commandes et base de connaissances.</p><ul><li><p><strong>Product.search</strong></p></li></ul><p>Le jeu de données produit contient 65 produits fictifs. Voici un exemple de document :</p>{
      "sku": "ort3M7k",
      "name": "Ortovox Free Rider 26 Backpack",
      "price": 189,
      "currency": "USD",
      "image": "https://via.placeholder.com/150",
      "description": "The Ortovox Free Rider 26 is a technical freeride backpack with a dedicated safety compartment and diagonal ski carry system. Perfect for backcountry missions.\n\nKey Features:\n- 26L capacity\n- Diagonal ski carry system\n- Safety equipment compartment\n- Helmet holder\n- Hydration system compatible",
      "category": "Accessories",
      "subCategory": "Backpacks",
      "brand": "Ortovox",
      "sizes": ["One Size"],
      "colors": ["Black", "Blue", "Orange"],
      "materials": ["Nylon", "Polyester"]
    }<p>Les champs « name » et « description » sont mappés sur <code>semantic_text</code>, ce qui permet au LLM d’effectuer une recherche sémantique via ES|QL pour retrouver les produits pertinents. La requête de recherche hybride effectue une correspondance sémantique sur les deux champs, en appliquant une pondération légèrement supérieure au champ « name » grâce à un boost.</p><p>La requête récupère d’abord les 20 meilleurs résultats, classés selon leur score de pertinence initial. Ces résultats sont ensuite reclassés en fonction de leur champ « description » à l’aide du modèle d’inférence <code>.rerank-v1-elasticsearch</code> , puis réduits aux cinq produits les plus pertinents.</p>type: ES|QL
toolId: products.search
description: Use this tool to search through the product catalogue by keywords.
query: |
    FROM products
        METADATA _score
      | WHERE
          MATCH(name, ?query, {"boost": 0.6}) OR
            MATCH(description, ?query, {"boost": 0.4})
      | SORT _score DESC
      | LIMIT 20
      | RERANK ?query
            ON description
            WITH {"inference_id": ".rerank-v1-elasticsearch"}
      | LIMIT 5

parameters:
    query: space separated keywords to search for in catalogue<ul><li><p><strong>Knowledgebase.search</strong></p></li></ul><p>Les jeux de données de la base de connaissances contiennent des documents structurés comme suit, avec les champs de titre et de contenu stockés sous forme de texte sémantique :</p>{
        id: "8273645",
        createdAt: "2025-11-14",
        title: "International Orders",
        content: `International orders are processed through our international shipping partner. Below are the countries we ship to and average delivery times.
        Germany: 3-5 working days
        France: 3-5 working days
        Italy: 3-5 working days
        Spain: 3-5 working days
        United Kingdom: 3-5 working days
        United States: 3-5 working days
        Canada: 3-5 working days
        Australia: 3-5 working days
        New Zealand: 3-5 working days
        `
}<p>L’outil utilise une requête similaire à celle de <code>product.search</code> :</p>type: "ES|QL"
toolId: knowledgebase.search
description: Use this tool to search the knowledgebase.
query: |
  FROM knowledge_base
    METADATA _score
  | WHERE
      MATCH(title, ?query, {"boost": 0.6}) OR
      MATCH(content, ?query, {"boost": 0.4})
  | SORT _score DESC
  | LIMIT 20
  | RERANK ?query
      ON content
      WITH {"inference_id": ".rerank-v1-elasticsearch"}
  | LIMIT 5

parameters:
  query: space separated keywords or natural language phrase to semantically search for in the knowledge base<ul><li><p><strong>Orders.search</strong></p></li></ul><p>Le dernier outil que nous allons ajouter permet de récupérer les commandes à partir de <code>order_id</code> :</p>type: "ES|QL"
toolId: order.search
description: Use this tool to retrieve an order by its ID.
query: |
  FROM orders
    METADATA _score
  | WHERE order_id == ?order_id
  | SORT _score DESC
  | LIMIT 1

parameters:
  order_id: "the ID of the order"<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfaaf9634f27f70d7/6a17dea07f6f15b8d2c09a3d/d22bdd540a95b5a9c2bd5f308620835e8e6f7ecb-1600x1361.png" alt="configuration d’un agent vocal" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8f4c704ab96c294a/6a17dea23e03d74af14f2b7e/d91709a50fb5391876b714885242d998b2b21027-1600x1443.png" alt="Outils pour agent vocal" /><p>Une fois l’agent configuré et les workflows ainsi que les outils ES|QL associés, vous pouvez tester l’agent dans Kibana.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdbfd2934a9582c04/6a17dea463baff1532741b5e/8691f41624247a6b1352d158c970031e1426ce5e-1600x1056.png" alt="Test de l’agent vocal" /><p>Au-delà de l’agent de support ElasticSport, l’agent, les workflows et les outils peuvent être adaptés à d’autres cas d’usage, comme un agent commercial pour qualifier des prospects, un agent de dépannage à domicile, un système de réservation pour restaurant ou encore un agent de planification de rendez-vous.</p><p></p><p>La dernière étape consiste à connecter l’agent que nous venons de créer à LiveKit, à la synthèse vocale et à la reconnaissance vocale. Le dépôt mentionné à la fin de ce billet contient un nœud LLM personnalisé pour Elastic Agent Builder, compatible avec LiveKit. Il vous suffit de remplacer <code>AGENT_ID</code> par le vôtre et de le connecter à votre instance Kibana.</p><h2>Premiers pas</h2><p>Consultez le code et testez-le vous-même <a href="https://github.com/KDKHD/elastic_agent_builder_livekit">ici</a>. </p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/build-voice-agents-elastic-agent-builder</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/build-voice-agents-elastic-agent-builder</guid>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Kenneth Kreindler]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2732d87a324baa78/6a17dea6e9ea873632a9c4cc/43ceabb9e2c0966261c188bd40e03178d5a91e5c-1280x720.png" length="0" type="image/png"/>
    <pubDate>Thu, 22 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Gestion de la mémoire agentique avec Elasticsearch.]]></title>
    <description><![CDATA[Création d'agents plus sensibles au contexte et plus efficaces grâce à la gestion des mémoires avec Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Dans la discipline émergente de l'<strong>ingénierie contextuelle</strong>, il est crucial de fournir aux agents d'IA les bonnes informations au bon moment. L'un des aspects les plus importants de l'ingénierie contextuelle est la gestion de la <strong>mémoire</strong> d'une IA. Tout comme les humains, les systèmes d'IA s'appuient à la fois sur une mémoire à court terme et sur une mémoire à long terme pour se souvenir des informations. Si nous voulons que les agents à grand modèle de langage (LLM) poursuivent des conversations logiques, se souviennent des préférences des utilisateurs ou s'appuient sur des résultats ou des réponses antérieurs, nous devons les doter de mécanismes de mémoire efficaces.</p><p>Après tout, tout ce qui figure dans le contexte influence les réponses de l’IA. Le principe de l'<em>entrée et de la sortie</em> des déchets est vrai.</p><p>Dans cet article, nous allons présenter ce que signifie la mémoire à court et à long terme pour les agents IA, en particulier :</p><ul><li><p>La différence entre la mémoire à court terme et la mémoire à long terme.</p></li><li><p>Comment elles se rapportent aux techniques de génération augmentée de récupération (RAG) avec des bases vectorielles, comme Elasticsearch, et pourquoi une gestion attentive de la mémoire est nécessaire.</p></li><li><p>Les risques liés à la négligence de la mémoire, y compris le débordement de contexte et l'empoisonnement contextuel.</p></li><li><p>Les bonnes pratiques, telles que l'élagage du contexte, la synthèse et la récupération uniquement des informations pertinentes, permettent de maintenir la mémoire de l'agent à la fois utile et sécurisée.</p></li><li><p>Enfin, nous examinerons comment la mémoire peut être partagée et propagée dans les systèmes multi-agents pour permettre une collaboration sans confusion grâce à Elasticsearch.</p></li></ul><h2>Mémoire à court terme versus mémoire à long terme dans les agents d’IA</h2><p><em><strong>La mémoire à court terme</strong></em> dans un agent IA fait généralement référence au contexte ou à l’état immédiat de la conversation — essentiellement, l’historique de discussion actuel ou les messages récents dans la session active. Cela inclut la dernière requête de l’utilisateur et les échanges récents d’allers-retours. C’est très similaire aux informations qu’une personne garde en tête lors d’une conversation en cours.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blteb714ce810d1c472/6a170f321949f782cbe7aaf6/4fbcc6f68055b2bccefc4176297a4ca50056dc0d-764x498.png" alt="Mémoire agentique à court et long terme" /><p>Les frameworks d'IA maintiennent souvent cette mémoire transitoire dans l'état de l'agent (par exemple, en utilisant un pointeur de contrôle pour stocker l'état de la conversation, comme le montre <a href="https://docs.langchain.com/oss/python/langgraph/persistence#checkpoints">cet exemple de LangGraph</a>). La mémoire à court terme est <em><strong>limitée à une session</strong></em>, c'est-à-dire qu'elle existe dans le cadre d'une conversation ou d'une tâche unique et qu'elle est réinitialisée ou effacée à la fin de cette session, à moins qu'elle ne soit explicitement sauvegardée ailleurs. Un exemple de mémoire à court terme liée à une session serait le <a href="https://help.openai.com/en/articles/8914046-temporary-chat-faq"><strong>chat temporaire</strong></a>disponible dans ChatGPT.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4b8680e22d4e1185/6a170f341949f78bbae7aafa/150bdf209cda5ed20b59cddf34e624ad1a8016aa-1100x577.png" alt="Mémoire des frameworks d'IA" /><p><em><strong>La mémoire à long terme</strong></em>, en revanche, désigne les informations qui persistent <strong>au fil des conversations ou des sessions</strong>. Il s'agit des connaissances qu'un agent conserve au fil du temps, des faits qu'il a appris précédemment, des préférences de l'utilisateur ou de toute autre donnée que nous lui avons demandé de garder en mémoire de manière permanente.</p><p>La mémoire à long terme est généralement mise en œuvre en stockant et en récupérant les données à partir d'une source externe, telle qu'un fichier ou une base vectorielle située en dehors de la fenêtre contextuelle immédiate. Contrairement à l'historique de discussion à court terme, la mémoire à long terme n’est pas automatiquement incluse dans chaque requête. Au lieu de cela, sur la base d'un scénario donné, l'agent doit le <strong>rappeler</strong> ou le retrouver lorsque les outils pertinents sont invoqués. En pratique, la mémoire à long terme peut inclure les informations de profil de l’utilisateur, des réponses ou analyses antérieures produites par l’agent, ou une base de connaissances que l’agent peut consulter.</p><p>Par exemple, si vous avez un agent planificateur de voyage, la <em>mémoire à court terme</em> contiendrait les détails de la demande de voyage actuelle (dates, destination, budget) et toutes les questions de suivi dans cette conversation ; tandis que la <em>mémoire à long terme</em> pourrait stocker les préférences générales de voyage de l'utilisateur, les itinéraires passés et d'autres faits partagés lors de sessions précédentes. Lorsque l'utilisateur revient plus tard, l'agent peut puiser dans cette base de données à long terme (par exemple, l'utilisateur aime les plages et les montagnes, dispose d'un budget moyen de 100 000 INR, a une liste de lieux à visiter et préfère découvrir l'histoire et la culture plutôt que les attractions pour enfants) afin de ne pas traiter l'utilisateur comme une page blanche à chaque fois.</p><p>La mémoire à court terme (historique des conversations) fournit un contexte immédiat et une continuité, tandis que la mémoire à long terme fournit un contexte plus large dans lequel l'agent peut puiser en cas de besoin. Les cadres d'agents d'IA les plus avancés permettent les deux : ils gardent la trace des dialogues récents pour maintenir le contexte <em>et</em> proposent des mécanismes pour rechercher ou stocker des informations dans un référentiel à plus long terme. La gestion de la mémoire à court terme garantit qu'elle reste dans la fenêtre de contexte, tandis que la gestion de la mémoire à long terme aide l'agent à ancrer les réponses sur la base d'interactions et de personas antérieures.</p><h2>Mémoire et RAG en ingénierie contextuelle</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt98c1514741bea460/6a170f36509168083ce1bbae/46635aa11ceff89b8d6a26ac3e22da52407d82f3-1600x900.png" alt="Mémoire et RAG en ingénierie contextuelle" /><p><em><strong>Comment pouvons-nous donner à un agent IA une mémoire à long terme utile en pratique ?</strong></em></p><p>La <em><strong>mémoire sémantique</strong></em>, souvent mise en œuvre par le biais de la <strong>retrieval-augmented generation (RAG),</strong> constitue l'une des principales approches pour la mémoire à long terme. Cela consiste à couler le LLM avec un stockage de connaissances externe ou un datastore vectoriel, comme Elasticsearch. Lorsque le LLM a besoin d'informations au-delà de ce qui est contenu dans l'invite ou dans son entraînement intégré, il effectue une récupération sémantique contre Elasticsearch et injecte les résultats les plus pertinents dans l'invite en tant que contexte. Ainsi, le contexte effectif du modèle inclut non seulement la conversation récente (mémoire à court terme), mais aussi des faits pertinents à long terme récupérés à la volée. Le LLM fonde ensuite sa réponse sur son propre raisonnement et les informations récupérées, combinant efficacement la mémoire à court terme et la mémoire à long terme pour produire une réponse plus précise et contextuelle.</p><p><strong>Elasticsearch </strong>peut être utilisé pour mettre en place une mémoire à long terme pour les agents d’IA. Voici un exemple de haut niveau montrant comment le contexte peut être récupéré depuis Elasticsearch pour la mémoire à long terme.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt44f5a6887b0bca32/6a170f37a6c2b9c735e797be/41ccbc7b5171e8170ac300139a963c0708816ba6-1600x900.png" alt="RAG en action" /><p>De cette façon, l’agent « se souvient » en recherchant des données pertinentes plutôt que de tout stocker dans son invite limitée, <strong>ce qui entraîne différents risques.</strong></p><p><strong>L'utilisation de RAG avec Elasticsearch ou tout stockage de vecteurs offre de multiples avantages :</strong></p><p>Premièrement, il <strong>étend la connaissance du</strong> modèle au-delà de son seuil d'apprentissage. L’agent peut récupérer des informations à jour ou des données spécifiques au domaine que le LLM pourrait ne pas connaître. Ceci est crucial pour les questions concernant des événements récents ou des sujets spécialisés.</p><p>Deuxièmement, récupérer le contexte à la demande aide à réduire les hallucinations, surtout que les LLM ne sont pas entraînés sur des données propriétaires ou très spécialisées par rapport à votre cas d'utilisation spécifique, ce qui est très susceptible de les exposer à des hallucinations. Au lieu que le LLM devine ou invente de nouvelles informations comme il a été incité par évaluation, comme l’a souligné un article récent d’OpenAI (<a href="https://arxiv.org/pdf/2509.04664">Why Language Models Hallucinate</a>), le modèle peut être fondé sur des références factuelles provenant d’Elasticsearch. Bien entendu, le LLM dépend de la fiabilité des données du référentiel vectoriel pour prévenir véritablement la désinformation, et les données pertinentes sont extraites conformément aux mesures de pertinence fondamentales.</p><p>Troisièmement, RAG permet à un agent de travailler avec des bases de connaissances bien plus vastes que tout ce que vous pourriez inclure dans une invite. Au lieu d'insérer des documents entiers, comme de longs documents de recherche ou des documents politiques, dans la fenêtre contextuelle et de risquer une surcharge ou un <a href="https://www.elastic.co/search-labs/blog/agentic-memory-management-elasticsearch#context-poisoning">empoisonnement du contexte</a> du raisonnement du modèle par une information non pertinente, RAG s'appuie sur le <a href="https://www.elastic.co/search-labs/blog/chunking-strategies-elasticsearch">découpage</a>. Les documents volumineux sont divisés en morceaux plus petits et sémantiquement significatifs, et le système ne récupère que les quelques segments les plus pertinents pour la requête. Ainsi, le modèle n'a pas besoin d'un contexte d'un million de mots pour paraître bien informé ; il lui suffit d'avoir accès aux bons morceaux d'un corpus beaucoup plus vaste.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4c90f81a56db0a33/6a170f3960084be7ba3c462e/e6897356c9f0940e35a63d005e9cd20bc33e5dd7-1600x931.png" alt="Évolution de l'ingénierie du contexte des LLM" /><p>Il est important de noter qu’à mesure que les fenêtres contextuelles des LLM se sont agrandies (<a href="https://www.anthropic.com/news/1m-context">certains modèles supportent désormais des centaines de milliers, voire des millions de jetons</a><em>),</em> un débat a surgi sur la question de savoir si RAG est « mort ». Pourquoi ne pas intégrer toutes les données dans l'invite ? Si vous êtes du même avis, reportez-vous à cet excellent article de mes collègues Jeffrey Rengifo et Eduard Martin, <a href="https://www.elastic.co/search-labs/blog/rag-vs-long-context-model-llm">Longer context ≠ better : Why RAG still matters</a>. Cela évite le problème du « déchets en entrée, déchets en sortie » : le LLM reste concentré sur les quelques morceaux qui comptent, plutôt que de parcourir du bruit.</p><p>Cela dit, l'intégration d'Elasticsearch ou de n'importe quelle mémoire vectorielle dans une architecture d'agent d'IA offre une <strong>mémoire à long terme</strong>. L'agent stocke les connaissances à l'extérieur et les intègre au contexte de la mémoire en cas de besoin. Cela pourrait être implémenté sous forme <em>d’architecture</em>, où après chaque requête utilisateur, l’agent effectue une recherche sur Elasticsearch pour des informations pertinentes puis ajoute les premiers résultats à l’invite avant d’appeler le LLM. La réponse peut également être enregistrée dans le stockage à long terme si elle contient de nouvelles informations utiles (création d'une boucle d'apprentissage). En utilisant cette mémoire basée sur la récupération, l’agent reste informé et à jour, sans avoir à tout condenser dans chaque invite, même si la fenêtre de contexte prend en charge <em>un million de tokens</em>. Cette technique est une pierre angulaire de l'ingénierie contextuelle, combinant les forces de la récupération d'informations et de l'IA générative. </p><p>Voici un exemple d'état de conversation géré en mémoire utilisant le système de points de contrôle de LangGraph pour la mémoire à court terme pendant la session. (Reportez-vous à notre <a href="https://github.com/someshwaranM/elastic-context-engineering-short-term-long-term-memory">application d'ingénierie contextuelle</a>.)</p># Initialize chat memory (Note: This is in-memory only, not persistent)
memory = MemorySaver()

# Create a LangGraph agent
langgraph_agent = create_react_agent(model=llm, tools=tools, checkpointer=memory)

...
...
# Only process and display checkpoints if verbose mode is enabled
if args.verbose:
    # List all checkpoints that match a given configuration
    checkpoints = memory.list({"configurable": {"thread_id": "1"}})
    # Process the checkpoints
    process_checkpoints(checkpoints)<p>Voici comment il stocke les <strong>points de contrôle</strong> :</p>Checkpoint:
Timestamp: 2025-12-30T09:19:41.691087+00:00
Checkpoint ID: 1f0e560a-c2fa-69ec-8001-14ee5373f9cf
User: Hi I'm Som, how are you? (Message ID: ad0a8415-5392-4a58-85ad-84154875bbf2)
Agent: Hi Som! I'm doing well, thank you! How about you? (Message ID: 
56d31efb-14e3-4148-806e-24a839799ece)
Agent:  (Message ID: lc_run--019b6e8e-553f-7b52-8796-a8b1fbb206a4-0)

Checkpoint:
Timestamp: 2025-12-30T09:19:40.350507+00:00
Checkpoint ID: 1f0e560a-b631-6a08-8000-7796d108109a
User: Hi I'm Som, how are you? (Message ID: ad0a8415-5392-4a58-85ad-84154875bbf2)
Agent: Hi Som! I'm doing well, thank you! How about you? (Message ID: 
56d31efb-14e3-4148-806e-24a839799ece)

Checkpoint:
Timestamp: 2025-12-30T09:19:40.349027+00:00
Checkpoint ID: 1f0e560a-b62e-6010-bfff-cbebe1d865f6<p>Pour la mémoire à long terme, voici comment nous effectuons une recherche sémantique sur Elasticsearch pour récupérer des conversations précédentes pertinentes en utilisant des vecteurs d'intégration après la résumé et l'indexation des points de contrôle dans Elasticsearch.</p>Functions: 
retrieve_from_elasticsearch() 

# Enhanced Elasticsearch retrieval with rank_window and verbose display
def retrieve_from_elasticsearch(query: str, k: int = 5, rank_window: int = None) -&gt; tuple[List[Dict[str, Any]], str]:
    """
    Retrieve context from Elasticsearch with score-based ranking
    
    Args:
        query: Search query
        k: Number of results to return
        rank_window: Number of candidates to retrieve before ranking (default: args.rank_window)
        
    Returns:
        Tuple of (retrieved_documents, formatted_context_string)
    """
    if not es_client or not es_index_name:
        return [], "Elasticsearch is not available. Cannot search long-term memory."
    
    if rank_window is None:
        rank_window = args.rank_window
    
    try:
        # Check if index exists and has documents
        if not es_client.indices.exists(index=es_index_name):
            return [], "No previous conversations stored in long-term memory yet."
        
        # Get document count
        try:
            doc_count = es_client.count(index=es_index_name)["count"]
            if doc_count == 0:
                return [], "Long-term memory is empty. No previous conversations to search."
        except Exception as e:
            return [], f"Error checking memory: {str(e)}"
        
        # Generate embedding for the query
        try:
            query_embedding = embeddings.embed_query(query)
        except Exception as e:
            return [], f"Error generating embedding: {str(e)}"
        
        # Perform semantic search using kNN with rank_window
        try:
            search_body = {
                "knn": {
                    "field": "vector",
                    "query_vector": query_embedding,
                    "k": k,
                    "num_candidates": rank_window  # Retrieve more candidates, then rank top k
                },
                "_source": ["text", "content", "message_type", "timestamp", "thread_id"],
                "size": k
            }
            
            response = es_client.search(index=es_index_name, body=search_body)
            
            if not response.get("hits") or len(response["hits"]["hits"]) == 0:
                return [], "No relevant previous conversations found in long-term memory."
            
            # Extract documents with scores
            retrieved_docs = []
            for hit in response["hits"]["hits"]:
                source = hit["_source"]
                score = hit["_score"]
                retrieved_docs.append({
                    "content": source.get("content", source.get("text", "")),
                    "message_type": source.get("message_type", "unknown"),
                    "timestamp": source.get("timestamp", "unknown"),
                    "thread_id": source.get("thread_id", "unknown"),
                    "score": score
                })
            
            # Format context string
            context_parts = []
            for i, doc in enumerate(retrieved_docs, 1):
                context_parts.append(doc["content"])
            
            context_string = "\n\n".join(context_parts)
            
            # Verbose display
            if args.verbose:
                rich.print(f"\n[bold yellow]🔍 RETRIEVAL ANALYSIS[/bold yellow]")
                rich.print("="*80)
                rich.print(f"[blue]Query:[/blue] {query}")
                rich.print(f"[blue]Retrieved:[/blue] {len(retrieved_docs)} documents (from {rank_window} candidates)")
                rich.print(f"[blue]Total context length:[/blue] {len(context_string)} characters\n")
                
                for i, doc in enumerate(retrieved_docs, 1):
                    rich.print(f"[cyan]📄 Document {i} | Score: {doc['score']:.4f} | Type: {doc['message_type']}[/cyan]")
                    rich.print(f"[cyan]   Timestamp: {doc['timestamp']} | Thread: {doc['thread_id']}[/cyan]")
                    content_preview = doc['content'][:200] + "..." if len(doc['content']) &gt; 200 else doc['content']
                    rich.print(f"[cyan]   Content: {content_preview}[/cyan]")
                    rich.print("-" * 80)
            
            return retrieved_docs, context_string
            
        except Exception as e:
            return [], f"Error searching memory: {str(e)}"
            
    except Exception as e:
        return [], f"Error accessing long-term memory: {str(e)}"<p>Maintenant que nous avons exploré comment la mémoire à court terme et la mémoire à long terme sont indexées et récupérées à l’aide des points de contrôle de LangGraph dans Elasticsearch, prenons un moment pour comprendre pourquoi l'indexation et le vidage des conversations complètes peut être risqué.</p><h2>Risques liés à une mauvaise gestion de la mémoire de contexte</h2><p>Alors que nous parlons beaucoup d’ingénierie du contexte, ainsi que de la mémoire à court et à long terme, comprenons ce qui se passe si nous ne gérons pas bien la mémoire et le contexte d’un agent.</p><p>Malheureusement, de nombreux problèmes peuvent survenir lorsque le contexte d’une IA devient extrêmement long ou contient des informations erronées. Au fur et à mesure que les fenêtres contextuelles s’agrandissent, de <strong>nouveaux modes de défaillance</strong> apparaissent, comme :</p><ul><li><p><strong>Empoisonnement contextuel</strong></p></li><li><p><strong>Distraction contextuelle</strong></p></li><li><p><strong>Confusion de contexte</strong></p></li><li><p><strong>Conflit de contexte</strong></p></li><li><p><strong>Fuite de contexte et conflits de connaissances</strong></p></li><li><p><strong>Hallucinations et désinformation.</strong></p></li></ul><p>Examinons ces problèmes et les autres risques qui découlent d'une mauvaise gestion du contexte :</p><h3>Empoisonnement contextuel</h3><p><em>L'empoisonnement du contexte</em> fait référence au fait que des informations incorrectes ou nuisibles apparaissent dans le contexte et « empoisonne » les sorties ultérieures du modèle. Un exemple courant est une hallucination du modèle qui est traitée comme un fait et insérée dans l'historique de la conversation. Le modèle pourrait alors s'appuyer sur cette erreur dans les réponses ultérieures, aggravant la faute. Dans les boucles itératives d'agents, une fois qu'une fausse information s'est intégrée dans le contexte partagé (par exemple, dans un résumé des notes de travail de l'agent), elle peut être renforcée à maintes reprises. </p><p><a href="https://storage.googleapis.com/deepmind-media/gemini/gemini_v2_5_report.pdf">Les chercheurs de DeepMind, dans la publication du rapport Gemini 2.5</a> (TL;DR, consultez <a href="https://www.dbreunig.com/2025/06/17/an-agentic-case-study-playing-pok%C3%A9mon-with-gemini.html">ici</a>), ont observé ce phénomène chez un agent <em>joueur de Pokémon de</em>longue date : si l'agent hallucinait un état de jeu erroné et que celui-ci était enregistré dans son <em>contexte </em>(sa mémoire des objectifs), il formait des <strong>stratégies absurdes</strong> autour d'un objectif impossible et se retrouvait bloqué. En d'autres termes, une mémoire empoisonnée peut envoyer l'agent sur la mauvaise voie indéfiniment.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd56e9e0681f32239/6a170f3b4a531bd79536aa21/3f2facf5aad67613ad557422e09ec23a66adc0ed-1600x1388.png" alt="Empoisonnement contextuel" /><p>L'empoisonnement du contexte peut se produire de manière innocente (par erreur) ou même de manière malveillante, par exemple via des attaques par injection de requêtes où un utilisateur ou un tiers introduit une instruction cachée ou une fausse information que l'agent mémorise ensuite et suit.</p><p><strong>Contre-mesures recommandées :</strong></p><p>S’appuyant sur les informations de <a href="https://www.wiz.io/academy/data-poisoning">Wiz</a>, <a href="https://zerlo.net/en/blog/what-is-llm-data-poisoning">Zerlo</a> et <a href="https://www.anthropic.com/research/small-samples-poison">Anthropic</a>, les contre-mesures contre l’empoisonnement du contexte visent à empêcher que des informations erronées ou trompeuses ne pénètrent dans l’invite, la fenêtre de contexte ou le pipeline de récupération d’un LLM. Parmi les principales étapes, citons :</p><ul><li><p>Vérifiez constamment le contexte : surveillez la conversation ou le texte récupéré afin de détecter tout élément suspect ou nuisible, et pas seulement l’invite de départ.</p></li><li><p>Utilisez des sources fiables : attribuez une note ou un label aux documents en fonction de leur crédibilité afin que le système privilégie les informations fiables et ignore les données mal notées.</p></li><li><p>Repérez les données inhabituelles : utilisez des outils qui détectent les contenus bizarres, déplacés ou manipulés, et supprimez-les avant que le modèle ne les utilise.</p></li><li><p>Filtrez les entrées et les sorties : ajoutez des garde-fous pour que les textes nuisibles ou trompeurs ne puissent pas facilement entrer dans le système ou être répétés par le modèle.</p></li><li><p>Mettez le modèle à jour avec des données propres : actualisez régulièrement le système avec des informations vérifiées afin de corriger les éventuelles données erronées.</p></li><li><p>Supervision humaine : faites examiner les sorties importantes par des personnes ou comparez-les à des sources connues et fiables.</p></li></ul><p>De simples habitudes utilisateur sont également utiles : réinitialiser les longues conversations, ne partager que les informations pertinentes, découper les tâches complexes en étapes plus simples et conserver des notes claires en dehors du modèle.</p><p>Ensemble, ces mesures créent une défense en couches qui protège les LLM contre l'empoisonnement du contexte et maintient les sorties précises et dignes de confiance.</p><p>Sans les contre-mesures mentionnées ici, un agent pourrait se souvenir d'instructions, comme ignorer des lignes directrices antérieuresou des faits triviaux insérés par un attaquant, ce qui conduirait à des sorties nuisibles.</p><h3>Distraction contextuelle</h3><p>On parle de <em>distraction contextuelle</em> lorsqu'un contexte devient si long que le modèle se concentre excessivement sur le contexte, négligeant ce qu'il a appris pendant la formation. Dans les cas extrêmes, cela ressemble à un <a href="https://en.wikipedia.org/wiki/Catastrophic_interference"><em>oubli catastrophique</em></a>, c'est-à-dire que le modèle « oublie » effectivement ses connaissances sous-jacentes et s'attache excessivement aux informations qui lui sont présentées. Des études précédentes ont montré que les LLM perdent souvent leur concentration lorsque l'invite est extrêmement longue.</p><p>L'agent Gemini 2.5, par exemple, prenait en charge une fenêtre d'un million de jetons, mais dès que son contexte dépassait un certain seuil (de l'ordre de 100 000 jetons dans une expérience), il commençait à <strong>s'attacher à répéter ses actions passées</strong> au lieu de proposer de nouvelles solutions. En un sens, l’agent est devenu prisonnier de sa longue histoire. Il a continué à regarder son long log de mouvements précédents (le contexte) et à les imiter, plutôt que d'utiliser ses connaissances d'entraînement sous-jacentes pour concevoir des stratégies nouvelles et inédites.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt91ea0056bbda6e2d/6a170f3d2b835fdd2bf4b2db/e08e5b6d2e8ec7e3511d455985eed3d7fa6241e0-1352x636.png" alt="Distraction contextuelle " /><p>C'est contreproductif. Nous voulons que le modèle utilise un contexte pertinent pour faciliter le raisonnement, et non qu'il prenne le pas sur sa capacité de réflexion. Fait notable, même les modèles disposant de fenêtres très larges présentent une forme de <a href="https://research.trychroma.com/context-rot"><em>dégradation du contexte</em></a> : leurs performances se détériorent de manière non uniforme à mesure que le nombre de jetons augmente. Il semble exister un <em>budget d’attention</em> : tout comme les humains ont une mémoire de travail limitée, un LLM dispose d’une capacité finie pour traiter les jetons, et plus ce budget est sollicité, plus sa précision et sa concentration diminuent.</p><p>Pour atténuer ce problème, vous pouvez empêcher la distraction contextuelle en utilisant la segmentation, en concevant les bonnes informations, en résumant régulièrement le contexte et en appliquant des techniques d’évaluation et de surveillance pour mesurer la précision de la réponse à l’aide de la notation.</p><p>Ces méthodes permettent au modèle de rester ancré dans un contexte pertinent et dans sa formation sous-jacente, ce qui réduit le risque de distraction et améliore la qualité globale du raisonnement.</p><h3>Confusion de contexte</h3><p>La <em>confusion contextuelle</em> se produit lorsque le modèle utilise du contenu superflu dans le contexte pour générer une réponse de faible qualité. Un bon exemple est de fournir à un agent un large éventail d'outils ou de définitions d'API qu'il peut utiliser. Si bon nombre de ces outils n'ont aucun rapport avec la tâche en cours, le modèle peut tout de même essayer de les utiliser de manière inappropriée, simplement parce qu'ils sont présents dans le contexte. Les expériences ont montré que fournir <em>plus</em> d'outils ou de documents peut <em>nuire</em> aux performances s'ils ne sont pas tous nécessaires. L’agent commence à faire des erreurs, comme appeler la mauvaise fonction ou référer un texte sans importance. </p><p>Dans un cas, un petit modèle <strong>Llama 3.1 8B</strong> a échoué à une tâche lorsqu'on lui a donné 46 outils à prendre en compte, mais a réussi lorsqu'on ne lui a donné que 19 outils. Ces outils supplémentaires ont créé de la confusion, même si le contexte respectait les limites de longueur. Le problème sous-jacent est que toute information contenue dans l'invite sera <em>prise en compte</em> par le modèle. Si un système ne sait pas ignorer quelque chose, ce quelque chose pourrait influencer sa sortie de manière indésirable. Des éléments non pertinents peuvent « détourner » une partie de l'attention du modèle et l'induire en erreur (par exemple, un document non pertinent pourrait amener l'agent à répondre à une question différente de celle posée). La confusion contextuelle se manifeste souvent par la production, par le modèle, d'une réponse de faible qualité intégrant un contexte non pertinent. Se référer à l'article de recherche : <a href="https://arxiv.org/pdf/2411.15399">Less is More: Optimizing Function Calling for LLM Execution on Edge Devices.</a></p><p>Cela nous rappelle qu'il n'est pas toujours préférable d'avoir plus de contexte, surtout si ce n'est pas <strong>organisé</strong> pour des raisons de pertinence.</p><h3>Conflit de contexte</h3><p>Il y a <em>conflit de contexte</em> lorsque <strong>des éléments du contexte se contredisent</strong>, provoquant des incohérences internes qui font dérailler le raisonnement du modèle. Un conflit peut survenir si l'agent accumule plusieurs éléments d'information qui sont en conflit. </p><p>Par exemple, imaginez un agent qui a récupéré des données de deux sources : l'une dit <em>Le vol A part à 17 h</em>, et l'autre dit <em>Le vol A part à 18 h</em>. Si les deux faits se retrouvent dans le contexte, le modèle pauvre n'a aucun moyen de savoir lequel est correct ; il peut s'embrouiller ou produire une réponse incorrecte ou non similaire.</p><p>Le conflit de contexte se produit aussi fréquemment dans les conversations à plusieurs tours, lorsque les <strong>tentatives</strong> de réponse antérieures du modèle sont encore présentes dans le contexte avec des informations affinées ultérieurement.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd86976266867c0ed/6a170f3e66c4f9c785f8c105/500d7a80dc8db1923f9b5ca84728eed64fa296f7-1316x580.png" alt="Conflit de contexte" /><p>Une <a href="https://arxiv.org/pdf/2505.06120">étude menée</a> par Microsoft et Salesforce montre que si l'on divise une requête complexe en plusieurs échanges avec un chatbot (en ajoutant progressivement des détails), la précision finale diminue considérablement, comparée à la fourniture de tous les détails en une seule requête. Pourquoi ? Parce que les premiers tours contiennent des réponses intermédiaires partielles ou incorrectes du modèle, et que celles-ci restent dans le contexte. Lorsque le modèle tente par la suite de répondre avec toutes les informations, sa <em>mémoire</em> contient encore ces tentatives erronées, qui entrent en conflit avec les informations corrigées et l'éloignent de la bonne voie. En substance, le contexte de la conversation entre en conflit avec lui-même. Le modèle peut utiliser par inadvertance un élément de contexte obsolète (d'un tour précédent) qui ne s'applique plus après l'ajout de nouvelles informations.</p><p>Dans les systèmes agents, le conflit de contexte est particulièrement dangereux, car un agent peut combiner des sorties provenant de différents outils ou sous-agents. Si ces sorties divergent, le contexte agrégé est incohérent. L'agent pourrait alors se retrouver bloqué ou produire des résultats absurdes en essayant de réconcilier les contradictions. Prévenir les conflits de contexte implique de s’assurer que le contexte est <strong>frais et cohérent</strong>,par exemple en effaçant .ou en mettant à jour toute information obsolète et en ne mélangeant pas les sources qui n’ont pas été vérifiées pour leur cohérence.</p><h3>Fuite de contexte et conflits de connaissances</h3><p>Dans les systèmes où plusieurs agents ou utilisateurs partagent un stockage de mémoire, il existe un risque de fuite d'informations entre les contextes.</p><p>Par exemple, si les intégrations de données de deux utilisateurs distincts résident dans la même base vectorielle sans un contrôle d’accès approprié, un agent répondant à la requête de l’utilisateur A pourrait accidentellement récupérer une partie de la mémoire de l’utilisateur B. Cette <em><strong>fuite intercontextuelle</strong></em> peut révéler des informations privées ou simplement créer de la confusion dans les réponses.</p><p>Selon le <a href="https://wtit.com/blog/2025/04/17/owasp-top-10-for-llm-applications-2025/">Top 10 de l'OWASP pour les applications LLM</a>, les bases vectorielles multitenant doivent se prémunir contre de telles fuites :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte433216805a66d29/6a170f404a531b2c4e36aa25/8f0ccf0b2f7bd6715c14aceee2deffb213d50bd9-1600x936.png" alt="Fuite de contexte" /><p>Selon <a href="https://wtit.com/blog/2025/04/17/owasp-top-10-for-llm-applications-2025/">LLM08:2025 Vector and Embedding Weaknesses</a><em>,</em> l'un des risques courants est la fuite de contexte :</p><em>Dans les environnements multi-locataires où plusieurs classes d’utilisateurs ou d’applications partagent la même base vectorielle, il existe un risque de fuite de contexte entre utilisateurs ou requêtes. Les erreurs de conflit de connaissances dans la fédération de données peuvent survenir lorsque les données provenant de sources multiples se contredisent les unes les autres. Cela peut également se produire lorsqu'un LLM ne peut pas remplacer les anciennes connaissances qu'il a acquises pendant la formation par les nouvelles données issues de l'augmentation de la récupération.</em><p>Un autre aspect est qu'un LLM peut avoir du mal à remplacer ses <strong>connaissances intégrées</strong> par de nouvelles informations de mémoire. Si le modèle a été formé sur la base d'un fait et que le contexte retrouvé dit le contraire, le modèle peut ne pas savoir à quoi se fier. Sans une conception appropriée, l'agent pourrait confondre les contextes ou ne pas mettre à jour les anciennes connaissances avec de nouvelles preuves, conduisant à des réponses obsolètes ou incorrectes.</p><h3><strong>Hallucinations et désinformation.</strong></h3><p>Si l'<em>hallucination </em>(le LLM invente des informations plausibles mais fausses) est un problème connu, même sans contexte prolongé, une mauvaise gestion de la mémoire peut l'amplifier. </p><p>Si la mémoire de l'agent manque d'un fait crucial, le modèle peut simplement <strong>combler cette lacune par une supposition</strong>, et si cette supposition entre ensuite dans le contexte (en l'empoisonnant), l'erreur persiste. </p><p>Le rapport de sécurité OWASP LLM <a href="https://wtit.com/blog/2025/04/17/owasp-top-10-for-llm-applications-2025/"><strong>(LLM09:2025 Désinformation)</strong></a> met en évidence la désinformation comme une vulnérabilité fondamentale : les LLM peuvent produire des réponses confiantes mais fabriquées, et les utilisateurs peuvent leur accorder trop de crédit. Un agent dont la mémoire à long terme est mauvaise ou obsolète peut citer en toute confiance une information qui était vraie l'année dernière mais qui est fausse aujourd'hui, à moins que sa mémoire ne soit mise à jour. </p><p>Une dépendance excessive à la sortie de l'IA (par l'utilisateur ou l'agent lui-même dans la boucle) peut aggraver cette situation. Si personne ne vérifie jamais les informations en mémoire, l'agent peut accumuler de fausses informations. C’est pourquoi la méthode RAG est souvent utilisée pour réduire les hallucinations : en se référant à une source faisant autorité, le modèle n’a pas besoin d’inventer des faits. Mais si votre recherche aboutit au mauvais document (par exemple, un document contenant des informations erronées) ou si une hallucination précoce n'est pas élaguée, le système peut propager ces informations erronées dans toutes ses actions. </p><p>En résumé : une mauvaise gestion de la mémoire peut conduire à des <strong>sorties incorrectes et trompeuses</strong>, ce qui peut être préjudiciable, surtout si les enjeux sont importants (par exemple, de mauvais conseils dans le domaine financier ou médical). Un agent doit disposer de mécanismes pour vérifier ou corriger le contenu de sa mémoire, et non simplement faire confiance de manière inconditionnelle à ce qui se trouve dans le contexte.</p><p>En résumé, doter un agent d'IA d'une mémoire infiniment longue ou déverser tout ce qui est possible dans son contexte <em>n'</em> est pas une recette pour le succès.</p><h2>Bonnes pratiques pour la gestion de la mémoire dans les applications LLM</h2><p>Pour éviter les pièges ci-dessus, les développeurs et les chercheurs ont élaboré un certain nombre de <strong>bonnes pratiques pour gérer le contexte et la mémoire</strong> dans les systèmes d'IA. Ces pratiques visent à maintenir le contexte de travail de l'IA allégé, pertinent et actualisé. Voici quelques-unes des stratégies clés, accompagnées d'exemples de leur utilité.</p><h3>RAG : utiliser le contexte ciblé.</h3><p>Une grande partie de RAG a déjà été abordée dans la section précédente, ceci constitue donc un rappel pratique et concis :</p><ul><li><p>Utilisez une récupération ciblée, pas un chargement en masse : récupérez uniquement les extraits les plus pertinents au lieu d'insérer des documents entiers ou des historiques de conversation complets dans l'invite.</p></li><li><p>Considérez RAG comme un rappel de mémoire à la demande : récupérez le contexte uniquement lorsqu’il est nécessaire, plutôt que de tout conserver d’un échange à l’autre.</p></li><li><p>Privilégiez des stratégies de récupération sensibles à la pertinence : des approches telles que la recherche sémantique top-k, la fusion de rangs réciproques (Reciprocal Rank Fusion) ou le filtrage par configuration d’outils permettent de réduire le bruit et d’améliorer l’ancrage.</p></li><li><p>Des fenêtres de contexte plus larges ne suppriment pas le besoin de RAG : deux paragraphes hautement pertinents sont presque toujours plus efficaces que 20 pages vaguement liées.</p></li></ul><p>Cela dit, RAG ne vise pas à ajouter plus de contexte ; il s’agit d’ajouter le bon contexte.</p><h3>Chargement des outils</h3><p><em>Le loadout d’outils</em> consiste à donner à un modèle uniquement les outils dont il a réellement besoin pour une tâche. Le terme vient du jeu : vous choisissez une configuration qui convient à la situation. Trop d'outils vous ralentissent ; les mauvais sont à l'origine de l'échec. Les LLM se comportent de la même manière, selon l'article de recherche <a href="https://arxiv.org/abs/2411.15399">Less is more</a>. Une fois que vous dépassez ~30 outils, les descriptions commencent à se chevaucher et le modèle se trouve dérouté. Plus de 100 outils, l'échec est presque garanti. Ce n’est pas un problème de fenêtre contextuelle, c’est une confusion de contexte.</p><p>Une solution simple et efficace est <a href="https://arxiv.org/abs/2505.03275"><strong>RAG-MCP</strong></a>. Au lieu de saisir tous les outils dans l'invite, les descriptions d'outils sont stockées dans une base vectorielle et seuls les outils les plus pertinents sont récupérés par demande. En pratique, cela permet de réduire la taille de l'équipement et de le concentrer, de raccourcir considérablement les instructions et d'améliorer la précision de la sélection des outils jusqu'à 3 fois.</p><p>Les modèles plus petits atteignent ce plafond encore plus tôt. La recherche montre qu'un modèle 8B échoue avec des dizaines d'outils mais réussit une fois que la configuration est réduite. La sélection dynamique des outils, parfois précédée d’une réflexion par un LLM sur ce dont il pense avoir besoin, peut améliorer les performances de 44 %, tout en réduisant la consommation d’énergie et la latence. La principale leçon est que la plupart des agents n’ont besoin que de quelques outils, mais à mesure que votre système se développe, la configuration des outils et le RAG-MCP deviennent des choix de conception de premier ordre.</p><h3>Élagage du contexte : limiter la longueur de l'historique de conversation</h3><p>Si une conversation se poursuit sur de nombreux tours, l'historique de discussion accumulé peut devenir trop volumineux pour tenir, entraînant un débordement de contexte ou devenant trop distrayant pour le modèle. </p><p><em>Le rognage</em> consiste à supprimer ou à raccourcir par programmation les parties les moins importantes du dialogue au fur et à mesure qu'il grandit. Une forme simple consiste à supprimer les tours de parole les plus anciens lorsque vous atteignez une certaine limite, en ne conservant que les <em>N</em> derniers messages. Un élagage plus sophistiqué pourrait supprimer les digressions non pertinentes ou les instructions précédentes devenues inutiles. L'objectif est de <strong>ne pas encombrer la fenêtre contextuelle</strong> par les anciennes actualités. </p><p>Par exemple, si l’agent a résolu un sous-problème il y a 10 échanges et que nous sommes passés à autre chose depuis, nous pourrions supprimer cette partie de l’historique du contexte (en supposant qu’elle ne sera plus nécessaire). De nombreuses implémentations basées sur le chat font cela : elles assurent la maintenance d'une fenêtre dynamique de messages récents. </p><p>La suppression peut être aussi simple que le fait d’« oublier » les premières parties d’une conversation une fois qu’elles ont été résumées ou jugées non pertinentes. Ce faisant, nous réduisons le risque d'erreurs de débordement du contexte et nous réduisons également la <a href="https://www.elastic.co/search-labs/blog/agentic-memory-management-elasticsearch#context-distraction"><strong>distraction du contexte</strong></a>, de sorte que le modèle ne voit pas et ne se laisse pas distraire par un contenu ancien ou hors sujet. Cette approche ressemble beaucoup à celle des humains, qui ne se souviennent peut-être pas de chaque mot d’une conférence d’une heure, mais en retiennent les points essentiels. </p><p>Si vous avez des doutes sur l'élagage de contexte, comme le souligne l'auteur Drew Breunig <a href="https://www.dbreunig.com/2025/06/26/how-to-fix-your-context.html#tool-loadout:~:text=Provence%20is%20fast%2C%20accurate%2C%20simple%20to%20use%2C%20and%20relatively%20small%20%E2%80%93%20only%201.75%20GB.%20You%20can%20call%20it%20in%20a%20few%20lines%2C%20like%20so%3A">ici</a>, l'utilisation du modèle Provence (<a href="https://huggingface.co/naver/provence-reranker-debertav3-v1">`naver/provence-reranker-debertav3-v1`</a>), un élagueur de contexte léger (1,75 Go), efficace et précis pour la réponse aux questions, peut faire la différence. Il peut réduire de gros documents à seulement le texte le plus pertinent pour une requête donnée. Vous pouvez l'appeler à des intervalles précis.</p><p>Voici comment nous invoquons le modèle `provence-reranker` dans notre code pour élaguer le contexte :</p># Context pruning with Provence
def prune_with_provence(query: str, context: str, threshold: Optional[float] = None) -&gt; str:
    """
    Prune context using Provence reranker model
    
    Args:
        query: User's query/question
        context: Original context to prune
        threshold: Relevance threshold (0-1) for Provence reranker.
                   If None, uses args.pruning_threshold.
                   0.1 = conservative (recommended, no performance drop)
                   0.3-0.5 = moderate to aggressive pruning
    
    Returns:
        Pruned context with only relevant sentences
    """
    if provence_model is None:
        return context
    
    if threshold is None:
        threshold = args.pruning_threshold
    
    try:
        # Use Provence's process method
        provence_output = provence_model.process(
            question=query,
            context=context,
            threshold=threshold,
            always_select_title=False,
            enable_warnings=False
        )
        
        # Extract pruned context from output
        pruned_context = provence_output.get('pruned_context', context)
        reranking_score = provence_output.get('reranking_score', 0.0)
        
        # Log statistics
        original_length = len(context)
        pruned_length = len(pruned_context)
        reduction_pct = ((original_length - pruned_length) / original_length * 100) if original_length &gt; 0 else 0
        
        if args.verbose:
            rich.print(f"[cyan]📊 Pruning stats: {pruned_length}/{original_length} chars ({reduction_pct:.1f}% reduction, threshold={threshold:.2f}, rerank_score={reranking_score:.3f})[/cyan]")
        
        return pruned_context if pruned_context else context
        
    except Exception as e:
        rich.print(f"[yellow]⚠️ Error in Provence pruning: {str(e)}[/yellow]")
        rich.print(f"[yellow]⚠️ Falling back to original context[/yellow]")
        return context<p>Nous utilisons le modèle de reranker Provence (`naver/provence-reranker-debertav3-v1`) pour évaluer la pertinence des phrases. La filtration basée sur des seuils conserve les phrases au-dessus du seuil de pertinence. Nous introduisons également un mécanisme de repli, qui permet de revenir au contexte d'origine en cas d'échec de l'élagage. Enfin, le logging des statistiques permet de suivre le pourcentage de réduction en mode verbeux.</p><h3>Synthèse du contexte : condenser les anciennes informations au lieu de les supprimer entièrement</h3><p><em>Le résumé va</em> de pair avec le découpage. Lorsque l’historique ou la base de connaissances devient trop vaste, vous pouvez utiliser le LLM pour générer un bref résumé des points importants et utiliser ce résumé à la place du contenu complet par la suite, comme nous l’avons fait dans notre code ci-dessus.</p><p>Par exemple, si un assistant IA a eu une conversation de 50 tours, au lieu d'envoyer tous les 50 tours au modèle au tour 51 (ce qui ne rentrera probablement pas), le système pourrait prendre les tours 1 à 40, demander au modèle de les résumer en un paragraphe, et ensuite ne fournir que ce résumé plus les 10 derniers tours dans la prochaine invite. De cette façon, le modèle reste conscient de ce qui a été discuté sans avoir besoin de tous les détails. Les premiers utilisateurs de chatbots faisaient cela manuellement en demandant : « Pouvez-vous résumer ce dont nous avons parlé jusqu'à présent ? » puis en continuant dans une nouvelle session avec le résumé. Maintenant, cela peut être automatisé. Le résumé permet non seulement d'économiser de l'espace dans la fenêtre contextuelle, mais aussi de réduire la <strong>confusion et la distraction</strong> en éliminant les détails supplémentaires et en ne conservant que les faits saillants.</p><p>Voici comment nous utilisons les modèles OpenAI (vous pouvez utiliser n’importe quel LLM) pour condenser le contexte tout en préservant toutes les informations pertinentes, en éliminant la redondance et la duplication.
</p># Context summarization
def summarize_context(query: str, context: str) -&gt; str:
    """
    Summarize context using LLM to reduce duplication and focus on relevant information
    
    Args:
        query: User's query/question
        context: Context to summarize
        
    Returns:
        Summarized context
    """
    try:
        summary_prompt = f"""You are an expert at summarizing conversation context.

Your task: Analyze the provided conversation context and produce a condensed summary that fully answers or supports the user's specific question.

The summary must:
1. Preserve every fact, detail, and information that directly relates to the question
2. Eliminate redundancy and duplicate information
3. Maintain chronological flow when relevant
4. Focus on information that helps answer: "{query}"

Context to summarize:
{context}

Provide a concise summary that preserves all relevant information:"""

        summary = llm.invoke(summary_prompt).content
        
        if args.verbose:
            original_length = len(context)
            summary_length = len(summary)
            reduction_pct = ((original_length - summary_length) / original_length * 100) if original_length &gt; 0 else 0
            rich.print(f"[cyan]📝 Summarization stats: {summary_length}/{original_length} chars ({reduction_pct:.1f}% reduction)[/cyan]")
        
        return summary
        
    except Exception as e:
        rich.print(f"[yellow]⚠️ Error in context summarization: {str(e)}[/yellow]")
        rich.print(f"[yellow]⚠️ Falling back to original context[/yellow]")
        return context<p>Il est important de noter que lorsque le contexte est résumé, le modèle est moins susceptible d'être submergé par des détails insignifiants ou des erreurs passées (en supposant que le résumé soit exact). </p><p>Cependant, le résumé doit être fait avec soin. Un mauvais résumé peut omettre un détail crucial ou même introduire une erreur. Il s’agit essentiellement d’une autre invite adressée au modèle (« résumez ceci »), ce qui peut entraîner des hallucinations ou une perte de nuances. Une bonne pratique consiste à résumer de manière incrémentielle et peut-être conserver certains faits canoniques non résumés.</p><p>Néanmoins, il s'est avéré très utile. <a href="https://storage.googleapis.com/deepmind-media/gemini/gemini_v2_5_report.pdf">Dans le scénario de l'agent Gemini, le </a>fait de résumer le contexte tous les 100 000 jetons environ a permis de contrecarrer la tendance du modèle à se répéter. Le résumé agit comme une mémoire compressée de la conversation ou des données. En tant que développeurs, nous pouvons mettre cela en œuvre en demandant à un agent d'appeler périodiquement une fonction de résumé (peut-être un LLM plus petit ou une routine dédiée) sur l'historique de la conversation ou un long document. Le résumé résultant remplace le contenu original dans la consigne. Cette tactique est largement utilisée pour limiter les contextes et distiller l'information.</p><h3>Quarantaine contextuelle : isolez les contextes lorsque c'est possible</h3><p>Cela est plus pertinent dans les systèmes d'agents complexes ou les workflows à plusieurs étapes. L'idée de la segmentation du contexte est de diviser une grande tâche en sous-tâches plus petites et isolées, chacune ayant son propre contexte, de sorte que vous n'accumuliez jamais un contexte énorme qui contient tout. Chaque sous-agent ou sous-tâche travaille sur une partie du problème dans un contexte précis, puis un agent de niveau supérieur, un superviseur ou un coordinateur intègre les résultats.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt09d1eac7442aea2b/6a170f42dc55deb10de00ea7/f2de68c3339883d7658e633af3948f29f427e6cf-1600x900.png" alt="Quarantaine contextuelle" /><p><a href="https://www.anthropic.com/engineering/multi-agent-research-system">La stratégie de recherche d’Anthropic utilise plusieurs sous-agents</a>, chacun examinant un aspect différent d’une question, avec ses propres fenêtre de contexte, et un agent principal qui lit les résultats synthétisés de ces sous-agents. Cette approche parallèle et modulaire signifie qu'aucune fenêtre contextuelle unique ne devient trop volumineuse. Cela réduit également le risque de mélange d'informations non pertinentes, chaque fil de discussion reste sur le sujet (pas de confusion de contexte), et il ne transporte pas de bagages superflus lors de la réponse à sa sous-question spécifique. Dans un sens, c'est comme suivre des fils de réflexion distincts qui ne partagent que leurs résultats, et non l'ensemble de leur processus de réflexion.</p><p>Dans les systèmes multi-agents, cette approche est essentielle. Si l'agent A gère la tâche A et l'agent B gère la tâche B, il n'y a aucune raison pour que l'un ou l'autre agent consomme le contexte complet de l'autre, sauf si c'est vraiment nécessaire. Les agents ne peuvent échanger que les informations nécessaires. Par exemple, l'agent A peut transmettre un résumé consolidé de ses résultats à l'agent B via un agent superviseur, tandis que chaque sous-agent assure la maintenance de son propre fil de contexte dédié. Cette configuration ne nécessite pas d'intervention humaine ; elle repose sur un agent de supervision doté d'outils activés avec un partage de contexte minimal et contrôlé.</p><p>Néanmoins, concevoir votre système de manière à ce que les agents ou les outils fonctionnent avec un chevauchement minimal du contexte nécessaire peut grandement améliorer la clarté et les performances. Pensez-y comme à des <strong>microservices pour l'IA</strong>, chaque composant s'occupe de son contexte, et vous passez des messages entre eux de manière contrôlée, au lieu d'un contexte monolithique. Ces bonnes pratiques sont souvent utilisées de manière combinée. Cela vous offre également la possibilité de supprimer l'historique trivial, de résumer les anciens messages ou conversations importants, de décharger les logs détaillés vers Elasticsearch pour un contexte à long terme et d'utiliser la récupération pour retrouver tout élément pertinent en cas de besoin.</p><p>Comme indiqué <a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents#:~:text=While%20some%20models,to%20the%20LLM">ici</a>, le principe directeur est que le contexte est une ressource limitée et précieuse. Vous souhaitez que chaque élément de l'invite soit utile, c'est-à-dire qu'il contribue à la qualité de la sortie. Si quelque chose en mémoire ne joue pas son rôle (ou pire, provoque activement de la confusion), alors il devrait être élagué, résumé ou tenu à l'écart.</p><p>En tant que développeurs, nous pouvons désormais programmer le contexte comme nous programmons du code, en décidant quelles informations inclure, comment les formater et quand les omettre ou les mettre à jour. En suivant ces pratiques, nous pouvons fournir aux agents LLM le contexte indispensable pour effectuer des tâches sans être victimes des modes de défaillance décrits précédemment. Le résultat : des agents qui retiennent ce qu’ils doivent, oublient ce qui leur est inutile et récupèrent ce dont ils ont besoin juste à temps.</p><h2>Conclusion</h2><p>La mémoire n'est pas quelque chose que l'on ajoute à un agent, c'est quelque chose que l'on développe. La mémoire à court terme est le bloc-notes de travail de l'agent, et la mémoire à long terme est son stock de connaissances durable. RAG est le pont entre les deux, transformant un datastore passif, comme Elasticsearch, en un mécanisme de rappel actif qui peut ancrer les sorties et maintenir l'agent à jour.</p><p>Mais la mémoire est une arme à double tranchant. Dès que vous laissez le contexte se développer sans contrôle, vous invitez l'empoisonnement, la distraction, la confusion et les conflits, et dans les systèmes partagés, même des fuites de données. C’est pourquoi le travail de mémoire le plus important n’est pas de « stocker davantage », mais de « mieux sélectionner » : récupérer de manière sélective, élaguer avec rigueur, résumer avec soin et éviter de mélanger des contextes non liés, sauf si la tâche l’exige réellement.</p><p>En pratique, une bonne ingénierie du contexte ressemble à une bonne conception de systèmes : des contextes plus petits et suffisants, des interfaces contrôlées entre les composants, et une séparation claire entre l'état brut et l'état distillé que vous voulez réellement que le modèle voie. Si l'on procède correctement, on ne se retrouve pas avec un agent qui se souvient de tout, mais avec un agent qui se souvient des bonnes choses, au bon moment et pour la bonne raison.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agentic-memory-management-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agentic-memory-management-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Someshwaran Mohankumar]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3bad6b045392e641/6a170f43a29299c189d010cc/80907fd072e72d6ec902470b449c9f337957a0d7-1280x720.png" length="0" type="image/png"/>
    <pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Premiers pas avec Elastic Agent Builder et le SDK Strands Agents]]></title>
    <description><![CDATA[Découvrez comment créer un agent avec Elastic Agent Builder, puis explorez comment utiliser cet agent via le protocole A2A orchestré à l’aide du SDK Strands Agents.]]></description>
    <content:encoded><![CDATA[<p>Vous avez une idée d’agent IA ? Cela implique sans doute d’exploiter des données : pour que l’agent exécute une action utile, il doit prendre une décision, et pour cela, il lui faut les bonnes données.</p><p>Elastic Agent Builder simplifie la création d’agents IA connectés aux données. Nous vous expliquons comment faire dans cet article de blog. Voici toutes les étapes pour créer un agent avec un outil MCP capable d’accéder aux données stockées dans Elastic. Nous utiliserons ensuite le SDK Strands Agents et ses fonctionnalités Agent2Agent (A2A) pour piloter l’agent. Le <a href="https://strandsagents.com/">SDK Strands Agents</a> est une plateforme de développement d’IA multi-agents, conçue pour créer des applications autonomes avec juste ce qu’il faut de code pour obtenir les résultats souhaités.</p><p>Construisons un agent IA capable de jouer à RPS+, une version revisitée du jeu classique « Pierre, feuille, ciseaux », enrichie de quelques choix supplémentaires pour les joueurs.</p><h2>Produits requis</h2><p>Voici ce dont vous avez besoin pour suivre les étapes décrites dans cet article de blog :</p><ul><li><p>Un éditeur de texte fonctionnant sur votre ordinateur local</p><ul><li><p>Nous utiliserons <a href="https://code.visualstudio.com/download">Visual Studio Code</a> pour suivre les exemples présentés dans cet article de blog.</p></li></ul></li><li><p><a href="https://www.python.org/downloads/">Python 3.10 ou version supérieure</a> installé localement sur votre machine</p></li></ul><h2>Créez un projet sans serveur</h2><p>La première étape consiste à créer un projet Elasticsearch Serverless, qui inclut Elastic Agent Builder.</p><p>Accédez à <a href="http://cloud.elastic.co/">cloud.elastic.co</a> et créez un nouveau projet Elasticsearch Serverless.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3472edce39ec0b81/6a17060e66c4f93c17f8bf57/31b6a5c1c30dacbb4d5e58d1c566071e7143a0c8-1600x879.gif" alt="" /><h2>Créer un index et ajouter des données</h2><p>Ensuite, nous allons ajouter des données à notre projet Elasticsearch. Ouvrez les Developer Tools pour exécuter des commandes : nous allons créer un nouvel index et y insérer des données. Dans le menu principal, sélectionnez Developer Tools.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaedaa94068c07a17/6a17060f961e697558c4ce5f/f97d5af077504463155655a9e27c171a7f974f71-1600x879.jpg" alt="" /><p>Copiez-collez la commande PUT suivante dans la zone de saisie de requêtes de la console Developer Tools. Cette commande crée un index Elasticsearch nommé « game-docs ».</p>PUT /game-docs
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "content": { 
        "type": "text"
      },
      "filename": { "type": "keyword" },
      "last_modified": { "type": "date" }
    }
  }
}<p>Cliquez sur le bouton <strong>Envoyer la requête</strong> à droite de l’instruction dans Developer Tools. Une notification doit confirmer que l’index <em>game-docs</em> a bien été créé, dans la zone de réponse de Developer Tools.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt430c357b479d93af/6a170611a6c2b98191e79624/be0555a1930e4d4f58b7ed8b669c9b702532ed17-1600x880.jpg" alt="" /><p>L’index nommé <em>game-docs</em> est l’endroit idéal pour stocker les données du jeu que nous créons. Ajoutons maintenant un document nommé <em>rps++-md</em> dans cet index, contenant toutes les données nécessaires au jeu. Copiez-collez la commande PUT suivante dans la console Developer Tools.</p>PUT /game-docs/_doc/rps+-md
{
  "title": "Rock Paper Scissors +",
  "content": "
# Game Name
RPS+

# Starting Prompt
Let's play RPS+ !
---
What do you choose?

# Game Objects
1. Rock 🪨 👊
2. Paper 📜 🖐
3. Scissors ✄ ✌️
4. Light ☼ 👍
5. Dark Energy ☄ 🫱

# Judgement of Victory
* Rock beats Scissors
  * because rocks break scissors
* Paper beats Rock
  * because paper covers rock
* Scissors beat Paper
  * because scissors cut paper
* Rock beats Light
  * because you can build a rock structure to block out light
* Paper beats Light
  * because knowledge stored in files and paper books helps us understand light
* Light beats Dark Energy
  * because light enables humans to lighten up and laugh in the face of dark energy as it causes the eventual heat death of the universe
* Light beats Scissors
  * because light is needed to use scissors safely
* Dark Energy beats Rock
  * because dark energy rocks more than rocks. It rocks rocks and everything else in its expansion of the universe
* Dark Energy beats Paper
  * because humans, with their knowledge stored in files and paper books, can't explain dark energy 
* Scissors beat Dark Energy
  * because a human running with scissors is darker than dark energy

# Invalid Input
I was hoping for an worthy opponent
  - but alas it appears that time has past
  - but alas there's little time for your todo list when [todo:fix this] is so vast

# Cancel Game
The future belongs to the bold. Goodbye..
",
  "filename": "RPS+.md",
  "last_modified": "2025-11-25T12:00:00Z"
}<p>Cliquez sur le bouton <strong>Envoyer la requête</strong> à côté de l’instruction pour l’exécuter et ajouter le document <em>rps++-md</em> à l’index game-docs.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt64d49e13754d5b25/6a17061214b270524be3c55d/3c01d8a4602de5c33337457591a388a4a4e3fad3-1600x879.jpg" alt="" /><p>Nous avons maintenant des données à interroger, et avec Agent Builder, c’est plus simple que jamais.</p><p>Dans le menu de navigation principal, sélectionnez <strong>Agents</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb4d374bf2ba9135c/6a1706147d8d67468570e63e/82dbd2e9a439cabd5a5eea3d0ce005b87df0c3ea-1600x879.jpg" alt="" /><p>Ensuite, il vous suffit de demander à l'agent Elastic AI par défaut, « Quelles données ai-je ? »</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc0f879cf28772718/6a1706161949f7f25ee7a92d/f7a2f39c9d1486bdf02d9e88a732b540ac2e2cd1-1600x872.gif" alt="" /><p>L’agent IA Elastic analyse les données et fournit une explication claire des informations disponibles.</p><h2>Créer un outil</h2><p>Nous avons maintenant des données dans Elastic, mettons-les à profit. Agent Builder inclut un support natif pour créer des outils <a href="https://modelcontextprotocol.io/">MCP</a>, qui permettent aux agents d’accéder aux données dont ils ont besoin pour disposer du bon contexte. Créons un outil simple pour récupérer les données de notre jeu.</p><p>Cliquez sur le menu des actions dans Agent Builder.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7802a6b94e81440c/6a170618ab7f085287db9db4/0e327c202674dda33bcc0e494d2b588fa8b32e4f-1600x879.png" alt="" /><p>Dans les options du menu, sélectionnez <strong>Afficher tous les outils</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9f52ffe114fb6ea7/6a17061a4a531b801b36a884/1ebf58650e9fb56750d3f0b1700fab50b44f9bdf-1600x879.png" alt="" /><p>Cliquez sur <strong>+ Nouvel outil</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8090769f6c4d1899/6a17061c286714294093e219/6c03a7f28b99ac2d805f34f39948979893316a00-1600x879.png" alt="" /><p>Dans le formulaire <strong>Créer un outil</strong> , sélectionnez <a href="https://www.elastic.co/docs/explore-analyze/query-filter/languages/esql"><strong>ES|QL</strong></a> <strong>Saisissez</strong> l'outil et entrez les valeurs suivantes.</p><p>Pour <strong>Tool ID </strong>:</p>example.get_game_docs<p>Pour <strong>Description</strong> :</p>Get RPS+ doc from Elasticsearch game-docs index.<p>Pour <strong>Configuration, </strong>saisissez la requête suivante dans la zone de texte <strong>ES|QL Query</strong> :</p>FROM game-docs | WHERE filename == "RPS+.md"<p>Le formulaire <strong>Créer outil</strong> complété devrait ressembler à ceci. Cliquez sur <strong>Enregistrer</strong> pour créer l'outil.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt77034c305198217a/6a17061e66c4f9e54ef8bf5e/b6c93e344600f319b9d2c3030020cf2d171ac1c4-1600x1312.png" alt="" /><p>Un nouvel outil a été ajouté à notre tableau de bord. Les outils ne sont pas faits pour rester inutilisés : ils doivent être mis à profit. Créons un agent qui saura exploiter notre nouvel outil personnalisé.</p><h2>Créez un agent et attribuez-lui un outil</h2><p>Créer un agent est d’une simplicité rafraîchissante avec Agent Builder. Il vous suffit de saisir quelques instructions pour l’agent, avec quelques détails : c’est tout. Créons un agent dès maintenant.</p><p>Cliquez sur <strong>Gérer les agents.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaa8a83fc2f3758a9/6a1706201949f71a10e7a931/53934b93db07187e251d4b321cb9ca647e2fd51b-1600x858.png" alt="" /><p>Cliquez<strong> + Nouvel agent.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3778403c5101a000/6a17062160084be12f3c449e/fae3ad8f31e71a6dfd044e1daa025a4e280b4e68-1600x490.png" alt="" /><p>Saisissez les informations suivantes dans le formulaire <strong>Nouvel agent</strong>.</p><p>Pour <strong>l'identification de l'agent, </strong>saisissez le texte ci-dessous :</p>rps_plus_agent<p>Dans la section texte <strong>Instructions personnalisées </strong>, saisissez les instructions suivantes :</p>When prompted, if the prompt contains an integer, then select the corresponding numbered item in the list of "Game Objects" from your documents. Otherwise select a random game object. This is your chosen game object for a single round of the game.

# General Game Rules
* 2 players
    - the user: the person playing the game
    - you: the agent playing the game and serving as the game master
* Each player chooses a game object which will be compared and cause them to tie, win or lose.

# Start the game
1. This is the way each new game always starts. You make the first line of your response only the name of your chosen game object. 

2. The remainder of your response should be the "Starting Prompt" text from your documents and generate a list of "Game Objects" for the person playing the game to choose a game object from.  

# End of Game: The game ends in one of the following three outcomes:
1. Invalid Input: If the player responds with an invalid game object choice, respond with variations of the "Invalid Input" text from your documents and then end the game.

2. Tie: The game ends in a tie if the user chooses the same game object as your game object choice.

3. Win or Lose: The game winner is decided based on the "Judgement of Victory" conditions from your documents. Compare the user's game object choice and your game object choice and determine who chose the winning game object.

# Game conclusion
Respond with a declaration of the winner of the game by outputting the corresponding text in the "Judgement of Victory" section of your documents.<p>Pour le <strong>Nom d'affichage, </strong>entrez le texte ci-dessous :</p>RPS+ Agent<p>Pour la <strong>Description de l’affichage, </strong>saisissez le texte ci-dessous :</p>An agent that plays the game RPS+<p>Donnez à l'agent l'outil personnalisé que nous avons créé précédemment en cliquant sur l'onglet <strong>Outils</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5b0fe00abdde07c/6a17062314b2704bc4e3c563/1778f64bc3a1b4004998dc3668ef7f666788e193-1600x1390.png" alt="" /><p>Sélectionnez uniquement <em>example.get_game_docs</em>, l'outil que nous avons créé précédemment.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2210212e07e06104/6a170625a929cf3277ae08d1/7d734cd80161bcc058817482eb330ffcf1cb567b-1600x1363.png" alt="" /><p>Cliquez sur <strong>Enregistrer</strong> pour créer le nouvel agent.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6e3afc1918e26f14/6a170627ab7f084746db9db8/c0014faf605ce50c03679ed0d073bd9f3ae7234d-1600x468.png" alt="" /><p>Testons notre nouvel agent. Un lien pratique vous permet de démarrer une conversation avec n’importe quel agent de la liste.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blteb4b69dc5971d3a0/6a1706286f7f046840914743/b7d6943ad90a4f68691207caf66b81742e712145-1600x560.png" alt="" /><p>Saisissez simplement « start game » pour lancer la partie. Ça fonctionne !</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5b621d602223dff/6a17062ab339d568a1769ef8/984d008e4cc3f08cc1f101720673b0f7347c066c-1600x874.gif" alt="" /><p>L’agent affiche son choix pour la partie en haut de sa réponse. Cela permet de visualiser le choix de l’agent et de vérifier que le jeu fonctionne comme prévu. Cela dit, connaître le choix de votre adversaire avant de jouer n’est pas idéal pour une partie de pierre-feuille-ciseaux. Pour peaufiner le jeu, on peut utiliser une plateforme d’orchestration d’agents capable de les piloter via du code.</p><p>Le SDK Strands Agents entre en scène.</p><h2>Strands Agents SDK</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt73901ec745a97fbf/6a17062c964cea23c808bab3/c195bba6ff2754f5d8fda174a0c1d247bc283710-456x156.png" alt="" /><p>Si vous souhaitez essayer de nouveaux frameworks de développement d'agents, le <a href="https://strandsagents.com/latest/">SDK Strands Agents</a> vaut la peine d'être essayé. <a href="https://aws.amazon.com/blogs/opensource/introducing-strands-agents-an-open-source-ai-agents-sdk/">Le SDK Strands Agents a été publié par AWS (mai 2025)</a> en tant qu'implémentation <a href="https://github.com/strands-agents/sdk-python">Python</a> open source, et il existe désormais une version <a href="https://dev.to/aws/strands-agents-now-speaks-typescript-a-side-by-side-guide-12b3">Typescript</a>.</p><h2>Premiers pas avec le SDK Strands Agents en Python</h2><p>Lancez vos environnements de développement : nous allons cloner et exécuter une application d’exemple qui utilise Strands Agents pour piloter l’<em>agent RPS+</em> via le protocole A2A. Créons une version personnalisée du jeu RPS+ dans laquelle le choix de l’agent est révélé après votre propre décision, afin de préserver l’effet de surprise et le côté ludique du jeu Pierre-Feuille-Ciseaux.</p><p>Sur votre ordinateur local, ouvrez <a href="https://code.visualstudio.com/download">Visual Studio Code</a> et ouvrez un nouveau terminal.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3de752025d62993f/6a17062d0c4857f16501a997/2339cc37c89a3524f2b2a21684bc61dae958e1cf-915x460.jpg" alt="" /><p>Dans le terminal que vous venez d’ouvrir, exécutez la commande suivante pour cloner le dépôt Elasticsearch Labs :</p>git clone https://github.com/elastic/elasticsearch-labs<p>Exécution de la commande <em>cd </em>suivante pour changer de répertoire dans le répertoire Elasticsearch Labs :</p>cd elasticsearch-labs<p>Ensuite, exécutez cette commande pour ouvrir le dépôt dans Visual Studio Code :</p>code .<p>Dans l'explorateur de fichiers de Visual Studio, développez les dossiers <em>supporting-blog-content</em> et <em>agent-builder-a2a-strands-agents</em> , puis ouvrez le fichier <em>elastic_agent_builder_a2a_rps+.py.</em> Voici à quoi ressemble le fichier ouvert dans Visual Studio Code :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt65ef8036a70bcaf1/6a17062f1949f7af36e7a935/d153b19e0e016c701576edb99ccab5af7c554f34-1484x1530.jpg" alt="" /><p>Voici le contenu de <em>elastic_agent_builder_a2a_rps+.py </em>que vous devriez voir dans votre éditeur de texte :</p>import asyncio
from dotenv import load_dotenv
from uuid import uuid4
import httpx
import os
import random
from a2a.client import A2ACardResolver, ClientConfig, ClientFactory
from a2a.types import Message, Part, Role, TextPart

DEFAULT_TIMEOUT = 60  # set request timeout to 1 minute


def create_message(*, role: Role = Role.user, text: str, context_id=None) -&gt; Message:
    return Message(
        kind="message",
        role="user",
        parts=[Part(TextPart(kind="text", text=text))],
        message_id=uuid4().hex,
        context_id=context_id,
    )


async def main():
    load_dotenv()
    a2a_agent_host = os.getenv("ES_AGENT_URL")
    a2a_agent_key = os.getenv("ES_API_KEY")
    custom_headers = {"Authorization": f"ApiKey {a2a_agent_key}"}

    async with httpx.AsyncClient(
        timeout=DEFAULT_TIMEOUT, headers=custom_headers
    ) as httpx_client:
        # Get agent card
        resolver = A2ACardResolver(httpx_client=httpx_client, base_url=a2a_agent_host)
        agent_card = await resolver.get_agent_card(
            relative_card_path="/rps_plus_agent.json"
        )
        # Create client using factory
        config = ClientConfig(
            httpx_client=httpx_client,
            streaming=True,
        )
        factory = ClientFactory(config)
        client = factory.create(agent_card)
        # Use the client to communicate with the agent
        print("\nSending 'start game' message to Elastic A2A agent...")
        random_game_object = random.randint(1, 5)
        msg = create_message(text=f"start with game object {random_game_object}")
        async for event in client.send_message(msg):
            if isinstance(event, Message):
                context_id = event.context_id
                response_complete = event.parts[0].root.text
                # Get agent choice from the first line of the response
                parsed_response = response_complete.split("\n", 1)
                agent_choice = parsed_response[0]
                print(parsed_response[1])
        # User choice sent for game results from the agent
        prompt = input("Your Choice  : ")
        msg = create_message(text=prompt, context_id=context_id)
        async for event in client.send_message(msg):
            if isinstance(event, Message):
                print(f"Agent Choice : {agent_choice}")
                print(event.parts[0].root.text)


if __name__ == "__main__":
    asyncio.run(main())<p>Examinons ce qui se passe dans ce code. En commençant par la méthode <em><code>main()</code></em> , le code commence par accéder aux variables d’environnement pour l’URL de l’agent et la clé API. Ensuite, nous utilisons ces valeurs pour créer un <em><code>httpx</code></em><code> client</code> que nous pouvons utiliser pour obtenir la carte d'agent de l'agent. Le client utilise ensuite les détails de la carte d’agent pour envoyer une demande de « démarrer la partie » à l’agent. Il est intéressant de noter que nous incluons la valeur <code>random_game_object</code> dans la requête <code>"start game"</code>. Cette valeur est un nombre aléatoire généré par le module <em>aléatoire</em> de la bibliothèque standard de Python. La raison pour laquelle nous faisons cela est qu'il s'avère que les puissants LLM (qui rendent possibles les agents IA) ne sont pas très doués pour le hasard. Pas de problème, Python vient à la rescousse.</p><p>En poursuivant dans le code, une fois que l’agent a répondu à la requête start game, le code extrait le choix de l’agent et le stocke dans la variable <em>agent_choice</em>. Le reste de la réponse est affiché sous forme de texte à destination de l’utilisateur final. L’utilisateur est ensuite invité à saisir son propre choix d’objet de jeu, qui est envoyé à l’agent. Le code affiche ensuite le choix de l’agent, ainsi que le résultat final du jeu selon l’agent.</p><h2>Définir l’URL de votre agent et la clé API comme variables d’environnement</h2><p>Comme l’application d’exemple sera exécutée en local, nous devons fournir au SDK Strands Agents une URL A2A et une clé API pour communiquer avec notre agent. L’application d’exemple utilise un fichier nommé <em>.env</em> pour stocker ces valeurs.</p><p>Faites une copie du fichier <em>env.example</em> et nommez le nouveau fichier <em>.env</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta17961cbcb42985c/6a170631b0367dc5a072bc55/25ead5f15a17dedb777132a082097cffb06cae4d-1600x843.jpg" alt="" /><p>Retournez dans Elastic Agent Builder pour récupérer les deux valeurs nécessaires.</p><p>Sélectionnez <strong>Afficher tous les outils</strong> dans le menu d'action d'Agent Builder en haut à droite de la page.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt140885d7ebfcb969/6a1706327d8d67b17670e646/9c4f4e4a3bd76e11e0a182fa007a2f6aec7777b4-1600x880.jpg" alt="" /><p>Cliquez sur le menu déroulant <strong>MCP Server</strong> en haut de la page Outils et sélectionnez <strong>Copier l’URL MCP Server.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc153c2caa27e949b/6a170634a292997793d00f6d/6cde0de678bb6f81bef8a59deffb110ad6c6ce26-1600x882.jpg" alt="" /><p>Collez <strong>l’URL du serveur MCP</strong> dans le <em>fichier .env</em> fichier en remplacement de la valeur d'espace réservé <strong>&lt;YOUR-ELASTIC-AGENT-BUILDER-URL&gt; </strong>. Nous devons maintenant apporter une modification à l'URL, à savoir remplacer le texte final « mcp » par « a2a », car le <a href="https://a2a-protocol.org/">protocole A2A</a> est celui que le SDK Agent Strands utilisera pour communiquer avec l'agent exécuté dans Elastic Agent Builder.</p><p>L’URL modifiée devrait ressembler à ceci :</p>https://rps-game-project-12345a.kb.us-east-1.aws.elastic.cloud/api/agent_builder/a2a<p>L'autre valeur dont nous avons besoin d'obtenir pendant que nous sommes ici dans Elastic Cloud est une clé d'API. Cliquez sur <strong>Elasticsearch </strong>dans la navigation principale.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltada5de819f31d8ff/6a170635b339d55ae9769efc/651676b9be65178cdad50b5d24f26441c0bf3f97-1600x549.jpg" alt="" /><p>Cliquez sur le <strong>bouton Copier la clé API </strong>pour copier la clé API.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta18f85790df00706/6a170637cf4f257145b2d0bd/17f1e2ed5c7682630c71e75b0b09ffb1d9036210-1600x879.jpg" alt="" /><p>Maintenant, de retour dans Visual Studio Code, collez la Clé d'API dans le fichier <em>.env</em> fichier pour remplacer le texte de l'espace réservé <strong>&lt;YOUR-ELASTIC-API-KEY&gt; </strong>. Votre <em>.env</em> Le fichier devrait ressembler à ceci :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt92ab4b37cdcca85e/6a1706386f7f0472ed914747/a357947e07f29c8c03382e00c7baedf04a399297-1600x286.jpg" alt="" /><h2>Lancer l’application d’exemple</h2><p>Ouvrez un nouveau terminal dans Visual Studio Code.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8702d826849755d0/6a17063a60084b45ca3c44a2/33e1174c68ea1ed47c7fe62ab6a6da657c606f56-1413x711.jpg" alt="" /><p>Commencez par exécuter la commande <em>cd</em> suivante dans le terminal :</p>cd elasticsearch-labs/supporting-blog-content/agent-builder-a2a-strands-agents<p>Exécutez la commande suivante pour créer un environnement virtuel Python.</p>python -m venv .venv<p>Selon le système d’exploitation de votre machine, exécutez la commande suivante pour activer l’environnement virtuel.</p><ul><li><p>MacOS/Linux</p></li></ul>source .venv/bin/activate<ul><li><p>Windows</p></li></ul>.venv\Scripts\activate<p>L’application d’exemple utilise le SDK Strands Agents, et nous arrivons à l’étape où il faut l’installer. Exécutez la commande suivante pour installer le SDK Strands Agents avec toutes ses dépendances Python.</p>pip install -r requirements.txt<p>Il est temps de dégager la rampe de lancement et de commencer le compte à rebours. Nous sommes prêts à lancer cette application. Reculez un peu. Lançons-la avec la commande suivante :</p>python elastic_agent_builder_a2a_rps+.py<p>Le défi ? Une partie de RPS+ vous attend. Bravo et bonne chance pour la suite !</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbb3715672995fcfa/6a17063c6234e07b76db195f/041df81fbf1776f09e1243af0a435c4c0af6aca1-1600x948.gif" alt="" /><h2>Créez vos applications d'IA avec un contexte pertinent</h2><p>La création d'un agent IA fait désormais partie de vos compétences. Vous avez vu aussi combien il est facile d'utiliser Elastic Agent Builder via A2A dans des frameworks de développement d'agents comme les SDK Strands Agents. <a href="https://cloud.elastic.co/registration?utm_source=agentic-ai-category&amp;utm_medium=search-labs&amp;utm_campaign=agent-builder">Essayez Elastic</a> pour créer des agents IA connectés au contexte pertinent dans vos données personnalisées.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agent-builder-a2a-strands-agents-guide</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agent-builder-a2a-strands-agents-guide</guid>
    <category><![CDATA[IA]]></category>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Jonathan Simon]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3472edce39ec0b81/6a17060e66c4f93c17f8bf57/31b6a5c1c30dacbb4d5e58d1c566071e7143a0c8-1600x879.gif" length="0" type="image/gif"/>
    <pubDate>Mon, 15 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Présentation de la prise en charge d'Elasticsearch dans Google MCP Toolbox for Databases]]></title>
    <description><![CDATA[Découvrez les caractéristiques de la prise en charge d'Elasticsearch maintenant disponible dans Google MCP Toolbox for Databases et utilisez les outils ES|QL pour intégrer en toute sécurité votre index à n'importe quel client MCP.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous allons expliquer comment utiliser Google MCP Toolbox avec <a href="https://github.com/elastic/elasticsearch">Elasticsearch</a> pour créer un outil simple permettant d'extraire des informations d'un index Elasticsearch.</p><p>Nous avons récemment contribué au projet open source <a href="https://github.com/googleapis/genai-toolbox">Google MCP Toolbox for Databases</a> en ajoutant la prise en charge d'Elasticsearch en tant que base de données.</p><p>Grâce à cette nouvelle fonctionnalité, vous pouvez désormais utiliser Google MCP Toolbox pour vous connecter à Elasticsearch et "dialoguer" directement avec vos données.</p><h2>Elasticsearch</h2><p>Nous avons besoin d'une instance Elasticsearch en cours d'exécution. Vous pouvez activer un essai gratuit sur <a href="https://www.elastic.co/cloud">Elastic Cloud</a> ou l'installer localement via le script <a href="https://github.com/elastic/start-local">start-local</a> :</p>curl -fsSL https://elastic.co/start-local | sh<p>Cela installera Elasticsearch et Kibana sur votre ordinateur et générera une clé API à utiliser pour configurer Google MCP Toolbox.</p><p>La clé API sera affichée comme sortie de la commande précédente et stockée dans un fichier .env dans le dossier elastic-start-local.</p><h2>Installer l'ensemble de données d'exemple</h2><p>Après l'installation, connectez-vous à Kibana en utilisant le nom d'utilisateur <em>elastic</em> et le mot de passe généré par le script "start-local" (stocké dans un fichier .env).</p><p>Vous pouvez installer l'ensemble de données <strong>eCommerce orders </strong>disponible dans Kibana. Il comprend un seul index nommé <strong>kibana_sample_data_ecommerce</strong> contenant des informations sur 4 675 commandes provenant d'un site web. Pour chaque commande, nous disposons des informations suivantes :</p><ul><li><p>Informations client (nom, identifiant, date de naissance, e-mail, etc.)</p></li><li><p>Date de la commande</p></li><li><p>ID de la commande</p></li><li><p>Produits (liste de tous les produits avec prix, quantité, ID, catégorie, réduction, etc.)</p></li><li><p>SKU</p></li><li><p>Prix total (hors taxes, taxes incluses)</p></li><li><p>Quantité totale</p></li><li><p>Informations géographiques (ville, pays, continent, localisation, région)</p></li></ul><p>Pour installer les données d'exemple, ouvrez la page <strong>Intégrations</strong> dans Kibana (recherchez "Integration" dans la barre de recherche supérieure), puis installez l'ensemble de données "Sample Data". Pour plus de détails, consultez la documentation ici : <a href="https://www.elastic.co/docs/explore-analyze/#gs-get-data-into-kibana">https://www.elastic.co/docs/explore-analyze/#gs-get-data-into-kibana</a>.</p><p>Cet article a pour but de montrer combien il est facile de configurer Google MCP Toolbox pour se connecter à Elasticsearch et interagir avec l'index <strong>kibana_sample_data_ecommerce</strong> en utilisant le langage naturel.</p><h2>Google MCP Toolbox</h2><p>Google MCP Toolbox est un serveur MCP open source conçu pour faciliter l'interaction sécurisée et efficace des applications et des agents IA avec les bases de données. Auparavant appelé "GenAI Toolbox for Databases", le projet a été renommé après l'adoption d'une compatibilité totale avec le protocole <a href="https://www.anthropic.com/news/model-context-protocol">MCP</a> (Model Context Protocol). Son objectif est de supprimer les tâches complexes traditionnellement requises lors de la connexion d'agents à des bases de données en gérant en arrière-plan les pools de connexion, l'authentification, l'observabilité et d'autres aspects opérationnels.</p><p>Essentiellement, la boîte à outils permet aux développeurs de définir des outils réutilisables de haut niveau qui encapsulent les interactions avec la base de données. Ces outils peuvent ensuite être invoqués par n'importe quel client compatible MCP, tel qu'un agent IA, sans que le client n'ait à implémenter des requêtes SQL de bas niveau ni à gérer des connexions de base de données. Cette approche réduit considérablement la quantité de code répétitif nécessaire à la création d'agents compatibles avec les bases de données, permettant ainsi d'intégrer des opérations de données avancées en seulement quelques lignes de logique applicative. Une fois qu'un outil est défini, il peut être partagé entre plusieurs agents, frameworks, ou langages (Figure 1).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte90070297ee83546/6a16fa29964cea694b08b972/137cea290bb70ad5da21853f9a6358cef4cf7451-1248x1056.png" alt="" /><p>L'un des principaux avantages de la boîte à outils est le modèle de sécurité intégré. Les flux d'authentification tels que OAuth2 et OIDC sont pris en charge de manière native, ce qui permet aux développeurs d'éviter de manipuler ou de stocker des informations sensibles d'identification de base de données dans les agents. La plateforme fournit également des fonctionnalités d'observabilité via OpenTelemetry, y compris les métriques et le traçage, ce qui est essentiel pour le débogage, la surveillance et les déploiements en production. De manière générale, MCP Toolbox sert d'interface unifiée, sécurisée et extensible pour interagir avec vos données depuis n'importe quel système compatible MCP.</p><h2>Comment installer MCP Toolbox</h2><p>Vous pouvez installer le serveur MCP Toolbox sur Linux en utilisant la commande suivante :</p>export VERSION=0.21.0
curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
chmod +x toolbox<p>Si vous souhaitez l'installer sur macOS ou Windows, vous pouvez suivre les instructions <a href="https://googleapis.github.io/genai-toolbox/getting-started/introduction/#installing-the-server">détaillées ici</a>.</p><h2>Configurer Toolbox pour Elasticsearch</h2><p>Pour configurer MCP Toolbox pour Elasticsearch, nous devons créer un fichier <strong>tools.yaml</strong> comme suit :</p>sources:
  my-cluster:
    kind: elasticsearch
    addresses:
      - http://localhost:9200
    apikey: &lt;insert-here-api-key&gt;

tools:
  customer-orders:
    kind: elasticsearch-esql
    source: my-cluster
    description: Get the orders made by a customer identified by name.
    query: |
    	FROM kibana_sample_data_ecommerce | WHERE MATCH(customer_full_name, ?name, {"operator": "AND"})
    parameters:
      - name: name
        type: string
        description: The customer name.

toolsets:
  elasticsearch-tools:
    - customer-orders<p>Vous devez remplacer la valeur <strong>&lt;insert-here-api-key&gt;</strong> par une clé API Elasticsearch valide. Si vous exécutez Elasticsearch localement avec la commande "start-local", vous trouverez la clé API dans le fichier .env généré par start-local, sous la variable <strong>ES_LOCAL_API_KEY</strong>. Si vous utilisez Elastic Cloud, vous pouvez générer une clé API en suivant la procédure <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elastic-cloud-api-keys">décrite ici</a>.</p><p>Les outils précédents contiennent la requête ES|QL suivante pour Elasticsearch :</p><p>Si vous ne connaissez pas ES|QL, il s'agit d'un langage de requête développé par Elastic, similaire à SQL, qui peut être utilisé pour effectuer des recherches sur un ou plusieurs indices. Pour en savoir plus sur ES|QL, consultez la documentation officielle <a href="https://www.elastic.co/docs/reference/query-languages/esql">ici</a>.</p><p>La requête ci-dessus recherche toutes les commandes stockées dans l'index <strong>kibana_sample_data_ecommerce</strong> qui contiennent le nom du client spécifié, en utilisant le paramètre <strong>?name</strong> (le point d'interrogation indique un paramètre).</p><p>Le nom du client est défini dans la configuration YAML précédente en utilisant le type chaîne et la description "The customer name" (nom du client).</p><p>Cet outil peut être utilisé pour répondre à des questions sur les commandes d'un client, par exemple : <em>Combien de commandes le client Foo a-t-il passées en octobre 2025 ?</em></p><p>Les descriptions des outils et de leurs paramètres sont essentielles pour extraire les informations pertinentes de la requête en langage naturel de l'utilisateur. Cette extraction est réalisée à l'aide de la capacité d'<strong>appel de fonctions</strong> d'un grand modèle de langage (LLM). En pratique, un LLM peut déterminer quelle fonction (outil) doit être exécutée pour obtenir les informations nécessaires, ainsi que les paramètres appropriés pour cette fonction.</p><p>Pour plus d'informations sur les appels de fonctions, nous vous invitons à lire l'article <a href="https://www.elastic.co/search-labs/blog/function-calling-with-elastic">OpenAI function calling with Elasticsearch</a> (en anglais) par Ashish Tiwari.</p><h2>Exécuter le serveur Toolbox</h2><p>Vous pouvez exécuter le serveur MCP Toolbox à l'aide du fichier "tools.yaml" précédent avec la commande suivante :</p>./toolbox --tools-file tools.yaml --ui<p>Le paramètre<strong> –ui</strong> exécute une application web à l'adresse <a href="http://127.0.0.1:5000/ui">http://127.0.0.1:5000/ui</a> (Figure 2).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0fb3953fae603572/6a16fa2aa6c2b92763e794fb/3caf2339b632bafd5847af1ed8b33b518a25b8a2-1600x314.png" alt="" /><p>Sélectionnez <strong>Tools</strong> (Outils) &gt; <strong>customer-orders</strong> et insérez un nom de client dans le paramètre <strong>name</strong> (par ex. Gwen Sanders), puis cliquez sur le bouton <strong>Run Tool</strong> (Exécuter l'outil). Une réponse JSON devrait s'afficher comme illustré dans la figure 3.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca02df8c78cb39ff/6a16fa2c961e6909b5c4cd22/b167e0142afb8919d9cedf6d0fa431d33d0e55f8-1600x933.png" alt="" /><p>La configuration est terminée et MCP Toolbox peut exécuter l'outil <strong>customer-orders</strong> pour communiquer avec Elasticsearch, en lançant la requête ES|QL.</p><h2>Utiliser MCP Toolbox avec Gemini CLI</h2><p>Nous pouvons utiliser n'importe quel client MCP pour communiquer avec MCP Toolbox for Databases. Par exemple, nous pouvons choisir <a href="https://github.com/google-gemini/gemini-cli">Gemini CLI</a>, un outil en ligne de commande permettant d'utiliser Gemini. Si vous souhaitez installer Gemini CLI, suivez les instructions <a href="https://geminicli.com/docs/get-started/installation/">indiquées ici</a>.</p><p>Gemini CLI propose une extension préconfigurée pour MCP Toolbox, disponible sur <a href="https://github.com/gemini-cli-extensions/mcp-toolbox">gemini-cli-extensions/mcp-toolbox</a>. Vous pouvez installer cette extension en exécutant la commande suivante :</p>gemini extensions install https://github.com/gemini-cli-extensions/mcp-toolbox<p>Après l'installation, vous devez accéder au répertoire dans lequel vous avez stocké le fichier de configuration "tools.yaml" pour MCP Toolbox et exécuter Gemini CLI comme suit (cette étape est nécessaire pour que Gemini CLI soit automatiquement configuré avec MCP Toolbox) :</p>gemini<p>Un message de sortie devrait s'afficher comme illustré dans la figure 4.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf7245c10b9e32cd6/6a16fa2d964cea073208b976/0f22df6d3da13c1dc50dcb560414fa7c630eb9a7-1434x341.png" alt="" /><p>Vous pouvez vérifier si la boîte à outils MCP est connectée en utilisant la commande suivante :</p>/mcp list<p>Vous devriez voir s'afficher <strong>mcp_toolbox</strong> avec les outils<strong> customer-orders</strong> répertoriés (Figure 5).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte857b42dbe604203/6a16fa2f8b73cb531b189e33/97edbc40de9e44f469f6f3a09427532be167de0e-493x155.png" alt="" /><p>Si MCP Toolbox est connecté à Gemini CLI, nous pouvons maintenant poser quelques questions, telles que : "<em>Indiquez-moi les commandes pour la cliente Gwen Sanders</em>". Gemini CLI demande alors l'autorisation d'exécuter l'outil "customer-orders" depuis le serveur mcp_toolbox (voir Figure 6).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfb7ea752c1a39da7/6a16fa30cdacbfdf937d27ff/c052f3b5e49436903b804280c0065f67ee02444b-1432x284.png" alt="" /><p>Après confirmation, Gemini CLI exécute la requête dans MCP Toolbox, reçoit une réponse JSON et l'utilise pour mettre en forme la réponse (Figure 7).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb9f6e04987137a9f/6a16fa320811ae2297e9fef7/7ea5128f1705951c2757af6da4b456d394d4a080-1432x734.png" alt="" /><p>La réponse de Gemini CLI indique que Gwen Sanders a passé une seule commande de 2 produits, pour un prix total de 132 EUR.</p><h2>SDK MCP Toolbox</h2><p>Google MCP Toolbox propose également un SDK pour accéder à toutes les fonctionnalités depuis un programme écrit en Go, Python et Javascript.</p><p>Par exemple, le SDK Python est disponible sur Github à la page suivante : <a href="https://github.com/googleapis/mcp-toolbox-sdk-python">https://github.com/googleapis/mcp-toolbox-sdk-python</a>.</p><p>Nous devons créer un agent simple pour nous connecter à MCP Toolbox. Nous devons installer les packages suivants :</p>pip install toolbox-core
pip install google-adk<p>Et créer un nouveau projet d'agent à l'aide la commande suivante :</p>adk create my_agent<p>Cela créera un nouveau répertoire nommé <strong>my_agent</strong> contenant un fichier <strong>agent.py</strong>.</p><p>Mettez à jour le fichier <strong>my_agent/agent.py</strong> avec le contenu suivant pour vous connecter à Toolbox :</p>from google.adk import Agent
from google.adk.apps import App
from toolbox_core import ToolboxSyncClient

client = ToolboxSyncClient("http://127.0.0.1:5000")

root_agent = Agent(
    name='root_agent',
    model='gemini-2.5-flash',
    instruction="You are a helpful AI assistant designed to search information about a dataset of ecommerce orders.",
    tools=client.load_toolset(),
)

app = App(root_agent=root_agent, name="my_agent")<p>Créez un fichier <strong>.env</strong> avec votre clé API Google :</p>echo 'GOOGLE_API_KEY="YOUR_API_KEY"' &gt; my_agent/.env<p>Enfin, nous pouvons lancer l'exécution de l'agent et observer les résultats. Pour ce faire, exécutez la commande suivante :</p>adk run my_agent<p>Ou, vous pouvez le servir via une interface web :</p>adk web --port 8000<p>Dans les deux cas, vous pouvez interagir avec MCP Toolbox à l'aide d'une interface de questions-réponses. Par exemple, vous pouvez poser la question précédente : <em>Indiquez-moi les commandes de la cliente Gwen Sanders</em>.</p><p>Pour plus d'informations sur les différents SDK, consultez cette <a href="https://googleapis.github.io/genai-toolbox/sdks/">page de documentation</a>.</p><h2>Conclusion</h2><p>Dans cet article, nous avons démontré l'intégration d'Elasticsearch pour Google MCP Toolbox for Databases. À l'aide d'un simple fichier de configuration YAML, nous pouvons définir un ensemble d'outils qui traduisent les questions en langage naturel en requêtes Elasticsearch en utilisant le langage ES|QL.</p><p>Nous avons montré comment interagir avec l'ensemble de données "kibana_sample_data_ecommerce", qui contient des commandes provenant d'un site web. Avec ce fichier de configuration, nous pouvons simplement lancer l'exécution du serveur MCP Toolbox et nous y connecter depuis n'importe quel client MCP.</p><p>Enfin, nous avons démontré comment utiliser Gemini CLI en tant que client pour nous connecter à MCP Toolbox for Databases et interroger les données e-commerce stockées dans Elasticsearch. Nous avons exécuté une requête en langage naturel pour récupérer des informations sur les commandes d'un client spécifique identifié par son nom.</p><p>À mesure que l'écosystème MCP se développe, ce modèle – des définitions d'outils légères soutenues par une infrastructure sécurisée et prête pour la production – crée de nouvelles possibilités pour construire des agents de plus en plus performants et sensibles aux données avec un minimum d'efforts. Qu'il s'agisse d'expérimenter localement les ensembles de données Elastic ou d'intégrer des fonctionnalités de recherche dans une application plus vaste, MCP Toolbox fournit une base fiable et extensible pour interagir avec vos données Elasticsearch en langage naturel.</p><p>Pour en savoir plus sur le développement d'applications d'IA agentique, consultez l'article <a href="https://search-labs-redesign.vercel.app/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder">Construire des workflows d'IA agentique avec Elasticsearch</a> par Anish Mathur et Dana Juratoni.</p><p>Pour plus d'informations sur Google MCP Toolbox, consultez la page <a href="https://googleapis.github.io/genai-toolbox/getting-started/introduction/">vhttps://googleapis.github.io/genai-toolbox/getting-started/introduction/</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/google-mcp-toolbox-elasticsearch-support</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/google-mcp-toolbox-elasticsearch-support</guid>
    <category><![CDATA[ES|QL]]></category>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Enrico Zimuel,Laurent Saint-Félix]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72d49893c51407cf/6a16fa33cf4f2502bab2cf7e/425a48691f436ed47c9bdfaf5d561ac122b2c472-1062x668.png" length="0" type="image/png"/>
    <pubDate>Fri, 12 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Créez un workflow de recherche IA financière avec LangGraph.js et Elasticsearch]]></title>
    <description><![CDATA[Apprenez à utiliser LangGraph.js avec Elasticsearch pour créer un workflow de recherche financière alimenté par l'IA qui transforme les requêtes en langage naturel en filtres dynamiques et conditionnels pour l'analyse des investissements et du marché.]]></description>
    <content:encoded><![CDATA[<p>La création d'applications de recherche IA implique souvent la coordination de plusieurs tâches, la récupération et l'extraction de données dans un workflow fluide. LangGraph simplifie ce processus en permettant aux développeurs d'orchestrer les agents d'IA à l'aide d'une structure basée sur des nodes. Dans cet article, nous allons construire une solution financière en utilisant <a href="https://langchain-ai.github.io/langgraphjs/">LangGraph.js</a>.</p><h2>Qu'est-ce que LangGraph ?</h2><p><a href="https://langchain-ai.github.io/langgraphjs/">LangGraph</a> est un framework pour construire des agents d’IA et les orchestrer dans un workflow afin de créer des applications assistées par l’IA. LangGraph dispose d’une architecture de nodes où nous pouvons déclarer des fonctions représentant des tâches et les assigner comme nodes du workflow. Le résultat de l'interaction de plusieurs nodes sera un graphe. LangGraph fait partie du <a href="https://js.langchain.com/docs/introduction/">LangChain</a> écosystème plus large, qui fournit des outils pour construire des systèmes d'IA modulaires et composables.</p><p>Pour mieux comprendre l’utilité de LangGraph, résolvons une situation problématique en l’utilisant.</p><h2>Aperçu de la solution</h2><p>Dans une société de capital-risque, les investisseurs ont accès à une vaste base de données avec de nombreuses options de filtrage, mais lorsqu'ils veulent combiner des critères, cela devient difficile et lent. Il se peut donc que certaines start-ups pertinentes ne soient pas trouvées pour l'investissement. Cela conduit à passer beaucoup de temps à essayer d'identifier les meilleurs candidats, voire à perdre des opportunités.</p><p>Avec LangGraph et Elasticsearch, vous pouvez effectuer des recherches filtrées en utilisant le langage naturel, ce qui évite aux utilisateurs de devoir construire manuellement des requêtes complexes avec des dizaines de filtres. Pour plus de flexibilité, le workflow choisit automatiquement, en fonction de l'entrée de l'utilisateur, entre deux types de requêtes :</p><ul><li><p><strong>Requêtes d’investissement</strong> : elles visent les données financières et de financement des start-up, notamment les <a href="https://www.investopedia.com/articles/personal-finance/102015/series-b-c-funding-what-it-all-means-and-how-it-works.asp">tours de table</a>, la valorisation ou le <a href="https://www.investopedia.com/terms/r/revenue.asp">CA</a>. <em>Exemple :</em> « Trouvez des startups avec un financement de série A ou série B entre 8 millions et 25 millions de dollars et un chiffre d’affaires mensuel supérieur à 500 000 $. »</p></li><li><p><strong>Requêtes axées sur le marché</strong>: elles se concentrent sur <a href="https://en.wikipedia.org/wiki/Vertical_market">les secteurs d’activité</a>, <a href="https://en.wikipedia.org/wiki/Target_market">les marchés géographiques</a> ou <a href="https://www.investopedia.com/terms/b/businessmodel.asp">les modèles économiques</a>, en aidant à identifier des opportunités dans des secteurs ou régions spécifiques. <em>Exemple :</em> « Trouvez des startups de la fintech et de la santé à San Francisco, New York ou Boston. »</p></li></ul><p>Pour garantir la robustesse des requêtes, nous allons faire en sorte que le LLM génère des <a href="https://www.elastic.co/docs/solutions/search/search-templates">modèles de recherche</a> au lieu de <a href="https://www.elastic.co/docs/explore-analyze/query-filter/languages/querydsl">requêtes DSL</a> complètes. De cette façon, vous obtenez toujours la requête souhaitée, et le LLM n'a qu'à compléter les informations manquantes sans avoir à élaborer la requête dont vous avez besoin à chaque fois.</p><h2>Ce dont vous avez besoin pour commencer</h2><ul><li><p>Clé API Elasticsearch</p></li><li><p>Clé d'API OpenAPI</p></li><li><p>Node 18 ou version ultérieure</p></li></ul><h2>Instructions étape par étape</h2><p>Dans cette section, voyons comment l'application sera présentée. Nous utiliserons <a href="https://www.typescriptlang.org/">TypeScript</a>, un sur-ensemble de JavaScript qui ajoute des types statiques. Cela rend le code plus fiable, plus facile à maintenir et plus sûr en détectant les erreurs dès le début, tout en assurant une compatibilité totale avec JavaScript.</p><p>Le flux des nœuds se présentera comme suit :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt90db8f03f372608c/6a170986dc55de6e16e00d93/b47d7f238c4964a6febc0de7fe5e68b186f539c3-363x555.png" alt="" /><p>L'image ci-dessus est générée par LangGraph et représente le workflow qui définit l'ordre d'exécution et la logique conditionnelle entre les nodes :</p><ul><li><p><strong>decideStrategy : </strong>utilise un LLM pour rechercher la requête de l'utilisateur et choisir entre deux stratégies de recherche spécialisées, axée sur l'investissement ou axée sur le marché.</p></li><li><p><strong>PrepareInvestmentSearch : </strong>extrait les valeurs de filtre de la requête et crée un modèle prédéfini mettant l'accent sur les paramètres financiers et liés au financement.</p></li><li><p><strong>PrepareMarketSearch</strong>: extrait également les valeurs des filtres, mais crée dynamiquement des paramètres en mettant l'accent sur le marché, le secteur et le contexte géographique.</p></li><li><p><strong>ExecuteSearch : </strong>envoie la recherche construite à Elasticsearch à l'aide d'un modèle de recherche et extrait les documents de démarrage correspondants.</p></li><li><p><strong>VisualiserResults : </strong>met en forme les résultats finaux sous la forme d'un résumé clair et lisible présentant les principaux attributs de la start-up tels que le financement, le secteur d'activité et le chiffre d'affaires.</p></li></ul><p>Ce flux comprend un <a href="https://langchain-ai.github.io/langgraphjs/how-tos/branching/?h=conditional#how-to-create-branches-for-parallel-node-execution">branchement conditionnel</a>, fonctionnant comme une instruction « si », qui détermine s'il faut rechercher le chemin d'investissement ou de recherche de marché en fonction de l'entrée de l'utilisateur. Cette logique de décision, pilotée par le LLM, rend le workflow adaptatif et conscient du contexte, un mécanisme que nous explorerons plus en détail dans les sections suivantes.</p><h3>État de LangGraph</h3><p>Avant de voir chaque node individuellement, nous devons comprendre comment les nodes communiquent et partagent les données. Pour cela, LangGraph nous permet de définir l'état du workflow. Cela définit l'état partagé qui sera transmis entre les nodes.</p><p>L’état agit comme un conteneur partagé stockant les données intermédiaires du workflow : il enregistre d’abord la requête en langage naturel de l’utilisateur, puis la stratégie de recherche choisie, les paramètres prêts pour Elasticsearch, les résultats de recherche et, pour finir, le résultat formaté.</p><p>Cette architecture permet à chaque nœud de lire et de modifier l’état, ce qui garantit un flux d’informations constant, de l’entrée de l’utilisateur jusqu’à la visualisation finale.</p>const VCState = Annotation.Root({
  input: Annotation&lt;string&gt;(), // User's natural language query
  searchStrategy: Annotation&lt;string&gt;(), // Search strategy chosen by LLM
  searchParams: Annotation&lt;any&gt;(), // Prepared search parameters
  results: Annotation&lt;any[]&gt;(), // Search results
  final: Annotation&lt;string&gt;(), // Final formatted response
});<h3>Configurer l'application</h3><p>Tout le code de cette section se trouve dans le <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch">dépôt elasticsearch-labs</a>.</p><p>Dans le dossier où l’application sera installée, ouvrez un terminal et initialisez une application Node.js avec la commande :</p>npm init -y<p>Nous pouvons maintenant installer les dépendances nécessaires à ce projet :</p>npm install @elastic/elasticsearch @langchain/langgraph @langchain/openai @langchain/core dotenv zod &amp;&amp; npm install --save-dev @types/node tsx typescript<ul><li><p><strong><code>@elastic/elasticsearch</code></strong>: Permet de gérer les requêtes Elasticsearch, comme l’ingestion et la récupération des données.</p></li><li><p><strong><code>@langchain/langgraph</code></strong>: Dépendance JS pour fournir tous les outils LangGraph.</p></li><li><p><strong><code>@langchain/openai</code></strong>: Client OpenAI LLM pour LangChain.</p></li><li><p>@langchain/core : Offre les composantes de base essentielles aux applications LangChain, notamment les modèles d’invite.</p></li><li><p><strong><code>dotenv</code></strong>: Dépendance nécessaire pour utiliser les variables d'environnement en JavaScript.</p></li><li><p><strong><code>zod</code></strong>: Dépendance au type de données.</p></li></ul><p><code>@types/node</code> <code>tsx</code> <code>typescript</code> nous permet d'écrire et d'exécution du code TypeScript.</p><p>Créez maintenant les fichiers suivants :</p><ul><li><p><code>elasticsearchSetup</code><a href="http://ingest.ts/"><code>.ts</code></a>: Créera les mapping d'index, chargera les données à partir d'un fichier JSON, et ingérera les données dans Elasticsearch.</p></li><li><p><a href="http://main.ts/"><code>main.ts</code></a>: inclura l’application LangGraph.</p></li><li><p><code>.env</code>: fichier pour stocker les variables d’environnement</p></li></ul><p>Dans le fichier <code>.env</code>, ajoutons les variables d’environnement suivantes :</p>ELASTICSEARCH_ENDPOINT="your-endpoint-here"
ELASTICSEARCH_API_KEY="your-key-here"
OPENAI_API_KEY="your-key-here"<p>La clé APIK de l'OpenAPI ne sera pas utilisée directement dans le code ; elle sera utilisée en interne par la bibliothèque <code>@langchain/openai</code>.</p><p>Toute la logique concernant la création de mappages, la création de modèles de recherche et l’ingestion des ensembles de données se trouve dans le fichier <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch/elasticsearchSetup.ts"><code>elasticsearchSetup.ts</code></a>. Dans les prochaines étapes, nous nous concentrerons sur le fichier <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch/main.ts"><code>main.ts</code></a>. Vous pouvez également consulter l'ensemble de données pour mieux comprendre l'aspect des données sur le site <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch/dataset.json"><code>dataset.json</code></a>.</p><h3>Application LangGraph</h3><p>Dans le fichier <code>main.ts</code>, importons certaines dépendances nécessaires pour consolider l'application LangGraph. Dans ce fichier, vous devez également inclure les fonctions node et la déclaration d’état. La déclaration du graphe sera effectuée dans une méthode <code>main</code> dans les prochaines étapes. Le fichier <code>elasticsearchSetup.ts</code> contiendra les aides Elasticsearch que nous allons utiliser dans les Nodes dans les étapes suivantes.</p>import { writeFileSync } from "node:fs";
import { StateGraph, Annotation, START, END } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
import {
  esClient,
  ingestDocuments,
  createSearchTemplates,
  INDEX_NAME,
  INVESTMENT_FOCUSED_TEMPLATE,
  MARKET_FOCUSED_TEMPLATE,
  createIndex,
} from "./elasticsearchSetup.js";

const llm = new ChatOpenAI({ model: "gpt-4o-mini" });<p>Ainsi que nous l’avons vu, le client LLM sera mobilisé pour générer les paramètres du modèle de recherche Elasticsearch en fonction de la question de l’utilisateur.</p>async function saveGraphImage(app: any): Promise&lt;void&gt; {
  try {
    const drawableGraph = app.getGraph();
    const image = await drawableGraph.drawMermaidPng();
    const arrayBuffer = await image.arrayBuffer();

    const filePath = "./workflow_graph.png";
    writeFileSync(filePath, new Uint8Array(arrayBuffer));
    console.log(`📊 Workflow graph saved as: ${filePath}`);
  } catch (error: any) {
    console.log("⚠️  Could not save graph image:", error.message);
  }
}<p>La méthode ci-dessus génère l'image du graphe au format png et utilise l'<a href="https://mermaid.ink/">API Mermaid.INK</a> en arrière-plan. Ceci est utile si vous souhaitez voir comment les nodes de l'application interagissent dans le cadre d'une visualisation stylisée.</p><h3>Nodes LangGraph</h3><p>À présent, voyons chaque node en détail :</p><h3>Node decideSearchStrategy</h3><p>Le node <code>decideSearchStrategy</code> analyse les entrées de l'utilisateur et détermine s'il convient d'effectuer une rechercher axée sur les investissements ou axée sur le marché. Il utilise un LLM avec un schéma de sortie structuré (défini avec Zod) pour classer le type de requête. Avant de prendre la décision, il récupère les filtres disponibles de l'index en utilisant une agrégation, en garantissant que le modèle dispose d'un contexte à jour sur les industries, les localisations et les données de financement.</p><p>Pour extraire les valeurs possibles des filtres et les envoyer au LLM, utilisons une requête d'<a href="https://www.elastic.co/docs/explore-analyze/query-filter/aggregations">agrégation</a> pour les récupérer directement depuis l'index Elasticsearch. Cette logique est allouée dans une méthode appelée <code>getAvailableFilters</code>:</p>async function getAvailableFilters() {
  try {
    const response = await esClient.search({
      index: INDEX_NAME,
      size: 0,
      aggs: {
        industries: {
          terms: { field: "industry", size: 100 },
        },
        locations: {
          terms: { field: "location", size: 100 },
        },
        funding_stages: {
          terms: { field: "funding_stage", size: 20 },
        },
        business_models: {
          terms: { field: "business_model", size: 10 },
        },
        lead_investors: {
          terms: { field: "lead_investor", size: 100 },
        },
        funding_amount_stats: {
          stats: { field: "funding_amount" },
        },
      },
    });

    return response.aggregations;
  } catch (error) {
    console.error("❌ Error getting available filters:", error);
    return {};
  }
}<p>Avec la requête d'agrégation ci-dessus, nous avons les résultats suivants :</p>{
  "industries": {
    "doc_count_error_upper_bound": 0,
    "sum_other_doc_count": 0,
    "buckets": [
      {
        "key": "logistics",
        "doc_count": 5
      },
      ...
    ]
  },
  "locations": {
    "doc_count_error_upper_bound": 0,
    "sum_other_doc_count": 0,
    "buckets": [
      {
        "key": "San Francisco, CA",
        "doc_count": 4
      },
      {
        "key": "New York, NY",
        "doc_count": 3
      },
      ...
    ]
  },
  "funding_stages": {
    "doc_count_error_upper_bound": 0,
    "sum_other_doc_count": 0,
    "buckets": [
      {
        "key": "Series A",
        "doc_count": 8
      },
      ...
    ]
  },
  "business_models": {
    "doc_count_error_upper_bound": 0,
    "sum_other_doc_count": 0,
    "buckets": [
      {
        "key": "B2B",
        "doc_count": 13
      },
      ...
    ]
  },
  "lead_investors": {
    "doc_count_error_upper_bound": 0,
    "sum_other_doc_count": 0,
    "buckets": [
      {
        "key": "Battery Ventures",
        "doc_count": 1
      },
      {
        "key": "Benchmark Capital",
        "doc_count": 1
      },
      ...
    ]
  },
  "funding_amount_stats": {
    "count": 20,
    "min": 4500000,
    "max": 35000000,
    "avg": 14075000,
    "sum": 281500000
  }
}<p>Découvrez tous les résultats <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch/responses/aggregationsResponse.json">ici</a>.</p><p>Pour les deux stratégies, nous allons utiliser la recherche hybride afin de détecter à la fois la partie structurée de la question (filtres) et les parties plus subjectives (sémantique). Voici un exemple des deux requêtes utilisant des <a href="https://www.elastic.co/docs/solutions/search/search-templates">modèles de recherche</a> :</p>await esClient.putScript({
      id: INVESTMENT_FOCUSED_TEMPLATE,
      script: {
        lang: "mustache",
        source: `{
          "size": 5,
          "retriever": {
            "rrf": {
              "retrievers": [
                {
                  "standard": {
                    "query": {
                      "semantic": {
                        "field": "semantic_field",
                        "query": "{{query_text}}"
                      }
                    }
                  }
                },
                {
                  "standard": {
                    "query": {
                      "bool": {
                        "filter": [
                          {"terms": {"funding_stage": {{#join}}{{#toJson}}funding_stage{{/toJson}}{{/join}}}},
                          {"range": {"funding_amount": {"gte": {{funding_amount_gte}}{{#funding_amount_lte}},"lte": {{funding_amount_lte}}{{/funding_amount_lte}}}}},
                          {"terms": {"lead_investor": {{#join}}{{#toJson}}lead_investor{{/toJson}}{{/join}}}},
                          {"range": {"monthly_revenue": {"gte": {{monthly_revenue_gte}}{{#monthly_revenue_lte}},"lte": {{monthly_revenue_lte}}{{/monthly_revenue_lte}}}}}
                        ]
                      }
                    }
                  }
                }
              ],
              "rank_window_size": 100,
              "rank_constant": 20
            }
          }
        }`,
      },
    });<p>Regardez les requêtes détaillées dans le fichier <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch/elasticsearchSetup.ts#L119"><code>elasticsearchSetup.ts</code></a> . Dans le node suivant, il sera décidé laquelle des deux requêtes sera utilisée :</p>// Node 1: Decide search strategy using LLM
async function decideSearchStrategy(state: typeof VCState.State) {
  // Zod schema for specialized search strategy decision
  const SearchDecisionSchema = z.object({
    search_type: z
      .enum(["investment_focused", "market_focused"])
      .describe("Type of specialized search strategy to use"),
    reasoning: z
      .string()
      .describe("Brief explanation of why this search strategy was chosen"),
  });

  const decisionLLM = llm.withStructuredOutput(SearchDecisionSchema);

  // Get dynamic filters from Elasticsearch
  const availableFilters = await getAvailableFilters();

  const prompt = `Query: "${state.input}"
    Available filters: ${JSON.stringify(availableFilters, null, 2)}

    Choose between two specialized search strategies:
    
    - investment_focused: For queries about funding stages, funding amounts, monthly revenue, lead investors, financial performance
    
    - market_focused: For queries about industries, locations, business models, market segments, geographic markets
    
    Analyze the query intent and choose the most appropriate strategy.
  `;

  try {
    const result = await decisionLLM.invoke(prompt);
    console.log(
      `🤔 Search strategy: ${result.search_type} - ${result.reasoning}`
    );

    return {
      searchStrategy: result.search_type,
    };
  } catch (error: any) {
    console.error("❌ Error in decideSearchStrategy:", error.message);
    return {
      searchStrategy: "investment_focused",
    };
  }
}<h3>Nodes prepareInvestmentSearch et prepareMarketSearch</h3><p>Les deux nœuds utilisent une fonction d’assistance partagée, <code>extractFilterValues</code>, qui exploite le LLM pour identifier les filtres pertinents mentionnés dans les entrées de l’utilisateur, tels que l’industrie, la localisation, le stade de financement, le modèle économique, etc. Nous utilisons ce schéma pour construire notre <a href="https://www.elastic.co/docs/solutions/search/search-templates">modèle de recherche</a>.</p>// Extract all possible filter values from user input
async function extractFilterValues(input: string) {
  const FilterValuesSchema = z.object({
    // Investment-focused filters
    funding_stage: z
      .array(z.string())
      .default([])
      .describe("Funding stage values mentioned in query"),
    funding_amount_gte: z
      .number()
      .default(0)
      .describe("Minimum funding amount in USD"),
    funding_amount_lte: z
      .number()
      .default(100000000)
      .describe("Maximum funding amount in USD"),
    lead_investor: z
      .array(z.string())
      .default([])
      .describe("Lead investor values mentioned in query"),
    monthly_revenue_gte: z
      .number()
      .default(0)
      .describe("Minimum monthly revenue in USD"),
    monthly_revenue_lte: z
      .number()
      .default(10000000)
      .describe("Maximum monthly revenue in USD"),
    industry: z
      .array(z.string())
      .default([])
      .describe("Industry values mentioned in query"),
    location: z
      .array(z.string())
      .default([])
      .describe("Location values mentioned in query"),
    business_model: z
      .array(z.string())
      .default([])
      .describe("Business model values mentioned in query"),
  });

  const extractorLLM = llm.withStructuredOutput(FilterValuesSchema);
  const availableFilters = await getAvailableFilters();

  const extractPrompt = `Extract ALL relevant filter values from: "${input}"
    Available options: ${JSON.stringify(availableFilters, null, 2)}
    Extract only values explicitly mentioned in the query. Leave fields empty if not mentioned.`;

  return await extractorLLM.invoke(extractPrompt);
}<p>Selon l'intention détectée, le workflow sélectionne l'un des deux chemins :</p><p><strong>prepareInvestmentSearch :</strong> définit des paramètres de rechercher orientés sur la finance, notamment l''étape du financement, le montant du financement, les informations relatives à l''investisseur et au renouvellement. Vous pouvez trouver le modèle complet de requête dans le fichier <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch/elasticsearchSetup.ts"><code>elasticsearchSetup.ts</code></a> :</p>// Node 2A: Prepare Investment-Focused Search Parameters 
async function prepareInvestmentSearch(state: typeof VCState.State) {
  console.log(
    "💰 Preparing INVESTMENT-FOCUSED search parameters with financial emphasis..."
  );

  try {
    // Extract all filter values from input
    const values = await extractFilterValues(state.input);

    let searchParams: any = {
      template_id: INVESTMENT_FOCUSED_TEMPLATE,
      query_text: state.input,
      ...values,
    };

    return { searchParams };
  } catch (error) {
    console.error("❌ Error preparing investment-focused params:", error);
    return {
      searchParams: {},
    };
  }
}<p><strong>prepareMarketSearch :</strong> crée des paramètres orientés vers le marché, axés sur les industries, les régions géographiques et les modèles économiques. Voir l’intégralité de la requête dans le fichier <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/langgraph-js-elasticsearch/elasticsearchSetup.ts"><code>elasticsearchSetup.ts</code></a> :</p>// Node 2B: Prepare Market-Focused Search Parameters
async function prepareMarketSearch(state: typeof VCState.State) {
  console.log(
    "🔍 Preparing MARKET-FOCUSED search parameters with market emphasis..."
  );

  try {
    // Extract all filter values from input
    const values = await extractFilterValues(state.input);

    let searchParams: any = {
      template_id: MARKET_FOCUSED_TEMPLATE,
      query_text: state.input,
      ...values,
    };

    return { searchParams };
  } catch (error) {
    console.error("❌ Error preparing market-focused params:", error);
    return {};
  }
}<h3>Node executeSearch</h3><p>Ce node prend les paramètres de rechercher générés à partir de l'état et les envoie d'abord à Elasticsearch, en utilisant l'<a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-render-search-template">API _render</a> pour visualiser la requête à des fins de débogage, puis envoie une demande pour récupérer les résultats.</p>// Node 3: Execute Search
async function executeSearch(state: typeof VCState.State) {
  const { searchParams } = state;

  try {
    // getting formed query from template for debugging
    const renderedTemplate = await esClient.renderSearchTemplate({
      id: searchParams.template_id,
      params: searchParams,
    });

    console.log(
      "📋 Complete query:",
      JSON.stringify(renderedTemplate.template_output, null, 2)
    );

    const results = await esClient.searchTemplate({
      index: INDEX_NAME,
      id: searchParams.template_id,
      params: searchParams,
    });

    return {
      results: results.hits.hits.map((hit: any) =&gt; hit._source),
    };
  } catch (error: any) {
    console.error(`❌ ${state.searchParams.search_type} search error:`, error);
    return { results: [] };
  }
}<h3>Node visualizeResults</h3><p>Enfin, ce node affiche les résultats d’Elasticsearch.</p>// Node 4: Visualize results
async function visualizeResults(state: typeof VCState.State) {
  const results = state.results || [];

  let formattedResults = `🎯 Found ${results.length} startups matching your criteria:\n\n`;

  results.forEach((startup: any, index: number) =&gt; {
    formattedResults += `${index + 1}. **${startup.company_name}**\n`;
    formattedResults += `   📍 ${startup.location} | 🏢 ${startup.industry} | 💼 ${startup.business_model}\n`;
    formattedResults += `   💰 ${startup.funding_stage} - $${(
      startup.funding_amount / 1000000
    ).toFixed(1)}M\n`;
    formattedResults += `   👥 ${startup.employee_count} employees | 📈 $${(
      startup.monthly_revenue / 1000
    ).toFixed(0)}K MRR\n`;
    formattedResults += `   🏦 Lead: ${startup.lead_investor}\n`;
    formattedResults += `   📝 ${startup.description}\n\n`;
  });

  return {
    final: formattedResults,
  };
}<p>Par programmation, l'ensemble du graphe ressemble à ceci :</p>  const workflow = new StateGraph(VCState)
    // Register nodes - these are the processing functions
    .addNode("decideStrategy", decideSearchStrategy)
    .addNode("prepareInvestment", prepareInvestmentSearch)
    .addNode("prepareMarket", prepareMarketSearch)
    .addNode("executeSearch", executeSearch)
    .addNode("visualizeResults", visualizeResults)
    // Define execution flow with conditional branching
    .addEdge(START, "decideStrategy") // Start with strategy decision
    .addConditionalEdges(
      "decideStrategy",
      (state: typeof VCState.State) =&gt; state.searchStrategy, // Conditional function
      {
        investment_focused: "prepareInvestment", // If investment focused -&gt; RRF template preparation
        market_focused: "prepareMarket", // If market focused -&gt; dynamic query preparation
      }
    )
    .addEdge("prepareInvestment", "executeSearch") // Investment prep -&gt; execute
    .addEdge("prepareMarket", "executeSearch") // Market prep -&gt; execute
    .addEdge("executeSearch", "visualizeResults") // Execute -&gt; visualize
    .addEdge("visualizeResults", END); // End workflow<p>Comme vous pouvez le constater, nous avons une arête conditionnelle où l'application décide quel « chemin » ou node sera exécuté ensuite. Cette fonctionnalité est utile lorsque les workflows nécessitent une logique de branchement, comme le choix entre plusieurs outils ou l’inclusion d’une étape humaine dans la boucle.</p><p>Maintenant que vous maîtrisez les fonctionnalités clés de LangGraph, nous pouvons préparer l’application qui exécutera le code :</p><p>Rassemblons tout dans une méthode <code>main</code> , ici nous déclarons le graphe avec tous les éléments sous la variable workflow :</p>async function main() {
  await createIndex();
  await createSearchTemplates();
  await ingestDocuments();

  // Create the workflow graph with shared state
  const workflow = new StateGraph(VCState)
    // Register nodes - these are the processing functions
    .addNode("decideStrategy", decideSearchStrategy)
    .addNode("prepareInvestment", prepareInvestmentSearch)
    .addNode("prepareMarket", prepareMarketSearch)
    .addNode("executeSearch", executeSearch)
    .addNode("visualizeResults", visualizeResults)
    // Define execution flow with conditional branching
    .addEdge(START, "decideStrategy") // Start with strategy decision
    .addConditionalEdges(
      "decideStrategy",
      (state: typeof VCState.State) =&gt; state.searchStrategy, // Conditional function
      {
        investment_focused: "prepareInvestment", // If investment focused -&gt; RRF template preparation
        market_focused: "prepareMarket", // If market focused -&gt; dynamic query preparation
      }
    )
    .addEdge("prepareInvestment", "executeSearch") // Investment prep -&gt; execute
    .addEdge("prepareMarket", "executeSearch") // Market prep -&gt; execute
    .addEdge("executeSearch", "visualizeResults") // Execute -&gt; visualize
    .addEdge("visualizeResults", END); // End workflow


  const app = workflow.compile();

  await saveGraphImage(app);

  const query =
    "Find startups with Series A or Series B funding between $8M-$25M and monthly revenue above $500K";

  const marketResult = await app.invoke({ input: query });
  console.log(marketResult.final);
}<p>La variable de requête simule l'entrée utilisateur saisie dans une barre de recherche hypothétique :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba7189d5f4e63403/6a1709880e2e49cc3041a076/e8d76909eb2bc1bb62f3ca9a8b3e4b85fcec2893-1600x164.png" alt="" /><p>D’après la phrase en langage naturel « Trouvez des startups avec un financement de la série A ou de la série B entre 8 millions et 25 millions de dollars et un chiffre d’affaires mensuel supérieur à 500 000 $ », tous les filtres seront extraits.</p><p>Enfin, invoquez la méthode principale :</p>main().catch(console.error);<h3>Résultats</h3>🔍 Checking if index exists...
🏗️ Creating index...
✅ Index created successfully!
Ingesting documents...
✅ Documents ingested successfully!
✅ Investment-focused template created successfully!
✅ Market-focused template created successfully!

📊 Workflow graph saved as: ./workflow_graph.png

🔍 Query: "Find startups with Series A or Series B funding between $8M-$25M and monthly revenue above $500K"

🤔 Search strategy: investment_focused - The query specifically seeks profitable fintech startups with defined funding amounts and high monthly revenue, which aligns closely with financial performance metrics and investment-related criteria.

💰 Preparing INVESTMENT-FOCUSED search parameters with financial emphasis...

📋 Complete query: {
  "size": 5,
  "retriever": {
    "rrf": {
      "retrievers": [
        {
          "standard": {
            "query": {
              "semantic": {
                "field": "semantic_field",
                "query": "Find startups with Series A or Series B funding between $8M-$25M and monthly revenue above $500K"
              }
            }
          }
        },
        {
          "standard": {
            "query": {
              "bool": {
                "filter": [
                  {
                    "terms": {
                      "funding_stage": [
                        "Series A",
                        "Series B"
                      ]
                    }
                  },
                  {
                    "range": {
                      "funding_amount": {
                        "gte": 8000000,
                        "lte": 25000000
                      }
                    }
                  },
                  {
                    "terms": {
                      "lead_investor": []
                    }
                  },
                  {
                    "range": {
                      "monthly_revenue": {
                        "gte": 500000,
                        "lte": 0
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      ],
      "rank_window_size": 100,
      "rank_constant": 20
    }
  }
}
🎯 Found 5 startups matching your criteria:

1. **TechFlow**
   📍 San Francisco, CA | 🏢 logistics | 💼 B2B
   💰 Series A - $8.0M
   👥 45 employees | 📈 $500K MRR
   🏦 Lead: Sequoia Capital
   📝 TechFlow optimizes supply chain operations using AI-powered route optimization and real-time tracking. Founded in 2023, shows remarkable growth with $500K monthly revenue.

2. **DataViz**
   📍 New York, NY | 🏢 enterprise software | 💼 B2B
   💰 Series A - $10.0M
   👥 42 employees | 📈 $450K MRR
   🏦 Lead: Battery Ventures
   📝 DataViz creates intuitive data visualization tools for enterprise customers. No-code platform allows business users to create dashboards without technical expertise.

3. **FinanceAI**
   📍 San Francisco, CA | 🏢 fintech | 💼 B2C
   💰 Series C - $25.0M
   👥 120 employees | 📈 $1200K MRR
   🏦 Lead: Tiger Global Management
   📝 FinanceAI provides AI-powered investment advisory services to retail investors. Uses machine learning to analyze market trends with over 100,000 active users.

4. **UrbanMobility**
   📍 New York, NY | 🏢 logistics | 💼 B2B2C
   💰 Series B - $15.0M
   👥 78 employees | 📈 $750K MRR
   🏦 Lead: Kleiner Perkins
   📝 UrbanMobility revolutionizes urban transportation through autonomous delivery drones and smart logistics hubs. Partners with major retailers for same-day delivery across Manhattan and Brooklyn.

5. **HealthTech Solutions**
   📍 Boston, MA | 🏢 healthcare | 💼 B2B
   💰 Series B - $18.0M
   👥 95 employees | 📈 $900K MRR
   🏦 Lead: General Catalyst
   📝 HealthTech Solutions develops medical devices and software for remote patient monitoring. Comprehensive telehealth platform reducing hospital readmissions by 30%.

✨  Done in 18.80s.<p>Pour l'entrée envoyée, l'application choisit le chemin <strong>axé sur l'investissement</strong> et, par conséquent, nous pouvons voir la requête Elasticsearch générée par le workflow, qui extrait les valeurs et les plages de l'entrée de l'utilisateur. Nous pouvons également voir la requête envoyée à Elasticsearch avec les valeurs extraites appliquées, et enfin, les résultats formatés par le nœud <code>visualizeResults</code> avec les résultats.</p><p>Testons maintenant le node <strong>axé sur le marché</strong> en utilisant la requête « Trouver des startups fintech et de la santé à San Francisco, New York ou Boston » :</p>...

🔍 Query: Find fintech and healthcare startups in San Francisco, New York, or Boston

🤔 Search strategy: market_focused - The query is focused on finding fintech startups in San Francisco that are disrupting traditional banking and payment systems, which pertains to specific industries (fintech) and locations (San Francisco). Thus, a market-focused strategy is more appropriate.

🔍 Preparing MARKET-FOCUSED search parameters with market emphasis...

📋 Complete query: {
  "size": 5,
  "retriever": {
    "rrf": {
      "retrievers": [
        {
          "standard": {
            "query": {
              "semantic": {
                "field": "semantic_field",
                "query": "Find fintech and healthcare startups in San Francisco, New York, or Boston"
              }
            }
          }
        },
        {
          "standard": {
            "query": {
              "bool": {
                "filter": [
                  {
                    "terms": {
                      "industry": [
                        "fintech",
                        "healthcare"
                      ]
                    }
                  },
                  {
                    "terms": {
                      "location": [
                        "San Francisco, CA",
                        "New York, NY",
                        "Boston, MA"
                      ]
                    }
                  },
                  {
                    "terms": {
                      "business_model": []
                    }
                  }
                ]
              }
            }
          }
        }
      ],
      "rank_window_size": 50,
      "rank_constant": 10
    }
  }
}
🎯 Found 5 startups matching your criteria:

1. **FinanceAI**
   📍 San Francisco, CA | 🏢 fintech | 💼 B2C
   💰 Series C - $25.0M
   👥 120 employees | 📈 $1200K MRR
   🏦 Lead: Tiger Global Management
   📝 FinanceAI provides AI-powered investment advisory services to retail investors. Uses machine learning to analyze market trends with over 100,000 active users.

2. **CryptoWallet**
   📍 Miami, FL | 🏢 fintech | 💼 B2C
   💰 Series B - $16.0M
   👥 73 employees | 📈 $820K MRR
   🏦 Lead: Coinbase Ventures
   📝 CryptoWallet provides secure digital wallet solutions for cryptocurrency trading and storage. Multi-chain support with enterprise-grade security features.

...

✨  Done in 7.41s.<h2>Enseignements</h2><p>Pendant le processus d'écriture, j'ai appris :</p><ul><li><p>Nous devons montrer au LLM les valeurs exactes des filtres, sinon nous attendons de l'utilisateur qu'il saisisse les valeurs exactes des éléments. Pour une faible cardinalité, cette approche convient, mais lorsque la cardinalité est élevée, nous avons besoin d'un mécanisme pour filtrer les résultats</p></li><li><p>Utiliser des modèles de recherche rend les résultats bien plus cohérents que de laisser le LLM écrire la requête Elasticsearch, et c’est aussi plus rapide</p></li><li><p>Les arêtes conditionnelles constituent un mécanisme puissant pour construire des applications avec de multiples variantes et chemins de branchement.</p></li><li><p>La sortie structurée est extrêmement utile lors de la génération d'informations avec des LLM, car elle applique des réponses prévisibles et sécurisées. Cela améliore la fiabilité et réduit les erreurs d'interprétation.</p></li></ul><p>La combinaison de la recherche sémantique et de la recherche structurée par le biais d'une recherche hybride produit des résultats meilleurs et plus pertinents, en équilibrant précision et compréhension du contexte.</p><h2>Conclusion</h2><p>Dans cet exemple, nous combinons LangGraph.js avec Elasticsearch pour créer un workflow dynamique capable d'interpréter les requêtes en langage naturel et de décider entre des stratégies de recherche axées sur la finance ou le marché. Cette approche réduit la complexité de la création de requêtes manuelles tout en améliorant la flexibilité et la précision pour les analystes en capital-risque.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agent-workflow-finance-langgraph-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agent-workflow-finance-langgraph-elasticsearch</guid>
    <category><![CDATA[IA]]></category>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Jeffrey Rengifo]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt013eba5d152f11f3/6a1709892b835f6784f4b1a6/12b6057d84c6356267cd178a3c6c1a5c61123ece-2000x1256.png" length="0" type="image/png"/>
    <pubDate>Fri, 05 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Créer un connecteur ChatGPT avec Elasticsearch pour interroger les issues GitHub]]></title>
    <description><![CDATA[Découvrez comment créer un connecteur ChatGPT personnalisé et déployer un serveur MCP Elasticsearch qui utilise la rechercher hybride pour interroger les issues GitHub internes.]]></description>
    <content:encoded><![CDATA[<p>OpenAI a récemment annoncé la fonctionnalité <a href="https://help.openai.com/en/articles/11487775-connectors-in-chatgpt">connecteurs personnalisés</a> pour ChatGPT sur les plans Pro/Business/Entreprise et Edu. En plus des connecteurs prêts à l'emploi pour accéder aux données sur Gmail, GitHub, Dropbox, etc., il est possible de créer des connecteurs personnalisés en utilisant des serveurs MCP.</p><p>Les connecteurs personnalisés vous donnent la possibilité de combiner vos connecteurs ChatGPT existants avec des sources de données supplémentaires comme Elasticsearch pour obtenir des réponses complètes.</p><p>Dans cet article, nous allons créer un serveur <a href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a> qui connecte ChatGPT à un index Elasticsearch contenant des informations sur les issues GitHub internes et les requêtes pull. Cela permet de répondre aux requêtes en langage naturel en utilisant vos données Elasticsearch.</p><p>Nous déploierons le serveur MCP en utilisant <a href="https://gofastmcp.com/getting-started/welcome">FastMCP</a> sur Google Colab avec ngrok pour obtenir une URL publique à laquelle ChatGPT peut se connecter, éliminant ainsi le besoin d'une configuration complexe de l'infrastructure.</p><p>Pour un aperçu complet de MCP et de son écosystème, reportez-vous à la section <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">État actuel du MCP</a>.</p><h2>Prérequis</h2><p>Avant de commencer, vous aurez besoin des éléments suivants :</p><ul><li><p>Cluster Elasticsearch (8.X ou supérieur)</p></li><li><p>Clé API Elasticsearch avec accès en lecture à votre index</p></li><li><p>Compte Google (pour Google Colab)</p></li><li><p>Compte ngrok (fonctionne avec le niveau gratuit)</p></li><li><p>Compte ChatGPT avec un forfait Pro/Entreprise/Business ou Edu</p></li></ul><h2>Comprendre les exigences du connecteur ChatGPT MCP</h2><p>Les connecteurs ChatGPT MCP nécessitent l'implémentation de deux outils : <code>search</code> et <code>fetch</code>. Pour plus de détails, consultez <a href="https://platform.openai.com/docs/mcp#create-an-mcp-server">OpenAI Docs</a>.</p><h3><a href="https://platform.openai.com/docs/mcp#search-tool">Outil de recherche</a></h3><p>Renvoie une liste de résultats pertinents depuis votre index Elasticsearch en fonction d'une requête utilisateur.</p><h4>Ce qu'il reçoit :</h4><ul><li><p>Une chaîne unique contenant la requête en langage naturel de l'utilisateur.</p></li><li><p>Exemple : "Recherchez les issues liées à la migration d'Elasticsearch."</p></li></ul><h4>Ce qu'il renvoie : </h4><ul><li><p>Un objet avec une clé <code>result</code> contenant un tableau d'objets de résultats. Chaque résultat inclut :</p><ul><li><p><code>id</code> - Identifiant de document unique</p></li><li><p><code>title</code> - Titre de l'issue ou de la PR</p></li><li><p><code>url</code> - Lien vers l'issue/la PR</p></li></ul></li></ul><h4>Dans notre implémentation :</h4>return {
    "results": [
        {
            "id": "PR-612",
            "title": "Fix memory leak in WebSocket notification service",
            "url": "https://internal-git.techcorp.com/pulls/612"
        },
        # ... more results
    ]
}<h3><a href="https://platform.openai.com/docs/mcp#fetch-tool">Outil de récupération</a></h3><p>Récupère le contenu complet d'un document spécifique.</p><h4>Ce qu'il reçoit :</h4><ul><li><p>Chaîne unique contenant l'ID du document Elasticsearch extrait du résultat de la recherche</p></li><li><p>Exemple : "Donnez-moi les détails de la PR-578."</p></li></ul><h4>Ce qu'il renvoie :</h4><ul><li><p>Objet de document complet contenant :</p><ul><li><p><code>id</code> - Identifiant de document unique</p></li><li><p><code>title</code> - Titre de l'issue ou de la PR</p></li><li><p><code>text</code> - Description complète du problème/PR et détails</p></li><li><p><code>url</code> - Lien vers l'issue/la PR</p></li><li><p><code>type</code> - Type de document (issue, pull_request)</p></li><li><p><code>status</code> - Statut actuel (ouvert, en cours, résolu)</p></li><li><p><code>priority</code> - Niveau de priorité (faible, moyen, élevé, critique)</p></li><li><p><code>assignee</code> - Personne en charge de l'issue/la PR</p></li><li><p><code>created_date</code> - Date de création</p></li><li><p><code>resolved_date</code> - Date de résolution (le cas échéant)</p></li><li><p><code>labels</code> - Balises associées au document</p></li><li><p><code>related_pr</code> - ID de la requête pull associée</p></li></ul></li></ul>return {
    "id": "PR-578",
    "title": "Security hotfix: Patch SQL injection vulnerabilities",
    "text": "Description: CRITICAL SECURITY FIX for ISSUE-1889. Patches SQL...",
    "url": "https://internal-git.techcorp.com/pulls/578",
    "type": "pull_request",
    "status": "closed",
    "priority": "critical",
    "assignee": "sarah_dev",
    "created_date": "2025-09-19",
    "resolved_date": "2025-09-19",
    "labels": "security, hotfix, sql",
    "related_pr": null
}<p><strong>Remarque</strong> : Cet exemple utilise une structure plate où tous les champs se trouvent au niveau racine. Les exigences d'OpenAI sont flexibles et prennent également en charge les objets de métadonnées imbriqués.</p><h2>Issues GitHub et ensemble de données de PR</h2><p>Pour ce tutoriel, nous allons utiliser un ensemble de données interne de GitHub contenant des issues et des requêtes pull. Ceci représente un scénario dans lequel vous souhaitez interroger des données privées et internes via ChatGPT.</p><p>L'ensemble de données est accessible <a href="https://gist.github.com/TomasMurua/4e7bbdf7a7ebbdffaa663c43578d934a">ici</a>. Et nous mettrons à jour l'index des données à l'aide de l'<a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk">API Bulk</a>.</p><p>Cet ensemble de données comprend :</p><ul><li><p>Issues avec description, état, niveau de priorité et personnes en charge</p></li><li><p>Requêtes pull avec modifications de code, révisions et informations de déploiement</p></li><li><p>Relations entre les issues et les PR (p. ex., la PR-578 corrige l'ISSUE-1889)</p></li><li><p>Étiquettes, dates et autres métadonnées</p></li></ul><h3>Mappings de l'index</h3><p>L'index utilise les <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">mappings</a> suivants pour prendre en charge la recherche hybride avec <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-elser">ELSER</a>. Le champ <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">text_semantic</a> est utilisé pour la recherche sémantique, tandis que les autres champs permettent la recherche par mot-clé.</p>{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text"
      },
      "text": {
        "type": "text"
      },
      "text_semantic": {
        "type": "semantic_text",
        "inference_id": ".elser-2-elasticsearch"
      },
      "url": {
        "type": "keyword"
      },
      "type": {
        "type": "keyword"
      },
      "status": {
        "type": "keyword"
      },
      "priority": {
        "type": "keyword"
      },
      "assignee": {
        "type": "keyword"
      },
      "created_date": {
        "type": "date",
        "format": "iso8601"
      },
      "resolved_date": {
        "type": "date",
        "format": "iso8601"
      },
      "labels": {
        "type": "keyword"
      },
      "related_pr": {
        "type": "keyword"
      }
    }
  }
}<h2>Créer le serveur MCP</h2><p>Notre serveur MCP implémente deux outils conformes aux spécifications d'OpenAI qui utilisent la recherche hybride pour combiner la sémantique et la correspondance de texte pour de meilleurs résultats.</p><h3>Outil de recherche</h3><p>Utilise la recherche hybride avec <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">RRF</a> (fusion des rangs réciproques) qui combine la recherche sémantique avec la correspondance de texte :</p>@mcp.tool()
    async def search(query: str) -&gt; Dict[str, List[Dict[str, Any]]]:
        """
        Search for internal issues and PRs using hybrid search (semantic + text with RRF).
        Returns list with id, title, and url per OpenAI spec.
        """
        if not query or not query.strip():
            return {"results": []}

        logger.info(f"Searching for: '{query}'")

        try:
            # Hybrid search with RRF (Reciprocal Rank Fusion)
            response = es_client.search(
                index=ELASTICSEARCH_INDEX,
                size=10,
                source=["id", "title", "url", "type", "priority"],
                retriever={
                    "rrf": {
                        "retrievers": [
                            {
                                # Semantic search with ELSER
                                "standard": {
                                    "query": {
                                        "semantic": {
                                            "field": "text_semantic",
                                            "query": query
                                        }
                                    }
                                }
                            },
                            {
                                # Text search (BM25) for keyword matching
                                "standard": {
                                    "query": {
                                        "multi_match": {
                                            "query": query,
                                            "fields": [
                                                "title^3",
                                                "text^2",
                                                "assignee^2",
                                                "type",
                                                "labels",
                                                "priority"
                                            ],
                                            "type": "best_fields",
                                            "fuzziness": "AUTO"
                                        }
                                    }
                                }
                            }
                        ],
                        "rank_window_size": 50,
                        "rank_constant": 60
                    }
                }
            )

            results = []
            if response and 'hits' in response:
                for hit in response['hits']['hits']:
                    source = hit['_source']
                    results.append({
                        "id": source.get('id', hit['_id']),
                        "title": source.get('title', 'Unknown'),
                        "url": source.get('url', '')
                    })

            logger.info(f"Found {len(results)} results")
            return {"results": results}

        except Exception as e:
            logger.error(f"Search error: {e}")
            raise ValueError(f"Search failed: {str(e)}")<h3>Points clés :</h3><ul><li><p><strong>Recherche hybride avec RRF</strong> : combine la recherche sémantique (ELSER) et la recherche de texte (BM25) pour de meilleurs résultats.</p></li><li><p><strong>Requête à correspondance multiple</strong> : <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-multi-match-query">Recherches sur plusieurs champs</a> avec boosting (title^3, text^2, assignee^2). Le symbole caret (^) multiplie les scores de pertinence, en privilégiant les correspondances dans les titres plutôt que dans le contenu.</p></li><li><p><strong>Fuzzy matching (correspondance approximative)</strong> : <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/common-options#fuzziness"><code>fuzziness: AUTO</code></a> gère les fautes de frappe et d'orthographe en autorisant les correspondances approximatives.</p></li><li><p><strong>Ajustement des paramètres RRF :</strong></p><ul><li><p><code>rank_window_size: 50</code> - Spécifie le nombre de résultats principaux de chaque récupérateur (sémantique et texte) pris en compte avant la fusion.</p></li><li><p><code>rank_constant: 60</code> - Cette valeur détermine l'influence des documents dans chaque ensemble de résultats sur le classement final.</p></li></ul></li><li><p><strong>Ne renvoie que les champs obligatoires</strong> : <code>id</code>, <code>title</code>, <code>url</code> conformément à la spécification d'OpenAI, et évite d'exposer inutilement des champs supplémentaires.</p></li></ul><h3>Outil de récupération</h3><p>Récupère les détails du document par ID de document, s'il existe :</p>@mcp.tool()
    async def fetch(id: str) -&gt; Dict[str, Any]:
        """
        Retrieve complete issue/PR details by ID.
        Returns id, title, text, url.
        """
        if not id:
            raise ValueError("ID is required")

        logger.info(f"Fetching: {id}")

        try:
            # Search by the 'id' field (not _id) since IDs are stored as a field
            response = es_client.search(
                index=ELASTICSEARCH_INDEX,
                body={
                    "query": {
                        "term": {
                            "id": id  # Search by your custom 'id' field
                        }
                    },
                    "size": 1
                }
            )

            if not response or not response['hits']['hits']:
                raise ValueError(f"Document with id '{id}' not found")

            hit = response['hits']['hits'][0]
            source = hit['_source']

            result = {
                "id": source.get('id', id),
                "title": source.get('title', 'Unknown'),
                "text": source.get('text', ''),
                "url": source.get('url', ''),
                "type": source.get('type', ''),
                "status": source.get('status', ''),
                "priority": source.get('priority', ''),
                "assignee": source.get('assignee', ''),
                "created_date": source.get('created_date', ''),
                "resolved_date": source.get('resolved_date', ''),
                "labels": source.get('labels', ''),
                "related_pr": source.get('related_pr', '')
            }

            logger.info(f"Fetched: {result['title']}")
            return result

        except Exception as e:
            logger.error(f"Fetch error: {e}")
            raise ValueError(f"Failed to fetch '{id}': {str(e)}")<h3>Points clés :</h3><ul><li><p><strong>Recherche par champ d'ID de document</strong> : utilise une requête de terme sur le champ personnalisé <code>id</code></p></li><li><p><strong>Renvoie le document complet</strong> : inclut le champ complet <code>text</code> avec tout le contenu</p></li><li><p><strong>Structure plate</strong> : tous les champs au niveau racine, correspondant à la structure de document d'Elasticsearch.</p></li></ul><h2>Déployer sur Google Colab</h2><p>Nous utiliserons Google Colab pour exécuter notre serveur MCP et ngrok pour l'exposer publiquement afin que ChatGPT puisse s'y connecter.</p><h3>Étape 1 : Ouvrir le notebook Google Colab</h3><p>Accédez à notre notebook préconfiguré <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-chatgpt-connector">Elasticsearch MCP pour ChatGPT</a>.</p><h3>Étape 2 : Configurer vos identifiants</h3><p>Vous aurez besoin de trois informations :</p><ul><li><p><strong>URL Elasticsearch</strong> : l'<a href="https://www.elastic.co/docs/deploy-manage/deploy/cloud-enterprise/connect-elasticsearch">URL de votre cluster Elasticsearch</a>.</p></li><li><p><strong>Clé API Elasticsearch</strong> : <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">clé API</a> avec accès en lecture à votre index.</p></li><li><p><strong>Jeton d'authentification ngrok</strong> : jeton gratuit fourni par <a href="https://ngrok.com/">ngrok</a>. Nous utiliserons ngrok pour exposer l'URL du MCP à l'Internet afin que ChatGPT puisse s'y connecter.</p></li></ul><h4>Obtenir votre token ngrok</h4><ol><li><p>Créez un compte gratuit sur <a href="https://ngrok.com/">ngrok</a></p></li><li><p>Accédez à votre <a href="https://dashboard.ngrok.com/">tableau de bord ngrok</a></p></li><li><p>Copier votre jeton d'authentification</p></li></ol><h4>Ajouter des secrets à Google Colab</h4><p>Dans le notebook Google Colab :</p><ol><li><p>Cliquez sur l'<strong>icône clé</strong> dans la barre latérale gauche pour ouvrir <strong>Secrets</strong>.</p></li><li><p>Ajoutez ces trois secrets :</p></li></ol>ELASTICSEARCH_URL=https://your-cluster.elastic.com:443
ELASTICSEARCH_API_KEY=your-api-key
NGROK_TOKEN=your-ngrok-token<p>3. Activer l'accès aux notebooks pour chaque secret</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5acae97b386277f8/6a17f08f5ea30f74c964b6c2/d5dd6ac19fe816a562c6351fdb0f11369da0e877-609x321.jpg" alt="Ajouter des secrets à Google Colab" /><h3>Étape 3 : Exécuter le notebook</h3><ol><li><p>Cliquez sur <strong>Runtime</strong> (Exécution) puis sur <strong>Run all</strong> (Tout exécuter) pour exécuter toutes les cellules</p></li><li><p>Attendez que le serveur démarre (environ 30 secondes)</p></li><li><p>Recherchez l'URL publique de ngrok dans la sortie</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdd11aacf2deab67c/6a17f091e8fbce81f13a1a41/f185100e8869624bc9e1c7b2b4eb32785e2d89e7-1189x283.png" alt="" /><p>4. La sortie affichera quelque chose comme :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8891d917fdbaaf48/6a17f092abe0f208c7dfeaf6/e02e625e91ed9136454e4401b184575fb03a336e-1052x465.jpg" alt="La sortie de l'exécution d'un notebook dans Google Colab" /><h2>Se connecter à ChatGPT</h2><p>Nous allons maintenant connecter le serveur MCP à votre compte ChatGPT.</p><ol><li><p>Ouvrez ChatGPT et accédez aux <strong>Paramètres</strong>.</p></li><li><p>Accédez à <strong>Connectors</strong> (Connecteurs).Si vous utilisez un compte Pro, vous devez activer le <a href="https://platform.openai.com/docs/guides/developer-mode">mode développeur</a> dans les connecteurs.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt95efdcb2c39307e7/6a17f094abe0f24d8edfeafa/32c02192912fc0e7e5a52e9399077ba7ae3b4901-739x715.png" alt="Connexion du serveur MPC à un compte ChatGPT" /><p><em>Si vous utilisez ChatGPT Enterprise ou Business, vous devez publier le connecteur sur votre espace de travail.</em></p><p>3. Cliquez sur <strong>Create</strong> (Créer).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4c8fc8dd6033918/6a17f095631730de19585b7b/15c53e5ccc381108a9dc0052cca05bf0fc97679a-755x683.png" alt="Ajouter un connecteur à ChatGPT" /><p><em><strong>Remarque</strong></em><em> : Dans les espaces de travail Business, Entreprise et Edu, seuls les propriétaires, les administrateurs et les utilisateurs ayant activé l'option correspondante (pour Entreprise/Edu) peuvent ajouter des connecteurs personnalisés. Les utilisateurs ayant un rôle de membre standard ne peuvent pas ajouter de connecteurs personnalisés eux-mêmes.</em></p><p><em>Une fois qu'un connecteur est ajouté et activé par un propriétaire ou un utilisateur administrateur, il devient accessible à tous les membres de l'espace de travail.</em></p><p>4. Saisissez les informations requises et votre URL ngrok se terminant par <code>/sse/</code>. Notez le "/" après "sse". Cela ne fonctionnera pas sans cet élément :</p><ul><li><p><strong>Nom :</strong> Elasticsearch MCP</p></li><li><p><strong>Description</strong> : MCP personnalisé pour la recherche et la récupération d'informations GitHub internes.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd716ad0beeeb1d35/6a17f09714d90c11cc79b6d7/162a85705cc8ac48a3f2f665551d513e0719f93d-479x684.png" alt="Créer un connecteur MCP Elastic " /><p>5. Appuyez sur <strong>Créer</strong> pour enregistrer le MCP personnalisé.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857794237d7d3b5a/6a17f0983e03d729b74f2d54/97eb5fb0a32b86bfadfb35561f698616f217c049-913x629.png" alt="Sauvegarder le connecteur MCP personnalisé en cliquant sur Créer" /><p>La connexion est instantanée si votre serveur est en cours d'exécution. Aucune authentification supplémentaire n'est requise, car la clé API Elasticsearch est configurée sur votre serveur.</p><h2>Tester le serveur MCP</h2><p>Avant de poser des questions, vous devez sélectionner le connecteur que ChatGPT doit utiliser.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" alt="Sélection du connecteur que ChatGPT doit utiliser" /><h3>Prompt 1 : Recherchez les issues</h3><p>Demandez : "<strong>Recherchez les issues liées à la migration d'Elasticsearch</strong>", puis confirmez l'appel à l'outil d'action.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6c204ceacf897f61/6a17f09c9da390fb1de4657d/cfd781acbff8cd7c8095bbe29224f8b26d581f77-650x375.png" alt="Demandez à ChatGPT « Trouve les problèmes liés à la migration d'Elasticsearch » et confirmez l'appel de l'outil Actions." /><p>ChatGPT appellera l'outil <code>search</code> avec votre requête. Vous pouvez voir qu'il recherche des outils disponibles et se prépare à appeler l'outil Elasticsearch, et confirme auprès de l'utilisateur avant de prendre toute action sur l'outil.</p><h4>Demande d'appel d'outil :</h4>{
  "query": "Elasticsearch migration issues"
}<h4>Réponse de l'outil :</h4>{
  "results": [
    {
      "id": "PR-598",
      "title": "Elasticsearch 8.x migration - Application code changes",
      "url": "https://internal-git.techcorp.com/pulls/598"
    },
    {
      "id": "ISSUE-1712",
      "title": "Migrate from Elasticsearch 7.x to 8.x",
      "url": "https://internal-git.techcorp.com/issues/1712"
    },
    {
      "id": "RFC-045",
      "title": "Design Proposal: Microservices Migration Architecture",
      "url": "https://internal-git.techcorp.com/rfcs/045"
    }
    // ... 7 more results
  ]
}<p>ChatGPT traite les résultats et les présente dans un format conversationnel naturel.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b4378e7d26b4ad0/6a17f09ddbb4ff4de1fb57bf/9d5b6cff85c7e54ccc2584b8ae96d45495fae8c1-923x1352.png" alt="Comment ChatGPT traite les résultats de la demande d'appel d'outil et de la réponse de l'outil" /><h3>En coulisses</h3><h4>Prompt : "Recherchez les issues liées à la migration d'Elasticsearch"</h4><p>1. Appels de ChatGPT <code>search(“Elasticsearch migration”)</code></p><p>2. Elasticsearch effectue une recherche hybride.</p><ul><li><p>La <strong>recherche sémantique</strong> comprend des concepts tels que "mise à niveau" et "<em>compatibilité des versions</em>".</p></li><li><p>La <strong>recherche de texte</strong> trouve des correspondances exactes pour "<em>Elasticsearch</em>" et "migration".</p></li><li><p><strong>RRF</strong> combine et classe les résultats des deux approches</p></li></ul><p>3. Renvoie les 10 événements les plus pertinents avec <code>id</code>, <code>title</code>, <code>url</code></p><p>4. ChatGPT identifie "<em>ISSUE-1712: migrate from Elasticsearch 7.x to 8.x</em>" (Migrer d'Elasticsearch 7.x vers 8.x) comme résultat le plus pertinent.</p><h3>Prompt 2 : Obtenez tous les détails</h3><p>Demandez : <em><strong>"Donnez-moi les détails de l'ISSUE-1889"</strong></em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d1a53db8bfe8326/6a17f09f445de966104d021a/5c0db5245535ce67a36056e61e135bddc97ce496-934x629.png" alt="ChatGPT comprend que vous souhaitez obtenir des informations détaillées sur un problème spécifique, appelle l'outil fetch et confirme auprès de l'utilisateur avant d'entreprendre toute action sur l'outil." /><p>ChatGPT comprend que vous souhaitez obtenir des informations détaillées sur un problème spécifique, appelle l'outil <code>fetch</code> et confirme auprès de l'utilisateur avant d'entreprendre des actions sur l'outil.</p><h4>Demande d'appel d'outil :</h4>{
  "id": "ISSUE-1889"
}<h4>Réponse de l'outil :</h4>{
  "id": "ISSUE-1889",
  "title": "SQL injection vulnerability in search endpoint",
  "text": "Description: Security audit identified SQL injection vulnerability in /api/v1/search endpoint. User input from query parameter is not properly sanitized before being used in raw SQL query. Severity: HIGH - Immediate action required Affected Code: - File: services/search/query_builder.py - Line: 145-152 - Issue: String concatenation used instead of parameterized queries Investigation: - @security_team_alice: Confirmed exploitable with UNION-based injection - @sarah_dev: Checking all other endpoints for similar patterns - @john_backend: Found 3 more instances in legacy codebase Remediation: - Rewrite using SQLAlchemy ORM or parameterized queries - Add input validation and sanitization - Implement WAF rules as additional layer - Security regression tests Comments: - @tech_lead_mike: Stop all other work, this is P0 - @sarah_dev: PR-578 ready with fixes for all 4 vulnerable endpoints - @alex_devops: Deployed hotfix to production 2025-09-19 at 14:30 UTC - @security_team_alice: Verified fix, conducting full pentest next week Resolution: All vulnerable endpoints patched. Added pre-commit hooks to catch raw SQL queries. Security training scheduled for team.",
  "url": "https://internal-git.techcorp.com/issues/1889",
  "type": "issue",
  "status": "closed",
  "priority": "critical",
  "assignee": "sarah_dev",
  "created_date": "2025-09-18",
  "resolved_date": "2025-09-19",
  "labels": "security, vulnerability, bug, sql",
  "related_pr": "PR-578"
}<p>ChatGPT synthétise les informations et les présente clairement.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt560958fa3bd212d0/6a17f0a0faa91355ba93c974/410f19f213e94fc4e3c47eeef6e04b69e0c86159-602x462.png" alt="Comment ChatGPT synthétise les informations et les présente " /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcccf35a584e8373b/6a17f0a2505ac3471cad8c2e/54d8ffa117628a1e3afc317c3ab75d4f7731d7ab-767x1600.png" alt="Comment ChatGPT présente les informations" /><h3>En coulisses</h3><h4>Prompt : "Donnez-moi les détails de l'ISSUE-1889"</h4><ol><li><p>Appels ChatGPT <code>fetch(“ISSUE-1889”)</code></p></li><li><p>Elasticsearch extrait le document complet</p></li><li><p>Retourne un document complet avec tous les champs au niveau racine</p></li><li><p>ChatGPT synthétise les informations et répond avec les citations appropriées.</p></li></ol><h2>Conclusion</h2><p>Dans cet article, nous avons créé un serveur MCP personnalisé qui connecte ChatGPT à Elasticsearch à l'aide d'outils MCP de <strong>recherche</strong> et de <strong>récupération</strong> dédiés, permettant de lancer des requêtes en langage naturel sur des données privées.</p><p>Ce modèle MCP fonctionne pour n'importe quel index Elasticsearch, documentation, produit, log ou toute autre donnée que vous souhaitez interroger en langage naturel.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/chatgpt-connector-mcp-server-github-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/chatgpt-connector-mcp-server-github-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Recherche hybride]]></category>
    <dc:creator><![CDATA[Tomás Murúa]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" length="0" type="image/gif"/>
    <pubDate>Mon, 01 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Développement d'un assistant RAG agentique utilisant LangChain et Elasticsearch]]></title>
    <description><![CDATA[Apprenez à construire un assistant de presse agentique utilisant LangChain et Elasticsearch qui répond aux requêtes sur les articles avec un routage adaptatif.]]></description>
    <content:encoded><![CDATA[<p>Cet article de blog se penche sur les flux de travail agentiques RAG, en expliquant leurs principales caractéristiques et les modèles de conception courants. Il démontre en outre comment mettre en œuvre ces flux de travail au moyen d'un exemple pratique qui utilise Elasticsearch comme magasin de vecteurs et LangChain pour construire le cadre agentique RAG. Enfin, l'article aborde brièvement les meilleures pratiques et les défis associés à la conception et à la mise en œuvre de ces architectures. Vous pouvez suivre la création d'un simple pipeline RAG agentique avec ce <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/agentic-rag/agent_rag_news_assistant.ipynb">carnet Jupyter</a>.</p><h2>Introduction au RAG agentique</h2><p>La Génération Augmentée de Récupération<a href="https://www.elastic.co/docs/solutions/search/rag">(RAG)</a> est devenue la pierre angulaire des applications basées sur le LLM, permettant aux modèles de fournir des réponses optimales en récupérant le contexte pertinent basé sur les requêtes de l'utilisateur. Les systèmes RAG améliorent la précision et le contexte des réponses LLM en s'appuyant sur des informations externes provenant d'API ou de magasins de données, au lieu d'être limités à des connaissances LLM préformées. D'autre part, les agents d'intelligence artificielle fonctionnent de manière autonome, prenant des décisions et des mesures pour atteindre les objectifs qui leur sont assignés.</p><p>Le RAG agentique est un cadre qui unifie les forces de la génération augmentée par la recherche et du raisonnement agentique. Il intègre le RAG dans le processus décisionnel de l'agent, ce qui permet au système de choisir dynamiquement les sources de données, d'affiner les requêtes pour une meilleure récupération du contexte, de générer des réponses plus précises et d'appliquer une boucle de rétroaction pour améliorer continuellement la qualité des résultats.</p><h2>Principales caractéristiques du RAG agentic</h2><p>Le cadre agentique des RAG constitue une avancée majeure par rapport aux systèmes traditionnels de RAG. Au lieu de suivre un processus de recherche fixe, il s'appuie sur des agents dynamiques capables de planifier, d'exécuter et d'optimiser les résultats en temps réel.</p><p>Examinons quelques-unes des principales caractéristiques qui distinguent les pipelines RAG agentiques :</p><ul><li><p><strong>Prise de décision dynamique</strong>: Le RAG agentique utilise un mécanisme de raisonnement pour comprendre l'intention de l'utilisateur et acheminer chaque requête vers la source de données la plus pertinente, produisant ainsi des réponses précises et adaptées au contexte.</p></li><li><p><strong>Analyse complète des requêtes :</strong> Agentic RAG analyse en profondeur les requêtes des utilisateurs, y compris les sous-questions et leur intention générale. Il évalue la complexité des requêtes et sélectionne de manière dynamique les sources de données les plus pertinentes pour récupérer les informations, garantissant ainsi des réponses précises et complètes.</p></li><li><p><strong>Collaboration en plusieurs étapes</strong>: Ce cadre permet une collaboration en plusieurs étapes grâce à un réseau d'agents spécialisés. Chaque agent s'occupe d'une partie spécifique d'un objectif plus large, travaillant de manière séquentielle ou simultanée pour atteindre un résultat cohérent.</p></li><li><p><strong>Mécanismes d'auto-évaluation</strong>: Le pipeline RAG agentique utilise l'autoréflexion pour évaluer les documents récupérés et les réponses générées. Il peut vérifier si les informations extraites répondent entièrement à la requête, puis vérifier l'exactitude, l'exhaustivité et la cohérence factuelle des résultats.</p></li><li><p><strong>Intégration avec des outils externes</strong>: Ce flux de travail peut interagir avec des API externes, des bases de données et des sources d'information en temps réel, en incorporant des informations actualisées et en s'adaptant dynamiquement à l'évolution des données.</p></li></ul><h2>Modèles de flux de travail des RAG agentiques</h2><p>Les modèles de flux de travail définissent la manière dont l'IA agentique structure, gère et orchestre les applications basées sur le LLM de manière fiable et efficace. Plusieurs cadres et plateformes, tels que <a href="https://www.langchain.com/">LangChain</a>, <a href="https://www.langchain.com/langgraph">LangGraph</a>, <a href="https://www.crewai.com/">CrewAI</a> et <a href="https://www.llamaindex.ai/">LlamaIndex</a>, peuvent être utilisés pour mettre en œuvre ces flux de travail agentiques.</p><ol><li><p><strong>Chaîne de récupération séquentielle</strong>: Les flux de travail séquentiels divisent les tâches complexes en étapes simples et ordonnées. Chaque étape améliore les données de l'étape suivante, ce qui permet d'obtenir de meilleurs résultats. Par exemple, lors de la création d'un profil de client, un agent peut extraire les détails de base d'un CRM, un autre récupère l'historique des achats dans une base de données de transactions, et un dernier agent combine ces informations pour générer un profil complet en vue de recommandations ou de rapports.</p></li><li><p><strong>Chaîne de recherche de routage</strong>: Dans ce modèle de flux de travail, un agent routeur analyse l'entrée et la dirige vers le processus ou la source de données la plus appropriée. Cette approche est particulièrement efficace lorsqu'il existe plusieurs sources de données distinctes se chevauchant très peu. Par exemple, dans un système de service à la clientèle, l'agent de routage classe les demandes entrantes, telles que les problèmes techniques, les remboursements ou les réclamations, et les achemine vers le service approprié pour un traitement efficace.</p></li><li><p><strong>Chaîne de recherche parallèle</strong>: Dans ce modèle de flux de travail, plusieurs sous-tâches indépendantes sont exécutées simultanément et leurs résultats sont ensuite agrégés pour générer une réponse finale. Cette approche permet de réduire considérablement le temps de traitement et d'accroître l'efficacité du flux de travail. Par exemple, dans un flux de travail parallèle de service à la clientèle, un agent récupère les demandes antérieures similaires et un autre consulte les articles pertinents de la base de connaissances. Un agrégateur combine ensuite ces résultats pour produire une résolution complète.</p></li><li><p><strong>Chaîne de travail de l'Orchestrator</strong>: Ce flux de travail présente des similitudes avec la parallélisation en raison de l'utilisation de sous-tâches indépendantes. Cependant, une distinction essentielle réside dans l'intégration d'un agent orchestrateur. Cet agent est chargé d'analyser les requêtes des utilisateurs, de les segmenter dynamiquement en sous-tâches au cours de l'exécution et d'identifier les processus ou outils appropriés nécessaires pour formuler une réponse précise.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1e2e634cf9c94e25/6a17ff81b1e113c9fc79f4e0/ece6fc2403f211556c93e99d5227bfb7053b0c31-1600x1047.png" alt="Modèle de flux de travail dans un RAG agentique" /><h2>Construire un pipeline RAG agentique à partir de zéro</h2><p>Pour illustrer les principes du RAG agentique, concevons un flux de travail utilisant LangChain et Elasticsearch. Ce flux de travail adopte une architecture basée sur le routage, où plusieurs agents collaborent pour analyser les requêtes, récupérer les informations pertinentes, évaluer les résultats et générer des réponses cohérentes. Vous pouvez vous référer à ce <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/agentic-rag/agent_rag_news_assistant.ipynb">carnet Jupyter</a> pour suivre cet exemple.</p><p>Le flux de travail commence par l'agent routeur, qui analyse la requête de l'utilisateur pour sélectionner la méthode de recherche optimale, c'est-à-dire l'approche <code>vectorstore</code>, <code>websearch</code> ou <code>composite</code>. Le magasin vectoriel gère la recherche traditionnelle de documents basée sur le RAG, la recherche sur le web récupère les informations les plus récentes qui ne sont pas stockées dans le magasin vectoriel, et l'approche composite combine les deux lorsque des informations provenant de sources multiples sont nécessaires.</p><p>Si les documents sont jugés appropriés, l'agent de synthèse génère une réponse claire et adaptée au contexte. Toutefois, si les documents sont insuffisants ou non pertinents, l'agent de réécriture des requêtes reformule la requête pour améliorer la recherche. Cette requête révisée réinitialise alors le processus de routage, ce qui permet au système d'affiner sa recherche et d'améliorer le résultat final.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt16020333cf6dda91/6a17ff82e8fbceb4d83a1c00/ed8701a7f15558fbf2e967a884b3e770eccb826b-1256x1092.png" alt="Comment un système agentique affine sa production avec différentes requêtes" /><h3>Produits requis</h3><p>Ce flux de travail s'appuie sur les composants de base suivants pour exécuter l'exemple de manière efficace :</p><ul><li><p>Python 3.10</p></li><li><p><a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/agentic-rag/agent_rag_news_assistant.ipynb">Bloc-notes Jupyter</a></p></li><li><p>Azure OpenAI</p></li><li><p>Elasticsearch</p></li><li><p>LangChain</p></li></ul><p>Avant de poursuivre, vous serez invité à configurer l'ensemble des variables d'environnement requises pour cet exemple.</p>AZURE_OPENAI_ENDPOINT="Add your azure openai endpoint"
AZURE_OPENAI_KEY="Add your azure openai key"
AZURE_OPENAI_DEPLOYMENT="gpt-4.1"
AZURE_OPENAI_API_VERSION="Add your azure openai api version"

ES_ENDPOINT = "Add your Elasticsearch ENDPOINT"
ES_API_KEY = "Add your Elasticsearch API KEY"<h3>Sources de données</h3><p>Ce processus est illustré à l'aide d'un sous-ensemble du jeu de données AG News. L'ensemble des données comprend des articles d'actualité dans diverses catégories, telles que International, Sports, Affaires et Science/Technologie.</p>dataset = load_dataset("ag_news", split="train[:1000]")
docs = [
    Document(
        page_content=sample["text"],
        metadata={"category": sample["label"]}
    )
    for sample in dataset
]<p>Le <a href="https://python.langchain.com/docs/integrations/vectorstores/elasticsearch/">module ElasticsearchStore</a> est utilisé à partir de <code>langchain_elasticsearch</code> comme magasin de vecteurs. Pour la recherche, nous mettons en œuvre la stratégie SparseVectorStrategy, en utilisant <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-elser">ELSER</a>, le modèle d'intégration propriétaire d'Elastic. Il est essentiel de confirmer que le modèle ELSER est correctement installé et déployé dans votre environnement Elasticsearch avant d'initier le magasin de vecteurs.</p>elastic_vectorstore = ElasticsearchStore.from_documents(
    docs,
    es_url=ES_ENDPOINT,
    es_api_key=ES_API_KEY,
    index_name=index_name,
    strategy=SparseVectorStrategy(model_id=".elser_model_2"),
)

elastic_vectorstore.client.indices.refresh(index=index_name)<p>La fonctionnalité de recherche sur le web est mise en œuvre à l'aide de <a href="https://python.langchain.com/api_reference/community/tools/langchain_community.tools.ddg_search.tool.DuckDuckGoSearchRun.html">DuckDuckGoSearchRun</a> des outils de la communauté LangChain, ce qui permet au système de récupérer efficacement des informations en direct sur le web. Vous pouvez également envisager d'utiliser d'autres API de recherche qui peuvent fournir des résultats plus pertinents. Cet outil a été choisi car il permet d'effectuer des recherches sans avoir besoin d'une clé API.</p>duckduckgo = DuckDuckGoSearchRun(description= "A custom DuckDuckGo search tool for finding latest news stories.", verbose=True)
def websearch_retriever(query):
    results = duckduckgo.run(f"{query}")
    return results<p>L'extracteur composite est conçu pour les requêtes qui nécessitent une combinaison de sources. Il est utilisé pour fournir une réponse complète et contextuelle précise en récupérant simultanément des données en temps réel sur le web et en consultant les informations historiques du magasin de vecteurs.</p>def composite_retriever(query):
    related_docs = vectorstore_retriever(query)
    related_docs += websearch_retriever(query)
    return related_docs<h3>Mise en place des agents</h3><p>Dans l'étape suivante, les agents LLM sont définis pour fournir des capacités de raisonnement et de prise de décision au sein de ce flux de travail. Les chaînes LLM que nous créerons sont les suivantes <code>router_chain</code>, <code>grade_docs_chain</code>, <code>rewrite_query_chain</code>, et <code>summary_chain</code>.</p><p>L'agent routeur utilise un assistant LLM pour déterminer la source de données la plus appropriée pour une requête donnée au moment de l'exécution. L'agent de classement évalue la pertinence des documents récupérés. Si les documents sont jugés pertinents, ils sont transmis à l'agent de synthèse pour générer un résumé. Dans le cas contraire, l'agent de réécriture reformule la requête et la renvoie au processus de routage pour une nouvelle tentative de recherche. Vous trouverez les instructions pour tous les agents dans la section chaînes LLM du <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/agentic-rag/agent_rag_news_assistant.ipynb">carnet de notes</a>.</p>class RouteQuery(BaseModel):
    datasource: Literal["vectorstore", "websearch", "composite"] = Field(
        ...,
        description="Choose to route the query to web search, vectorstore or composite."
    )

router_prompt = ChatPromptTemplate.from_template("""You are an assistant that decides the best data source for questions based on news articles.
Choose one of the following options:
- 'vectorstore': for general, background, or historical news articles.
- 'websearch': for recent discoveries, 'latest', 'current', or '2025' type queries.
- 'composite': when the question needs both historical and current knowledge on news articles.

Question: {query}

Return one word: 'vectorstore', 'websearch', or 'composite'.
""")
router_structured = llm.with_structured_output(RouteQuery)
router_chain: RunnableSequence = router_prompt | router_structured<p>Le site <code>llm.with_structured_output</code> contraint les résultats du modèle à suivre un schéma prédéfini par le BaseModel sous la classe <code>RouteQuery</code>, ce qui garantit la cohérence des résultats. La deuxième ligne compose un <code>RunnableSequence</code> en reliant <code>router_prompt</code> à <code>router_structured</code>, formant un pipeline dans lequel l'invite d'entrée est traitée par le modèle de langage pour produire des résultats structurés et conformes au schéma.</p><h3>Définir les nœuds d'un graphique</h3><p>Cette partie consiste à définir les états du graphe, qui représentent les données circulant entre les différents composants du système. Une spécification claire de ces états garantit que chaque nœud du flux de travail sait à quelles informations il peut accéder et les mettre à jour.</p>class RAGState(TypedDict):
    query: str
    docs: List[Document]
    router: str
    summary: str
    self_reflection: bool
    retry_count: int = 0<p>Une fois les états définis, l'étape suivante consiste à définir les nœuds du graphe. Les nœuds sont en quelque sorte les unités fonctionnelles du graphique qui effectuent des opérations spécifiques sur les données. Il y a 7 nœuds différents dans notre pipeline.</p>def router(state: RAGState):
   router = router_chain.invoke({'query': state["query"]})
   logger.info(f"Router selected the datasource: {router.datasource}")
   logger.info(f"User query: {state['query']}")
   return {"router": router.datasource}

def vectorstore(state: RAGState):
   return {"docs": vectorstore_retriever(state["query"])}

def websearch(state: RAGState):
   return {"docs": websearch_retriever(state["query"])}

def composite(state: RAGState):
   return {"docs": composite_retriever(state["query"])}

def self_reflection(state: RAGState):
   evaluation = grade_docs_chain.invoke(
       {"query": state["query"], "docs": state["docs"]}
   )
   if evaluation.binary_score:
       logger.info(f"Self-reflection passed -- binary_score={evaluation.binary_score}")
   else:
       logger.info(f"Self-reflection failed -- binary_score={evaluation.binary_score}")

   return {
       "self_reflection": evaluation.binary_score,
   }

def query_rewriter(state: RAGState):
   retry_count = state.get("retry_count", 0) + 1
   new_query = rewrite_query_chain.invoke({"query": state["query"]})
   logger.info(f"Query rewritten: {new_query}, retry_count: {retry_count}")
   return {
       "query": new_query,
       "retry_count": retry_count,
   }

def summarize(state: RAGState):
   summary = summarize_chain.run(
       query=state["query"],
       docs=state["docs"],
   )
   return {"summary": summary}<p>Le nœud <code>query_rewriter</code> a deux fonctions dans le flux de travail. Tout d'abord, il réécrit la requête de l'utilisateur à l'aide du site <code>rewrite_query_chain</code> pour améliorer la recherche lorsque les documents évalués par l'agent d'autoréflexion sont jugés insuffisants ou non pertinents. Deuxièmement, il sert de compteur pour savoir combien de fois la requête a été réécrite.</p><p>Chaque fois que le nœud est invoqué, il incrémente le site <code>retry_count</code> stocké dans l'état du flux de travail. Ce mécanisme empêche le flux de travail d'entrer dans une boucle infinie. Si le site <code>retry_count</code> dépasse un seuil prédéfini, le système peut passer à un état d'erreur, à une réponse par défaut ou à toute autre condition prédéfinie de votre choix.</p><h3>Compilation du graphique</h3><p>La dernière étape consiste à définir les arêtes du graphe et à ajouter toutes les conditions nécessaires avant de le compiler. Chaque graphe doit partir d'un nœud de départ désigné, qui sert de point d'entrée au flux de travail. Les arêtes du graphique représentent le flux de données entre les nœuds et peuvent être de deux types :</p><ul><li><p>Arêtes droites : Ils définissent un flux direct et inconditionnel d'un nœud à l'autre. Chaque fois que le premier nœud termine sa tâche, le flux de travail passe automatiquement au nœud suivant le long de la ligne droite.</p></li><li><p>Arêtes conditionnelles : Elles permettent au flux de travail de se ramifier en fonction de l'état actuel ou des résultats du calcul d'un nœud. Le nœud suivant est sélectionné dynamiquement en fonction de conditions telles que les résultats de l'évaluation, les décisions de routage ou le nombre de tentatives.</p></li></ul>graph.add_edge(START, "router")

def after_router(state: RAGState):
   route = state.get("router", None)
   if route == "vectorstore":
       return "vectorstore"
   elif route == "websearch":
       return "websearch"
   else:
       return "composite"

def after_self_reflection(state: RAGState):
   if state["self_reflection"]:
           return "summarize"
   return "query_rewriter"

def after_query_rewriter(state: RAGState):
   while state['retry_count'] &lt;= 3:
           return "router"
   raise RuntimeError("Maximum retries (3) reached -- evaluation failed.")

graph.add_conditional_edges(
   "router",
   after_router,
   {
       "vectorstore": "vectorstore",
       "websearch": "websearch",
       "composite": "composite"
   }
)

graph.add_edge("vectorstore", "self_reflection")
graph.add_edge("websearch", "self_reflection")
graph.add_edge("composite", "self_reflection")
graph.add_conditional_edges(
   "self_reflection",
   after_self_reflection,
   {
       "summarize": "summarize",
       "query_rewriter": "query_rewriter"
   }
)
graph.add_conditional_edges("query_rewriter", after_query_rewriter, {"router": "router"})
graph.add_edge("summarize", END)
agent=graph.compile()<p>Votre premier pipeline RAG agentique est donc prêt et peut être testé à l'aide de l'agent compilé.</p>result = agent.invoke({"query": query1})
logger.info(f"\nFinal Summary:\n: {result['summary']}")<h3>Test du pipeline RAG agentique</h3><p>Nous allons maintenant tester ce pipeline en utilisant trois types de requêtes distinctes, comme indiqué ci-dessous. Il convient de noter que les résultats peuvent varier et que les exemples présentés ci-dessous n'illustrent qu'un résultat potentiel.</p>query1="What are the latest AI models released this month?"
query2="What technological innovations are discussed in Sci/Tech news?"
query3="Compare a Sci/Tech article from the dataset with a current web article about AI trends."<p>Pour la première requête, le routeur sélectionne <code>websearch</code> comme source de données. La requête échoue à l'évaluation de l'autoréflexion et est ensuite redirigée vers l'étape de réécriture de la requête, comme le montre la sortie.</p>INFO     | __main__:router:11 - Router selected the datasource: websearch
INFO     | __main__:router:12 - User query: What are the latest AI models released this month?
Latest Singapore news, including the city state's relationships with Malaysia and Mahathir, China and Xi Jinping, and the rest of Southeast Asia. 3 days ago · The latest military news, insights and analysis from China. All the latest news, opinions and analysis on Hong Kong, China, Asia and around the world Latest news, in-depth features and opinion on Malaysia, covering politics, economy, society and the Asean member-nation's relationships with China, Singapore, and other Southeast Asian ... Oct 12, 2025 · Brics (an acronym for Brazil, Russia, India, China and South Africa) refers to an association of 10 leading emerging markets. The other member states are Egypt, Ethiopia, ...
INFO     | __main__:self_reflection:31 - Self-reflection failed -- binary_score=False
INFO     | __main__:query_rewriter:40 - Query rewritten: query='Which AI models have been officially released in June 2024?', retry_count: 1
INFO     | __main__:router:11 - Router selected the datasource: websearch
INFO     | __main__:router:12 - User query: query='Which AI models have been officially released in June 2024?'
Dream Machine is a text-to-video model created by Luma Labs and launched in June 2024 . It generates video output based on user prompts or still images. Dream Machine has been noted for its ability to realistically capture motion... Released in June 2023. In June 2024 , Baidu announced Ernie 4.0 Turbo. In April 2025, Ernie 4.5 Turbo and X1 Turbo were released . These models are optimized for faster response times and lower operational costs.[28][29]. The meaning of QUERY is question, inquiry. How to use query in a sentence. Synonym Discussion of Query. QUERY definition: 1. a question, often expressing doubt about something or looking for an answer from an authority.... Learn more. Query definition: a question; an inquiry.. See examples of QUERY used in a sentence.
INFO     | __main__:self_reflection:29 - Self-reflection passed -- binary_score=True
INFO     | __main__:&lt;module&gt;:2 - 
Final Summary:
: In June 2024, two AI models were officially released: Dream Machine, a text-to-video model launched by Luma Labs, and Ernie 4.0 Turbo, announced by Baidu, which is optimized for faster response times and lower operational costs.<p>Ensuite, nous examinons un exemple où <code>vectorstore</code> est utilisé, avec la deuxième requête.</p>INFO     | __main__:router:11 - Router selected the datasource: vectorstore
INFO     | __main__:router:12 - User query: What technological innovations are discussed in Sci/Tech news?
INFO     | __main__:self_reflection:29 - Self-reflection passed -- binary_score=True
INFO     | __main__:&lt;module&gt;:2 - 
Final Summary:
: Recent Sci/Tech news highlights several technological innovations: NASA is collaborating with Silicon Valley firms to build a powerful Linux-based supercomputer to support theoretical research and shuttle engineering; new chromatin transfer techniques have enabled the cloning of cats; cybersecurity advancements are being discussed in relation to protecting personal technology; Princeton University scientists assert that existing technologies can be used immediately to stabilize global warming; and a set of GameBoy micro-games has been recognized for innovation in game design.<p>La requête finale est dirigée vers la recherche composite, qui utilise à la fois le magasin de vecteurs et la recherche sur le web.</p>INFO     | __main__:router:11 - Router selected the datasource: composite
INFO     | __main__:router:12 - User query: Compare a Sci/Tech article from the dataset with a current web article about AI trends.
Atlas currently only available on macOS, built on Chromium with planned features like ad-blocking still in development. OpenAI's Atlas browser launched with bold promises of AI -powered web browsing, but early real-world testing reveals a different story. Career-long data are updated to end-of-2024 and single recent year data pertain to citations received during calendar year 2024. The selection is based on the top 100,000 scientists by c-score (with and without self-citations) or a percentile rank of 2% or above in the sub-field. In this article I list 45 AI tools across 21 different categories. After exploring all the available options in each category, I've carefully selected the best tools based on my personal experience. Reading a complex technical article ? Simply highlight confusing terminology and ask "what's this?" to receive instant explanations. compare browsers. Comparison showing traditional browser navigation versus OpenAI Atlas AI -powered workflows. After putting Gemini, ChatGPT, Grok, and DeepSeek through rigorous testing in October 2025, it's clear that there isn't one AI that reigns supreme across all categories.
INFO     | __main__:self_reflection:29 - Self-reflection passed -- binary_score=True
INFO     | __main__:&lt;module&gt;:2 - 
Final Summary:
: A Sci/Tech article from the dataset highlights NASA's development of robust artificial intelligence software for planetary rovers, aiming to make them more self-reliant and capable of decision-making during missions. In contrast, a current web article about AI trends focuses on the proliferation of AI-powered tools across various categories, including browsers like OpenAI Atlas, and compares leading models such as Gemini, ChatGPT, Grok, and DeepSeek, noting that no single AI currently excels in all areas. While the NASA article emphasizes specialized AI applications for autonomous robotics in space exploration, the current trends article showcases the broadening impact of AI across consumer and professional technologies, with ongoing competition and rapid innovation among major AI platforms.<p>Dans le flux de travail ci-dessus, le RAG agentique détermine intelligemment quelle source de données utiliser lors de la recherche d'informations pour une requête de l'utilisateur, améliorant ainsi la précision et la pertinence de la réponse. Vous pouvez créer des exemples supplémentaires pour tester l'agent et examiner les résultats pour voir s'ils produisent des résultats intéressants.</p><h2>Meilleures pratiques pour l'élaboration de flux de travail agentiques de RAG</h2><p>Maintenant que nous comprenons le fonctionnement du RAG agentique, examinons quelques bonnes pratiques pour la mise en place de ces flux de travail. Le respect de ces lignes directrices contribuera à maintenir l'efficacité du système et à en faciliter l'entretien.</p><ul><li><p><strong>Préparez-vous à des solutions de repli</strong>: Planifiez à l'avance des stratégies de repli pour les scénarios dans lesquels une étape du flux de travail échoue. Il peut s'agir de renvoyer des réponses par défaut, de déclencher des états d'erreur ou d'utiliser d'autres outils. Cela permet au système de gérer les défaillances de manière gracieuse sans interrompre le flux de travail global.</p></li><li><p><strong>Mettre en œuvre une journalisation complète</strong>: Essayez de mettre en œuvre la journalisation à chaque étape du flux de travail, comme les tentatives, les résultats générés, les choix de routage et les réécritures de requêtes. Ces journaux permettent d'améliorer la transparence, de faciliter le débogage et d'affiner les messages-guides, le comportement de l'agent et les stratégies de recherche au fil du temps.</p></li><li><p><strong>Sélectionner le modèle de flux de travail approprié</strong>: Examinez votre cas d'utilisation et sélectionnez le modèle de flux de travail qui répond le mieux à vos besoins. Utilisez des flux séquentiels pour le raisonnement étape par étape, des flux parallèles pour les sources de données indépendantes et des modèles d'orchestrateur-worker pour les requêtes multi-outils ou complexes.</p></li><li><p><strong>Incorporer des stratégies d'évaluation</strong>: Intégrer des mécanismes d'évaluation à différents stades du processus. Il peut s'agir d'agents d'autoréflexion, de classement des documents extraits ou de contrôles de qualité automatisés. L'évaluation permet de vérifier que les documents récupérés sont pertinents, que les réponses sont exactes et que toutes les parties d'une requête complexe sont traitées.</p></li></ul><h2>Défis</h2><p>Si les systèmes agentiques RAG offrent des avantages significatifs en termes d'adaptabilité, de précision et de raisonnement dynamique, ils s'accompagnent également de certains défis qui doivent être relevés lors de leur conception et de leur mise en œuvre. Voici quelques-uns des principaux défis à relever :</p><ul><li><p><strong>Flux de travail complexes</strong>: Au fur et à mesure de l'ajout d'agents et de points de décision, le flux de travail global devient de plus en plus complexe. Cela peut augmenter les risques d'erreurs ou de défaillances au moment de l'exécution. Dans la mesure du possible, donnez la priorité à la rationalisation des flux de travail en éliminant les agents redondants et les points de décision inutiles.</p></li><li><p><strong>Évolutivité</strong>: Il peut être difficile de faire évoluer les systèmes RAG agentiques pour traiter de grands ensembles de données et des volumes d'interrogation élevés. Incorporer des stratégies efficaces d'indexation, de mise en cache et de traitement distribué pour maintenir les performances à l'échelle.</p></li><li><p><strong>Orchestration et surcharge de calcul</strong>: L'exécution de flux de travail avec plusieurs agents nécessite une orchestration avancée. Cela implique une programmation minutieuse, la gestion des dépendances et la coordination des agents afin d'éviter les goulets d'étranglement et les conflits, autant d'éléments qui ajoutent à la complexité globale du système.</p></li><li><p><strong>Complexité de l'évaluation</strong>: L'évaluation de ces flux de travail présente des défis inhérents, car chaque étape nécessite une stratégie d'évaluation distincte. Par exemple, l'étape RAG doit être évaluée en fonction de la pertinence et de l'exhaustivité des documents récupérés, tandis que les résumés générés doivent être vérifiés en termes de qualité et d'exactitude. De même, l'efficacité de la reformulation de la requête nécessite une logique d'évaluation distincte pour déterminer si la requête réécrite améliore les résultats de la recherche.</p></li></ul><h2>Conclusion</h2><p>Dans cet article de blog, nous avons présenté le concept de RAG agentique et souligné comment il améliore le cadre traditionnel de RAG en incorporant des capacités autonomes de l'IA agentique. Nous avons exploré les caractéristiques principales du RAG agentique et les avons démontrées à l'aide d'un exemple pratique, en construisant un assistant de nouvelles utilisant Elasticsearch comme magasin de vecteurs et LangChain pour créer le cadre agentique.</p><p>En outre, nous avons discuté des meilleures pratiques et des principaux défis à prendre en compte lors de la conception et de la mise en œuvre d'un pipeline RAG agentique. Ces idées sont destinées à guider les développeurs dans la création de systèmes agentiques robustes, évolutifs et efficaces qui combinent de manière effective la recherche, le raisonnement et la prise de décision.</p><h2>Prochaines étapes</h2><p>Le flux de travail que nous avons mis en place est simple et laisse une large place aux améliorations et à l'expérimentation. Nous pouvons l'améliorer en expérimentant divers modèles d'intégration et en affinant les stratégies de recherche. En outre, l'intégration d'un agent de reclassement pour hiérarchiser les documents récupérés pourrait être bénéfique. Un autre domaine d'exploration concerne le développement de stratégies d'évaluation pour les cadres agentiques, en particulier l'identification d'approches communes et réutilisables applicables à différents types de cadres. Enfin, l'expérimentation de ces cadres sur des ensembles de données plus vastes et plus complexes.</p><p>En attendant, si vous avez des expériences similaires à partager, nous serions ravis de les connaître ! N'hésitez pas à nous faire part de vos commentaires ou à vous connecter avec nous via notre <a href="https://ela.st/slack">canal Slack communautaire</a> ou nos <a href="https://discuss.elastic.co/c/security">forums de discussion</a>.</p><h2>Ressources</h2><ul><li><p><a href="https://arxiv.org/abs/2310.11511">Self-RAG : Apprendre à retrouver, générer et critiquer par l'autoréflexion</a></p></li><li><p><a href="https://arxiv.org/abs/2501.09136">Génération assistée par récupération agentique : Une enquête sur la recherche agentique et la génération augmentée : une enquête sur la recherche agentique et la génération augmentée</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/agentic-rag-news-assistant-langchain-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/agentic-rag-news-assistant-langchain-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Kirti Sodhi]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8c7a9f3b0d141d5d/6a17ff83fbc5f86686491d15/59dc0077f5dab00561d9f1b1e7dbf8ec3456259e-1600x1047.heif" length="0" type="image/*"/>
    <pubDate>Fri, 28 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Construire un agent d'IA pour les RH avec Elastic Agent Builder et GPT-OSS]]></title>
    <description><![CDATA[Découvrez comment créer un agent d'intelligence artificielle capable de répondre à des requêtes en langage naturel sur les données RH de vos employés en utilisant Elastic Agent Builder et GPT-OSS.]]></description>
    <content:encoded><![CDATA[<h2>Introduction</h2><p>Cet article vous montrera comment construire un agent d'IA pour les RH en utilisant <a href="https://openai.com/index/introducing-gpt-oss/">GPT-OSS</a> et Elastic Agent Builder. L'agent peut répondre à vos questions sans envoyer de données à OpenAI, Anthropic ou tout autre service externe.</p><p>Nous allons utiliser LM Studio pour servir GPT-OSS localement et le connecter à Elastic Agent Builder.</p><p>À la fin de cet article, vous disposerez d'un agent d'IA personnalisé capable de répondre à des questions en langage naturel sur les données de vos employés, tout en conservant un contrôle total sur vos informations et votre modèle.</p><h2>Produits requis</h2><p>Pour cet article, vous avez besoin de :</p><ul><li><p><a href="https://www.elastic.co/cloud">Elastic Cloud</a> hébergé 9.2, déploiement sans serveur ou <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">local</a>.</p></li><li><p>Machine avec 32 Go de RAM recommandée (minimum 16 Go pour GPT-OSS 20B)</p></li><li><p><a href="https://lmstudio.ai/">LM Studio</a> installé</p></li><li><p><a href="https://www.docker.com/products/docker-desktop/">Docker Desktop</a> installé</p></li></ul><h2>Pourquoi utiliser GPT-OSS ?</h2><p>Avec un LLM local, vous avez la possibilité de le déployer dans votre propre infrastructure et de l'adapter à vos besoins. Tout cela en gardant le contrôle sur les données que vous partagez avec le modèle et, bien sûr, sans avoir à payer de licence à un fournisseur externe.</p><p>OpenAI <a href="https://openai.com/index/introducing-gpt-oss/">a publié GPT-OSS</a> le 5 août 2025, dans le cadre de son engagement envers l'écosystème des modèles ouverts.</p><p>Le modèle de paramètres 20B offre :</p><ul><li><p><strong>Capacités d'utilisation des outils</strong></p></li><li><p><strong>Inférence efficace</strong></p></li><li><p><strong>Compatible avec le SDK OpenAI</strong></p></li><li><p><strong>Compatible avec les flux de travail agentiques</strong></p></li></ul><p>Comparaison des points de repère :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt58fab956edb40412/6a170cfcb0367da43a72bd80/29160e3345352088e8213297630882f252b00c47-1600x680.png" alt="" /><h2>Architecture de la solution</h2><p>L'architecture fonctionne entièrement sur votre machine locale. Elastic (exécuté dans Docker) communique directement avec votre LLM local via LM Studio, et Elastic Agent Builder utilise cette connexion pour créer des agents d'IA personnalisés qui peuvent interroger les données de vos employés.</p><p>Pour plus de détails, consultez cette <a href="https://www.elastic.co/docs/solutions/observability/connect-to-own-local-llm">documentation</a>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80db5bb0a797f51b/6a170cfd0e2e492f2c41a16f/a4a886750ff25fa8bb7aefc7448161e52cf73ed3-1600x896.png" alt="" /><h2>Construire un agent d'IA pour les RH : étapes</h2><p>Nous diviserons la mise en œuvre en 5 étapes :</p><ol><li><p>Configurer LM studio avec un modèle local</p></li><li><p>Déployer Elastic local avec Docker</p></li><li><p>Créer le connecteur OpenAI dans Elastic</p></li><li><p>Téléchargement des données des employés vers Elasticsearch</p></li><li><p>Créez et testez votre agent d'intelligence artificielle</p></li></ol><h2>Étape 1 : Configurer LM Studio avec GPT-OSS 20B</h2><p>LM Studio est une application conviviale qui vous permet d'exécuter localement de grands modèles linguistiques sur votre ordinateur. Il fournit un serveur d'API compatible avec OpenAI, ce qui facilite l'intégration avec des outils tels qu'Elastic sans processus de configuration complexe. Pour plus de détails, reportez-vous à la <a href="https://lmstudio.ai/docs/app">documentation de LM Studio</a>.</p><p>Tout d'abord, téléchargez et installez LM Studio depuis le site officiel. Une fois installée, ouvrez l'application.</p><h3>Dans l'interface de LM Studio :</h3><ol><li><p>Allez dans l'onglet recherche et cherchez "GPT-OSS"</p></li><li><p>Sélectionnez le site <code>openai/gpt-oss-20b</code> à partir d'OpenAI</p></li><li><p>Cliquez sur télécharger</p></li></ol><p>La taille de ce modèle devrait être d'environ <strong>12,10 Go.</strong> Le téléchargement peut prendre quelques minutes, en fonction de votre connexion internet.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2dc341a6625e34b7/6a170cff839dfa2eb4dcff44/5d01bc4dcb377b5259fc6b521fe2425a31b90ca4-1312x872.png" alt="" /><h4>Une fois le modèle téléchargé :</h4><ol><li><p>Aller dans l'onglet du serveur local</p></li><li><p>Sélectionner l'openai/gpt-oss-20b</p></li><li><p>Utiliser le port par défaut 1234</p></li><li><p>Dans le panneau de droite, cliquez sur <strong>Charger </strong>et réglez la longueur du contexte sur <strong>40K</strong> ou plus.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3704ca1b28465cc4/6a170d00d7c022ed8fde64ef/e546033f916381647b876815b2c1f1ae2a08365f-326x337.png" alt="" /><p>5. Cliquez sur démarrer le serveur</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7b9170a4945ff857/6a170d0266c4f9ffadf8c0a6/28ee78a3caa84d14e04db3d42f30acbe4d4d005a-1312x872.png" alt="" /><p>Vous devriez voir ceci si le serveur est en cours d'exécution.</p>[LM STUDIO SERVER] Success! HTTP server listening on port 1234
[LM STUDIO SERVER] Supported endpoints:
[LM STUDIO SERVER] -&gt;	GET  http://localhost:1234/v1/models
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/responses
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/chat/completions
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/completions
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/embeddings
Server started.<h2>Étape 2 : Déployer Elastic local avec Docker</h2><p>Nous allons maintenant configurer Elasticsearch et Kibana localement à l'aide de Docker. Elastic fournit un script pratique qui gère l'ensemble du processus d'installation. Pour plus de détails, voir la <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">documentation officielle</a>.</p><h3>Exécuter le script start-local</h3><p>Exécutez la commande suivante dans votre terminal :</p>curl -fsSL https://elastic.co/start-local | sh<p>Ce script va :</p><ul><li><p>Télécharger et configurer Elasticsearch et Kibana</p></li><li><p>Démarrer les deux services à l'aide de Docker Compose</p></li><li><p>Activation automatique d'une licence d'essai Platinum de 30 jours</p></li></ul><h3>Résultats attendus</h3><p>Attendez le message suivant et enregistrez le mot de passe et la clé API indiqués ; vous en aurez besoin pour accéder à Kibana :</p>🎉 Congrats, Elasticsearch and Kibana are installed and running in Docker!
🌐 Open your browser at http://localhost:5601
   Username: elastic
   Password: KSUlOMNr
🔌 Elasticsearch API endpoint: http://localhost:9200
🔑 API key: cnJGX0pwb0JhOG00cmNJVklUNXg6cnNJdXZWMnM4bncwMllpQlFlUTlWdw==
Learn more at https://github.com/elastic/start-local<h3>Accéder à Kibana</h3><p>Ouvrez votre navigateur et naviguez vers :</p>http://localhost:5601<p>Connectez-vous en utilisant les informations d'identification obtenues dans la sortie du terminal.</p><h3>Activer le constructeur d'agents</h3><p>Une fois connecté à Kibana, naviguez vers <strong>Management </strong>&gt;<strong> AI </strong>&gt;<strong> Agent Builder </strong>et activez l'Agent Builder.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a934bd99fa6a0ce/6a170d046234e019c3db1a5a/92e104cb846c20d875865ded8a3d37f5c7daae9b-1491x1528.png" alt="" /><h2>Étape 3 : Créer le connecteur OpenAI dans Elastic</h2><p>Nous allons maintenant configurer Elastic pour qu'il utilise votre LLM local.</p><h3>Connecteurs d'accès</h3><ol><li><p>Dans Kibana</p></li><li><p>Allez dans <strong>Paramètres du projet</strong> &gt; <strong>Gestion</strong></p></li><li><p>Sous <strong>Alertes et aperçus</strong>, sélectionnez <strong>Connecteurs</strong></p></li><li><p>Cliquez sur Créer un connecteur</p></li></ol><h3>Configurer le connecteur</h3><p>Sélectionnez <strong>OpenAI</strong> dans la liste des connecteurs. LM Studio utilise le SDK OpenAI, ce qui le rend compatible.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt762023c39781eb78/6a170d06a29299a59ed01087/5ac87042e086c7a2bd47a8039e646ec831f0dcc6-923x974.png" alt="" /><p>Remplissez les champs avec ces valeurs :</p><ul><li><p><strong>Nom du connecteur : </strong>LM Studio - GPT-OSS 20B</p></li><li><p><strong>Sélectionnez un fournisseur OpenAI : </strong>Autre (Service compatible avec l'OpenAI)</p></li><li><p><strong>URL : </strong><code>http://host.docker.internal:1234/v1/chat/completions</code></p></li><li><p><strong>Modèle par défaut : </strong>openai/gpt-oss-20b</p></li><li><p><strong>Clé API :</strong> testkey-123 (n'importe quel texte fonctionne, car le serveur LM Studio ne nécessite pas d'authentification).</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt980e595f80e2be2e/6a170d086f7f0468a19148cc/2084ac32fcf1fb810c8b54ecab1c85a1e3e8905b-672x1302.png" alt="" /><p>Pour terminer la configuration, cliquez sur <strong>Save &amp; test.</strong></p><p><strong>Important :</strong> Activez l'option "<strong>Enable native function calling</strong>" (activer l'appel de fonctions natives) ; cette option est nécessaire pour que l'Agent Builder fonctionne correctement. Si vous ne l'activez pas, vous obtiendrez une erreur <strong><code>No tool calls found in the response</code></strong>.</p><h3>Tester la connexion</h3><p>Elastic devrait automatiquement tester la connexion. Si tout est configuré correctement, vous obtiendrez un message de réussite comme celui-ci :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4d2e815dd558f881/6a170d090e2e49076541a177/f567d767f1969c4730c1daa92f651789dc3742ac-1042x812.png" alt="" /><p>Réponse :</p>{
  "status": "ok",
  "data": {
    "id": "chatcmpl-flj9h0hy4wcx4bfson00an",
    "object": "chat.completion",
    "created": 1761189456,
    "model": "openai/gpt-oss-20b",
    "choices": [
      {
        "index": 0,
        "message": {
          "role": "assistant",
          "content": "Hello! 👋 How can I assist you today?",
          "reasoning": "Just greet.",
          "tool_calls": []
        },
        "logprobs": null,
        "finish_reason": "stop"
      }
    ],
    "usage": {
      "prompt_tokens": 69,
      "completion_tokens": 23,
      "total_tokens": 92
    },
    "stats": {},
    "system_fingerprint": "openai/gpt-oss-20b"
  },
  "actionId": "ee1c3aaf-bad0-4ada-8149-118f52dad757"
}<h2>Étape 4 : Téléchargement des données des employés vers Elasticsearch</h2><p>Nous allons maintenant télécharger l'<a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">ensemble de données relatives aux employés des RH</a> afin de montrer comment l'agent travaille avec des données sensibles. J'ai généré un ensemble de données fictives avec cette structure.</p><h3>Structure de l'ensemble de données</h3>{
  "employee_id": "0f4dce68-2a09-4cb1-b2af-6bcb4821539b",
  "full_name": "Daffi Stiebler",
  "email": "lscutchings0@huffingtonpost.com",
  "date_of_birth": "1975-06-20T15:39:36Z",
  "hire_date": "2025-07-28T00:10:45Z",
  "job_title": "Physical Therapy Assistant",
  "department": "HR",
  "salary": "108455",
  "performance_rating": "Needs Improvement",
  "years_of_experience": 2,
  "skills": "Java",
  "education_level": "Master's Degree",
  "manager": "Carl MacGibbon",
  "emergency_contact": "Leigha Scutchings",
  "home_address": "5571 6th Park"
}<h3>Créer l'index avec les correspondances</h3><p>Tout d'abord, créez l'index avec les correspondances appropriées. Notez que nous utilisons des champs <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">semantic_text</a> pour certains champs clés ; cela permet des capacités de recherche sémantique pour notre index.</p>​​PUT hr-employees
{
  "mappings": {
    "properties": {
      "@timestamp": {
        "type": "date"
      },
      "employee_id": {
        "type": "keyword"
      },
      "full_name": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "email": {
        "type": "keyword"
      },
      "date_of_birth": {
        "type": "date",
        "format": "iso8601"
      },
      "hire_date": {
        "type": "date",
        "format": "iso8601"
      },
      "job_title": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "department": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "salary": {
        "type": "double"
      },
      "performance_rating": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "years_of_experience": {
        "type": "long"
      },
      "skills": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "education_level": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "manager": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "emergency_contact": {
        "type": "keyword"
      },
      "home_address": {
        "type": "keyword"
      },
      "employee_semantic": {
        "type": "semantic_text"
      }
    }
  }
}<h3>Index avec Bulk API</h3><p>Copiez et collez le <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">jeu de données</a> dans votre Dev Tools dans Kibana et exécutez-le :</p>POST hr-employees/_bulk
{"index": {}}
{"employee_id": "57728b91-e5d7-4fa8-954a-2384040d3886", "full_name": "Filide Gane", "email": "vhallahan1@booking.com", "job_title": "Business Systems Development Analyst", "department": "Marketing", "salary": "$52330.27", "performance_rating": "Meets Expectations", "years_of_experience": 12, "skills": "Java", "education_level": "Bachelor's Degree", "date_of_birth": "2000-02-07T16:49:32Z", "hire_date": "2023-11-07T13:03:16Z", "manager": "Freedman Kings", "emergency_contact": "Vilhelmina Hallahan", "home_address": "75 Dennis Junction"}
{"index": {}}
{"employee_id": "...", ...}<h3>Vérifier les données</h3><p>Exécutez une requête pour vérifier :</p>GET hr-employees/_search<h2>Étape 5 : Créer et tester votre agent d'intelligence artificielle</h2><p>Une fois tout configuré, il est temps de créer un agent d'IA personnalisé à l'aide d'Elastic Agent Builder. Pour plus de détails, voir la <a href="https://www.elastic.co/docs/solutions/search/agent-builder/get-started">documentation Elastic</a>.</p><h3>Ajouter le connecteur</h3><p>Avant de pouvoir créer notre nouvel agent, nous devons configurer notre Agent builder pour qu'il utilise notre connecteur personnalisé appelé <code>LM Studio - GPT-OSS 20B</code>, car le connecteur par défaut est <a href="https://www.elastic.co/docs/reference/kibana/connectors-kibana/elastic-managed-llm">Elastic Managed LLM</a>. Pour cela, nous devons aller dans <strong>Project Setting</strong> &gt; <strong>Management</strong> &gt; <strong>GenAI Settings</strong>; nous sélectionnons alors celui que nous avons créé et cliquons sur <strong>Save.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc42f079c5e756057/6a170d0acf4f2501d9b2d1c7/11e830c3e2fb4c298b020c928fa5422f3397ba08-1600x1152.png" alt="" /><h3>Agent d'accès Constructeur</h3><ol><li><p>Aller aux <strong>agents</strong></p></li><li><p>Cliquez sur <strong>Créer un nouvel agent</strong></p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb8e734817c5a7c6a/6a170d0ca929cf867cae0a34/c1e60541563650163f972ac9088dc1ed1de759a7-1600x1054.png" alt="" /><h3>Configurer l'agent</h3><p>Pour créer un nouvel agent, les champs obligatoires sont l'<strong>identifiant de l'agent</strong>, le <strong>nom d'affichage</strong> et les <strong>instructions d'affichage.</strong></p><p>Mais il existe d'autres options de personnalisation, comme les instructions personnalisées qui indiquent comment votre agent va se comporter et interagir avec vos outils, à la manière d'une invite système, mais pour notre agent personnalisé. Les étiquettes permettent d'organiser les agents, la couleur de l'avatar et le symbole de l'avatar.</p><p>Ceux que j'ai choisis pour notre agent sur la base de l'ensemble des données sont les suivants :

<strong>Agent ID :</strong> <code>hr_assistant</code></p><p><strong>Instructions personnalisées :</strong></p>You are an HR Analytics Assistant that helps answer questions about employee data.
When responding to queries:
- Provide clear, concise answers
- Include relevant employee details (name, department, salary, skills)
- Format monetary values with currency symbols
- Be professional and maintain data confidentiality<p>
Étiquettes : <code>Human Resources</code> et <code>GPT-OSS</code></p><p>Nom d'affichage : <code>HR Analytics Assistant</code></p><p>Description de l'affichage :</p>A specialized AI assistant for Human Resources that helps analyze employee data, compensation, performance metrics, and talent management. Ask questions about employees, departments, salaries, or performance analytics.<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt23fb011e5b4f4d49/6a170d0e7d8d67f47a70e77f/f94bb2bf08497e5e756ca76b30a3a51f42927756-1424x1217.png" alt="" /><p>Une fois toutes les données saisies, nous pouvons cliquer sur <strong>Enregistrer</strong> notre nouvel agent.</p><h3>Tester l'agent</h3><p>Vous pouvez désormais poser des questions en langage naturel sur les données de vos employés, et GPT-OSS 20B comprendra l'intention et générera une réponse appropriée.</p><h4>Prompt :</h4>Which employee is the one with the highest salary in the hr-employees index?<h4>Réponse :</h4><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc0c52faacf63b583/6a170d0f0e2e497bfd41a17b/94ad19f80b96304028a59f60beca51dfc9aecc8a-899x631.png" alt="" /><p>Le processus de l'agent a été le suivant :</p><p>1. Comprendre votre question à l'aide du connecteur GPT-OSS</p><p>2. Générer la requête Elasticsearch appropriée (à l'aide des outils intégrés ou d'<a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> personnalisés)</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte32a8a7e6363c7f2/6a170d115091680077e1bb44/6f2961d0d1b97475f6dda300acee84da540938e6-844x466.png" alt="" /><p>3. Récupérer les enregistrements des salariés correspondants</p><p>4. Présenter les résultats en langage naturel avec un formatage approprié</p><p>Contrairement à la recherche lexicale traditionnelle, l'agent alimenté par GPT-OSS comprend l'intention et le contexte, ce qui facilite la recherche d'informations sans connaître les noms exacts des champs ou la syntaxe de la requête. Pour plus de détails sur le processus de réflexion de l'agent, voir cet <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance">article</a>.</p><h2>Conclusion</h2><p>Dans cet article, nous avons construit un agent d'IA personnalisé à l'aide de l'Agent Builder d'Elastic pour se connecter au modèle OpenAI GPT-OSS fonctionnant localement. En déployant à la fois Elastic et le LLM sur votre machine locale, cette architecture vous permet de tirer parti des capacités d'IA générative tout en conservant un contrôle total sur vos données, le tout sans envoyer d'informations à des services externes.</p><p>Nous avons utilisé GPT-OSS 20B à titre expérimental, mais les modèles officiellement recommandés pour Elastic Agent Builder sont référencés <a href="https://www.elastic.co/docs/solutions/search/agent-builder/models#recommended-models">ici.</a> Si vous avez besoin de capacités de raisonnement plus avancées, il existe également la <a href="https://huggingface.co/openai/gpt-oss-120b">variante de paramètre 120B</a> qui est plus performante pour les scénarios complexes, bien qu'elle nécessite une machine plus sophistiquée pour fonctionner localement. Pour plus de détails, consultez la <a href="https://openai.com/open-models/">documentation officielle d'OpenAI</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/build-an-ai-agent-hr-elastic-agent-builder-gpt-oss</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/build-an-ai-agent-hr-elastic-agent-builder-gpt-oss</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Tomás Murúa]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt664f490053e46e6b/6a170d13b0367d2d7e72bd84/05d2d0513fff67d975f9223d75108aa9f50646bc-1600x914.png" length="0" type="image/png"/>
    <pubDate>Wed, 26 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <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[Création d'une salle de presse avec agent LLM, protocole A2A et MCP dans Elasticsearch : Partie II]]></title>
    <description><![CDATA[Découvrez comment construire une salle de presse hybride spécialisée pour les agents LLM en utilisant le protocole A2A pour la collaboration entre agents et MCP pour l'accès aux outils dans Elasticsearch.]]></description>
    <content:encoded><![CDATA[<h2>A2A et MCP : le code en action</h2><p>Cet article est le complément de l'article "Creating an LLM Agent newsroom with A2A protocol and MCP in Elasticsearch !", qui expliquait les avantages de la mise en œuvre des architectures A2A et MCP au sein du même agent afin de profiter pleinement des avantages uniques des deux frameworks. Un <a href="https://github.com/justincastilla/elastic-newsroom">référentiel</a> est disponible si vous souhaitez exécuter la démo par vous-même.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt232e466d2153c764/6a17f15f631730042d585b8d/7196f004089127f83547b2e5dc3f663205cfcdce-1162x1600.png" alt="A2A &amp; Flux de travail de l'agent de protocole MCP" /><p>Voyons comment les agents de notre salle de presse collaborent en utilisant à la fois A2A et MCP pour produire un article. Le référentiel d'accompagnement pour voir les agents en action est disponible <a href="https://github.com/justincastilla/elastic-newsroom">ici.</a></p><h3>Étape 1 : Attribution de l'histoire</h3><p>Le <strong>chef de l'information</strong> (agissant en tant que client) attribue un sujet :</p>{
  "message_type": "task_request",
  "sender": "news_chief",
  "receiver": "reporter_agent",
  "payload": {
    "task_id": "story_renewable_energy_2024",
    "assignment": {
      "topic": "Renewable Energy Adoption in Europe",
      "angle": "Policy changes driving solar and wind expansion",
      "target_length": 1200,
      "deadline": "2025-09-30T18:00:00Z"
    }
  }
}<h3>Étape 2 : Le journaliste demande des recherches</h3><p>L'<strong>agent rapporteur</strong> reconnaît qu'il a besoin d'informations générales et délègue à l'<strong>agent chercheur</strong> par l'intermédiaire de l'A2A :</p>{
  "message_type": "task_request",
  "sender": "reporter_agent",
  "receiver": "researcher_agent",
  "payload": {
    "task_id": "research_eu_renewable_2024",
    "parent_task_id": "story_renewable_energy_2024",
    "capability": "fact_gathering",
    "parameters": {
      "queries": [
        "EU renewable energy capacity 2024",
        "Solar installations growth Europe",
        "Wind energy policy changes 2024"
      ],
      "depth": "comprehensive"
    }
  }
}<h3>Étape 3 : Le rapporteur demande le contexte historique à l'agent d'archivage</h3><p>L'<strong>agent rapporteur</strong> reconnaît que le contexte historique renforcerait l'histoire. Il délègue à l'<strong>agent d'archivage</strong> (alimenté par l'<a href="https://www.elastic.co/docs/solutions/search/elastic-agent-builder">agent A2A d'Elastic</a>), via A2A, le soin d'effectuer des recherches dans les archives d'articles de la salle de presse alimentées par Elasticsearch :</p>{
  "message_type": "task_request",
  "sender": "reporter_agent",
  "receiver": "archive_agent",
  "payload": {
    "task_id": "archive_search_renewable_2024",
    "parent_task_id": "story_renewable_energy_2024",
    "capability": "search_archive",
    "parameters": {
      "query": "European renewable energy policy changes and adoption trends over past 5 years",
      "focus_areas": ["solar", "wind", "policy", "Germany", "France"],
      "time_range": "2019-2024",
      "result_count": 10
    }
  }
}<h3>Étape 4 : L'agent d'archivage utilise l'agent Elastic A2A avec MCP</h3><p>L'<strong>agent d'archivage</strong> utilise l'agent A2A d'Elastic, qui à son tour utilise MCP pour accéder aux outils Elasticsearch. Ceci démontre l'architecture hybride où A2A permet la collaboration des agents tandis que MCP fournit l'accès aux outils :</p># Archive Agent using Elastic A2A Agent
async def search_historical_articles(self, query_params):
    # The Archive Agent sends a request to Elastic's A2A Agent
    elastic_response = await self.a2a_client.send_request(
        agent="elastic_agent",
        capability="search_and_analyze",
        parameters={
            "natural_language_query": query_params["query"],
            "index_pattern": "newsroom-articles-*",
            "filters": {
                "topics": query_params["focus_areas"],
                "date_range": query_params["time_range"]
            },
            "analysis_type": "trend_analysis"
        }
    )
    
    # Elastic's A2A Agent internally uses MCP tools:
    # - platform.core.search (to find relevant articles)
    # - platform.core.generate_esql (to analyze trends)
    # - platform.core.index_explorer (to identify relevant indices)
    
    return elastic_response<p>L'<strong>agent d'archivage</strong> reçoit des données historiques complètes de l'agent A2A d'Elastic et les renvoie au rapporteur :</p>{
  "message_type": "task_response",
  "sender": "archive_agent",
  "receiver": "reporter_agent",
  "payload": {
    "task_id": "archive_search_renewable_2024",
    "status": "completed",
    "archive_data": {
      "historical_articles": [
        {
          "title": "Germany's Energiewende: Five Years of Solar Growth",
          "published": "2022-06-15",
          "key_points": [
            "Germany added 7 GW annually 2020-2022",
            "Policy subsidies drove 60% of growth"
          ],
          "relevance_score": 0.94
        },
        {
          "title": "France Balances Nuclear and Renewables",
          "published": "2023-03-20",
          "key_points": [
            "France increased renewable target to 40% by 2030",
            "Solar capacity doubled 2021-2023"
          ],
          "relevance_score": 0.89
        }
      ],
      "trend_analysis": {
        "coverage_frequency": "EU renewable stories increased 150% since 2019",
        "emerging_themes": ["policy incentives", "grid modernization", "battery storage"],
        "coverage_gaps": ["Small member states", "offshore wind permitting"]
      },
      "total_articles_found": 47,
      "search_confidence": 0.91
    }
  }
}<p>Cette étape montre comment l'agent A2A d'Elastic s'intègre dans le flux de travail de la salle de presse. L'Archive Agent (un agent spécifique à la salle de presse) se coordonne avec l'A2A Agent d'Elastic (un spécialiste tiers) pour exploiter les puissantes capacités de recherche et d'analyse d'Elasticsearch. L'agent Elastic utilise MCP en interne pour accéder aux outils Elasticsearch, ce qui montre la séparation nette entre la coordination de l'agent (A2A) et l'accès aux outils (MCP).</p><h3>Étape 5 : Le chercheur utilise les serveurs MCP</h3><p>L'<strong>agent chercheur</strong> accède à plusieurs serveurs MCP pour recueillir des informations :</p># Researcher Agent using MCP to access tools
async def gather_facts(self, queries):
    results = []
    
    # Use News API MCP Server
    news_data = await self.mcp_client.invoke_tool(
        server="news_api_mcp",
        tool="search_articles",
        parameters={
            "query": queries[0],
            "date_range": "2024-01-01 to 2024-09-30",
            "sources": ["reuters", "bloomberg", "euractiv"]
        }
    )
    
    # Use Statistics MCP Server
    stats_data = await self.mcp_client.invoke_tool(
        server="eurostat_mcp",
        tool="get_energy_statistics",
        parameters={
            "metrics": ["solar_capacity_mw", "wind_capacity_mw"],
            "countries": ["EU27"],
            "year": 2024
        }
    )
    
    # Use Fact-Checking MCP Server
    verified_facts = await self.mcp_client.invoke_tool(
        server="factcheck_mcp",
        tool="verify_claims",
        parameters={
            "claims": [
                "EU solar capacity increased 40% in 2024",
                "Germany leads in wind installations"
            ]
        }
    )
    
    return self._synthesize_research(news_data, stats_data, verified_facts)<h3>Étape 6 : Le chercheur renvoie les données au rapporteur</h3><p>L'<strong>agent chargé de la recherche</strong> renvoie la recherche complète par l'intermédiaire de l'A2A :</p>{
  "message_type": "task_response",
  "sender": "researcher_agent",
  "receiver": "reporter_agent",
  "payload": {
    "task_id": "research_eu_renewable_2024",
    "status": "completed",
    "research_data": {
      "key_facts": [
        {
          "claim": "EU solar capacity reached 260 GW in 2024",
          "source": "Eurostat Q3 2024 Report",
          "confidence": 0.95,
          "verified": true
        },
        {
          "claim": "Germany installed 12 GW of wind capacity in 2024",
          "source": "German Federal Network Agency",
          "confidence": 0.92,
          "verified": true
        }
      ],
      "statistics": {
        "solar_growth_rate": "35%",
        "wind_growth_rate": "28%"
      },
      "sources_count": 15
    }
  }
}<h3>Étape 7 : Le journaliste rédige un article</h3><p>L'<strong>agent rapporteur</strong> utilise les données de recherche et ses propres capacités LLM pour rédiger l'article. Pendant la rédaction, le Reporter utilise les serveurs MCP pour le style et les modèles :</p># Reporter Agent writing with MCP assistance
async def write_article(self, research_data, assignment):
    # Get style guidelines via MCP
    style_guide = await self.mcp_client.get_resource(
        server="newsroom_mcp",
        resource="style://editorial/ap_style_guide"
    )
    
    # Get article template via MCP
    template = await self.mcp_client.get_resource(
        server="newsroom_mcp",
        resource="template://articles/news_story"
    )
    
    # Generate article using LLM + research + style
    draft = await self.llm.generate(
        prompt=f"""
        Write a news article following these guidelines:
        {style_guide}
        
        Using this template:
        {template}
        
        Based on this research:
        {research_data}
        
        Assignment: {assignment}
        """
    )
    
    # Self-evaluate confidence in claims
    confidence_check = await self._evaluate_confidence(draft)
    
    return draft, confidence_check<h3>Étape 8 : le manque de confiance déclenche une nouvelle recherche</h3><p>L'<strong>agent déclarant</strong> évalue son projet et constate qu'une créance a un faible degré de confiance. Il envoie une autre demande à l'<strong>agent du chercheur :</strong></p>{
  "message_type": "collaboration_request",
  "sender": "reporter_agent",
  "receiver": "researcher_agent",
  "payload": {
    "request_type": "fact_verification",
    "claims": [
      {
        "text": "France's nuclear phase-down contributed to 15% increase in renewable capacity",
        "context": "Discussing policy drivers for renewable growth",
        "current_confidence": 0.45,
        "required_confidence": 0.80
      }
    ],
    "urgency": "high"
  }
}<p>Le <strong>chercheur</strong> vérifie l'allégation à l'aide des serveurs MCP de vérification des faits et renvoie les informations mises à jour :</p>{
  "message_type": "collaboration_response",
  "sender": "researcher_agent",
  "receiver": "reporter_agent",
  "payload": {
    "verified_claims": [
      {
        "original_claim": "France's nuclear phase-down contributed to 15% increase...",
        "verified_claim": "France's renewable capacity increased 18% in 2024, partially offsetting reduced nuclear output",
        "confidence": 0.88,
        "corrections": "Percentage was 18%, not 15%; nuclear phase-down is gradual, not primary driver",
        "sources": ["RTE France", "French Energy Ministry Report 2024"]
      }
    ]
  }
}<h3>Étape 9 : Le journaliste révise le texte et le soumet au rédacteur en chef</h3><p>Le <strong>rapporteur</strong> incorpore les faits vérifiés et envoie le projet complet à l'<strong>agent rédacteur</strong> par l'intermédiaire de l'A2A :</p>{
  "message_type": "task_request",
  "sender": "reporter_agent",
  "receiver": "editor_agent",
  "payload": {
    "task_id": "edit_renewable_story",
    "parent_task_id": "story_renewable_energy_2024",
    "content": {
      "headline": "Europe's Renewable Revolution: Solar and Wind Surge 30% in 2024",
      "body": "[Full article text...]",
      "word_count": 1185,
      "sources": [/* array of sources */]
    },
    "editing_requirements": {
      "check_style": true,
      "check_facts": true,
      "check_seo": true
    }
  }
}<h3>Étape 10 : Examens des éditeurs à l'aide des outils MCP</h3><p>L'<strong>agent rédacteur</strong> utilise plusieurs serveurs MCP pour réviser l'article :</p># Editor Agent using MCP for quality checks
async def review_article(self, content):
    # Grammar and style check
    grammar_issues = await self.mcp_client.invoke_tool(
        server="grammarly_mcp",
        tool="check_document",
        parameters={"text": content["body"]}
    )
    
    # SEO optimization check
    seo_analysis = await self.mcp_client.invoke_tool(
        server="seo_mcp",
        tool="analyze_content",
        parameters={
            "headline": content["headline"],
            "body": content["body"],
            "target_keywords": ["renewable energy", "Europe", "solar", "wind"]
        }
    )
    
    # Plagiarism check
    originality = await self.mcp_client.invoke_tool(
        server="plagiarism_mcp",
        tool="check_originality",
        parameters={"text": content["body"]}
    )
    
    # Generate editorial feedback
    feedback = await self._generate_feedback(
        grammar_issues, 
        seo_analysis, 
        originality
    )
    
    return feedback<p>Le <strong>rédacteur en chef</strong> approuve l'article et le transmet :</p>{
  "message_type": "task_response",
  "sender": "editor_agent",
  "receiver": "reporter_agent",
  "payload": {
    "status": "approved",
    "quality_score": 9.2,
    "minor_edits": [
      "Changed 'surge' to 'increased' in paragraph 3 for AP style consistency",
      "Added Oxford comma in list of countries"
    ],
    "approved_content": "[Final edited article]"
  }
}<h3>Étape 11 : L'éditeur publie via CI/CD</h3><p>Enfin, l'<strong>agent imprimeur</strong> publie l'article approuvé en utilisant les serveurs MCP pour le CMS et le pipeline CI/CD :</p># Publisher Agent publishing via MCP
async def publish_article(self, content, metadata):
    # Upload to CMS via MCP
    cms_result = await self.mcp_client.invoke_tool(
        server="wordpress_mcp",
        tool="create_post",
        parameters={
            "title": content["headline"],
            "body": content["body"],
            "status": "draft",
            "categories": metadata["categories"],
            "tags": metadata["tags"],
            "featured_image_url": metadata["image_url"]
        }
    )
    
    post_id = cms_result["post_id"]
    
    # Trigger CI/CD deployment via MCP
    deploy_result = await self.mcp_client.invoke_tool(
        server="cicd_mcp",
        tool="trigger_deployment",
        parameters={
            "pipeline": "publish_article",
            "environment": "production",
            "post_id": post_id,
            "schedule": "immediate"
        }
    )
    
    # Track analytics
    await self.mcp_client.invoke_tool(
        server="analytics_mcp",
        tool="register_publication",
        parameters={
            "post_id": post_id,
            "publish_time": datetime.now().isoformat(),
            "story_id": metadata["story_id"]
        }
    )
    
    return {
        "status": "published",
        "post_id": post_id,
        "url": f"https://newsroom.example.com/articles/{post_id}",
        "deployment_id": deploy_result["deployment_id"]
    }<p>L'<strong>éditeur</strong> confirme la publication via A2A :</p>{
  "message_type": "task_complete",
  "sender": "printer_agent",
  "receiver": "news_chief",
  "payload": {
    "task_id": "story_renewable_energy_2024",
    "status": "published",
    "publication": {
      "url": "https://newsroom.example.com/articles/renewable-europe-2024",
      "published_at": "2025-09-30T17:45:00Z",
      "post_id": "12345"
    },
    "workflow_metrics": {
      "total_time_minutes": 45,
      "agents_involved": ["reporter", "researcher", "archive", "editor", "printer"],
      "iterations": 2,
      "mcp_calls": 12
    }
  }
}<p>Voici la séquence complète du flux de travail A2A dans le référentiel d'accompagnement en utilisant les mêmes agents que ceux décrits ci-dessus.</p><p>#</p><p>De</p><p>Pour</p><p>Action</p><p>Protocole</p><p>Description</p><p>1</p><p>Utilisateur</p><p>Chef de l'information</p><p>Attribuer l'histoire</p><p>HTTP POST</p><p>L'utilisateur soumet le sujet et l'angle de l'article</p><p>2</p><p>Chef de l'information</p><p>Interne</p><p>Créer une histoire</p><p>-</p><p>Création d'un enregistrement d'histoire avec un identifiant unique</p><p>3</p><p>Chef de l'information</p><p>Reporter</p><p>Affectation des délégués</p><p>A2A</p><p>Envoi de l'article via le protocole A2A</p><p>4</p><p>Reporter</p><p>Interne</p><p>Accepter l'affectation</p><p>-</p><p>Stockage interne de l'affectation</p><p>5</p><p>Reporter</p><p>Serveur MCP</p><p>Générer un plan</p><p>MCP/HTTP</p><p>Création d'un plan d'article et de questions de recherche</p><p>6a</p><p>Reporter</p><p>Chercheur</p><p>Demande de recherche</p><p>A2A</p><p>Envoie des questions (parallèle avec 6b)</p><p>6b</p><p>Reporter</p><p>Archiviste</p><p>Recherche dans les archives</p><p>A2A JSONRPC</p><p>Recherche d'articles historiques (parallèle avec 6a)</p><p>7</p><p>Chercheur</p><p>Serveur MCP</p><p>Questions de recherche</p><p>MCP/HTTP</p><p>Utilise l'Anthropique via le MCP pour répondre aux questions</p><p>8</p><p>Chercheur</p><p>Reporter</p><p>Recherche en matière de retour</p><p>A2A</p><p>Réponses à la recherche sur les retours</p><p>9</p><p>Archiviste</p><p>Elasticsearch</p><p>Index de recherche</p><p>API REST ES</p><p>Requêtes news_archive index</p><p>10</p><p>Archiviste</p><p>Reporter</p><p>Retour à l'archive</p><p>A2A JSONRPC</p><p>Renvoie les résultats de la recherche historique</p><p>11</p><p>Reporter</p><p>Serveur MCP</p><p>Générer un article</p><p>MCP/HTTP</p><p>Création d'un article dans un contexte de recherche ou d'archives</p><p>12</p><p>Reporter</p><p>Interne</p><p>Projet de magasin</p><p>-</p><p>Sauvegarde interne du projet</p><p>13</p><p>Reporter</p><p>Chef de l'information</p><p>Soumettre le projet</p><p>A2A</p><p>Soumission d'un projet achevé</p><p>14</p><p>Chef de l'information</p><p>Interne</p><p>Mise à jour de l'histoire</p><p>-</p><p>Stocke le projet, met à jour le statut à "draft_submitted"</p><p>15</p><p>Chef de l'information</p><p>Éditeur</p><p>Projet de révision</p><p>A2A</p><p>Routes automatiques vers l'éditeur pour révision</p><p>16</p><p>Éditeur</p><p>Serveur MCP</p><p>Article de synthèse</p><p>MCP/HTTP</p><p>Analyse du contenu à l'aide d'Anthropic via MCP</p><p>17</p><p>Éditeur</p><p>Chef de l'information</p><p>Retourner à l'examen</p><p>A2A</p><p>Envoi d'un retour d'information et de suggestions éditoriales</p><p>18</p><p>Chef de l'information</p><p>Interne</p><p>Revue des magasins</p><p>-</p><p>Stocke les commentaires des éditeurs</p><p>19</p><p>Chef de l'information</p><p>Reporter</p><p>Appliquer les modifications</p><p>A2A</p><p>Acheminement du retour d'information sur l'examen au rapporteur</p><p>20</p><p>Reporter</p><p>Serveur MCP</p><p>Appliquer les modifications</p><p>MCP/HTTP</p><p>Révision de l'article en fonction du retour d'information</p><p>21</p><p>Reporter</p><p>Interne</p><p>Projet de mise à jour</p><p>-</p><p>Mise à jour du projet avec des révisions</p><p>22</p><p>Reporter</p><p>Chef de l'information</p><p>Retour Révisé</p><p>A2A</p><p>Retourne l'article révisé</p><p>23</p><p>Chef de l'information</p><p>Interne</p><p>Mise à jour de l'histoire</p><p>-</p><p>Stocker le projet révisé, statut à "révisé"</p><p>24</p><p>Chef de l'information</p><p>Éditeur</p><p>Publier un article</p><p>A2A</p><p>Routes automatiques vers l'éditeur</p><p>25</p><p>Éditeur</p><p>Serveur MCP</p><p>Générer des étiquettes</p><p>MCP/HTTP</p><p>Création d'étiquettes et de catégories</p><p>26</p><p>Éditeur</p><p>Elasticsearch</p><p>Index Article</p><p>API REST ES</p><p>Indexe l'article dans l'index news_archive</p><p>27</p><p>Éditeur</p><p>Système de fichiers</p><p>Sauvegarder la démarque</p><p>Fichier E/S</p><p>Enregistre l'article au format .md fichier dans /articles</p><p>28</p><p>Éditeur</p><p>Chef de l'information</p><p>Confirmer la publication</p><p>A2A</p><p>Renvoie l'état de réussite</p><p>29</p><p>Chef de l'information</p><p>Interne</p><p>Mise à jour de l'histoire</p><p>-</p><p>Mise à jour du statut de l'article à "publié"</p><h2>Conclusion</h2><p>L'A2A et le MCP ont tous deux un rôle important à jouer dans le paradigme moderne de l'infrastructure augmentée-LLM. L'A2A offre une certaine souplesse pour les systèmes multi-agents complexes, mais potentiellement moins de portabilité et une plus grande complexité opérationnelle. MCP offre une approche standardisée pour l'intégration des outils, plus simple à mettre en œuvre et à maintenir, bien qu'il ne soit pas conçu pour gérer l'orchestration multi-agents.</p><p>Le choix n'est pas binaire. Comme le montre notre exemple de salle de presse, les systèmes les plus sophistiqués et les plus efficaces soutenus par le LLM combinent souvent les deux approches : les agents se coordonnent et se spécialisent par le biais de protocoles A2A tout en accédant à leurs outils et à leurs ressources par le biais de serveurs MCP. Cette architecture hybride offre les avantages organisationnels des systèmes multi-agents ainsi que les avantages de la normalisation et de l'écosystème du MCP. Cela suggère qu'il n'est peut-être pas nécessaire de faire un choix : il suffit d'utiliser les deux en tant qu'approche standard.</p><p>C'est à vous, en tant que développeur ou architecte, de tester et de déterminer le meilleur mélange de ces deux solutions pour obtenir le bon résultat pour votre cas d'utilisation spécifique. Comprendre les points forts, les limites et les applications appropriées de chaque approche vous permettra de construire des systèmes d'IA plus efficaces, plus faciles à maintenir et plus évolutifs.</p><p>Que vous construisiez une salle de presse numérique, une plateforme de service à la clientèle, un assistant de recherche ou toute autre application alimentée par le LLM, l'examen attentif de vos besoins de coordination (A2A) et des exigences d'accès aux outils (MCP) vous mettra sur la voie de la réussite.</p><h2>Ressources supplémentaires</h2><ul><li><p><strong>Elasticsearch Agent Builder </strong><a href="https://www.elastic.co/docs/solutions/search/elastic-agent-builder">: https://www.elastic.co/docs/solutions/search/elastic-agent-builder</a></p></li><li><p><strong>Spécification A2A</strong> <a href="https://a2a-protocol.org/latest/specification/">: https://a2a-protocol.org/latest/specification/</a></p></li><li><p><strong>Intégration A2A et MCP</strong> <a href="https://a2a-protocol.org/latest/topics/a2a-and-mcp/">: https://a2a-protocol.org/latest/topics/a2a-and-mcp/</a></p></li><li><p><strong>Modèle de protocole de contexte</strong> <a href="https://modelcontextprotocol.io/">: https://modelcontextprotocol.io</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/a2a-protocol-mcp-llm-agent-workflow-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/a2a-protocol-mcp-llm-agent-workflow-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Justin Castilla]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b1f22cdc2130333/6a17f161ec0f8917fa5a6712/f87330e5d4ca961593b3cfb861ca850a4cc34186-1519x1173.png" length="0" type="image/png"/>
    <pubDate>Mon, 24 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Vous savez, pour le contexte - Partie III : La puissance de la recherche hybride dans l'ingénierie contextuelle]]></title>
    <description><![CDATA[Découvrez comment utiliser l'ingénierie contextuelle et la recherche hybride pour améliorer la précision des résultats de l'IA avec des agrégations, RBAC et des signaux sans contenu.]]></description>
    <content:encoded><![CDATA[<p>Nous avons abordé la recherche hybride<a href="https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai">(partie I</a>) et l'ingénierie contextuelle<a href="https://www.elastic.co/search-labs/blog/context-engineering-llm-evolution-agentic-ai">(partie II)</a>; nous allons maintenant voir comment ces deux techniques fonctionnent ensemble pour fournir un contexte ciblé aux opérations de RAG et d'IA agentique.</p><h2>La recherche n'est pas morte, elle s'est simplement déplacée</h2><p>Nous sommes donc passés d'une recherche de contexte à l'aide d'une zone de texte et de l'utilisation des informations (le contexte) renvoyées pour construire les réponses nous-mêmes, à l'utilisation du langage naturel pour dire à un agent ce que nous voulons et lui permettre de rechercher et de compiler automatiquement la réponse pour nous. Nombreux sont ceux qui, dans le monde de la technologie, soulignent ce changement et proclament que "la recherche est morte" (certes, le monde du référencement et des mots publicitaires est en train de <a href="https://www.pewresearch.org/short-reads/2025/07/22/google-users-are-less-likely-to-click-on-links-when-an-ai-summary-appears-in-the-results/">changer</a>: les <a href="https://www.wired.com/story/goodbye-seo-hello-geo-brandlight-openai/">GEO</a>, par exemple), mais la recherche reste absolument essentielle pour les opérations agentiques - elle est simplement réalisée en grande partie à l'abri des regards par le biais d'outils.</p><p>Auparavant, les humains étaient les principaux arbitres de la pertinence subjective : chaque utilisateur a ses propres raisons d'effectuer une recherche, et son expérience personnelle influence la précision relative des résultats. Si nous voulons que les agents parviennent à la même conclusion (ou à une meilleure conclusion) que nous, nous devons nous assurer que les informations contextuelles auxquelles ils ont accès sont aussi proches que possible de notre intention subjective. Nous devons concevoir le contexte dans lequel nous fournissons les LLM en fonction de cet objectif !</p><h2>Générer du contexte avec la recherche hybride</h2><p>Je vous rappelle que la recherche hybride d'Elastic combine les points forts de la recherche traditionnelle par mot-clé (flexibilité syntaxique, précision des mots-clés et évaluation de la pertinence) avec la compréhension sémantique de la recherche par similarité vectorielle, et offre plusieurs techniques de reclassement. Cette synergie (il n'y a jamais eu d'usage plus vrai de ce mot !) permet d'obtenir des résultats très pertinents, avec des requêtes qui peuvent être beaucoup plus nuancées dans la manière dont elles ciblent le contenu. Il ne s'agit pas seulement d'appliquer la pertinence subjective à l'<em>une des</em> étapes de la recherche ; il s'agit en fait d'inclure la notation de la pertinence dans la première étape de la recherche, ainsi que tous les autres modes à la fois.</p><h3>Précision supérieure &amp; efficacité</h3><p>L'utilisation d'une plateforme de données capable de fournir des services de recherche, d'extraction et de reclassement distribués en tant que principal moteur de recherche contextuelle est très judicieuse. Vous pouvez utiliser une syntaxe d'interrogation avancée pour ajouter la composante manquante de l'intention subjective et filtrer le contenu qui pourrait distraire ou brouiller la valeur des informations contextuelles renvoyées. Vous pouvez sélectionner l'une des options syntaxiques individuelles disponibles ou combiner les modalités dans une recherche unique qui cible chaque type de données de la manière qu'elle comprend le mieux, puis les combiner ou les réordonner avec le reranking. Vous pouvez filtrer la réponse pour qu'elle ne contienne que les champs/valeurs que vous souhaitez, en évitant les données superflues. Au service des agents, cette souplesse de ciblage vous permet de créer des outils extrêmement précis dans la manière dont ils récupèrent le contexte.</p><h3>Raffinement du contexte (agrégations et signaux non liés au contenu)</h3><p>Les agrégations peuvent être particulièrement utiles pour façonner le contenu d'un outil dans la fenêtre contextuelle. Les agrégations fournissent naturellement des faits numériques sur la forme des données contextuelles renvoyées, ce qui permet aux LLM de raisonner plus facilement et avec plus de précision. Les agrégations pouvant être imbriquées hiérarchiquement, il est facile d'ajouter des détails à plusieurs niveaux pour que le mécanisme d'apprentissage tout au long de la vie génère une compréhension plus nuancée. Les agrégations peuvent également faciliter la gestion de la taille de la fenêtre contextuelle - vous pouvez facilement réduire le résultat d'une requête de 100 000 documents à quelques centaines de tokens d'informations agrégées.</p><p>Les signaux non liés au contenu sont les indicateurs inhérents à vos données qui vous donnent une vue d'ensemble de ce que vous regardez ; il s'agit des caractéristiques supplémentaires des résultats, comme la popularité, la fraîcheur, la géolocalisation, les catégories, la diversité des hôtes ou les fourchettes de prix. Ces éléments d'information peuvent être utiles à l'agent pour évaluer l'importance du contexte qu'il a reçu. Quelques exemples simples permettent d'illustrer au mieux ce propos :</p><ul><li><p><strong>Renforcer le contenu récemment publié et populaire</strong> - Imaginez que vous disposiez d'une base de connaissances contenant des articles. Vous souhaitez trouver des articles pertinents par rapport à la requête d'un utilisateur, mais vous voulez également favoriser les articles qui sont récents et qui ont été jugés utiles par d'autres utilisateurs (par exemple, qui ont un nombre élevé de "likes" ). Dans ce scénario, nous pouvons utiliser une recherche hybride pour trouver les articles pertinents, puis les classer en fonction de leur date de publication et de leur popularité.</p></li><li><p><strong>Recherche dans le domaine du commerce électronique avec ajustement des ventes et des stocks</strong> - Dans le cadre du commerce électronique, vous souhaitez montrer aux clients les produits qui correspondent à leur recherche, mais vous voulez également promouvoir les produits qui se vendent bien et qui sont en stock. Vous pouvez également déclasser les produits dont le stock est faible afin d'éviter la frustration des clients.</p></li><li><p><strong>Priorité aux problèmes de haute gravité dans un système de suivi des bogues</strong> - Pour une équipe de développement de logiciels, lorsqu'elle recherche des problèmes, il est essentiel de faire apparaître en premier les problèmes de haute gravité, de haute priorité et ceux qui ont été récemment mis à jour. Vous pouvez utiliser des signaux secondaires tels que "criticité" et "le plus discuté" pour pondérer les différents facteurs de manière indépendante, en veillant à ce que les questions les plus critiques et les plus activement discutées soient placées en tête.</p></li></ul><p>Ces exemples de requêtes et d'autres sont disponibles dans la <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/you-know-for-context/">page de contenu</a> Elasticsearch Labs qui les accompagne.</p><h3>Renforcement de la sécurité</h3><p>Un avantage essentiel de l'exploitation d'une couche de vitesse alimentée par la recherche telle qu'Elastic pour l'ingénierie contextuelle est son cadre de sécurité intégré. La plateforme d'Elastic garantit que le contexte fourni aux opérations d'IA agentique et générative respecte et protège les informations privées sensibles grâce à un contrôle d'accès granulaire basé sur les rôles (RBAC) et un contrôle d'accès basé sur les attributs (ABAC). Cela signifie que non seulement les requêtes sont traitées avec efficacité, mais aussi que les résultats sont filtrés en fonction des autorisations spécifiques de l'agent ou de l'utilisateur à l'origine de la demande.</p><p>Les agents s'exécutent en tant qu'utilisateur authentifié, de sorte que la sécurité est implicitement appliquée par le biais des fonctions de sécurité intégrées à la plateforme :</p><ul><li><p><strong>Permissions précises :</strong> Définissez l'accès au niveau du document, du champ ou même du terme, en veillant à ce que les agents d'intelligence artificielle ne reçoivent que les données qu'ils sont autorisés à consulter.</p></li><li><p><strong>Contrôle d'accès basé sur les rôles (RBAC) :</strong> Attribuer des rôles aux agents ou aux utilisateurs, en leur donnant accès à des ensembles de données ou à des fonctionnalités spécifiques en fonction des responsabilités qu'ils ont définies.</p></li><li><p><strong>Contrôle d'accès basé sur les attributs (ABAC) :</strong> Mettre en œuvre des politiques d'accès dynamiques basées sur les attributs des données, de l'utilisateur ou de l'environnement, permettant une sécurité hautement adaptable et consciente du contexte.</p></li><li><p><strong>Sécurité au niveau du document (DLS) et sécurité au niveau du champ (FLS) :</strong> Ces capacités garantissent que, même au sein d'un document récupéré, seules les parties autorisées sont visibles, empêchant ainsi l'exposition d'informations sensibles.</p></li><li><p><strong>Intégration avec la sécurité de l'entreprise :</strong> Intégration transparente avec les systèmes de gestion des identités existants (tels que LDAP, SAML, OIDC) afin d'appliquer des politiques de sécurité cohérentes dans l'ensemble de l'entreprise.</p></li></ul><p>En intégrant ces mesures de sécurité directement dans le mécanisme de récupération du contexte, Elastic agit comme un gardien sécurisé, garantissant que les agents d'intelligence artificielle opèrent dans des limites de données définies, empêchant l'exposition de données non autorisées et maintenant la conformité avec les réglementations en matière de confidentialité des données. Cela est primordial pour instaurer la confiance dans les systèmes d'IA agentique qui traitent des informations confidentielles ou exclusives.</p><p>En outre, l'utilisation d'une couche de vitesse unifiée sur les sources de données de l'entreprise permet d'alléger les charges de requêtes ad hoc inattendues sur ces référentiels que les outils agentiques créeraient. Vous disposez d'un lieu unique pour tout rechercher en temps quasi réel, et d'un lieu unique pour appliquer les contrôles de sécurité et de gouvernance.</p><h2>Outils hybrides basés sur la recherche</h2><p>La plateforme Elastic comporte certaines fonctionnalités de base (et d'<a href="https://www.elastic.co/blog/whats-new-elastic-9-2-0">autres sont en cours d'élaboration</a>) qui donnent un coup de fouet à l'ingénierie contextuelle. L'essentiel est que la plateforme offre une multitude de moyens de réaliser des choses, avec la flexibilité de s'adapter, de changer et d'étendre les méthodes au fur et à mesure que l'écosystème de l'IA progresse.</p><h3>Présentation de l'Agent Builder</h3><p>Elastic <a href="https://www.elastic.co/elasticsearch/agent-builder">Agent Builder</a> est notre première incursion dans le domaine des outils d'intelligence artificielle conçus pour dialoguer avec les données que vous stockez déjà dans Elastic. Agent Builder offre une interface de chat qui permet aux utilisateurs de créer et de gérer leurs propres agents et outils dans Kibana. Il est livré avec des serveurs MCP et A2A intégrés, des API programmatiques et un ensemble d'outils système prédéfinis pour l'interrogation et l'exploration des index Elasticsearch, ainsi que pour la génération de requêtes ES|QL à partir du langage naturel. Agent Builder vous permet de créer des outils personnalisés qui ciblent et sculptent les données contextuelles renvoyées à l'agent par le biais d'une syntaxe de requête <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> expressive.</p><p>Comment ES|QL effectue-t-il la recherche hybride ? La capacité de base est obtenue par la combinaison du type de champ <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">semantic_text</a> <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/fork">et des</a>commandes<a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/fuse">FORK/FUSE (FUSE utilise</a> <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">par défaut RRF</a> pour fusionner les résultats de chaque fourchette). Voici un exemple simple de recherche de produit fictif :</p>FROM products
| FORK
  (MATCH description "high performance gaming laptop" | EVAL search_type = "bm25"),
  (MATCH description_semantic "high performance gaming laptop" | EVAL search_type = "semantic")
| FUSE 
| LIMIT 20
| KEEP product_name, description, _score, search_type<p>La clause <a href="https://www.elastic.co/docs/reference/query-languages/esql/commands/eval">EVAL</a> incluse dans chacune des branches FORK de l'exemple ci-dessus n'est pas strictement nécessaire ; elle n'est incluse que pour démontrer comment vous pouvez suivre la modalité de recherche à partir de laquelle un résultat donné a été retourné.</p><h3>Recherche de modèles</h3><p>Supposons que vous souhaitiez faire pointer vos propres outils agentiques externes vers votre déploiement Elastic. Au lieu d'ES|QL, vous souhaitez utiliser des extracteurs à plusieurs niveaux ou réutiliser la syntaxe DSL existante que vous avez développée, et vous voulez également pouvoir contrôler les entrées acceptées par la requête, la syntaxe utilisée pour exécuter la recherche et les champs renvoyés dans le résultat. Les <a href="https://www.elastic.co/docs/solutions/search/search-templates">modèles de recherche</a> permettent aux utilisateurs de définir des structures prédéfinies pour les modèles de recherche courants, ce qui améliore l'efficacité et la cohérence de la recherche de données. Ceci est particulièrement bénéfique pour les outils agentiques qui interagissent avec les API de recherche, car ils aident à normaliser le code standard et permettent une itération plus rapide de la logique de recherche. Et si vous devez modifier l'un de ces facteurs, il vous suffit de mettre à jour le modèle de recherche et voilà, les changements sont appliqués. Si vous cherchez un exemple de modèles de recherche en action avec des outils agentiques, jetez un coup d'œil au blog d'Elasticsearch Labs "<a href="https://www.elastic.co/search-labs/blog/mcp-intelligent-search">MCP for intelligent search</a>", qui utilise un modèle de recherche derrière un appel d'outil à partir d'un serveur MCP externe.</p><h3>Flux de travail intégrés (FTW !)</h3><p>L'une des choses les plus difficiles à gérer dans notre nouveau monde d'IA agentique est la nature non déterministe des agents "raisonnants" semi-autonomes et autodirigés. L'ingénierie contextuelle est une discipline essentielle de l'IA agentique : il s'agit des techniques qui permettent de limiter les conclusions possibles de notre agent à ce que nous connaissons de la vérité de terrain. Même avec une fenêtre contextuelle très précise et pertinente (lorsque nous sortons du domaine des faits numériques), il nous manque toujours cette petite assurance que la réponse de l'agent est entièrement reproductible et fiable.</p><p>Lorsque vous soumettez plusieurs fois la même demande à un agent, les réponses peuvent être <em>essentiellement</em> les mêmes, avec <em>juste</em> une petite différence dans la réponse. C'est généralement bien pour les requêtes simples, peut-être à peine perceptible, et nous pouvons essayer de façonner le résultat à l'aide de techniques d'ingénierie contextuelle. Mais plus les tâches que nous demandons à nos agents sont complexes, plus il y a de chances qu'une ou plusieurs sous-tâches introduisent une variance qui modifie légèrement le résultat final. La situation s'aggravera probablement à mesure que nous commencerons à nous appuyer davantage sur les communications entre agents, et ces écarts deviendront cumulatifs. Cela confirme l'idée que les outils avec lesquels nos agents interagissent doivent être très souples et adaptables pour cibler précisément les données contextuelles, et qu'ils doivent répondre dans un format de sortie attendu. Il indique également que pour de nombreux cas d'utilisation, nous avons besoin de diriger les interactions entre l'agent et l'outil - c'est là que les flux de travail entrent en jeu !</p><p>Elastic disposera bientôt de flux de travail entièrement personnalisables, intégrés au cœur de la plateforme. Ces flux de travail pourront fonctionner avec des agents et des outils de manière bidirectionnelle, de sorte que les flux de travail pourront appeler des agents et des outils, et que les agents et les outils pourront appeler des flux de travail. L'intégration complète de ces capacités dans la même plateforme d'IA de recherche, où toutes vos données sont stockées, sera un facteur de transformation. Bientôt, très bientôt !</p><h3>Elastique comme la banque de mémoire unifiée</h3><p>En tant que plateforme de données distribuées conçue pour la recherche en temps quasi réel, Elastic remplit naturellement les fonctions de mémoire à long terme pour les systèmes d'IA agentique. Avec l'expérience de chat intégrée d'Agent Builder, nous disposons également d'un suivi et d'une gestion de la mémoire à court terme et de l'historique des chats. Et comme toute la plateforme est fondée sur l'API, il est extrêmement facile d'utiliser Elastic comme plateforme pour conserver les résultats contextuels d'un outil (et pouvoir s'y référer ultérieurement) qui pourraient dépasser la fenêtre contextuelle de l'agent ; cette technique est parfois appelée "<a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents#:~:text=Agents%20can%20assemble%20understanding%20layer%20by%20layer%2C%20maintaining%20only%20what%27s%20necessary%20in%20working%20memory%20and%20leveraging%20note%2Dtaking%20strategies%20for%20additional%20persistence">prise de notes</a>" dans les cercles de l'ingénierie contextuelle.</p><p>Le fait de disposer d'une mémoire à court terme et d'une mémoire à long terme sur la même plateforme de recherche présente de nombreux avantages intrinsèques : imaginez que vous puissiez utiliser les historiques de chat et les réponses contextuelles persistantes pour influencer sémantiquement les futures interactions de chat, ou pour effectuer une analyse des menaces, ou pour créer des produits de données persistants générés automatiquement à partir d'appels d'outils fréquemment répétés... Les possibilités sont infinies !</p><h2>Conclusion</h2><p>L'émergence de grands modèles de langage a modifié la façon dont nous pouvons faire correspondre le contenu et les méthodes que nous utilisons pour interroger nos données. Nous nous éloignons rapidement de notre monde actuel, où les humains effectuent les recherches, les considérations contextuelles et le raisonnement logique pour répondre à leurs propres questions, pour passer à un monde où ces étapes sont largement automatisées grâce à l'IA agentique. Pour que nous puissions faire confiance aux réponses générées que nous recevons, nous devons avoir l'assurance que l'agent a pris en compte <em>toutes les</em> informations <em>les plus pertinentes</em> (y compris le facteur de la pertinence subjective) pour générer sa réponse. Notre principale méthode pour rendre l'IA agentique digne de confiance consiste à ancrer les outils qui récupèrent un contexte supplémentaire grâce aux techniques de RAG et d'ingénierie contextuelle, mais la manière dont ces outils effectuent la <em>récupération initiale</em> peut être déterminante pour la précision de la réponse.</p><p>La plateforme d'IA Elastic Search offre la flexibilité et les avantages de la recherche hybride, ainsi que plusieurs fonctionnalités intégrées qui aident l'IA agentique en termes de précision, de performance et d'évolutivité ; en d'autres termes, Elastic est une plateforme fantastique pour plusieurs aspects de l'ingénierie contextuelle ! En normalisant la recherche de contexte via une plateforme de recherche, nous simplifions les opérations de l'outil agentique sur plusieurs fronts - et comme l'oxymore "ralentir pour aller plus vite", la simplicité au niveau de la couche de génération de contexte signifie une IA agentique plus rapide et plus digne de confiance.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-agentic-ai-accuracy</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-agentic-ai-accuracy</guid>
    <category><![CDATA[Recherche hybride]]></category>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Woody Walton]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt42a203a316f0e22e/6a170932b339d58ebc769f5f/b82ff25242e4229cc20b218d9cc91c60cfd680bc-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 20 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Vous savez, pour le contexte - Partie II : L'IA agentique et le besoin d'ingénierie contextuelle]]></title>
    <description><![CDATA[Découvrez comment l'évolution des LLM vers l'IA agentique augmente le besoin d'ingénierie contextuelle pour résoudre les limites du contexte RAG et la gestion de la mémoire.]]></description>
    <content:encoded><![CDATA[<p>Avec ce <a href="https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai">contexte</a> (relativement étendu) sur la façon dont les LLM ont changé les processus sous-jacents de la recherche d'informations, voyons comment ils ont également changé la façon dont nous interrogeons les données.</p><h2>Une nouvelle façon d'interagir avec les données</h2><p>L'IA générative (genAI) et l'IA agentique agissent différemment de la recherche traditionnelle. Alors que nous commencions à rechercher des informations par une recherche ("laissez-moi chercher cela sur Google..."), l'action initiale de l'IA générique et des agents se fait généralement par le biais d'un langage naturel saisi dans une interface de dialogue en ligne. L'interface de chat est une discussion avec un LLM qui utilise sa compréhension sémantique pour transformer notre question en une réponse distillée, une réponse résumée semblant provenir d'un oracle qui a une connaissance étendue de toutes sortes d'informations. Ce qui fait vraiment la différence, c'est la capacité du LLM à produire des phrases cohérentes et réfléchies qui rassemblent les éléments de connaissance qu'il fait apparaître - même s'ils sont inexacts ou totalement hallucinés, ils ont une certaine <a href="https://en.wikipedia.org/wiki/Truthiness">véracité</a>.</p><p>Cette vieille barre de recherche avec laquelle nous avons été tellement habitués à interagir peut être considérée comme le moteur RAG que nous utilisions lorsque <em><strong>nous</strong></em> étions nous-mêmes l'agent de raisonnement. Aujourd'hui, même les moteurs de recherche Internet transforment notre expérience de recherche lexicale bien connue en aperçus pilotés par l'IA qui répondent à la requête par un résumé des résultats, ce qui permet aux utilisateurs d'éviter de cliquer et d'évaluer eux-mêmes les résultats individuels.</p><h2>IA générative &amp; RAG</h2><p>L'IA générative tente d'utiliser sa compréhension sémantique du monde pour analyser l'intention subjective exprimée dans une demande de chat, puis utilise ses capacités d'inférence pour créer une réponse d'expert à la volée. L'interaction générative de l'IA comporte plusieurs parties : elle commence par l'entrée/la requête de l'utilisateur, les conversations précédentes dans la session de chat peuvent être utilisées comme contexte supplémentaire, et l'instruction qui indique au LLM comment raisonner et quelles sont les procédures à suivre pour construire la réponse. Les messages-guides ont évolué, passant d'une simple orientation du type ", "Expliquez-moi cela comme si j'étais un enfant de cinq ans", à des descriptions complètes de la manière de traiter les demandes. Ces décompositions comprennent souvent des sections distinctes décrivant les détails du personnage/rôle de l'IA, le raisonnement avant la génération/le processus de réflexion interne, les critères objectifs, les contraintes, le format de sortie, le public, ainsi que des exemples pour aider à démontrer les résultats attendus.</p><p>En plus de la requête de l'utilisateur et de l'invite du système, la génération augmentée de recherche (RAG) fournit des informations contextuelles supplémentaires dans ce que l'on appelle une "fenêtre contextuelle". RAG a été un ajout essentiel à l'architecture ; c'est ce que nous utilisons pour informer le LLM des pièces manquantes dans sa compréhension sémantique du monde.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbfa000ccfdd9d184/6a17ddb57b54f955f38b37da/5b9671d5d07d4caefde372bb3188000754a91eed-1470x746.png" alt="Comment les LLM traitent les demandes des utilisateurs et créent un contexte" /><p>Les fenêtres contextuelles peuvent être un peu <a href="https://www.dbreunig.com/2025/06/22/how-contexts-fail-and-how-to-fix-them.html">tatillonnes</a> en ce qui concerne le contenu, l'emplacement et la quantité que vous leur donnez. Le contexte sélectionné est bien sûr très important, mais le rapport signal/bruit du contexte fourni est également important, de même que la longueur de la fenêtre.</p><h3>Trop peu d'informations</h3><p>Le fait de fournir trop peu d'informations dans une fenêtre de requête, d'invite ou de contexte peut entraîner des hallucinations, car le LLM ne peut pas déterminer avec précision le contexte sémantique correct à partir duquel générer une réponse. La similarité vectorielle de la taille des morceaux de documents pose également des problèmes - une question courte et simple peut ne pas correspondre sémantiquement aux documents riches et détaillés trouvés dans nos bases de connaissances vectorisées. Des techniques d'expansion des requêtes telles que <a href="https://medium.com/data-science/how-to-use-hyde-for-better-llm-rag-retrieval-a0aa5d0e23e8">Hypothetical Document Embeddings (HyDE)</a> ont été développées. Elles utilisent les LLM pour générer une réponse hypothétique qui est plus riche et plus expressive que la requête courte. Le danger ici, bien sûr, est que le document hypothétique est lui-même une hallucination qui éloigne encore plus le LLM du contexte correct.</p><h3>Trop d'informations</h3><p>Tout comme pour nous, un excès d'informations dans une fenêtre contextuelle peut submerger un MLD et le rendre confus quant aux éléments importants. Le débordement de contexte (ou "<a href="https://research.trychroma.com/context-rot">pourriture de contexte</a>") affecte la qualité et les performances des opérations d'IA générative ; il a un impact considérable sur le "budget d'attention" du LLM (sa mémoire de travail) et dilue la pertinence parmi de nombreux éléments concurrents. Le concept de "rotation du contexte" comprend également l'observation selon laquelle les LLM ont tendance à avoir un <a href="https://alexandrabarr.beehiiv.com/p/context-windows">biais de position</a> - ils préfèrent le contenu au début ou à la fin d'une fenêtre contextuelle au contenu de la section centrale.</p><h3>Informations distrayantes ou contradictoires</h3><p>Plus la fenêtre contextuelle est grande, plus il y a de chances qu'elle contienne des informations superflues ou contradictoires qui peuvent distraire le LLM de la sélection et du traitement du contexte correct. D'une certaine manière, il s'agit d'un problème d'entrée et de sortie de déchets : le simple fait de déverser un ensemble de résultats de documents dans une fenêtre contextuelle donne au LLM beaucoup d'informations à mâcher (potentiellement trop), mais en fonction de la manière dont le contexte a été sélectionné, il y a une plus grande possibilité que des informations contradictoires ou non pertinentes s'infiltrent dans le système.</p><h2>IA agentique</h2><p>Je vous avais dit qu'il y avait beaucoup de terrain à couvrir, mais nous l'avons fait - nous parlons enfin de sujets liés à l'IA agentique ! L'IA agentique est une nouvelle utilisation très intéressante des interfaces de chat LLM qui développe la capacité de l'IA générative (peut-on déjà l'appeler "ancienne" ?) à synthétiser des réponses basées sur ses propres connaissances et sur les informations contextuelles que vous lui fournissez. Au fur et à mesure que l'IA générative gagnait en maturité, nous avons réalisé qu'il existait un certain niveau de tâches et d'automatisation que nous pouvions confier aux LLM, initialement reléguées à des activités fastidieuses à faible risque qui peuvent facilement être vérifiées/validées par un être humain. En peu de temps, ce champ d'application initial s'est élargi : une fenêtre de discussion LLM peut désormais être l'étincelle qui envoie un agent d'intelligence artificielle planifier, exécuter, évaluer et adapter son plan de manière itérative afin d'atteindre l'objectif spécifié. Les agents ont accès au raisonnement de leur LLM, à l'historique des discussions et à la mémoire de pensée (telle qu'elle est), et ils disposent également d'outils spécifiques qu'ils peuvent utiliser à cette fin. Nous voyons aussi maintenant des architectures qui permettent à un agent de haut niveau de fonctionner comme l'orchestrateur de plusieurs <a href="https://www.philschmid.de/the-rise-of-subagents">sous-agents</a>, chacun avec ses propres chaînes logiques, ses jeux d'instructions, son contexte et ses outils.</p><p>Les agents sont le point d'entrée d'un flux de travail essentiellement automatisé : ils sont autodirigés en ce sens qu'ils sont capables de discuter avec un utilisateur et d'utiliser ensuite la "logique" pour déterminer les outils dont ils disposent pour répondre à la question de l'utilisateur. Les outils sont généralement considérés comme passifs par rapport aux agents et construits pour effectuer un seul type de tâche. Les <em>types de</em> tâches qu'un outil pourrait accomplir sont en quelque sorte illimités (ce qui est vraiment passionnant !), mais l'une des principales tâches des outils est de rassembler des informations contextuelles qu'un agent doit prendre en compte lors de l'exécution de son flux de travail.</p><p>En tant que technologie, l'IA agentique en est encore à ses balbutiements et est sujette à l'équivalent LLM du trouble déficitaire de l'attention - elle oublie facilement ce qu'on lui a demandé de faire, et part souvent faire d'autres choses qui ne faisaient pas du tout partie du cahier des charges. Sous cette apparente magie, les capacités de "raisonnement" des LLM sont toujours basées sur la prédiction du prochain jeton le plus probable dans une séquence. Pour que le raisonnement (ou, un jour, l'intelligence artificielle générale (AGI)) devienne fiable et digne de confiance, nous devons être en mesure de vérifier que, lorsqu'on leur donne les informations correctes et les plus récentes, ils raisonnent de la manière que nous attendons d'eux (et nous donnent peut-être ce petit plus auquel nous n'aurions pas pensé nous-mêmes). Pour ce faire, les architectures agentiques devront être capables de communiquer clairement (protocoles), de respecter les flux de travail et les contraintes que nous leur imposons (garde-fous), de se rappeler où elles en sont dans une tâche (état), de gérer leur espace mémoire disponible et de valider que leurs réponses sont exactes et répondent aux critères de la tâche.</p><h2>Parlez-moi dans une langue que je peux comprendre</h2><p>Comme c'est souvent le cas dans les nouveaux domaines de développement (en particulier dans le monde des LLM), il existait initialement plusieurs approches pour les communications entre agents et outils, mais elles ont rapidement convergé vers le <a href="https://modelcontextprotocol.io/docs/getting-started/intro">protocole de contexte de modèle (MCP)</a> en tant que norme de facto. La définition du protocole de contexte de modèle est vraiment dans le nom - c'est le <strong>protocole</strong> qu'un <strong>modèle</strong> utilise pour demander et recevoir des informations <strong>contextuelles</strong>. MCP agit comme un adaptateur universel permettant aux agents LLM de se connecter à des outils et à des sources de données externes ; il simplifie et normalise les API de manière à ce que les différents cadres et outils LLM puissent facilement interopérer. Cela fait de MCP une sorte de point de pivot entre la logique d'orchestration et les invites du système données à un agent pour qu'il les exécute de manière autonome au service de ses objectifs, et les opérations envoyées à des outils pour qu'ils les exécutent de manière plus isolée (isolée au moins par rapport à l'agent qui en est à l'origine).</p><p>Cet écosystème est tellement nouveau que chaque direction d'expansion semble être une nouvelle frontière. Nous disposons de protocoles similaires pour les interactions entre agents<a href="https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/">(Agent2Agent (A2A)</a> natch !) ainsi que d'autres projets visant à améliorer la mémoire de raisonnement des agents<a href="https://venturebeat.com/ai/new-memory-framework-builds-ai-agents-that-can-handle-the-real-worlds">(ReasoningBank</a>), à sélectionner le meilleur serveur MCP pour le travail à effectuer<a href="https://arxiv.org/abs/2505.03275">(RAG-MCP</a>), et à utiliser l'analyse sémantique telle que la classification "zero-shot" et la détection de motifs sur les entrées et les sorties comme <a href="https://openai.github.io/openai-guardrails-python/">garde-fous</a> pour contrôler ce sur quoi un agent est autorisé à opérer.</p><p>Vous avez peut-être remarqué que l'intention sous-jacente de chacun de ces projets est d'améliorer la qualité et le contrôle des informations renvoyées à une fenêtre contextuelle agent/genAI ? Alors que l'écosystème de l'IA agentique continue de développer la capacité à mieux traiter ces informations contextuelles (pour les contrôler, les gérer et les exploiter), il sera toujours nécessaire d'extraire les informations contextuelles <em>les plus pertinentes</em> pour que l'agent puisse les mouliner.</p><h2>Bienvenue dans l'ingénierie contextuelle !</h2><p>Si vous êtes familier avec les termes de l'IA générative, vous avez probablement entendu parler de "l'ingénierie des messages" - à ce stade, il s'agit presque d'une pseudo-science à part entière. L'ingénierie des invites est utilisée pour trouver les moyens les meilleurs et les plus efficaces de décrire de manière proactive les comportements que vous souhaitez que le MLD utilise pour générer sa réponse. L'"<a href="https://www.elastic.co/search-labs/blog/context-engineering-overview">ingénierie du contexte</a>" étend les techniques d'"ingénierie de l'invite" au-delà du côté de l'agent pour couvrir également les sources de contexte et les systèmes disponibles du côté des outils du protocole MCP, et comprend les thèmes généraux de la gestion, du traitement et de la génération du contexte :</p><ul><li><p><strong>Gestion du contexte </strong>- liée au maintien de l'efficacité de l'état et du contexte dans des flux de travail agentiques de longue durée et/ou plus complexes. Planification itérative, suivi et orchestration des tâches et de l'utilisation des outils pour atteindre les objectifs de l'agent. En raison du "budget d'attention" limité dont disposent les agents, la gestion du contexte concerne principalement les techniques qui permettent d'affiner la fenêtre contextuelle afin de capturer à la fois la portée la plus complète et les éléments les plus importants du contexte (sa précision par rapport à son rappel !). Les techniques comprennent la compression, le résumé et la persistance du contexte des étapes précédentes ou des appels d'outils pour faire de la place dans la mémoire de travail pour le contexte supplémentaire des étapes suivantes.</p></li><li><p><strong>Traitement du contexte </strong>- Les étapes logiques et, espérons-le, essentiellement programmatiques visant à intégrer, normaliser ou affiner le contexte acquis à partir de sources disparates afin que l'agent puisse raisonner sur l'ensemble du contexte d'une manière quelque peu uniforme. Le travail sous-jacent consiste à faire en sorte que le contexte provenant de toutes les sources (invites, RAG, mémoire, etc.) soit consommé par l'agent le plus efficacement possible. </p></li><li><p><strong>Génération de contexte </strong>- Si le traitement du contexte consiste à rendre le contexte récupéré utilisable par l'agent, alors la génération de contexte donne à l'agent la possibilité de demander et de recevoir ces informations contextuelles supplémentaires à volonté, mais aussi avec des contraintes.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5e1e68c08fe050bc/6a17ddb7414c645035945073/4a8240e1eb078b2294b8d981b9caa8593589cac4-1600x900.png" alt="L'ingénierie contextuelle dans les programmes d'éducation et de formation tout au long de la vie" /><p>Les différents éphémères des applications de chat du LLM correspondent directement (et parfois de manière redondante) à ces fonctions de haut niveau de l'ingénierie contextuelle :</p><ul><li><p><strong>Instructions / invite du système</strong> - Les invites constituent l'échafaudage de la manière dont l'activité générative (ou agentique) de l'IA orientera sa réflexion vers la réalisation de l'objectif de l'utilisateur. Les messages-guides constituent un contexte à part entière ; il ne s'agit pas seulement d'instructions tonales - ils comprennent aussi souvent une logique d'exécution des tâches et des règles telles que "réfléchir étape par étape" ou "respirer profondément" avant de répondre afin de s'assurer que la réponse répond pleinement à la demande de l'utilisateur. Des tests récents ont montré que les langages de balisage sont très efficaces pour encadrer les différentes parties d'une invite, mais il faut également veiller à calibrer les instructions de manière à ce qu'elles soient à la fois trop vagues et trop spécifiques ; nous voulons donner suffisamment d'instructions pour que le LLM trouve le bon contexte, mais sans être trop prescriptif au point de passer à côté d'idées inattendues.</p></li><li><p><strong>Mémoire à court terme</strong> (état/historique) - La mémoire à court terme correspond essentiellement aux interactions de la session de chat entre l'utilisateur et le LLM. Ils sont utiles pour affiner le contexte lors des sessions en direct et peuvent être sauvegardés pour être retrouvés et poursuivis ultérieurement. </p></li><li><p><strong>Mémoire à long terme</strong> - La mémoire à long terme doit être constituée d'informations utiles pour plusieurs sessions. Et il ne s'agit pas seulement de bases de connaissances spécifiques à un domaine auxquelles on accède par le biais de RAG ; des recherches récentes utilisent les résultats de demandes d'IA agentique/générative antérieures pour apprendre et se référer aux interactions agentiques actuelles. Certaines des innovations les plus intéressantes dans le domaine de la mémoire à long terme sont liées à l'ajustement de la manière dont l'état est <a href="https://steve-yegge.medium.com/introducing-beads-a-coding-agent-memory-system-637d7d92514a">stocké et relié</a> afin que les agents puissent reprendre là où ils se sont arrêtés. </p></li><li><p><strong>Sortie structurée</strong> - La cognition nécessite un effort, il n'est donc pas surprenant que même avec des capacités de raisonnement, les LLM (tout comme les humains) veulent dépenser moins d'effort lorsqu'ils pensent, et en l'absence d'une API ou d'un protocole défini, avoir une carte (un schéma) sur la façon de lire les données renvoyées par un appel d'outil est extrêmement utile. L'inclusion de <a href="https://platform.openai.com/docs/guides/structured-outputs?lang=javascript">sorties structurées</a> dans le cadre agentique contribue à rendre ces interactions machine-machine plus rapides et plus fiables, en réduisant les besoins d'analyse.</p></li><li><p><strong>Outils disponibles</strong> - Les outils peuvent faire toutes sortes de choses, de la collecte d'informations supplémentaires (par exemple, en émettant des requêtes RAG vers les référentiels de données de l'entreprise, ou par le biais d'API en ligne) à l'exécution d'actions automatisées au nom de l'agent (comme la réservation d'une chambre d'hôtel sur la base des critères de la demande de l'agent). Les outils peuvent également être des sous-agents disposant de leur propre chaîne de traitement agentique. </p></li><li><p><strong>Retrieval Augmented Generation (RAG)</strong> - J'aime beaucoup la description de RAG en tant qu'"intégration dynamique des connaissances". Comme décrit précédemment, le RAG est la technique permettant de fournir les informations supplémentaires auxquelles le LLM n'a pas eu accès lors de sa formation, ou bien il s'agit d'une réitération des idées que nous pensons être les plus importantes pour obtenir la bonne réponse - celle qui est la plus pertinente par rapport à notre requête subjective.</p></li></ul><h2>Une puissance cosmique phénoménale, un espace de vie minuscule !</h2><p>L'IA agentique a tant de nouveaux domaines fascinants et passionnants à explorer ! Il y a encore beaucoup de problèmes traditionnels de recherche et de traitement de données à résoudre, mais aussi de toutes nouvelles catégories de défis qui commencent seulement à être exposés à la lumière du jour dans la nouvelle ère des LLM. Bon nombre des problèmes immédiats auxquels nous sommes confrontés aujourd'hui sont liés à l'ingénierie contextuelle, c'est-à-dire au fait de fournir aux MFR les informations contextuelles supplémentaires dont ils ont besoin sans surcharger leur espace de mémoire de travail, qui est limité.</p><p>La flexibilité des agents semi-autonomes ayant accès à un ensemble d'outils (et à d'autres agents) donne lieu à tant de nouvelles idées pour la mise en œuvre de l'IA qu'il est difficile d'imaginer les différentes façons dont nous pourrions assembler les pièces du puzzle. La plupart des recherches actuelles s'inscrivent dans le domaine de l'ingénierie contextuelle et se concentrent sur la construction de structures de gestion de la mémoire capables de gérer et de suivre de plus grandes quantités de contexte. En effet, les problèmes de réflexion approfondie que nous voulons vraiment que les LLM résolvent présentent une complexité accrue et des étapes de réflexion plus longues et multiphases, où la mémorisation est extrêmement importante.</p><p>Une grande partie de l'expérimentation en cours dans le domaine consiste à essayer de trouver la gestion optimale des tâches et les configurations d'outils pour alimenter la gueule de l'agent. Chaque appel d'outil dans la chaîne de raisonnement d'un agent entraîne un coût cumulatif, à la fois en termes de calcul pour exécuter la fonction de l'outil et d'impact sur la fenêtre contextuelle limitée. Certaines des dernières techniques de gestion du contexte pour les agents LLM ont provoqué des effets en chaîne involontaires tels que l'"<a href="https://venturebeat.com/ai/ace-prevents-context-collapse-with-evolving-playbooks-for-self-improving-ai">effondrement du contexte</a>", où la compression/le résumé du contexte accumulé pour les tâches de longue durée entraîne <em>trop</em> de pertes. Le résultat souhaité est de disposer d'outils qui renvoient un contexte succinct et précis, sans que des informations superflues ne viennent empiéter sur l'espace mémoire précieux de la fenêtre de contexte.</p><h3>Tant/trop de possibilités</h3><p>Nous voulons une séparation des tâches avec la possibilité de réutiliser les outils/composants, il est donc tout à fait logique de créer des outils agentiques dédiés pour se connecter à des sources de données spécifiques - chaque outil peut se spécialiser dans l'interrogation d'un type de référentiel, d'un type de flux de données, ou même d'un cas d'utilisation. Mais attention : dans le but de gagner du temps/de l'argent/de prouver que quelque chose est possible, la tentation sera grande d'utiliser les MLD comme outil de fédération... Essayez de ne pas le faire, nous sommes déjà passés par <a href="https://www.elastic.co/pdf/elastic-distributed-not-federated-search.pdf">là</a>! La recherche fédérée agit comme un "traducteur universel" qui convertit une requête entrante dans la syntaxe que le référentiel distant comprend, et qui doit ensuite rationaliser les résultats provenant de sources multiples en une réponse cohérente. La fédération en tant que technique <em>fonctionne</em> <em>bien</em> à petite échelle, mais à grande échelle et surtout lorsque les données sont multimodales, la fédération tente de combler des lacunes qui sont tout simplement trop importantes.</p><p>Dans le monde agentique, l'agent serait le fédérateur et les outils (par l'intermédiaire de MCP) seraient les connexions définies manuellement vers des ressources disparates. L'utilisation d'outils dédiés pour accéder à des sources de données non connectées peut sembler être une nouvelle façon puissante d'unir dynamiquement différents flux de données sur la base d'une requête, mais l'utilisation d'outils pour poser la même question à plusieurs sources finira probablement par causer plus de problèmes qu'elle n'en résoudra. Chacune de ces sources de données est probablement constituée de différents types de référentiels, chacun ayant ses propres capacités de récupération, de classement et de sécurisation des données qu'il contient. Ces écarts ou "décalages d'impédance" entre les référentiels augmentent bien entendu la charge de traitement. Ils peuvent également introduire des informations ou des signaux contradictoires, où quelque chose d'apparemment inoffensif comme un décalage de notation peut perturber considérablement l'importance accordée à un élément de contexte renvoyé, et affecter la pertinence de la réponse générée en fin de compte.</p><h3>Le changement de contexte est également difficile pour les ordinateurs</h3><p>Lorsque vous envoyez un agent en mission, sa première tâche consiste souvent à trouver toutes les données pertinentes auxquelles il a accès. Tout comme pour les humains, si chaque source de données à laquelle l'agent se connecte fournit des réponses dissemblables et désagrégées, il y aura une charge cognitive (mais pas exactement du même type) associée à l'extraction des éléments contextuels saillants du contenu récupéré. Cela prend du temps/du calcul, et chaque petit morceau s'additionne dans la chaîne logique agentique. Cela conduit à la conclusion que, à l'instar de ce qui est discuté pour <a href="https://blog.cloudflare.com/code-mode/">MCP</a>, la plupart des outils agentiques devraient plutôt se comporter comme des API - des fonctions isolées avec des entrées et des sorties connues, réglées pour répondre aux besoins de différents types d'agents. Ils <a href="https://arxiv.org/html/2501.12372v5">parviennent</a> beaucoup mieux à relier les points sémantiques, en particulier lorsqu'il s'agit d'une tâche telle que la traduction du langage naturel en syntaxe structurée, lorsqu'ils disposent d'un schéma auquel se référer (RTFM en effet !).</p><h2>7ème manche !</h2><p>Nous avons maintenant abordé l'<a href="https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai">impact des LLM sur la recherche et l'interrogation de données</a>, ainsi que la manière dont la fenêtre de discussion évolue vers l'expérience de l'IA agentique. Mettons les deux sujets ensemble et voyons comment nous pouvons utiliser nos nouvelles capacités de recherche et d'extraction pour améliorer nos résultats en matière d'ingénierie contextuelle. En route pour la <a href="https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-agentic-ai-accuracy">troisième partie : la puissance de la recherche hybride dans l'ingénierie contextuelle</a>!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/context-engineering-llm-evolution-agentic-ai</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/context-engineering-llm-evolution-agentic-ai</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Woody Walton]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5f98889141fba45b/6a17ddb80b0bed0822dd34a2/79c0378b68d74d9e018c35ee2c1fd17daeee9f2c-1080x608.webp" length="0" type="image/webp"/>
    <pubDate>Tue, 18 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Création d'une salle de presse LLM Agent avec le protocole A2A et MCP dans Elasticsearch : Partie I]]></title>
    <description><![CDATA[Explorer les concepts du protocole A2A et du MCP dans le cadre d'un exemple pratique de salle de presse où des agents LLM spécialisés collaborent à la recherche, à la rédaction, à l'édition et à la publication d'articles de presse.]]></description>
    <content:encoded><![CDATA[<h2>Introduction</h2><p>Les systèmes actuels soutenus par le LLM évoluent rapidement au-delà des applications à modèle unique vers des réseaux complexes où des agents spécialisés travaillent ensemble pour accomplir des tâches que l'informatique moderne n'aurait jamais cru possibles auparavant. Au fur et à mesure que ces systèmes gagnent en complexité, l'infrastructure permettant la communication entre les agents et l'accès aux outils devient l'objectif principal du développement. Deux approches complémentaires sont apparues pour répondre à ces besoins : Les protocoles <strong>Agent2Agent (A2A)</strong> pour la coordination multi-agents, et le <strong>Model Context Protocol (MCP)</strong> pour l'accès standardisé aux outils et aux ressources.</p><p>Comprendre quand utiliser l'un et l'autre en harmonie ou non peut avoir un impact significatif sur l'évolutivité, la maintenabilité et l'efficacité de vos applications. Cet article explore les concepts et les implémentations de l'<strong>A2A</strong> dans l'exemple pratique d'une salle de presse numérique, où des agents LLM spécialisés collaborent à la recherche, à la rédaction, à l'édition et à la publication d'articles de presse.</p><p>Un référentiel d'accompagnement est disponible <a href="https://github.com/justincastilla/elastic-newsroom/tree/main">ici</a>, et nous examinerons des exemples concrets d'A2A en action vers la fin de l'article, à la section 5.</p><h3>Produits requis</h3><p>Le <a href="https://github.com/justincastilla/elastic-newsroom/tree/main">référentiel</a> est constitué d'implémentations basées sur Python des agents A2A. Un serveur API est fourni en Flask, ainsi qu'un service de messagerie Python personnalisé appelé Event Hub, qui achemine les messages pour la journalisation et les mises à jour de l'interface utilisateur. Enfin, une interface utilisateur React est fournie pour une utilisation autonome des fonctionnalités de la salle de presse. Tout est contenu dans une image Docker pour faciliter la mise en œuvre. Si vous souhaitez utiliser les services directement sur votre machine, vous devez vous assurer que ces technologies sont installées :</p><p>Langages et moteurs d'exécution</p><ul><li><p>Python 13.12 - Langage de base du backend</p></li><li><p>Node.js 18+ - React UI en option</p></li></ul><p>Cadres de base et SDKS :</p><ul><li><p>A2A SDK 0.3.8 - Coordination et communication des agents</p></li><li><p>Anthropic SDK - Intégration de Claude pour la génération d'IA</p></li><li><p>Uvicorn - Serveur ASGI pour l'exécution des agents</p></li><li><p>FastMCP 2.12.5+ - Implémentation du serveur MCP</p></li><li><p>React 18.2 - Cadre d'interface utilisateur frontale</p></li></ul><p>Données &amp; recherche</p><ul><li><p>Elasticsearch 9.1.1+ - Indexation et recherche d'articles</p></li></ul><p>Déploiement de Docker (facultatif, mais recommandé)</p><ul><li><p>Docker 28.5.1+</p></li></ul><h2>Section 1 : Qu'est-ce que l'Agent2Agent (A2A) ?</h2><h3>Définition et concepts de base</h3><p>Agent2Agent (A2A) est un protocole standardisé pour l'interaction entre des agents LLM indépendants. Plutôt que de confier toutes les tâches à un seul système monolithique, l'A2A permet à plusieurs agents spécialisés de communiquer, de coordonner et de collaborer afin d'accomplir des flux de travail complexes qui seraient difficiles, lents ou carrément impossibles à gérer efficacement par un seul agent.</p><p><strong>Spécification officielle</strong> <a href="https://a2a-protocol.org/latest/specification/">: https://a2a-protocol.org/latest/specification/</a></p><h3>Origines et évolution</h3><p>Le concept de communication Agent2Agent, ou de systèmes multi-agents, trouve ses racines dans les systèmes distribués, les microservices et la recherche multi-agents qui remonte à <a href="https://en.wikipedia.org/wiki/Multi-agent_system">plusieurs dizaines d'années</a>. Les premiers travaux sur l'intelligence artificielle distribuée ont jeté les bases d'agents capables de négocier, de coordonner et de collaborer. Ces premiers systèmes étaient destinés à des <a href="https://www.jasss.org/5/1/7.html">simulations sociales</a> à grande échelle, à la <a href="https://arxiv.org/html/2410.09403v1">recherche universitaire</a> et à la <a href="https://www.researchgate.net/publication/334765661_Generation_Expansion_Planning_Considering_Investment_Dynamic_of_Market_Participants_Using_Multi-agent_System">gestion des réseaux électriques</a>.</p><p>Avec l'arrivée des LLM et la réduction des coûts d'exploitation, les systèmes multi-agents sont devenus accessibles aux marchés "grand public", avec le soutien de Google et de l'ensemble de la communauté des chercheurs en intelligence artificielle. Désormais connu sous le nom de systèmes Agent2Agent, l'ajout du protocole A2A a évolué pour devenir une norme moderne conçue spécifiquement pour l'ère des modèles linguistiques multiples et de grande envergure coordonnant les efforts et les tâches.</p><p>Le protocole A2A garantit une communication et une coordination transparentes entre les agents en appliquant des normes et des principes cohérents aux points d'interaction où les MFR se connectent et communiquent. Cette normalisation permet aux agents de différents développeurs - utilisant différents modèles sous-jacents - de travailler ensemble de manière efficace.</p><p>Les protocoles de communication ne sont pas nouveaux et sont largement ancrés dans presque toutes les transactions numériques effectuées sur l'internet. Si vous avez tapé <a href="https://www.elastic.co/search-labs">https://www.elastic.co/search-labs</a> dans un navigateur pour accéder à cet article, il y a de fortes chances que les protocoles TCP/IP, de transport HTTP et de recherche DNS aient tous été exécutés, ce qui nous garantit une expérience de navigation cohérente.</p><h3>Caractéristiques principales</h3><p>Les systèmes A2A reposent sur plusieurs principes fondamentaux qui garantissent une communication fluide. Le fait de s'appuyer sur ces principes garantit que différents agents, basés sur des LLM, des cadres et des langages de programmation différents, interagissent tous de manière transparente.</p><p>Voici les quatre grands principes :</p><ul><li><p><strong>Transmission de messages</strong>: Les agents communiquent par le biais de messages structurés dont les propriétés et les formats sont bien définis.</p></li><li><p><strong>Coordination</strong>: Les agents orchestrent des flux de travail complexes en se déléguant des tâches et en gérant les dépendances sans bloquer les autres agents.</p></li><li><p><strong>Spécialisation</strong>: Chaque agent se concentre sur un domaine ou une capacité spécifique, devenant ainsi un expert dans son domaine et offrant la possibilité d'accomplir des tâches basées sur cet ensemble de compétences.</p></li><li><p><strong>État distribué</strong>: L'état et les connaissances sont répartis entre les agents plutôt que centralisés, les agents ayant la possibilité de s'informer mutuellement de l'état d'avancement des tâches et des retours partiels (artefacts).</p></li></ul><h3>La salle de presse : Un exemple concret</h3><p>Imaginez une salle de rédaction numérique alimentée par des agents d'IA, chacun spécialisé dans un aspect différent du journalisme :</p><ul><li><p><strong>Chef de l'information</strong> (coordinateur/client) : Assigne les sujets et supervise le flux de travail</p></li><li><p><strong>Agent Reporter</strong>: Rédige des articles sur la base de recherches et d'interviews</p></li><li><p><strong>Agent de recherche</strong>: Recueille des faits, des statistiques et des informations de base</p></li><li><p><strong>Agent d'archivage</strong>: Recherche d'articles historiques et identification de tendances à l'aide d'Elasticsearch</p></li><li><p><strong>Agent rédacteur</strong>: Vérifie la qualité, le style et l'optimisation du référencement des articles.</p></li><li><p><strong>Agent de publication</strong>: Publie les articles approuvés sur la plateforme de blogs via CI/CD</p></li></ul><p>Ces agents ne travaillent pas isolément ; lorsque le chef de l'information confie un article sur l'<em>adoption des énergies renouvelables</em>, le journaliste a besoin du chercheur pour rassembler des statistiques, du rédacteur en chef pour réviser le projet et de l'éditeur pour publier l'article final. Cette coordination s'effectue par le biais de protocoles A2A.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb6c7215a96326481/6a17f2dd445de953024d0243/cc0760dbd74c49b92fa00dafbb8c2e8740eb70b6-963x693.png" alt="" /><h2>Section 2 : comprendre l'architecture A2A</h2><h3>Rôles de l'agent client et de l'agent distant</h3><p>Dans l'architecture A2A, les agents jouent deux rôles principaux. L'<strong>agent client</strong> est chargé de formuler et de communiquer des tâches aux autres agents du système. Il identifie les agents distants et leurs capacités, et utilise ces informations pour prendre des décisions éclairées en matière de délégation de tâches. L'agent client coordonne le flux de travail global, en veillant à ce que les tâches soient correctement réparties et à ce que le système progresse vers ses objectifs.</p><p>L'<strong>agent à distance</strong>, quant à lui, s'occupe des tâches déléguées par les clients. Il fournit des informations ou entreprend des actions spécifiques en réponse à des demandes, mais n'entreprend pas d'actions de manière indépendante. Les agents à distance peuvent également communiquer avec d'autres agents à distance si nécessaire pour s'acquitter des responsabilités qui leur sont confiées, créant ainsi un réseau collaboratif de capacités spécialisées.</p><p>Dans notre salle de presse, le chef de l'information joue le rôle d'agent client, tandis que le journaliste, le chercheur, le rédacteur en chef et l'éditeur sont des agents distants qui répondent aux demandes et se coordonnent les uns avec les autres.</p><h3>Capacités essentielles de l'A2A</h3><p>Les protocoles A2A définissent plusieurs capacités permettant une collaboration multi-agents :</p><h4>1. La découverte</h4><p>Les serveurs A2A doivent annoncer leurs capacités afin que les clients sachent quand et comment les utiliser pour des tâches spécifiques. Pour ce faire, les cartes d'agent sont des documents JSON qui décrivent les capacités, les entrées et les sorties d'un agent. Les cartes d'agent sont disponibles à des points d'extrémité cohérents et bien connus (tels que le point d'extrémité recommandé <code>/.well-known/agent-card.json</code> ), ce qui permet aux clients de découvrir et d'interroger les capacités d'un agent avant d'entamer une collaboration.</p><p>Voici un exemple de carte d'agent pour l'agent d'archivage personnalisé d'Elastic "Archie Archivist". Notez que les fournisseurs de logiciels tels qu'Elastic hébergent leurs agents A2A et fournissent une adresse URL pour l'accès :</p>{
  "name": "Archie Archivist",
  "description": "Helps find historical news documents in the Elasticsearch Index of archived news articles and content.",
  "url": "https://xxxxxxxxxxxxx-abc123.kb.us-central1.gcp.elastic.cloud/api/agent_builder/a2a/archive-agent",
  "provider": {
    "organization": "Elastic",
    "url": "https://elastic.co"
  },
  "version": "0.1.0",
  "protocolVersion": "0.3.0",
  "preferred_transport": "JSONRPC",
  "documentationURL": "https://www.elastic.co/docs/solutions/search/agent-builder/a2a-server"
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "stateTransitionHistory": false
  },
  "skills": [
    {
      "id": "platform.core.search",
      "name": "platform.core.search",
      "description": "A powerful tool for searching and analyzing data within your Elasticsearch cluster.",
      "inputModes": ["text/plain", "application/json"],
      "outputModes": ["text/plain", "application/json"]
    },
    {
      "id": "platform.core.index_explorer",
      "name": "platform.core.index_explorer",
      "description": "List relevant indices, aliases and datastreams based on a natural language query.",
      "inputModes": ["text/plain", "application/json"],
      "outputModes": ["text/plain", "application/json"]
    }
  ],
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain"]
}<p>Cette carte d'agent révèle plusieurs aspects importants de l'agent d'archivage d'Elastic. L'agent s'identifie comme "Archie Archivist" et indique clairement son objectif : aider à trouver des documents d'actualités historiques dans un index Elasticsearch. La carte précise le fournisseur (Elastic) et la version du protocole (0.3.0), ce qui garantit la compatibilité avec d'autres agents conformes à la norme A2A. Plus important encore, le tableau <code>skills</code> énumère les capacités spécifiques offertes par cet agent, notamment une puissante fonctionnalité de recherche et une exploration intelligente de l'index. Chaque compétence définit les modes d'entrée et de sortie qu'elle prend en charge, ce qui permet aux clients de savoir exactement comment communiquer avec cet agent. Cet agent est dérivé du service Agent Builder d'Elastic, qui fournit une suite d'outils et de points d'extrémité d'API natifs soutenus par LLM pour avoir une conversation avec votre magasin de données, et pas seulement pour en extraire des données. L'accès aux agents A2A dans Elasticsearch peut être trouvé <a href="https://www.elastic.co/docs/solutions/search/agent-builder/a2a-server">ici.</a></p><h4>2. Négociation</h4><p>Les clients et les agents doivent se mettre d'accord sur les méthodes de communication - que les interactions se fassent par le biais de textes, de formulaires, d'iframes ou même d'audio/vidéo - afin de garantir une interaction correcte entre les utilisateurs et l'échange de données. Cette négociation a lieu au début de la collaboration des agents et établit les protocoles qui régiront leur interaction tout au long du flux de travail. Par exemple, un agent du service clientèle basé sur la voix peut négocier pour communiquer via des flux audio, tandis qu'un agent chargé de l'analyse des données peut préférer JSON structuré. Le processus de négociation permet aux deux parties d'échanger efficacement des informations dans un format adapté à leurs capacités et aux exigences de la tâche à accomplir.</p><p>Les capacités énumérées dans l'extrait JSON ci-dessus ont toutes des schémas d'entrée et de sortie ; ces schémas définissent la manière dont les autres agents doivent interagir avec cet agent.</p><h4>3. Gestion des tâches et des états</h4><p>Les clients et les agents ont besoin de mécanismes pour communiquer l'état des tâches, les changements et les dépendances tout au long de l'exécution des tâches. Il s'agit notamment de gérer l'ensemble du cycle de vie d'une tâche, depuis sa création et son affectation jusqu'aux mises à jour et aux changements d'état. Les statuts typiques sont les suivants : en attente, en cours, terminé ou en échec. Le système doit également suivre les dépendances entre les tâches afin de s'assurer que les travaux préalables sont achevés avant que les tâches dépendantes ne commencent. La gestion des erreurs et la logique de réessai sont également des éléments essentiels, qui permettent au système de se remettre gracieusement des défaillances et de continuer à progresser vers l'objectif principal.</p><p>Exemple de message de tâche :</p>{
  "message_id": "msg_789xyz",
  "message_type": "task_request",
  "sender": "news_chief",
  "receiver": "researcher_agent",
  "timestamp": "2025-09-30T10:15:00Z",
  "payload": {
    "task_id": "task_456abc",
    "capability": "fact_gathering",
    "parameters": {
      "query": "renewable energy adoption rates in Europe 2024",
      "sources": ["eurostat", "iea", "ember"],
      "depth": "comprehensive"
    },
    "context": {
      "story_id": "story_123",
      "deadline": "2025-09-30T18:00:00Z",
      "priority": "high"
    }
  }
}<p>Cet exemple de message de tâche démontre plusieurs aspects clés de la communication A2A.</p><ul><li><p>La structure du <strong>message</strong> comprend des métadonnées telles qu'un identifiant de message unique, le type de message envoyé, l'identification de l'expéditeur et du destinataire, et un horodatage pour le suivi et le débogage.</p></li><li><p>La <strong>charge utile</strong> contient les informations relatives à la tâche proprement dite, spécifiant la capacité invoquée sur l'agent distant et fournissant les paramètres nécessaires à l'exécution de cette capacité.</p></li><li><p>La section <strong>contexte</strong> fournit des informations supplémentaires qui aident l'agent récepteur à comprendre le flux de travail général, y compris les délais et les niveaux de priorité qui indiquent comment l'agent doit allouer ses ressources et planifier son travail.</p></li></ul><h4>4. La collaboration</h4><p>Les clients et les agents <strong>doivent</strong> permettre une interaction dynamique mais structurée, permettant aux agents de demander des clarifications, des informations ou des sous-actions au client, à d'autres agents ou à des utilisateurs. Cela crée un environnement de collaboration dans lequel les agents peuvent poser des questions complémentaires lorsque les instructions initiales sont ambiguës, demander un contexte supplémentaire pour prendre de meilleures décisions, déléguer des sous-tâches à d'autres agents ayant une expertise plus appropriée et fournir des résultats intermédiaires pour obtenir un retour d'information avant de procéder à l'ensemble de la tâche. Cette communication multidirectionnelle garantit que les agents ne travaillent pas de manière isolée, mais qu'ils sont au contraire engagés dans un dialogue permanent qui aboutit à de meilleurs résultats.</p><h3>Communication distribuée, d'égal à égal</h3><p>L'A2A permet une communication distribuée où les agents peuvent être hébergés par différentes organisations, certains agents étant maintenus en interne tandis que d'autres sont fournis par des services tiers. Ces agents peuvent fonctionner sur différentes infrastructures - couvrant potentiellement plusieurs fournisseurs de services en nuage ou des centres de données sur site. Ils peuvent utiliser différents LLM sous-jacents, certains agents étant alimentés par des modèles GPT, d'autres par Claude, et d'autres encore par des alternatives à code source ouvert. Les agents peuvent même opérer dans différentes régions géographiques pour se conformer aux exigences en matière de souveraineté des données ou pour réduire les temps de latence. Malgré cette diversité, tous les agents conviennent d'un protocole de communication commun pour l'échange d'informations, ce qui garantit l'interopérabilité indépendamment des détails de la mise en œuvre. Cette architecture distribuée offre une certaine souplesse dans la manière dont les systèmes sont construits et déployés, ce qui permet aux organisations de combiner les agents et les infrastructures les mieux adaptés à leurs besoins spécifiques.</p><p>Il s'agit de l'architecture finale de l'application de la salle de presse :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt74d59cd9267f54d8/6a17f2de505ac31129ad8c71/82e01a0d9746038eafd69d11177042b5390507ae-1600x838.png" alt="" /><h2>Section 3 : Protocole de contexte de modèle (PCM)</h2><h3>Définition et objectif</h3><p>Le Model Context Protocol (MCP) est un protocole standardisé développé par Anthropic pour améliorer et renforcer un LLM individuel avec des outils, des ressources et des invites définis par l'utilisateur, ainsi que d'autres ajouts supplémentaires à la base de code. MCP fournit une interface universelle entre les modèles linguistiques et les ressources externes dont ils ont besoin pour accomplir efficacement leurs tâches. Cet <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">article</a> présente l'état actuel du MCP avec des exemples de cas d'utilisation, les tendances émergentes et la propre mise en œuvre d'Elastic.</p><h3>Concepts de base du MCP</h3><p>MCP fonctionne selon une architecture client-serveur avec trois composants principaux :</p><ul><li><p><strong>Clients :</strong> applications (comme Claude Desktop ou des applications IA personnalisées) qui se connectent aux serveurs MCP pour accéder à leurs capacités.</p></li><li><p><strong>Serveurs</strong>: applications qui exposent les ressources, les outils et les messages-guides aux modèles linguistiques. Chaque serveur est spécialisé dans l'accès à des capacités ou à des sources de données spécifiques.</p><ul><li><p><strong>Outils</strong>: fonctions définies par l'utilisateur que les modèles peuvent invoquer pour effectuer des actions, telles que la recherche dans des bases de données, l'appel à des API externes ou l'exécution de transformations sur les données.</p></li><li><p><strong>Ressources :</strong> sources de données que les modèles peuvent lire, servies avec des données dynamiques ou statiques, et accessibles via des modèles d'URI (similaires aux routes REST).</p></li><li><p><strong>Invitations : </strong>modèles d'invitations réutilisables avec des variables qui guident le modèle dans l'accomplissement de tâches spécifiques.</p></li></ul></li></ul><h3>Modèle demande-réponse</h3><p>MCP suit un modèle d'interaction demande-réponse familier, similaire aux API REST. Le client (LLM) demande une ressource ou invoque un outil, puis le serveur MCP traite la demande et renvoie le résultat, que le LLM utilise pour poursuivre sa tâche. Ce modèle centralisé avec des serveurs périphériques offre un modèle d'intégration plus simple que la communication d'agent pair à pair.</p><h3>MCP dans la salle de presse</h3><p>Dans notre exemple de salle de presse, les agents individuels utilisent des serveurs MCP pour accéder aux outils et aux données dont ils ont besoin :</p><ul><li><p><strong>Le chercheur</strong> utilise l'agent:</p><ul><li><p>Serveur MCP News API (accès aux bases de données d'actualités)</p></li><li><p>Fact-Checking MCP Server (vérification des affirmations par rapport à des sources fiables)</p></li><li><p>Base de données académique MCP Server (articles et recherches universitaires)</p></li></ul></li><li><p>Utilisation de l'<strong>agent rapporteur</strong>:</p><ul><li><p>Guide de style MCP Server (normes de rédaction des salles de presse)</p></li><li><p>Serveur de modèles MCP (modèles et formats d'articles)</p></li><li><p>Bibliothèque d'images MCP Server (photos d'archives et graphiques)</p></li></ul></li><li><p>L<strong>'éditeur</strong> utilise l'agent:</p><ul><li><p>Grammar Checker MCP Server (outils de qualité linguistique)</p></li><li><p>Serveur MCP de détection du plagiat (vérification de l'originalité)</p></li><li><p>Analyse SEO MCP Server (optimisation des titres et des mots-clés)</p></li></ul></li><li><p>L'<strong>agent éditeur</strong> utilise :</p><ul><li><p>Serveur CMS MCP (système de gestion de contenu API)</p></li><li><p>Serveur CI/CD MCP (pipeline de déploiement)</p></li><li><p>Serveur Analytics MCP (suivi et contrôle)</p></li></ul></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt195fe0bd36d36a48/6a17f2e0b1e113afe479f36c/b67311e3b58b27f9eb1b42a7b1dbad47ef3be4ad-808x535.png" alt="" /><h2>
Section 4 : comparaison des architectures</h2><h3>Quand utiliser A2A</h3><p>L'architecture A2A excelle dans les <strong>scénarios nécessitant une véritable collaboration multi-agents</strong>. Les flux de travail à plusieurs étapes nécessitant une coordination bénéficient grandement de l'A2A, en particulier lorsque les tâches impliquent plusieurs étapes séquentielles ou parallèles, les flux de travail nécessitant une itération et un affinement, et les processus avec des points de contrôle et des besoins de validation. Dans notre exemple de salle de presse, le flux de travail de l'article exige que le journaliste écrive, mais il peut être nécessaire de revenir au chercheur si la confiance en certains faits est faible, puis de passer au rédacteur en chef et enfin à l'éditeur.</p><p>La <strong>spécialisation spécifique à un domaine</strong> est un autre cas d'utilisation important de l'A2A. Lorsque plusieurs experts dans différents domaines sont nécessaires pour accomplir une tâche plus importante, chaque agent apportant une connaissance approfondie du domaine et des capacités de raisonnement spécialisées pour différents aspects, A2A fournit le cadre de coordination nécessaire pour établir ces connexions. La salle de rédaction en est un parfait exemple : le chercheur se spécialise dans la collecte d'informations, le journaliste dans la rédaction et le rédacteur en chef dans le contrôle de la qualité, chacun ayant une expertise distincte.</p><p>La nécessité d'un comportement autonome des agents rend l'A2A particulièrement utile. Les agents capables de<strong> prendre des décisions indépendantes, d'adopter un comportement proactif en fonction de l'évolution des conditions et de s'adapter de manière dynamique aux exigences du flux de travail</strong> s'épanouissent dans une architecture A2A. L'échelonnement horizontal des fonctions spécialisées est un autre avantage clé : plutôt que d'avoir un seul maître à tout faire, plusieurs agents spécialisés travaillent en coordination, et plusieurs instances du même agent peuvent gérer des tâches secondaires de manière asynchrone. Dans notre salle de presse, par exemple, lors d'une nouvelle de dernière minute, plusieurs agents de Reporter peuvent travailler simultanément sur différents aspects d'un même sujet.</p><p>Enfin, les tâches nécessitant une véritable collaboration multi-agents sont idéales pour l'A2A. Cela inclut les mécanismes d'<a href="https://arxiv.org/abs/2404.18796">évaluation du LLM en tant que jury</a>, les systèmes de consensus et de vote, et la <strong>résolution collaborative de problèmes où de multiples perspectives sont nécessaires</strong> pour atteindre le meilleur résultat.</p><h3>Quand utiliser MCP</h3><p>Le protocole de contexte de modèle est idéal pour étendre les capacités d'un modèle d'IA unique. Lorsqu'un modèle d'IA unique doit accéder à plusieurs outils et sources de données, MCP fournit la solution parfaite avec un raisonnement centralisé associé à des outils distribués et à une intégration simple des outils. Dans notre exemple de salle de presse, l'agent chercheur (un modèle) doit avoir accès à plusieurs sources de données, notamment l'API des actualités, les services de vérification des faits et les bases de données universitaires, toutes accessibles par l'intermédiaire de serveurs MCP normalisés.</p><p>L'intégration d'outils normalisés devient une priorité lorsque le partage et la réutilisation des intégrations d'outils sont importants. MCP se distingue ici par son écosystème de serveurs MCP préconstruits qui réduisent considérablement le temps de développement pour les intégrations courantes. Lorsque la simplicité et la facilité de maintenance sont requises, les modèles demande-réponse de MCP sont familiers aux développeurs, plus faciles à comprendre et à déboguer que les systèmes distribués, et leur complexité opérationnelle est moindre.</p><p>Enfin, le MCP est souvent proposé par les fournisseurs de logiciels pour faciliter la communication à distance avec leurs systèmes. Ces serveurs MCP proposés par les fournisseurs réduisent considérablement le temps d'intégration et de développement tout en offrant une interface standardisée avec les systèmes propriétaires, ce qui rend l'intégration beaucoup plus simple que le développement d'API personnalisées.</p><h3>Quand utiliser les deux (A2A ❤️'s MCP)</h3><p>De nombreux systèmes sophistiqués bénéficient de la combinaison d'A2A et de MCP, comme l'indique la <a href="https://a2a-protocol.org/latest/topics/a2a-and-mcp/">documentation d'A2A sur l'intégration de MCP</a>. Les systèmes nécessitant à la fois une coordination et une normalisation sont des candidats idéaux pour une approche hybride. A2A s'occupe de la coordination des agents et de l'orchestration du flux de travail, tandis que MCP permet aux agents individuels d'accéder aux outils. Dans notre exemple de salle de presse, les agents se coordonnent via A2A, le flux de travail passant du journaliste au chercheur, puis au rédacteur en chef et à l'éditeur. Cependant, chaque agent utilise des serveurs MCP pour ses outils spécialisés, ce qui crée une séparation architecturale nette.</p><p>Plusieurs agents spécialisés, chacun utilisant MCP pour l'accès aux outils, représentent un modèle commun où il y a une couche de coordination des agents gérée par A2A et une couche d'accès aux outils gérée par MCP. Cette séparation claire des préoccupations rend les systèmes plus faciles à comprendre et à entretenir.</p><p>Les avantages de la combinaison de ces deux approches sont considérables. Vous bénéficiez des avantages organisationnels des systèmes multi-agents, notamment la spécialisation, l'autonomie et le traitement parallèle, tout en profitant de la normalisation et des avantages de l'écosystème du MCP, tels que l'intégration des outils et l'accès aux ressources. Il existe une séparation claire entre la coordination des agents (A2A) et l'accès aux ressources (MCP) et, surtout, l'A2A n'est pas nécessaire pour les petites tâches telles que l'accès à l'API uniquement - MCP les gère efficacement sans les frais généraux de l'orchestration multi-agents.</p><p><strong>FAQ : A2A vs. MCP - Cas d'utilisation</strong></p><p>Fonctionnalité</p><p>Agent2Agent (A2A)</p><p>Protocole de contexte de modèle (MCP)</p><p>Hybride (A2A + MCP)</p><p>Objectif principal</p><p>Coordination multi-agents : Permet à une équipe d'agents spécialisés de travailler ensemble sur des flux de travail complexes à plusieurs étapes.</p><p>Amélioration de l'agent unique : Extension des capacités d'un seul LLM/Agent à l'aide d'outils, de ressources et de données externes.</p><p>Une force combinée : A2A gère le flux de travail de l'équipe, tandis que MCP fournit des outils à chaque membre de l'équipe.</p><p>Exemple d'équipe de salle de presse</p><p>La chaîne de travail : Chef de l'information → Reporter → Chercheur → Rédacteur en chef → Éditeur. Il s'agit de la couche de coordination.</p><p>Outils individuels de l'agent : L'agent rapporteur accède au serveur de guides de style et au serveur de modèles (via MCP). Il s'agit de la couche d'accès aux outils.</p><p>Le système complet : Le journaliste se coordonne avec le rédacteur en chef (A2A) et le journaliste utilise le serveur MCP de la bibliothèque d'images pour trouver un graphique pour l'article.</p><p>Quand utiliser quoi ?</p><p>Lorsque vous avez besoin d'une véritable collaboration, d'une itération et d'un perfectionnement, ou d'une expertise spécialisée répartie entre plusieurs agents.</p><p>Lorsqu'un agent unique a besoin d'accéder à plusieurs outils et sources de données ou nécessite une intégration standardisée avec des systèmes propriétaires.</p><p>Lorsque vous avez besoin des avantages organisationnels des systèmes multi-agents et des avantages de normalisation et d'écosystème du MCP.</p><p>Prestations de base</p><p>Autonomie et mise à l'échelle : Les agents peuvent prendre des décisions indépendantes et le système permet une mise à l'échelle horizontale des fonctions spécialisées.</p><p>Simplicité et normalisation : Le raisonnement centralisé facilite le débogage et la maintenance et fournit une interface universelle pour les ressources.</p><p>Séparation claire des préoccupations : Facilite la compréhension du système : A2A = travail d'équipe, MCP = accès aux outils.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1735ea5de41e10fd/6a17f2e26864a4125cb688c4/ddf6a29b1107ac6a63e94ecef703abc561a29e1e-986x656.png" alt="" /><h2>Conclusion</h2><p>Il s'agit de la première section de deux articles couvrant la mise en œuvre d'agents basés sur A2A et renforcés par des serveurs MCP pour fournir un support et un accès externe aux données et aux outils. La prochaine partie explorera le code réel pour démontrer qu'ils travaillent ensemble afin d'émuler les activités d'une salle de rédaction en ligne. Bien que les deux cadres soient extrêmement compétents et flexibles, vous verrez à quel point ils se complètent lorsqu'ils travaillent en tandem.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/a2a-protocol-mcp-llm-agent-newsroom-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/a2a-protocol-mcp-llm-agent-newsroom-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Justin Castilla]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2716d804698ec878/6a17f2e41480095fd7b48888/9f938d8e2f0fdf7509edf028816c48bdbc8b3fc7-1600x900.png" length="0" type="image/png"/>
    <pubDate>Thu, 13 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[Serveur MCP élastique : Expose les outils de l'Agent Builder à n'importe quel agent d'intelligence artificielle]]></title>
    <description><![CDATA[Découvrez comment utiliser le serveur Elastic MCP intégré dans Agent Builder pour étendre en toute sécurité n'importe quel agent d'IA avec un accès à vos données privées et à vos outils personnalisés.]]></description>
    <content:encoded><![CDATA[<p>Elastic Agent Builder est une plateforme permettant de créer des outils et des agents profondément intégrés à vos propres données dans Elasticsearch. Par exemple, vous pouvez créer des outils qui effectuent des recherches sémantiques sur des documents internes, analysent les journaux d'observabilité ou interrogent les alertes de sécurité.</p><p>Mais la véritable magie s'opère lorsque vous pouvez introduire ces outils personnalisés et conscients des données dans les environnements où vous passez le plus clair de votre temps. Et si l'agent de votre éditeur de code pouvait accéder en toute sécurité à la base de connaissances privée de votre organisation ?</p><p>C'est là qu'intervient le <strong>protocole de contexte de modèle (MCP).</strong> Elastic Agent Builder est livré avec un serveur MCP intégré qui permet d'accéder aux outils de la plateforme.</p><h2>Pourquoi utiliser le serveur MCP Elastic Agent Builder ?</h2><p>Les agents d'IA sont incroyablement puissants, mais leurs connaissances sont généralement limitées aux données sur lesquelles ils ont été formés et aux informations qu'ils peuvent activement rechercher sur l'internet public. Ils ne connaissent pas les documents de conception internes de votre entreprise, les manuels de déploiement spécifiques de votre équipe ou la structure unique des journaux de votre application.</p><p>Le défi consiste à donner à votre assistant d'intelligence artificielle le contexte spécialisé dont il a besoin. C'est précisément le problème que le MCP est censé résoudre. <strong>MCP est une norme ouverte qui permet à un modèle ou à un agent d'IA de découvrir et d'utiliser des outils externes.</strong></p><p>Pour rendre cela possible, l'Elastic Agent Builder expose nativement vos outils personnalisés par le biais d'un serveur MCP intégré. Cela signifie que vous pouvez facilement connecter n'importe quel client compatible MCP, comme <strong>Cursor</strong>, <strong>VS Code</strong> ou <strong>Claude Desktop</strong>, avec les outils spécialisés et sensibles aux données que vous avez construits avec Elastic Agent Builder.</p><h2>Quand utiliser MCP (et quand ne pas le faire)</h2><p>Elastic Agent Builder comprend plusieurs protocoles pour prendre en charge différents modèles d'intégration. Il est essentiel de choisir la bonne solution pour mettre en place des flux de travail efficaces en matière d'IA.</p><ul><li><p><strong>Utilisez </strong><a href="https://www.elastic.co/docs/solutions/search/agent-builder/mcp-server"><strong>MCP</strong></a> pour compléter votre agent d'intelligence artificielle (comme dans <strong>Cursor</strong> ou <strong>VS Code</strong>) avec des outils spécialisés. Il s'agit de l'approche ""apportez vos propres outils"", qui permet d'améliorer l'assistant que vous utilisez déjà grâce à un accès sécurisé à vos données privées. Seuls les outils sont exposés par l'intermédiaire du serveur MCP - les agents d'Elastic sont distincts.</p></li><li><p><strong>Utilisez le </strong><a href="https://www.elastic.co/docs/solutions/search/agent-builder/a2a-server"><strong>protocole A2A</strong></a> pour permettre à votre agent Elastic personnalisé de collaborer avec d'autres agents autonomes (comme dans <a href="https://www.elastic.co/search-labs/blog/a2a-protocol-elastic-agent-builder-gemini-enterprise"><strong>Gemini Enterprise de Google)</strong></a>. Il s'agit de la délégation d'agent à agent, où chaque agent travaille comme un pair pour résoudre un problème.</p></li><li><p><strong>Utilisez les </strong><a href="https://www.elastic.co/docs/solutions/search/agent-builder/kibana-api"><strong>API de l'Agent Builder</strong></a> pour un contrôle programmatique complet lors de la création d'une application personnalisée à partir de zéro.</p></li></ul><p>Pour un développeur qui cherche à obtenir des réponses dans sa documentation interne sans quitter son IDE, le MCP est la solution idéale.</p><h2>Exemple : vos outils personnalisés dans Cursor avec le serveur MCP Agent Builder</h2><p>Prenons un exemple pratique que j'utilise quotidiennement. Tout d'abord, j'ai exploré et indexé notre documentation technique interne dans un index Elasticsearch appelé <code>elastic-dev-docs</code>. Nous pourrions utiliser les outils génériques intégrés disponibles dans Agent Builder, mais nous allons créer notre propre outil personnalisé pour interroger cette base de connaissances spécifique.</p><p>La raison de la construction d'un outil sur mesure est simple : <strong>contrôle et précision</strong>. Cette approche nous permet d'exécuter une requête sémantique rapide directement sur notre index <code>elastic-dev-docs</code>. Nous avons un contrôle total sur l'index ciblé et sur la manière dont les données sont extraites.</p><p>Voici maintenant comment nous pouvons utiliser cette base de connaissances personnalisée dans un éditeur de code doté d'une intelligence artificielle, comme Cursor.</p><h3>Étape 1 : Créer un outil de base de connaissances personnalisé dans Agent Builder</h3><p>Tout d'abord, créez un nouvel outil dans Agent Builder. Une description claire et précise de l'outil est importante car c'est ainsi que tout agent d'IA, qu'il s'agisse de l'agent Elastic interne ou d'un outil externe tel que Cursor se connectant via MCP, découvre et sélectionne votre outil pour la bonne tâche.</p><p>Une description solide doit être explicite. Par exemple : "Effectue une recherche sémantique sur l'index elastic-dev-docs pour trouver la documentation d'ingénierie interne, les runbooks et les procédures de mise en production."</p><p>L'outil est alors configuré pour effectuer une recherche sémantique dans notre index spécifique. Une fois sauvegardé, il est immédiatement disponible pour être servi.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt011118f0a9279185/6a17f367dbb4ffc4f3fb581a/1eea079908fdf7cc72dbe81abd07ff51601a43d4-1472x1600.png" alt="Création d'un outil de base de connaissances personnalisé dans Agent Builder." /><p>Avant de le connecter au monde extérieur, vous pouvez le tester directement dans l'interface utilisateur. Il suffit de cliquer sur le bouton <strong>Test</strong> pour remplir manuellement les paramètres, émuler ce que le LLM fera, et inspecter les résultats pour confirmer que tout fonctionne correctement.</p><h3>Étape 2 : Connecter le curseur au serveur Elastic MCP</h3><p>Elastic Agent Builder expose automatiquement tous les outils disponibles via un point de terminaison MCP sécurisé. Vous pouvez trouver l'URL unique de votre serveur dans l'interface utilisateur Outils de Kibana.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdd0e62ae0f394c3d/6a17f368e317916ec32d5933/ba137be30f0eaa7f028b96bd8af4e2779c3f8a33-1600x589.png" alt="Comment connecter le curseur dans l'interface outils de Kibana au serveur Elastic MCP." /><p>Pour se connecter à Cursor, il suffit d'ajouter cette URL à son fichier de configuration, ainsi qu'une clé API Elastic pour l'authentification<a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">(découvrez comment créer une clé API ES</a>). Nous utilisons une clé API pour l'autorisation, car elle garantit que les outils ne s'exécutent qu'avec les permissions que vous avez accordées, en respectant toutes vos règles de contrôle d'accès.</p><p>La configuration MCP dans le site <code>~/.cursor/mcp.json</code> de Cursor se présente comme suit :</p>{
  "mcpServers": {
    "elastic-agent-builder": {
      "command": "npx",
      "args": [
        "mcp-remote",
        "https://your-kibana.kb.company.io/api/agent_builder/mcp",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "ApiKey &lt;ELASTIC_API_KEY&gt;"
      }
    }
  }
}<p>Une fois la configuration sauvegardée, vous devriez voir l'outil Elastic Agent Builder MCP server disponible dans Cursor.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2837638263e628ed/6a17f36adbb4ffeb9cfb5820/d302c6d3609fbf14fd40e21b9e69e567bf12553f-1600x1002.png" alt="Une image de l'outil serveur Elastic Agent Builder MCP disponible dans Cursor." /><h3>Étape 3 : Posez vos questions !</h3><p>Une fois la connexion établie, les agents Cursor peuvent maintenant invoquer vos outils personnalisés pour répondre à vos questions ou guider le processus de génération de code.</p><p>Posons une question précise :</p><p><em>"Consulter les étapes pour libérer le service de crawler de la documentation interne de l'ingénierie d'elastic search org"</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt83fa357261b30e93/6a17f36c4b055d16d1432326/14f572730203c23615bb9dd38234bcb3b0f81155-1600x1468.png" alt="Agents curseurs invoquant des outils personnalisés pour répondre aux questions et guider le processus de génération de code." /><p>En coulisses, la magie opère :</p><ol><li><p>L'agent du curseur décide de la meilleure façon de répondre à votre question et décide d'appeler la fonction <code>engineering_documentation_internal_search</code></p></li><li><p>Il invoque l'outil à l'aide d'une requête en langage naturel</p></li><li><p>L'outil effectue une recherche sémantique dans l'index <code>elastic-dev-docs</code> et renvoie les procédures les plus pertinentes et les plus récentes.</p></li></ol><p>Nous obtenons une réponse précise et fiable, basée sur notre documentation interne, sans jamais quitter l'éditeur de code. L'expérience est transparente et puissante.</p><h2>À vous de construire</h2><p>Vous avez maintenant vu comment utiliser le serveur MCP intégré dans Elastic Agent Builder pour étendre vos assistants IA avec un accès sécurisé à vos données privées. Pour que les modèles soient réellement utiles, il est essentiel de les ancrer dans vos propres informations.</p><p>Pour récapituler, nous avons couvert les principales étapes :</p><ul><li><p>Choisir le bon protocole pour vos besoins (MCP).</p></li><li><p>Création d'un outil de base de connaissances personnalisé.</p></li><li><p>Connecter cet outil à un assistant IDE comme Cursor.</p></li></ul><p>Vos agents et vos outils n'ont plus besoin d'être déconnectés de leur contexte le plus précieux. Nous espérons que ce guide vous aidera à créer des flux de travail plus efficaces et tenant compte des données. Bonne construction !</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elastic-mcp-server-agent-builder-tools</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elastic-mcp-server-agent-builder-tools</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <category><![CDATA[Outils d'IA ]]></category>
    <dc:creator><![CDATA[Jedr Blaszyk,Joe McElroy]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta5b61961b6269ab1/6a17f36ea29299d839d02db2/ef5153551a1d14833c7f512fede554d1dfb31553-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 20 Oct 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Évaluation des agents d'IA : Comment Elastic teste les frameworks agentiques]]></title>
    <description><![CDATA[Découvrez comment nous évaluons et testons les changements apportés à un système agentique avant de les communiquer aux utilisateurs d'Elastic afin de garantir des résultats précis et vérifiables.]]></description>
    <content:encoded><![CDATA[<h2>Introduction</h2><p>Dans la pile Elastic, il existe de nombreuses applications agentiques alimentées par LLM, telles que le futur agent Elastic AI dans<a href="https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder"> Agent Builder</a> (actuellement en tech preview) et <a href="https://www.elastic.co/docs/solutions/security/ai/attack-discovery">Attack Discovery</a> <a href="https://www.elastic.co/blog/whats-new-elastic-security-9-0-0">(GA</a> dans 8.18 et 9.0+), et d'autres sont en cours de développement. Pendant le développement, et même après le déploiement, il est important de répondre à ces questions :</p><ul><li><p>Comment évaluer la qualité des réponses de ces applications d'IA ?</p></li><li><p>Si nous apportons un changement, comment pouvons-nous garantir qu'il s'agit réellement d'une amélioration et qu'il n'entraînera pas une dégradation de l'expérience de l'utilisateur ?</p></li><li><p>Comment pouvons-nous facilement tester ces résultats de manière reproductible ?</p></li></ul><p>Contrairement aux tests de logiciels traditionnels, l'évaluation des applications d'IA générative fait appel à des méthodes statistiques, à un examen qualitatif nuancé et à une compréhension approfondie des objectifs des utilisateurs.</p><p>Cet article détaille le processus employé par l'équipe de développeurs d'Elastic pour effectuer des évaluations, garantir la qualité des changements avant leur déploiement et contrôler les performances du système. Nous voulons nous assurer que chaque changement est étayé par des preuves, ce qui permet d'obtenir des résultats fiables et vérifiables. Une partie de ce processus est intégrée directement dans Kibana, ce qui reflète notre engagement en matière de transparence dans le cadre de notre éthique des logiciels libres. En partageant ouvertement une partie de nos données d'évaluation et de nos paramètres, nous cherchons à renforcer la confiance de la communauté et à fournir un cadre clair à tous ceux qui développent des agents d'intelligence artificielle ou utilisent nos produits.</p><h2>Exemples de produits</h2><p>Les méthodes utilisées dans ce document ont servi de base à l'itération et à l'amélioration de solutions telles que Attack Discovery et Elastic AI Agent. Une brève présentation des deux, respectivement :</p><h3>Découverte d'attaques par Elastic Security</h3><p>Attack Discovery utilise les LLM pour identifier et résumer les séquences d'attaques dans Elastic. À partir des alertes d'Elastic Security dans un délai donné (24 heures par défaut), le flux de travail agentique d'Attack Discovery déterminera automatiquement si une ou plusieurs attaques ont eu lieu, ainsi que des informations importantes telles que l'hôte ou les utilisateurs compromis, et les alertes qui ont contribué à la conclusion de l'attaque.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb70932abe8d4de75/6a17f04ea292990c52d02d61/20fabb47642dad7b588daaaa8c3a98de860ad01d-1251x758.png" alt="" /><p></p><p>L'objectif est que la solution basée sur le LLM produise un résultat au moins aussi bon que celui d'un humain.</p><h3>Agent d'IA élastique</h3><p>L'<strong>Elastic Agent Builder</strong> est notre nouvelle plateforme pour la création d'agents d'intelligence artificielle sensibles au contexte qui tirent parti de toutes nos capacités de recherche. Il est livré avec l'<strong>agent Elastic AI</strong>, un agent général préconstruit conçu pour aider les utilisateurs à comprendre et à obtenir des réponses à partir de leurs données par le biais d'une interaction conversationnelle.</p><p>L'agent y parvient en identifiant automatiquement les informations pertinentes dans Elasticsearch ou dans les bases de connaissances connectées et en tirant parti d'une série d'outils prédéfinis pour interagir avec elles. Cela permet à l'agent Elastic AI de répondre à un large éventail de requêtes d'utilisateurs, allant de la simple Q&amp;A sur un seul document à des demandes complexes nécessitant une agrégation et des recherches en une ou plusieurs étapes dans plusieurs index.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3b9dbede85a56bd6/6a17f050e8fbce88943a1a30/d29dee100bb8a17bb623acd745773a5164a1df4f-1600x1014.png" alt="" /><h2>Mesurer les améliorations au moyen d'expériences</h2><p>Dans le contexte des agents d'intelligence artificielle, une expérience est une modification structurée et testable du système conçue pour améliorer les performances sur des aspects bien définis (par exemple, l'utilité, l'exactitude, la latence). L'objectif est de répondre de manière définitive à la question suivante "Si nous fusionnons ce changement, pouvons-nous garantir qu'il s'agit d'une véritable amélioration et qu'il ne dégradera pas l'expérience de l'utilisateur ?"</p><p>La plupart des expériences que nous menons comprennent généralement</p><ul><li><p><strong>Une hypothèse :</strong> Une affirmation spécifique et falsifiable. <em>Exemple :</em> "L'accès à un outil de découverte d'attaques améliore l'exactitude des requêtes liées à la sécurité.</p></li><li><p><strong>Critères de réussite :</strong> Des seuils clairs qui définissent ce qu'on entend par "succès". <em>Exemple :</em> "+5% amélioration du score de justesse sur l'ensemble de données de sécurité, pas de dégradation ailleurs".</p></li><li><p><strong>Plan d'évaluation :</strong> Comment nous mesurons le succès (mesures, ensembles de données, méthode de comparaison)</p></li></ul><p>Une expérience réussie est un processus systématique de recherche. Chaque changement, qu'il s'agisse d'une modification mineure ou d'un changement architectural majeur, suit ces sept étapes afin de garantir que les résultats sont significatifs et exploitables :</p><ul><li><p>Étape 1 : Identifier le problème</p></li><li><p>Étape 2 : Définir les indicateurs</p></li><li><p>Étape 3 : Formuler une hypothèse claire</p></li><li><p>Étape 4 : Préparation de l'ensemble de données d'évaluation</p></li><li><p>Étape 5 : Exécuter l'expérience</p></li><li><p>Étape 6 : Analyse des résultats + itération</p></li><li><p>Étape 7 : Prendre une décision et la documenter</p></li></ul><p>Un exemple de ces étapes est illustré à la <em>figure 1.</em> Les sous-sections suivantes expliquent chaque étape, et nous développerons les détails techniques de chaque étape dans les documents à venir.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt06bfe2f0e4205a18/6a17f052faa91358eb93c968/3a9f5a3e92dd4922a795a19104c6e4ad8c98958d-2400x1352.png" alt="" /><h2>Une démonstration pas à pas avec des exemples réels d'Elastic</h2><h3>Étape 1 : Identifier le problème</h3><p><em>Quel est exactement le problème que ce changement vise à résoudre ?</em></p><p>Exemple de découverte d'attaques : Les résumés sont parfois incomplets, ou une activité bénigne est signalée à tort comme une attaque (faux positifs).</p><p>Exemple d'agent d'IA élastique : La sélection des outils de l'agent, en particulier pour les requêtes analytiques, est sous-optimale et incohérente, conduisant souvent au choix du mauvais outil. Cela entraîne une augmentation des coûts des jetons et de la latence.</p><h3>Étape 2 : Définir les indicateurs</h3><p><em>Rendre le problème mesurable, afin de pouvoir comparer un changement à l'état actuel.</em></p><p>Les mesures courantes comprennent la <a href="https://developers.google.com/machine-learning/crash-course/classification/accuracy-precision-recall">précision et le rappel</a>, la <a href="https://en.wikipedia.org/wiki/Semantic_similarity">similarité sémantique</a>, la factualité, etc. Selon le cas d'utilisation, nous utilisons des vérifications de code pour calculer les mesures, telles que la correspondance des identifiants d'alerte ou des URL correctement récupérés, ou nous utilisons des techniques telles que LLM-as-judge pour des réponses plus libres.</p><p>Voici quelques exemples de mesures<em>(non exhaustifs</em>) utilisées dans les expériences :</p><p><strong>Attack Discovery</strong></p><p>Métrique</p><p>Description</p><p>Précision &amp; rappel</p><p>Faire correspondre les identifiants d'alerte entre les sorties réelles et les sorties prévues afin de mesurer la précision de la détection.</p><p>Similitude</p><p>Utilisez BERTScore pour comparer la similarité sémantique du texte de la réponse.</p><p>Factualité</p><p>Les principaux IOC (indicateurs de compromission) sont-ils présents ? Les tactiques de MITRE (taxonomie industrielle des attaques) sont-elles correctement prises en compte ?</p><p>Cohérence de la chaîne d'attaque</p><p>Comparez le nombre de découvertes pour vérifier si l'attaque a été sur ou sous-déclarée.</p><p><strong>Agent d'IA élastique</strong></p><p>Métrique</p><p>Description</p><p>Précision &amp; rappel</p><p>Faire correspondre les documents/informations récupérés par l'agent pour répondre à une requête de l'utilisateur avec les informations ou documents réels nécessaires pour répondre à la requête afin de mesurer la précision de la recherche d'informations.</p><p>Factualité</p><p>Les faits essentiels nécessaires pour répondre à la demande de l'utilisateur sont-ils présents ? Les faits sont-ils dans le bon ordre pour les questions de procédure ?</p><p>Pertinence de la réponse</p><p>La réponse contient-elle des informations périphériques ou sans rapport avec la requête de l'utilisateur ?</p><p>Complétude de la réponse</p><p>La réponse répond-elle à toutes les parties de la requête de l'utilisateur ? La réponse contient-elle toutes les informations présentes dans la vérité terrain ?</p><p>Validation ES|QL</p><p>La syntaxe de l'ES|QL générée est-elle correcte ? Est-il fonctionnellement identique à la vérité de terrain ES|QL ?</p><h3>Étape 3 : Formuler une hypothèse claire</h3><p><em>Établir des critères de réussite clairs en utilisant le problème et les paramètres définis ci-dessus.</em></p><p>Exemple d'agent d'IA élastique :</p><ol><li><p>Apporter des <strong>modifications aux descriptions des outils relevance_search et nl_search afin de définir clairement leurs fonctions spécifiques et leurs cas d'utilisation</strong>.</p></li><li><p>Nous prévoyons d'<strong>améliorer la</strong> <strong>précision de l'invocation des outils de</strong> <strong>25%</strong>.</p></li><li><p>Nous vérifierons qu'il s'agit d'un résultat positif net en nous assurant qu'il n'y a pas d'impact négatif sur d'autres indicateurs, par exemple l'<strong>exactitude et l'exhaustivité des données</strong>.</p></li><li><p>Nous pensons que cela fonctionnera parce que des <strong>descriptions précises des outils aideront l'agent à sélectionner et à appliquer avec plus de précision l'outil de recherche le plus approprié pour différents types de requêtes, ce qui réduira les erreurs d'application et améliorera l'efficacité globale de la recherche.</strong></p></li></ol><h3>Étape 4 : Préparation de l'ensemble de données d'évaluation</h3><p><em>Pour mesurer les performances du système, nous utilisons des ensembles de données qui représentent des scénarios réels.</em></p><p>Selon le type d'évaluation que nous menons, nous pouvons avoir besoin de différents types de formats de données, tels que les données brutes transmises à un LLM (par ex. scénarios d'attaque pour la découverte d'attaques) et les résultats attendus. Si l'application est un chatbot, les entrées peuvent être des requêtes d'utilisateurs, et les sorties peuvent être des réponses correctes du chatbot, des liens corrects qu'il aurait dû récupérer, etc.</p><p>Exemple de découverte d'attaque :</p><p>10 nouveaux scénarios d'attaque</p><p>8 épisodes de Oh My Malware (ohmymalware.com)</p><p>4 scénarios multi-attaques (créés en combinant les attaques des 2 premières catégories)</p><p>3 scénarios bénins</p><p>Exemple de jeu de données d'évaluation d'un agent d'IA élastique<a href="https://github.com/elastic/kibana/blob/main/x-pack/platform/packages/shared/onechat/kbn-evals-suite-onechat/evals/kb/kb.spec.ts">(lien vers le jeu de données Kibana</a>) :</p><p>14 Indices utilisant des ensembles de données open source pour simuler des sources multiples dans KB.</p><p>5 Types de requêtes (analytique, recherche de texte, hybride...)</p><p>7 Types d'intentions d'interrogation (procédurale, factuelle - classification, enquête ; ...)</p><h3>Étape 5 : Exécuter l'expérience</h3><p>Exécuter l'expérience en générant des réponses à partir de l'agent existant et de la version modifiée par rapport à l'ensemble de données d'évaluation. Calculer des paramètres tels que la factualité (voir étape 2).</p><p>Nous mélangeons plusieurs évaluations basées sur les paramètres requis à l'étape 2 :</p><ul><li><p>Évaluation basée sur des règles (par exemple utiliser Python/TypeScript pour vérifier si .json est valide)</p></li><li><p>LLM-as-judge (demander à un LLM séparé si une réponse est cohérente avec un document source)</p></li><li><p>Examen humain dans la boucle pour les contrôles de qualité des nuances</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt17ec63af0850d8dd/6a17f054505ac3e508ad8c1e/8648e75818d3291f0ac66f069438a500d42b8225-1600x1099.png" alt="Voici un exemple de résultat d'évaluation généré par notre cadre interne. Il présente diverses mesures issues d'une expérience menée sur différents ensembles de données." /><h3>Étape 6 : Analyse des résultats + itération</h3><p>Maintenant que nous disposons des mesures, nous analysons les résultats. <u><em>Même si les résultats satisfont aux critères de réussite définis à l'étape 3, il faut encore procéder à un examen humain avant de fusionner la modification avec la production</em></u>; si les résultats ne satisfont pas aux critères, il faut procéder à une itération et résoudre les problèmes, puis effectuer les évaluations sur la nouvelle modification.</p><p>Nous pensons qu'il faudra quelques itérations pour trouver la meilleure modification avant de procéder à la fusion. De la même manière que l'on exécute des tests logiciels locaux avant de valider un projet, les évaluations hors ligne peuvent être exécutées avec des modifications locales ou plusieurs propositions de modifications. Il est utile d'automatiser l'enregistrement des résultats d'expériences, des scores composites et des visualisations pour rationaliser l'analyse.</p><h3>Étape 7 : Prendre une décision et la documenter</h3><p>Sur la base d'un cadre de décision et de critères d'acceptation, décider de fusionner les changements et documenter l'expérience. La prise de décision comporte de multiples facettes et peut prendre en compte des facteurs au-delà de l'ensemble de données d'évaluation, tels que la vérification des scénarios de régression sur d'autres ensembles de données ou l'évaluation du rapport coût-bénéfice d'un changement proposé.</p><p>Exemple : Après avoir testé et comparé quelques itérations, choisissez la modification la mieux notée et envoyez-la aux chefs de produit et aux autres parties prenantes concernées pour approbation. Joignez les résultats des étapes précédentes pour vous aider à prendre une décision. Pour plus d'exemples sur la découverte d'attaques, voir <a href="https://www.elastic.co/blog/elastic-security-generative-ai-features">Dans les coulisses des fonctions d'IA générative d'Elastic Security.</a></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt62a466f3a0da114a/6a17f056faa91342c393c96c/74c80b8f34dce8ddd20873ecb2f553873587ed35-1600x618.png" alt="" /><h2>Conclusion</h2><p>Dans ce blog, nous avons parcouru le processus de bout en bout d'un flux d'expérimentation, illustrant comment nous évaluons et testons les changements apportés à un système agentique avant de les diffuser aux utilisateurs d'Elastic. Nous avons également fourni quelques exemples d'amélioration des flux de travail basés sur des agents dans Elastic. Dans les prochains billets de blog, nous développerons les détails des différentes étapes, telles que la création d'un bon ensemble de données, la conception de mesures fiables et la prise de décisions lorsque plusieurs mesures sont impliquées.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agent-evaluation-elastic</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agent-evaluation-elastic</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Susan Chang,Abhimanyu Anand]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte578b636637be6b1/6a17f057e8fbcebe9e3a1a36/ef3922076713872163e1aab47735361513b2c9ee-2400x1352.heif" length="0" type="image/*"/>
    <pubDate>Mon, 13 Oct 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Connexion des agents élastiques à Gemini Enterprise via le protocole A2A]]></title>
    <description><![CDATA[Apprenez à utiliser Agent Builder pour exposer votre agent Elastic personnalisé à des services externes tels que Gemini Enterprise avec le protocole A2A.]]></description>
    <content:encoded><![CDATA[<p><strong>Elastic Agent Builder</strong> est un ensemble de fonctionnalités permettant de créer des agents d'intelligence artificielle pilotés par les données directement dans Elasticsearch. Dans les articles précédents de cette <a href="https://www.elastic.co/search-labs/blog/series/context-aware-ai-agentic-workflows-with-elastic">série</a>, nous avons montré comment doter les agents personnalisés d'outils leur permettant d'effectuer des tâches complexes et leur fournir un ensemble d'instructions personnalisées pour guider leur comportement.</p><p>Mais qu'en est-il si vous souhaitez utiliser vos agents personnalisés avec les applications et les outils de productivité dont vous disposez déjà ?</p><p>C'est là qu'intervient le <strong>protocole Agent-to-Agent (A2A)</strong>. A2A est une <a href="https://github.com/a2aproject/A2A">norme ouverte</a> d'interopérabilité qui permet aux agents de différentes plateformes de communiquer et de collaborer. Et nous l'avons intégré directement dans l'Elastic Agent Builder.</p><p>Aujourd'hui, nous allons vous montrer comment prendre un agent personnalisé que vous avez construit et l'exposer à d'autres services, en particulier <strong>Gemini Enterprise </strong>(anciennement Agentspace).</p><h2>Le pouvoir des normes ouvertes : l'importance de l'A2A</h2><p>Dans l'article de blog <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">Votre premier agent Elastic</a>, nous avons montré comment créer des agents personnalisés, tels qu'un agent <em>Assistant financier</em> avec un accès sécurisé à vos données de marché. Mais sa valeur est limitée si vous ne pouvez pas rendre ses informations disponibles dans d'autres environnements, comme Gemini Enterprise, sans avoir à reconstruire votre travail.</p><p>C'est ce défi de l'interopérabilité qui freine l'IA agentique. Les agents ont besoin d'un langage commun pour communiquer entre les plateformes, ce qui est précisément le rôle du protocole A2A. Il fournit une couche de communication standard qui vous permet non seulement d'interagir directement avec votre agent, mais qui ouvre également la voie à un avenir où les agents spécialisés de votre organisation pourront collaborer et partager des informations.</p><p>Pour rendre cela possible, l'Elastic Agent Builder supporte nativement le protocole A2A à travers deux points de terminaison standard pour tous vos agents :</p><ol><li><p><strong>Le point de terminaison de la carte d'agent (</strong><strong><code>GET {your-kibana-url}/api/agent_builder/a2a/{agentId}.json</code></strong> )<strong>- </strong>Il s'agit de la carte de visite de votre agent personnalisé. Il fournit des métadonnées sur votre agent (nom, description, capacités, etc.) à tout service compatible A2A.</p></li><li><p><strong>Le point de terminaison du protocole A2A (</strong><strong><code>POST {your-kibana-url}/api/agent_builder/a2a/{agentId}</code></strong><strong>)</strong> - Il s'agit du canal de communication. D'autres agents envoient leurs demandes ici, et votre agent les traite et renvoie une réponse, conformément à la <a href="https://a2a-protocol.org/latest/specification/">spécification du protocole A2A</a>.</p></li></ol><h2>Testez votre agent avec l'inspecteur A2A</h2><p>Avant de connecter notre agent à un système de production, il est bon de vérifier qu'il communique correctement. Le moyen le plus simple d'y parvenir est d'utiliser l'<strong>inspecteur A2A</strong>, un outil spécialement conçu pour tester et déboguer les intégrations A2A.</p><p>La mise en route de l'inspecteur est simple. Vous pouvez cloner le dépôt <a href="https://github.com/a2aproject/a2a-inspector">a2a-inspector</a> et suivre les instructions du README pour <a href="https://github.com/a2aproject/a2a-inspector?tab=readme-ov-file#3-run-the-application">lancer l'application</a>. Une fois lancée, l'interface utilisateur est disponible par défaut à l'adresse <code>http://localhost:5001/</code>.</p><p>Pour connecter l'inspecteur A2A à votre agent, vous devez fournir deux informations essentielles :</p><ul><li><p>URL de la carte d'agent : Il s'agit du point de terminaison qui décrit votre agent. Pour l'<a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">agent assistant financier de notre poste précédent</a>, cette URL serait <code>{your-kibana-url}/api/agent_builder/a2a/financial_assistant.json</code>.</p></li><li><p>En-tête d'authentification : Nous utiliserons une clé API standard pour l'authentification.</p></li></ul><p>Une fois que vous avez saisi ces informations dans l'interface utilisateur de l'inspecteur, vous pouvez vous connecter et commencer à dialoguer avec votre agent immédiatement.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6381135e3fb297df/6a17ef4bec0f898b0c5a66ea/7231c72bf30bed2a854f58658c1eca2843f43bfc-1600x1296.png" alt="Configuration de la carte d'agent A2A et de l'inspecteur d'agent" /><p>Cette simple validation nous donne l'assurance que notre agent est configuré correctement et qu'il est prêt pour l'étape suivante.</p><h2>En direct ! Votre agent personnalisé dans Gemini Enterprise</h2><p>Passons maintenant à la partie la plus excitante : donner vie à notre agent financier personnalisé au sein de Gemini Enterprise (anciennement Agentspace). Cette intégration s'appuie sur l'<a href="https://console.cloud.google.com/marketplace/product/elastic-prod/elastic-ai-agent">agent Elastic AI, disponible sur Google Cloud Marketplace</a>.</p><p>Une fois connecté, Gemini Enterprise utilise le protocole A2A pour communiquer directement avec votre agent. C'est là que la véritable puissance de l'interopérabilité se manifeste : les utilisateurs peuvent désormais accéder aux informations approfondies et axées sur les données de votre agent Elasticsearch personnalisé sans jamais quitter leur environnement familier. Vous pouvez voir votre agent Elastic personnalisé dans la liste des agents :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7f54f0bb15216d8e/6a17ef4d6df73107d90a0fdb/37a39e92ebf3d72c6c8014397cd8e846336173a4-1600x834.png" alt="Affichage d'un agent personnalisé dans une liste Google Agentspace" /><p>Imaginez qu'un utilisateur de Gemini Enterprise demande :</p><p><em>"Je m'inquiète du sentiment du marché. Pouvez-vous m'indiquer quels sont nos clients les plus exposés aux mauvaises nouvelles ?</em>"</p><p>En coulisses, Gemini Enterprise achemine cette requête via le protocole A2A vers votre agent Elastic personnalisé. Votre agent utilise alors ses outils spécialisés pour interroger vos données, formuler une réponse et la renvoyer. Pour l'utilisateur final, l'expérience est transparente.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte130c332ee0648a6/6a17ef4fe9ea874426a9c6bb/e5f126c1a27a51c6e69a767aa87c9f746b62e39c-1600x1044.png" alt="Un utilisateur demande à Agentspace de répondre à une requête et ce qui se passe dans les coulisses." /><p>Et cela ne s'arrête pas là ! La réponse obtenue avec l'agent Elastic peut maintenant être utilisée comme contexte pour vos prochaines questions qui peuvent déclencher un agent spécialisé différent (par exemple, l'agent Elastic). l'agent de votre plateforme d'investissement pour ajuster l'exposition aux sociétés cotées). Le tout sans quitter votre barre de recherche.</p><p>Avec vos agents Elastic déployés sur Gemini Enterprise avec A2A, vous pouvez unifier l'accès, l'orchestration et les flux de travail en éliminant les frictions entre l'IA, la recherche et les systèmes d'entreprise en offrant une interface utilisateur unique où les utilisateurs parlent à leurs données et à leurs outils - le tout en contexte. Pour les utilisateurs, cela signifie moins de changements d'outils et des assistants d'IA plus intuitifs et plus compétents. Pour les organisations, cela signifie une gouvernance cohérente, une évolutivité et une interopérabilité intégrées.</p><h2>À vous de construire</h2><p>Vous disposez désormais des outils nécessaires pour que vos agents élastiques soient disponibles partout. En tirant parti du protocole ouvert A2A, vous pouvez étendre la portée de vos agents personnalisés et sensibles aux données.</p><p>Dans cet article, nous vous avons présenté les principales étapes :</p><ul><li><p>Exposer votre agent via la carte d'agent A2A et les points d'extrémité du protocole.</p></li><li><p>Tester la connexion avec l'inspecteur A2A.</p></li><li><p>Intégrer votre agent en direct dans un service externe tel que Gemini Enterprise de Google.</p></li></ul><p>Vos agents n'ont plus besoin d'être isolés. Nous sommes impatients de voir les systèmes puissants et interconnectés que vous créerez. Bonne construction !</p><p>Le moyen le plus simple de commencer est d'essayer gratuitement Elastic Cloud sur <a href="https://console.cloud.google.com/marketplace/product/elastic-prod/elastic-cloud?pli=1">Google Cloud Marketplace</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/a2a-protocol-elastic-agent-builder-gemini-enterprise</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/a2a-protocol-elastic-agent-builder-gemini-enterprise</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Jedr Blaszyk,Valerio Arvizzigno,Joe McElroy]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt63d7675adc5bc211/6a17ef51ddf97d38e8910bdf/5be8a425fab55dca2f9717d2e50812b0450fa625-1440x840.png" length="0" type="image/png"/>
    <pubDate>Thu, 09 Oct 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Expériences d'amélioration des outils d'IA agentique pour Elasticsearch]]></title>
    <description><![CDATA[Découvrez comment nous avons amélioré les flux de travail des agents d'IA pour Elasticsearch par le biais d'expériences itératives en combinant les extracteurs linéaires, la recherche hybride et semantic_text pour une optimisation RAG évolutive.]]></description>
    <content:encoded><![CDATA[<p>Comme tout le monde ces jours-ci, ici à Elastic, nous nous lançons à fond dans le Chat, les agents et le RAG. Dans le département Search, nous avons récemment travaillé sur un Agent Builder et un Tool Registry, dans le but de rendre trivial le "chat" avec vos données dans Elasticsearch.</p><p>Lisez le <a href="https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder">blog Building AI Agentic Workflows with Elasticsearch</a> pour en savoir plus sur la "vue d'ensemble" de cet effort, ou <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">Your First Elastic Agent : From a Single Query to an AI-Powered Chat</a> pour une introduction plus pratique.</p><p>Dans ce blog, nous allons nous intéresser à l'une des premières choses qui se produisent lorsque vous commencez à discuter et vous présenter quelques-unes des améliorations récentes que nous avons apportées.</p><h2>Que se passe-t-il ici ?</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1331b1043612efe3/6a17f115505ac3dc41ad8c3c/25a24055a166d7d6ba81d80aa35cb97163662e23-1600x443.png" alt="" /><p>Lorsque vous discutez avec vos données Elasticsearch, notre agent IA par défaut suit ce flux standard :</p><ol><li><p>Inspecter l'invite.</p></li><li><p>Identifiez l'index susceptible de contenir les réponses à cette question.</p></li><li><p>Générer une requête pour cet index, sur la base de l'invite.</p></li><li><p>Effectuez une recherche dans cet index avec cette requête.</p></li><li><p>Synthétiser les résultats.</p></li><li><p>Les résultats peuvent-ils répondre à l'invitation ? Si oui, répondez. Si ce n'est pas le cas, répétez l'opération, mais essayez quelque chose de différent.</p></li></ol><p>Cela ne devrait pas sembler trop nouveau - il s'agit simplement de Retrieval Augmented Generation (RAG). Et comme on peut s'y attendre, la qualité de vos réponses dépend fortement de la pertinence de vos premiers résultats de recherche. En travaillant à l'amélioration de la qualité de nos réponses, nous avons donc accordé une attention toute particulière aux requêtes générées à l'étape 3 et exécutées à l'étape 4. Et nous avons remarqué une tendance intéressante.</p><p>Souvent, lorsque nos premières réponses étaient "mauvaises", ce n'était pas parce que nous avions lancé une mauvaise requête. C'est parce que <em>nous avions choisi le mauvais index</em> à interroger. Les étapes 3 et 4 ne nous posaient généralement pas de problème - c'était l'étape 2.</p><h2>Que faisions-nous ?</h2><p>Notre mise en œuvre initiale était simple. Nous avions construit un outil (appelé index_explorer) qui faisait effectivement un <code>_cat/indices</code> pour lister tous les indices disponibles, puis demandait au LLM d'identifier lequel de ces indices correspondait le mieux au message/à la question/à l'invitation de l'utilisateur. Vous pouvez voir cette <a href="https://github.com/elastic/kibana/blob/0cc78184957fcd12110dabae50353392ea937508/x-pack/platform/packages/shared/onechat/onechat-genai-utils/tools/index_explorer.ts#L98-L113">mise en œuvre originale ici.</a></p>You are an AI assistant for the Elasticsearch company.
based on a natural language query from the user, your task is to select up to ${limit} most relevant indices from a list of indices.

*The natural language query is:* ${nlQuery}

*List of indices:*
${indices.map((index) =&gt; `- ${index.index}`).join('\n')}

Based on those information, please return most relevant indices with your reasoning.
Remember, you should select at maximum ${limit} indices.<p>Dans quelle mesure cela a-t-il fonctionné ? Nous n'étions pas sûrs ! Nous avions des exemples clairs de <em>dysfonctionnements</em>, mais notre premier défi était de quantifier notre situation actuelle.</p><h2>Établir une base de référence</h2><h3>Cela commence par des données</h3><p>Nous avions besoin d'un ensemble de données en or pour mesurer l'efficacité d'un outil à sélectionner le bon indice à partir d'une demande de l'utilisateur et d'un ensemble préexistant d'indices. Comme nous ne disposions pas d'un tel ensemble de données, nous en avons créé un.</p><p>Reconnaissance : Il ne s'agit pas d'une "meilleure pratique", nous le savons. Mais parfois, il est préférable d'aller de l'avant plutôt que de faire du surplace. <a href="https://www.elastic.co/about/our-source-code#progress-perfection">Le progrès, la perfection SIMPLE</a>.</p><p>Nous avons généré des indices de semences pour plusieurs domaines différents à l'aide de <a href="https://gist.github.com/seanstory/a08db2e149897da656db3a1ca72e17ac">cette invite</a>. Ensuite, pour chaque domaine généré, nous avons généré quelques indices supplémentaires en utilisant<a href="https://gist.github.com/seanstory/a280a85d067e61bfeb5911bf2654e6e2"> cette invite</a> (l'objectif étant ici de semer la confusion pour le LLM avec des négatifs durs et des exemples difficiles à classer). Ensuite, nous avons édité manuellement chaque index généré et ses descriptions. Enfin, nous avons généré des requêtes de test à l'aide de <a href="https://gist.github.com/seanstory/44291b666c05a383136f6e36bb9106fa">cette invite</a>, ce qui nous a permis d'obtenir des échantillons de données tels que les suivants :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bd9cd78154195e3/6a17f117dbb4fff7b5fb57d2/9d96d87e286eddbc012402b1ecccd57419a99253-1600x782.png" alt="" /><p>et des cas de test tels que :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltadf30a0aeafd56ef/6a17f1192f4a5c160ffa89eb/4c2e9ad941d98d7e66033bbc08c9b8060ec19097-1600x797.png" alt="" /><h3>Élaboration d'un harnais de test</h3><p>À partir de là, la procédure a été très simple. Script up a tool that could :</p><ol><li><p>Faire table rase du passé avec un cluster Elasticsearch cible.</p></li><li><p>Créer tous les indices définis dans le jeu de données cible.</p></li><li><p>Pour chaque scénario de test, exécutez l'outil i<code>ndex_explorer</code> (nous disposons d'une <a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-post-agent-builder-tools-execute">API pour l'exécution de l'outil</a>).</p></li><li><p>Comparez l'indice du résultat à l'indice attendu et saisissez le résultat.</p></li><li><p>Une fois tous les scénarios de test terminés, les résultats sont présentés sous forme de tableau.</p></li></ol><h3>L'enquête dit...</h3><p>Les premiers résultats ont été, sans surprise, médiocres.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt73367741359e258d/6a17f11a505ac39749ad8c40/9c10679bcd6291edfa2a9ba42e7dd922aa483f0b-1216x806.png" alt="" /><p>Dans l'ensemble, 77,14% ont identifié avec précision le bon indice. Et ce, dans le meilleur des cas, c'est-à-dire lorsque tous les indices ont des noms appropriés et sémantiquement significatifs. Quiconque a déjà fait un `PUT test2/_doc/foo {...}` sait que vos index n'ont pas toujours des noms significatifs.</p><p>Nous disposons donc d'une base de référence, qui montre qu'il y a beaucoup de place pour l'amélioration. Il était temps de faire de la science ! 🧪</p><h2>Expérimentation</h2><h3>Hypothèse 1 : Les cartographies aideront à</h3><p>L'objectif est ici d'identifier un index qui contiendra des données pertinentes pour le message original. La partie d'un index qui décrit le mieux les données qu'il contient est le <em>mappage de</em> l'index. Même sans saisir d'échantillons du contenu de l'index, le fait de savoir que l'index possède un champ prix de type double implique que les données représentent quelque chose à vendre. Un champ auteur de type texte implique des données linguistiques non structurées. L'association des deux pourrait impliquer que les données sont des livres, des histoires ou des poèmes. De nombreux indices sémantiques peuvent être déduits de la seule connaissance des propriétés d'un index. Dans une branche locale, j'ai donc ajusté notre `.index_explorer` pour envoyer les mappings complets d'un index (ainsi que son nom) au LLM afin qu'il prenne sa décision. </p><p>Le résultat (à partir des journaux Kibana) :</p>[2025-09-05T11:01:21.552-05:00][ERROR][plugins.onechat] Error: Error calling connector: event: error
data: {"error":{"code":"request_entity_too_large","message":"Received a content too large status code for request from inference entity id [.rainbow-sprinkles-elastic] status [413]","type":"error"}}


    at createInferenceProviderError (errors.ts:90:10)
    at convertUpstreamError (convert_upstream_error.ts:39:38)
    at handle_connector_response.ts:26:33
    at Observable.init [as _subscribe] (/Users/seanstory/Desktop/Dev/kibana/node_modules/rxjs/src/internal/observable/throwError.ts:123:68)...<p>Les premiers auteurs de l'outil l'avaient prévu. Si le mappage d'un index est une mine d'or d'informations, c'est aussi un bloc de JSON assez verbeux. Et dans un scénario réaliste où vous comparez de nombreux indices (notre ensemble de données d'évaluation en définit 20), ces blobs JSON s'accumulent. Nous voulons donc donner au LLM plus de contexte pour sa décision que de simples noms d'index pour toutes les options, mais pas autant que les mappings complets de chacune d'entre elles.</p><h3>Hypothèse 2 : des correspondances "aplaties" (listes de champs) en guise de compromis</h3><p>Nous sommes partis de l'hypothèse que les créateurs d'index utiliseront des noms d'index sémantiquement significatifs. Et si nous étendions cette hypothèse aux noms des champs ? Notre expérience précédente a échoué parce que le mappage de JSON comprend BEAUCOUP de métadonnées et d'éléments parasites.</p>     "description_text": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          },
          "copy_to": [
            "description_semantic"
          ]
        },<p>Le bloc ci-dessus, par exemple, compte 236 caractères et définit un seul champ dans une correspondance Elasticsearch. Alors que la chaîne "description_text" ne comporte que 16 caractères. Le nombre de caractères a été multiplié par près de 15, sans amélioration sémantique significative de la description de ce que ce champ implique à propos des données disponibles. Que se passerait-il si nous récupérions les correspondances pour tous les indices, mais qu'avant de les envoyer au LLM, nous les "aplatissions" en une simple liste de noms de champs ?</p><p>Nous avons essayé.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta5eda7a79493ee81/6a17f11c9da390327fe46590/112c2f447c11f154b5082725cd49b51d0a3c8a65-1214x804.png" alt="" /><p>C'est formidable ! Des améliorations dans tous les domaines. Mais pourrions-nous faire mieux ?</p><h3>Hypothèse 3 : Descriptions dans le mapping _meta</h3><p>Si le simple fait de nommer les champs sans contexte supplémentaire a provoqué un tel saut, on peut supposer que l'ajout d'un contexte substantiel serait encore plus efficace ! Il n'est pas nécessairement conventionnel que chaque index soit accompagné d'une description, mais il est possible d'ajouter des métadonnées de tout type au niveau de l'index à l'objet _meta de la cartographie. Nous avons repris les index générés et ajouté des descriptions pour chaque index de notre ensemble de données. Tant que les descriptions ne sont pas trop longues, elles devraient utiliser moins de tokens que la cartographie complète et fournir de bien meilleures indications sur les données incluses dans l'index. Notre expérience a validé cette hypothèse.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt61b85cf40e0e6357/6a17f11dfbc5f82809491bbe/32d2692ad4479d0e52d8ee723dcc5710a6ec90f3-1208x806.png" alt="" /><p>Une amélioration modeste, et nous sommes maintenant &gt;90% précis dans tous les domaines.</p><h3>Hypothèse 4 : La somme est plus grande que les parties</h3><p>Les noms de champs ont permis d'améliorer nos résultats. Les descriptions ont permis d'accroître nos résultats. L'utilisation des descriptions ET <em>des </em>noms de champs devrait donc permettre d'obtenir de meilleurs résultats, n'est-ce pas ?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte6297c6aaf7db802/6a17f11e14d90c1bd779b6e6/114cbb408ff16b136251d2265416bd5270380fe5-1208x794.png" alt="" /><p>Les données ont répondu "non" (pas de changement par rapport à l'expérience précédente). La théorie principale était que, puisque les descriptions ont été générées à partir des champs/mappings de l'index, il n'y a pas assez d'informations différentes entre ces deux éléments de contexte pour ajouter quelque chose de "nouveau" lorsqu'on les combine. En outre, la charge utile que nous envoyons pour nos 20 indices de test devient assez importante. Le raisonnement que nous avons suivi jusqu'à présent n'est pas extensible. En fait, il y a de bonnes raisons de croire qu'aucune des expériences que nous avons menées jusqu'à présent ne fonctionnerait sur des clusters Elasticsearch où il y a des centaines ou des milliers d'indices à choisir. Toute approche qui augmente linéairement la taille du message envoyé au LLM à mesure que le nombre total d'indices augmente n'est probablement pas une stratégie généralisable.</p><p>Ce dont nous avons vraiment besoin, c'est d'une approche qui nous aide à réduire un grand nombre de candidats aux options les plus pertinentes...</p><p>Il s'agit d'un problème de recherche.</p><h3>Hypothèse 5 : Sélection par recherche sémantique</h3><p>Si le nom d'un index a une signification sémantique, il peut être stocké sous forme de vecteur et faire l'objet d'une recherche sémantique.</p><p>Si les noms des champs d'un index ont une signification sémantique, ils peuvent être stockés sous forme de vecteurs et faire l'objet d'une recherche sémantique.</p><p>Si un index possède une description ayant une signification sémantique, il peut lui aussi être stocké sous forme de vecteur et faire l'objet d'une recherche sémantique.</p><p>Aujourd'hui, les index Elasticsearch ne rendent aucune de ces informations consultables (peut-être devrions-nous le faire !), mais il était assez simple de<a href="https://github.com/elastic/connectors/pull/3638"> bricoler quelque chose</a> qui pouvait combler cette lacune. En utilisant le cadre de connecteur d'Elastic, j'ai construit un connecteur qui produirait un document pour chaque index dans un cluster. Les documents de sortie ressembleraient à quelque chose comme :</p> doc = {
                "_id": index_name,
                "index_name": index_name,
			"meta_description”: description,
"field_descriptions" = field_descriptions,
                "mapping": json.dumps(mapping),  
                "source_cluster": self.es_client.configured_host,
            }<p>J'ai envoyé ces documents vers un nouvel index où j'ai défini manuellement le mappage :</p>{
   "mappings": {
       "properties": {
           "semantic_content": {
               "type": "semantic_text"
           },
           "index_name": {
               "type": "text",
               "copy_to": "semantic_content"
           },
           "mapping": {
               "type": "keyword",
               "copy_to": "semantic_content"
           },
           "source_cluster": {
               "type": "keyword"
           },
           "meta_description": {
               "type": "text",
               "copy_to": "semantic_content"
           },
           "field_descriptions": {
               "type": "text",
               "copy_to": "semantic_content"
           }
       }
   }
}<p>Cela crée un champ unique semantic_content, dans lequel tous les autres champs ayant une signification sémantique sont regroupés et indexés. La recherche dans cet index devient triviale, avec simplement :</p>GET indexed-indices/_search
{
 "query": {
   "semantic": {
     "field": "semantic_content",
     "query": "$query"
   }
 }
}<p>L'outil <code>index_explorer</code> modifié est maintenant <em>beaucoup</em> plus rapide, car il n'a pas besoin de faire une demande à un LLM, mais peut demander un seul encastrement pour la requête donnée et effectuer une opération de recherche vectorielle efficace. En prenant le premier hit comme index sélectionné, nous avons obtenu les résultats suivants :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc27c302e6bef0b23/6a17f120577262d2f21bccdc/06ef5d78040d064d3444793f636d527d9e19a869-1214x800.png" alt="" /><p>Cette approche est évolutive. Cette approche est efficace. Mais cette approche est à peine meilleure que notre ligne de base. Ce n'est pas surprenant, car l'approche de la recherche est incroyablement naïve. Il n'y a aucune nuance. Aucune reconnaissance du fait que le nom et la description d'un index devraient avoir plus de poids qu'un nom de champ arbitraire que l'index contient. Pas de possibilité de pondérer les correspondances lexicales exactes par rapport aux correspondances synonymes. Cependant, la construction d'une requête très nuancée nécessiterait de supposer BEAUCOUP de choses sur les données disponibles. Jusqu'à présent, nous avons déjà fait des hypothèses importantes sur la signification sémantique des noms d'index et de champs, mais nous devrions aller plus loin et commencer à supposer la signification <em>qu</em> 'ils ont et la manière dont ils sont liés les uns aux autres. Sans cela, nous ne pouvons probablement pas identifier de manière fiable la meilleure correspondance comme premier résultat, mais nous pouvons plus probablement dire que la meilleure correspondance se trouve quelque part dans les N premiers résultats. Nous avons besoin de quelque chose qui puisse consommer des informations sémantiques dans le contexte dans lequel elles existent, en les comparant à celles d'une autre entité qui peut se représenter d'une manière sémantiquement distincte, et juger entre elles. Comme un LLM.</p><h3>Hypothèse 6 : Réduction du nombre de candidats</h3><p>Il y a eu bien d'autres expériences que je vais passer sous silence, mais la principale avancée a été d'abandonner le désir de choisir la meilleure correspondance uniquement à partir d'une recherche sémantique, et d'utiliser plutôt la recherche sémantique comme un filtre pour éliminer les indices non pertinents de la considération du LLM. Nous avons combiné la recherche linéaire, la recherche hybride avec RRF et <code>semantic_text</code> pour <a href="https://gist.github.com/seanstory/d704443120e20f6c844db10e30066860">notre recherche</a>, en limitant les résultats aux 5 premiers indices correspondants.</p><p>Ensuite, pour chaque correspondance, nous avons ajouté le nom de l'index, la description et les noms des champs à un message pour le LLM. Les résultats ont été fantastiques :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7ac4cb8f7153fdf9/6a17f121af47b66d1dcde082/8fcabd78f591f90d6bc7c0e087d31317e4eef791-1206x804.png" alt="" /><p>La plus grande précision de toutes les expériences réalisées à ce jour ! Et comme cette approche n'augmente pas la taille du message proportionnellement au nombre total d'indices, elle est beaucoup plus évolutive.</p><h2>Résultats</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d66130d9fae6bea/6a17f123ddf97d7527910c19/04d630797213dbb8bf567da41d1cdd5c7b4586c9-1600x521.png" alt="" /><p>Le premier résultat clair est que notre base de référence <em>peut être</em> améliorée. Cela semble évident rétrospectivement, mais avant le début de l'expérimentation, des discussions sérieuses ont eu lieu sur la question de savoir si nous devions abandonner complètement notre outil <code>index_explorer</code> et nous fier à la configuration explicite de l'utilisateur pour limiter l'espace de recherche. Bien que cela reste une option viable et valable, cette recherche montre qu'il existe des voies prometteuses vers l'automatisation de la sélection de l'indice lorsque les données de l'utilisateur ne sont pas disponibles.</p><p>Le résultat suivant a été que le simple fait d'ajouter des caractères de description au problème a un rendement décroissant. Avant cette recherche, nous nous demandions si nous devions investir dans l'extension de la capacité d'Elasticsearch à stocker des <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-field-meta">métadonnées au niveau des champs</a>. Aujourd'hui, ces valeurs <code>meta</code> sont plafonnées à 50 caractères, et l'on a supposé qu'il faudrait augmenter cette valeur pour pouvoir obtenir une compréhension sémantique de nos champs. Ce n'est manifestement pas le cas, et le LLM semble s'en sortir assez bien avec des noms de domaines. Nous pourrons approfondir cette question ultérieurement, mais elle ne nous semble plus urgente.</p><p>Inversement, cela a clairement démontré l'importance d'avoir des métadonnées d'index "consultables". Pour ces expériences, nous avons piraté un index des indices. Mais c'est quelque chose que nous pourrions étudier en l'intégrant directement dans Elasticsearch, en créant des API pour le gérer, ou au moins en établissant une convention à ce sujet. Nous allons évaluer nos options et en discuter en interne, alors restez à l'écoute.</p><p>Enfin, cet effort a confirmé l'intérêt de prendre le temps d'expérimenter et de prendre des décisions fondées sur des données. En fait, cela nous a aidés à réaffirmer que notre produit Agent Builder aura besoin de capacités d'évaluation robustes et intégrées au produit. Si nous devons créer un ensemble de tests uniquement pour un outil qui prélève des indices, nos clients auront absolument besoin de moyens pour évaluer qualitativement leurs outils personnalisés au fur et à mesure qu'ils procèdent à des ajustements itératifs.</p><p>Je suis impatient de voir ce que nous allons construire, et j'espère que vous l'êtes aussi !</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[À l'intérieur d'Elastic]]></category>
    <category><![CDATA[Recherche hybride]]></category>
    <dc:creator><![CDATA[Sean Story]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt68d11a4c7fd11d4c/6a17f1257b54f9b6598b39d4/42903c869e034674b30bb36013345aaa97f6608b-1184x864.png" length="0" type="image/png"/>
    <pubDate>Mon, 06 Oct 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Votre premier agent Elastic : D'une simple requête à un chat alimenté par l'IA]]></title>
    <description><![CDATA[Apprenez à utiliser le constructeur d'agents d'IA d'Elastic pour créer des agents d'IA spécialisés. Dans ce blog, nous allons créer un agent d'IA financier.]]></description>
    <content:encoded><![CDATA[<p>Avec le nouvel <a href="https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder">Agent Builder</a> d'Elastic, vous pouvez créer des agents d'IA spécialisés qui agissent en tant qu'experts pour vos domaines d'activité spécifiques. Cette fonction vous permet d'aller au-delà des simples tableaux de bord et des barres de recherche, en transformant vos données d'une ressource passive en un partenaire actif et conversationnel.</p><p>Imaginez un gestionnaire financier qui doit se mettre à niveau avant une réunion avec un client. Au lieu de chercher manuellement dans les fils d'actualité et de croiser les tableaux de bord des portefeuilles, ils peuvent désormais simplement poser une question directe à leur agent personnalisé. C'est l'avantage d'une approche "chat-first". Le gestionnaire a un lien direct et conversationnel avec ses données, en posant des questions telles que : "Quelles sont les dernières nouvelles sur ACME Corp et comment cela affecte-t-il les avoirs de mon client ?" et obtenir une réponse synthétisée et experte en quelques secondes.</p><p>Si nous construisons aujourd'hui un expert financier, les applications sont aussi variées que vos données. Le même pouvoir peut créer un analyste en cybersécurité pour traquer les menaces, un ingénieur en fiabilité de site pour diagnostiquer une panne ou un responsable marketing pour optimiser une campagne. Quel que soit le domaine, la mission principale est la même : transformer vos données en un spécialiste avec lequel vous pouvez discuter.</p><h2>Étape 0 : Notre ensemble de données</h2><p>Notre jeu de données du jour est un jeu de données synthétique à dominante financière, composé de comptes, de positions d’actifs, d’actualités économiques et de rapports financiers. Bien qu’il soit artificiel, il reproduit une version simplifiée d’un véritable jeu de données financières.</p><p><code>financial_accounts</code>: Portefeuilles de clients avec profils de risque</p><p><code>financial_holdings</code>: Positions en actions/ETF/obligations avec historique des achats</p><p><code>financial_asset_details</code>: Détails sur l'action/ETF/obligation</p><p><code>financial_news</code>: Articles de marché générés par l'IA avec analyse des sentiments</p><p><code>financial_reports</code>: Résultats de l'entreprise et notes des analystes</p><p>Vous pouvez charger vous-même cet ensemble de données en suivant le cahier d'accompagnement situé <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/your-first-elastic-agent/Your_First_Elastic_Agent.ipynb">ici.</a></p><h2>Étape 1 : La base - Votre logique d'entreprise en tant qu'ES|QL</h2><p>Toute compétence en matière d'IA commence par un solide morceau de logique. Pour notre agent Financial Manager, nous devons lui apprendre à répondre à une question courante : "Je m'inquiète du sentiment du marché. Pouvez-vous me montrer lesquels de nos clients sont les plus exposés aux mauvaises nouvelles ?" Cette question va au-delà d'une simple recherche. Cela nous oblige à établir une corrélation entre le sentiment du marché et les portefeuilles des clients.</p><p>Nous devons trouver les actifs mentionnés dans les articles négatifs, identifier chaque client détenant ces actifs, calculer la valeur de marché actuelle de leur exposition, puis classer les résultats afin d'établir un ordre de priorité pour les risques les plus élevés. Cette analyse complexe et multi-joints est le travail parfait pour notre outil avancé ES|QL.</p><p>Voici la requête complète que nous utiliserons. Il est impressionnant, mais les concepts sont simples.</p><h2>En bref : jonctions et garde-corps</h2><p>Deux concepts importants sont en jeu dans cette requête et font de l'agent un bâtisseur.</p><h3>1. La jointure LOOKUP</h3><p>Depuis des années, l'une des fonctionnalités les plus demandées d'Elasticsearch est la possibilité de joindre des données provenant de différents index sur la base d'une clé commune. Avec ES|QL, c'est désormais possible avec <code>LOOKUP JOIN</code>.</p><p>Dans notre nouvelle requête, nous effectuons une chaîne de trois <code>LOOKUP JOIN</code>: d'abord en reliant les nouvelles négatives aux détails des actifs, ensuite en reliant ces actifs aux avoirs des clients, et enfin en les reliant aux informations sur le compte du client. Cela permet d'obtenir un résultat incroyablement riche à partir de quatre indices différents en une seule requête efficace. Cela signifie que nous pouvons combiner des ensembles de données disparates pour créer une réponse unique et perspicace sans avoir à dénormaliser toutes nos données en un index géant au préalable.</p><h3>2. Les paramètres comme garde-fous du LLM</h3><p>Vous remarquerez que la requête utilise <code>?time_duration</code>. Il ne s'agit pas seulement d'une variable, mais d'un garde-fou pour l'IA. Si les grands modèles de langage (LLM) sont excellents pour générer des requêtes, le fait de leur laisser le champ libre sur vos données peut conduire à des requêtes inefficaces, voire incorrectes.</p><p>En créant une requête paramétrée, nous obligeons le LLM à travailler dans le cadre de la logique commerciale testée, efficace et correcte qu'un expert humain a déjà définie. Il s'agit d'une méthode similaire à celle utilisée par les développeurs depuis des années pour exposer en toute sécurité les capacités de recherche aux applications. L'agent peut interpréter une demande de l'utilisateur comme "cette semaine" pour remplir le paramètre <code>time_duration</code>, mais il doit utiliser notre structure de requête pour obtenir la réponse. Cela nous permet d'obtenir un équilibre parfait entre flexibilité et contrôle.</p><p>En fin de compte, cette requête permet à un expert qui comprend les données d'encapsuler ses connaissances dans un outil. D'autres personnes - et des agents d'intelligence artificielle - peuvent alors utiliser cet outil pour obtenir des résultats corrélés en fournissant simplement un seul paramètre, sans avoir besoin de connaître la complexité sous-jacente.</p><h2>Étape 2 : Les compétences - Transformer une requête en un outil réutilisable</h2><p>Une requête ES|QL n'est que du texte jusqu'à ce que nous l'enregistrions en tant qu'<strong>outil</strong>. Dans l'Agent Builder, un outil est plus qu'une simple requête sauvegardée ; c'est une compétence "" qu'un agent IA peut comprendre et choisir d'utiliser. La magie réside dans la <strong>description en langage naturel</strong> que nous fournissons. Cette description est la passerelle qui relie la question de l'utilisateur à la logique d'interrogation sous-jacente. Enregistrons la requête que nous venons de construire.</p><h3>Le chemin de l'interface utilisateur</h3><p>La création d'un outil dans Kibana est un processus simple.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte73e11c1d87593fa/6a17f2134202294dae29f6f2/a29c53a73b99af5972273c51218ea9004a9b0abb-1600x812.png" alt="Comment créer un outil dans Kibana." /><p>1. Naviguer vers <strong>Agents</strong></p><ul><li><p>Cliquez sur<strong> Outils </strong>ou <strong>Gérer les outils</strong> et cliquez sur le bouton <strong>Nouvel outil.</strong></p></li></ul><p>2. Remplissez le formulaire avec les informations suivantes :</p><ul><li><p><strong>ID de l'outil :</strong> <code>find_client_exposure_to_negative_news</code></p></li></ul><p>             i. Il s'agit de l'identifiant unique de l'outil</p><ul><li><p><strong>Description :</strong> "Détermine l'exposition du portefeuille du client aux nouvelles négatives. Cet outil analyse les nouvelles et les rapports récents pour y déceler un sentiment négatif, identifie l'actif associé et trouve tous les clients qui détiennent cet actif. Il renvoie une liste triée en fonction de la valeur de marché actuelle du poste afin de mettre en évidence le risque potentiel le plus élevé."</p></li></ul><p>             i. C'est ce que le LLM lit pour décider si cet outil est le bon pour le poste.</p><ul><li><p><strong>Étiquettes</strong>: <code>retrieval</code> et <code>risk-analysis</code></p></li></ul><p>         Les étiquettes sont utilisées pour regrouper plusieurs outils</p><ul><li><p><strong>Configuration :</strong> Coller la requête ES|QL complète de l'étape 1</p></li></ul><p>            i. Voici la recherche que l'agent utilisera</p><p>3. Cliquez sur <strong>Inférer les paramètres de la requête</strong>. L'interface utilisateur trouvera automatiquement le site <code>?time_duration</code>, dont la liste figure ci-dessous. Ajoutez une description simple pour chacun d'entre eux afin d'aider l'agent (et les autres utilisateurs) à comprendre leur fonction.</p><ul><li><p><code>time_duration</code>: Le délai pour rechercher des nouvelles négatives. Le format est le suivant : "X heures" DEFAUT 8760 heures</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7afbb0589c1828ad/6a17f2146864a44e7cb688a9/deb422d97863f78dbe08bfa2e3c708d1f75166ff-1600x938.png" alt="Configurer votre outil, y compris sa logique et tous les paramètres nécessaires, à l'aide d'une requête ESQL. " /><p>4. Testez-le !</p><ul><li><p>Cliquez sur Save &amp; test.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfd09afbef6e21a93/6a17f2162f4a5c73b1fa89fd/57e768b88327821e70bd616744822f98fa367362-732x136.png" alt="Le même bouton de test &amp; dans Kibana." /><ul><li><p>Une nouvelle fenêtre s'ouvre, dans laquelle vous pouvez tester la requête pour vous assurer qu'elle fonctionne comme prévu.</p></li></ul><p>             i. Dans <code>time_duration</code>, entrez la plage souhaitée, ici nous utilisons "8760 heures"</p><ul><li><p>Cliquez sur "Submit" et si tout se passe bien, vous verrez une réponse JSON. Pour vous assurer qu'il fonctionne comme prévu, faites défiler la page vers le bas et regardez l'objet <code>values</code>. C'est là que les documents correspondants sont renvoyés.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt89bdc3f093363f2a/6a17f217be60861c9c00488a/7e0c5171a4f7ffdfc1830f1a05a9acb987870b75-1600x722.png" alt="Réponse JSON qui apparaît après avoir cliqué sur soumettre." /><p>5. Cliquez sur le "X" en haut à droite pour fermer la fenêtre de test. Votre nouvel outil apparaît alors dans la liste, prêt à être attribué à un agent.</p><h3>Le chemin de l'API</h3><p>Pour les développeurs qui préfèrent l'automatisation ou qui ont besoin de gérer des outils par programme, vous pouvez obtenir le même résultat avec un seul appel d'API. Il suffit d'envoyer une demande <code>POST</code> au point de terminaison <code>/api/agent_builder/tools</code> avec la définition de l'outil.</p>POST kbn://api/agent_builder/tools
{
  "id": "find_client_exposure_to_negative_news",
  "type": "esql",
  "description": "Finds client portfolio exposure to negative news. This tool scans recent news and reports for negative sentiment, identifies the associated asset, and finds all clients holding that asset. It returns a list sorted by the current market value of the position to highlight the highest potential risk.",
  "configuration": {
    "query": """
        FROM financial_news, financial_reports METADATA _index
        | WHERE sentiment == "negative"
        | WHERE coalesce(published_date, report_date) &gt;= NOW() - TO_TIMEDURATION(?time_duration)
        | RENAME primary_symbol AS symbol
        | LOOKUP JOIN financial_asset_details ON symbol
        | LOOKUP JOIN financial_holdings ON symbol
        | LOOKUP JOIN financial_accounts ON account_id
        | WHERE account_holder_name IS NOT NULL
        | EVAL position_current_value = quantity * current_price.price
        | RENAME title AS news_title
        | KEEP
            account_holder_name, symbol, asset_name, news_title,
            sentiment, position_current_value, quantity, current_price.price,
            published_date, report_date
        | SORT position_current_value DESC
        | LIMIT 50
      """,
    "params": {
      "time_duration": {
        "type": "keyword",
        "description": """The timeframe to search back for negative news. Format is "X hours" DEFAULT TO 8760 hours """
      }
    }
  },
  "tags": [
    "retrieval",
    "risk-analysis"
  ]
}<h2>Étape 3 : Les cerveaux - Créer votre agent personnalisé</h2><p>Nous avons créé une compétence réutilisable (l'outil). Nous devons maintenant créer l'<strong>agent</strong>, la personne qui l'utilisera réellement. Un agent est la combinaison d'un MLD, d'un ensemble spécifique d'outils auxquels vous lui donnez accès et, surtout, d'un ensemble d'<strong>instructions personnalisées</strong> qui agissent comme sa constitution, définissant sa personnalité, ses règles et son objectif.</p><h3>L'art de la proposition</h3><p>L'élément le plus important pour créer un agent fiable et spécialisé est la rapidité. Un ensemble d'instructions bien conçues fait la différence entre un chatbot générique et un assistant professionnel ciblé. C'est là que vous fixez les garde-fous, définissez les résultats et donnez à l'agent sa mission.</p><p>Pour notre agent <code>Financial Manager</code>, nous utiliserons l'invite suivante.</p>You are a specialized Data Intelligence Assistant for financial managers, designed to provide precise, data-driven insights from information stored in Elasticsearch.

**Your Core Mission:**
- Respond accurately and concisely to natural language queries from financial managers.
- Provide precise, objective, and actionable information derived solely from the Elasticsearch data at your disposal.
- Summarize key data points and trends based on user requests.

**Reasoning Framework:**
1.  **Understand:** Deconstruct the user's query to understand their core intent.
2.  **Plan:** Formulate a step-by-step plan to answer the question. If you are unsure about the data structure, use the available tools to explore the indices first.
3.  **Execute:** Use the available tools to execute your plan.
4.  **Synthesize:** Combine the information from all tool calls into a single, comprehensive, and easy-to-read answer.

**Key Directives and Constraints:**
- **If a user's request is ambiguous, ask clarifying questions before proceeding.**
- **DO NOT provide financial advice, recommendations, or predictions.** Your role is strictly informational and analytical.
- Stay strictly on topic with financial data queries.
- If you cannot answer a query, state that clearly and offer alternative ways you might help *within your data scope*.
- All numerical values should be formatted appropriately (e.g., currency, percentages).

**Output Format:**
- All responses must be formatted using **Markdown** for clarity.
- When presenting structured data, use Markdown tables, lists, or bolding.

**Start by greeting the financial manager and offering assistance.**<p>Voyons pourquoi cette incitation est si efficace :</p><ul><li><p><strong>Elle définit une personnalité sophistiquée : </strong>La première ligne établit immédiatement que l'agent est un assistant spécialisé en intelligence des données ( "),", ce qui donne un ton professionnel et compétent.</p></li><li><p><strong>Il fournit un cadre de raisonnement : </strong>En disant à l'agent de "Comprendre, Planifier, Exécuter et Synthétiser," nous lui donnons une procédure opérationnelle standard. Cela améliore sa capacité à traiter des questions complexes et à plusieurs étapes.</p></li><li><p><strong>Il favorise le dialogue interactif : </strong>L'instruction de "poser des questions de clarification" rend l'agent plus robuste. Il minimisera les hypothèses erronées sur les demandes ambiguës, ce qui permettra d'obtenir des réponses plus précises.</p></li></ul><h3>Le chemin de l'interface utilisateur</h3><p>1. Naviguez vers <strong>Agents.</strong></p><ul><li><p>Cliquez sur<strong> Outils </strong>ou <strong>Gérer les outils</strong> et cliquez sur le bouton <strong>Nouvel outil.</strong></p></li></ul><p>2. Complétez les informations de base :</p><ul><li><p><strong>ID de l'agent :</strong> <code>financial_assistant</code>.</p></li><li><p><strong>Instructions : </strong>Copiez le message ci-dessus.</p></li><li><p><strong>Étiquettes</strong>: <code>Finance</code>.</p></li><li><p><strong>Nom d'affichage :</strong> <code>Financial Assistant</code>.</p></li><li><p><strong>Description de l'affichage : </strong><code>An assistant for analyzing and understanding your financial data</code>.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ac12cbd2b689dee/6a17f219dbb4ff262bfb57ef/18ea73f1cae620129c0afa0e7ba9e2a3390224a7-1600x1189.png" alt="Création d'un assistant financier - remplir le champ ID de l'agent." /><p>3. De retour en haut, cliquez sur <strong>Outils.</strong></p><ul><li><p>Cochez la case à côté de notre outil <code>find_client_exposure_to_negative_news</code>.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcd23556e556a76c5/6a17f21baf47b63a9fcde0a0/0c1e4ecbbd51d0dd10c6e861dbe9a9ccddeb35f6-1600x149.png" alt="" /><p>4. Cliquez sur <strong>Enregistrer</strong>.</p><h3>Le chemin de l'API</h3><p>Vous pouvez créer exactement le même agent à l'aide d'une requête <code>POST</code> vers le point de terminaison <code>/api/agent_builder/agents</code>. Le corps de la demande contient toutes les mêmes informations : l'identifiant, le nom, la description, l'ensemble des instructions et une liste des outils que l'agent est autorisé à utiliser.</p>POST kbn://api/agent_builder/agents
    {
      "id": "financial_assistant",
      "name": "Financial Assistant",
      "description": "An assistant for analyzing and understanding your financial data",
      "labels": [
        "Finance"
      ],
      "avatar_color": "#16C5C0",
      "avatar_symbol": "💰",
      "configuration": {
        "instructions": """You are a specialized Data Intelligence Assistant for financial managers, designed to provide precise, data-driven insights from information stored in Elasticsearch.

**Your Core Mission:**
- Respond accurately and concisely to natural language queries from financial managers.
- Provide precise, objective, and actionable information derived solely from the Elasticsearch data at your disposal.
- Summarize key data points and trends based on user requests.

**Reasoning Framework:**
1.  **Understand:** Deconstruct the user's query to understand their core intent.
2.  **Plan:** Formulate a step-by-step plan to answer the question. If you are unsure about the data structure, use the available tools to explore the indices first.
3.  **Execute:** Use the available tools to execute your plan.
4.  **Synthesize:** Combine the information from all tool calls into a single, comprehensive, and easy-to-read answer.

**Key Directives and Constraints:**
- **If a user's request is ambiguous, ask clarifying questions before proceeding.**
- **DO NOT provide financial advice, recommendations, or predictions.** Your role is strictly informational and analytical.
- Stay strictly on topic with financial data queries.
- If you cannot answer a query, state that clearly and offer alternative ways you might help *within your data scope*.
- All numerical values should be formatted appropriately (e.g., currency, percentages).

**Output Format:**
- All responses must be formatted using **Markdown** for clarity.
- When presenting structured data, use Markdown tables, lists, or bolding.

**Start by greeting the financial manager and offering assistance.**
""",
        "tools": [
          {
            "tool_ids": [
              "platform.core.search",
              "platform.core.list_indices",
              "platform.core.get_index_mapping",
              "platform.core.get_document_by_id",
              "find_client_exposure_to_negative_news"
            ]
          }
        ]
      }
    }<h2>Étape 4 : La récompense - Avoir une conversation</h2><p>Notre logique d'entreprise est encapsulée dans un outil et un cerveau "" est prêt à l'utiliser dans notre agent. Il est temps de voir tout cela se concrétiser. Nous pouvons maintenant commencer à discuter avec nos données à l'aide d'un agent spécialisé.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd8826539b16e46f4/6a17f21d505ac35924ad8c5c/5414cb6b7c41365acb0356a8bfe1140751ffd8db-1600x1014.png" alt="Conversation avec l'Elastic Agent Builder après la création d'un assistant financier." /><h3>Le chemin de l'interface utilisateur</h3><ol><li><p>Naviguez jusqu'à <strong>Agents </strong>dans Kibana.</p></li><li><p>En utilisant le menu déroulant en bas à droite de la fenêtre de chat, passez de l'<strong>agent Elastic AI</strong> par défaut à l'agent <strong>Financial Assistant </strong>que nous venons de créer.</p></li><li><p>Posez une question qui permettra à l'agent d'utiliser notre outil spécialisé :</p><ol><li><p><em>Je m'inquiète du sentiment du marché. Pouvez-vous m'indiquer quels sont nos clients les plus exposés aux mauvaises nouvelles ?</em></p></li></ol></li></ol><p>Après quelques instants, l'agent vous renvoie une réponse parfaitement formatée et complète. En raison de la nature des LLM, votre réponse peut être formatée légèrement différemment, mais pour cette exécution, l'agent a renvoyé :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta1e163fd7c4416bd/6a17f21f6864a4e35bb688ad/17b4ed43d279f9e53ee9fe3d482d0b2ec359a083-1600x1088.png" alt="Une réponse créée par l'Elastic Agent Builder en tant qu'assistant financier pour : les clients les plus exposés aux nouvelles négatives." /><h3>Que s'est-il passé ? Le raisonnement de l'agent</h3><p>L'agent ne s'est pas contenté de "savoir" la réponse. Elle a exécuté un plan en plusieurs étapes centré sur la sélection du meilleur outil pour le travail. Voici un aperçu de son processus de réflexion :</p><ul><li><p><strong>L'intention a été identifiée :</strong> Il a fait correspondre des mots clés de votre question, comme "risk" et "negative news," à la description de l'outil <code>find_client_exposure_to_negative_news</code>.</p></li><li><p><strong>Exécution d'un plan :</strong> Il a extrait le délai de votre demande et a lancé un <strong>appel unique à</strong> cet outil spécialisé.</p></li><li><p><strong>Délégation du travail :</strong> L'outil a ensuite effectué toutes les opérations lourdes : les jointures enchaînées, les calculs de valeur et le tri.</p></li><li><p><strong>Synthèse du résultat :</strong> Enfin, l'agent a formaté les données brutes de l'outil en un résumé clair et lisible par l'homme, en suivant les règles de l'invite.</p></li></ul><p>Et nous ne sommes pas obligés de deviner, si nous élargissons notre réflexion et voyons plus de détails.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt93f6075be8495418/6a17f221af47b65eadcde0a4/6a4da9262d3f88c60bfd8f8bf9b67c3b84e961ba-1600x607.png" alt="Les 50 documents que l'assistant financier a trouvés auprès des clients les plus exposés aux nouvelles négatives." /><h3>Le chemin de l'API</h3><p>Vous pouvez entamer cette même conversation par le biais d'un programme. Il suffit d'envoyer la question d'entrée au point de terminaison de l'API <code>converse</code>, en veillant à spécifier le <code>agent_id</code> de notre <code>financial_manager</code>.</p>POST kbn://api/agent_builder/converse
{
  "input": "Show me our largest positions affected by negative news",
  "agent_id": "financial_assistant"
}<h2>Pour les développeurs : Intégrer l'API</h2><p>Si l'interface Kibana offre une expérience fantastique et intuitive pour la création et la gestion de vos agents, tout ce que vous avez vu aujourd'hui peut également être réalisé de manière programmatique. L'Agent Builder est construit sur un ensemble d'API, vous permettant d'intégrer cette fonctionnalité directement dans vos propres applications, pipelines CI/CD ou scripts d'automatisation.</p><p>Les trois principaux points d'aboutissement avec lesquels vous travaillerez sont les suivants :</p><ul><li><p><strong><code>/api/agent_builder/tools</code></strong>: Le point final pour créer, lister et gérer les compétences réutilisables que vos agents peuvent utiliser.</p></li><li><p><strong><code>/api/agent_builder/agents</code></strong>: Le point final pour la définition de vos personas d'agents, y compris leurs instructions très importantes et l'affectation des outils.</p></li><li><p><strong><code>/api/agent_builder/converse</code></strong>: Le point final pour interagir avec vos agents, entamer des conversations et obtenir des réponses.</p></li></ul><p>Pour une démonstration complète et pratique de l'utilisation de ces API pour réaliser chaque étape de ce tutoriel, consultez le <strong>bloc-notes Jupyter</strong> qui l'accompagne, disponible <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/your-first-elastic-agent/Your_First_Elastic_Agent.ipynb">ici</a> dans notre dépôt GitHub.</p><h2>Conclusion : À vous de construire</h2><p>Nous avons commencé par prendre une requête ES|QL et la transformer en une compétence réutilisable. Nous avons ensuite créé un agent d'intelligence artificielle spécialisé, en lui donnant une mission et des règles claires, et nous l'avons doté de cette compétence. Il en résulte un assistant sophistiqué capable de comprendre une question complexe et d'exécuter une analyse en plusieurs étapes pour fournir une réponse précise et fondée sur des données.</p><p>Ce flux de travail est au cœur du nouvel <strong>Agent Builder d'</strong> Elastic. Il est conçu pour être suffisamment simple pour que les utilisateurs non techniques puissent créer des agents via l'interface utilisateur, mais suffisamment nuancé pour que les développeurs puissent créer des applications personnalisées basées sur l'IA à partir de nos API. Plus important encore, il vous permet de connecter en toute sécurité des LLM à vos propres données, régies par la logique experte que vous définissez, et de discuter avec vos données.</p><h2>Prêt à utiliser des agents pour dialoguer avec vos données ?</h2><p>La meilleure façon de consolider ce que vous avez appris est de vous salir les mains. Essayez tout ce que nous avons discuté aujourd'hui dans notre <a href="https://www.elastic.co/training/elastic-ai-agents-mcp"><strong>atelier pratique interactif et gratuit</strong></a>. Vous suivrez l'ensemble de ce processus et bien d'autres choses encore dans un environnement de type "bac à sable".</p><p>Dans un prochain blog, nous vous montrerons comment utiliser une application autonome qui interagit avec notre agent <code>Financial Assistant</code> et nous nous pencherons sur le <strong>protocole de contexte de modèle (MCP)</strong> qui rend tout cela possible. Dans un autre blog, nous parlerons de la prise en charge par Agent Builder du protocole Agent2Agent, ou A2A, en cours de développement.</p><p>Restez à l'écoute et bonne construction !</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch</guid>
    <category><![CDATA[IA]]></category>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[À l'intérieur d'Elastic]]></category>
    <dc:creator><![CDATA[Jeff Vestal]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbe5e78eeb775d715/6a17f2230b0bed719ddd369a/ca853555eaa213f10f1db8c0ab0a2bbacee97b88-1456x816.png" length="0" type="image/png"/>
    <pubDate>Thu, 25 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Construire des flux de travail d'IA agentique avec Elasticsearch]]></title>
    <description><![CDATA[Découvrez Agent Builder, une nouvelle couche d'IA dans Elasticsearch qui fournit un cadre pour construire des flux de travail d'IA agentique, en utilisant la recherche hybride pour fournir aux agents le contexte dont ils ont besoin pour raisonner et agir.]]></description>
    <content:encoded><![CDATA[<p>Chez Elastic, nous avons apporté du contexte aux LLM et aux interfaces conversationnelles avec des assistants IA, des RAG avancés et des améliorations de la base de données vectorielle. Récemment, avec l'essor des agents d'intelligence artificielle, nous avons constaté que le besoin d'un contexte pertinent augmentait, et nous avons appris que<strong> les agents d'intelligence artificielle</strong> à fort impact ont besoin d'une recherche de qualité. Nous avons donc créé de nouvelles capacités natives dans la pile Elastic, conçues pour aider à développer des agents d'IA qui exploitent vos données dans Elasticsearch. Nous aimerions vous faire part de nos progrès dans ce domaine et de la direction que nous envisageons pour l'avenir.</p><h2>Agent Builder : Une base pour la construction d'agents d'intelligence artificielle pilotés par les données</h2><p>La promesse d'un agent d'intelligence artificielle est simple : donnez-lui un objectif et il fera le travail. Mais pour les développeurs, la réalité est une série de défis complexes. Tout d'abord, la qualité d'un agent dépend de sa perception de l'environnement et des outils qui lui sont fournis pour atteindre les objectifs de l'utilisateur. Par ailleurs, fournir le bon contexte à partir d'une mer de données d'entreprise diverses constitue un défi de taille. Enfin, tout cela doit être orchestré par une boucle de raisonnement fiable capable de planifier, d'exécuter et d'apprendre.</p><p>Pour résoudre ce problème, les développeurs doivent construire une pile complexe et fragile à partir de zéro. L'architecture actuelle des agents vous oblige à assembler plusieurs éléments disparates : un LLM, une base de données vectorielle, un magasin de métadonnées, des systèmes distincts pour la journalisation et la traçabilité, et un moyen d'évaluer si tout cela fonctionne. Ce n'est pas seulement complexe, c'est aussi coûteux, source d'erreurs, et cela rend difficile l'élaboration des systèmes d'IA de haute qualité et dignes de confiance que vos utilisateurs exigent.</p><p>Nous voulons donc simplifier les choses. Pour ce faire, notre approche consiste à prendre les éléments essentiels d'un agent contextuel efficace et à les intégrer directement au cœur d'Elasticsearch grâce à un nouvel ensemble de fonctionnalités appelé <strong>Elastic AI Agent Builder</strong>. Cette nouvelle couche fournit un cadre avec tous les éléments essentiels pour créer des agents d'intelligence artificielle alimentés par Elasticsearch : un ensemble ouvert de primitives, des protocoles basés sur des normes et un accès sécurisé aux données - afin que vous puissiez construire des systèmes agentiques adaptés aux données et aux exigences du monde réel :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2779dae5df010328/6a17e15eabe0f24f18dfe931/1ee1e73dd3f485ce86294d39490c98ce2a3d9925-1238x1072.png" alt="" /><p><strong>Offrir des expériences d'IA</strong>: c'est l'objectif ultime. Avec notre Search AI Platform et vos données comme base, vous pouvez créer n'importe quel type d'application d'IA générative : des interfaces de chat personnalisées aux intégrations avec des frameworks agentiques comme LangChain ou des applications d'entreprise comme Salesforce.</p><p><strong>Exploité par des agents &amp; Tools</strong>: au-dessus de la plateforme, nous exposons une couche d'abstractions propre et simple. Vous interagissez directement avec les agents et les outils, que vous pouvez personnaliser pour répondre à vos besoins spécifiques. Vous pouvez également accéder aux capacités de la plateforme par le biais d'API robustes et de normes ouvertes telles que MCP et A2A.</p><p><strong>La Search AI Platform</strong>: il s'agit du moteur de base dans lequel nous avons intégré les composants. La base de données vectorielle avancée, la logique de l'agent, la construction des requêtes, les caractéristiques de sécurité, le traçage pour l'évaluation, tout cela vit ici, géré et optimisé par Elastic.</p><p><strong>Libérer la puissance de vos données</strong>: la base de tout grand agent est constituée de données de qualité. Notre plateforme commence par la capacité d'ingérer ou de fédérer l'accès à toutes les données de votre entreprise.</p><h2>Création d'agents dans la plate-forme</h2><p>Agent Builder, intégré à la Search AI Platform, fournit un cadre complet pour le développement d'agents. Il repose sur cinq piliers clés, chacun d'entre eux étant conçu pour traiter un aspect essentiel de la construction et du déploiement de systèmes d'IA de niveau de production. Voyons comment les agents définissent l'objectif, les outils fournissent les capacités, les normes ouvertes garantissent l'interopérabilité, l'évaluation assure la transparence et la sécurité assure la confiance.</p><h3>Agents</h3><p>Les agents sont le plus haut niveau de construction de cette nouvelle couche d'Elasticsearch. Un agent définit l'objectif à atteindre, l'ensemble des outils disponibles pour l'exécution et les sources de données sur lesquelles il peut agir. Les agents ne se limitent pas aux interactions conversationnelles ; ils peuvent alimenter des flux de travail complets, l'automatisation des tâches ou des expériences face à l'utilisateur.</p><p>Lorsqu'une demande est adressée à un agent, elle suit un cycle structuré :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt774ffd7df65bd01d/6a17e15f25daabd5cc08a17f/627ad1744b629bbe27359325702f40d97e40d1f4-704x852.png" alt="" /><ol><li><p>Interpréter votre contribution et votre objectif</p></li><li><p>Sélectionner l'outil et les arguments adéquats pour l'exécution</p></li><li><p>Raisonner sur la réponse de l'outil</p></li><li><p>Décider si l'on renvoie un résultat ou si l'on poursuit les invocations d'outils.</p></li></ol><p>Elastic se charge de l'orchestration, du contexte et de l'exécution de ce cycle. Les développeurs se concentrent sur la définition de <em>ce que</em> l'agent doit faire : objectifs, outils et données, tandis que le système gère la <em>manière dont</em> le raisonnement et les flux de travail sont exécutés.</p><p><em>L'agent par défaut</em></p><p>Notre premier agent construit sur cette plateforme est un agent conversationnel natif dans Kibana, vous donnant la possibilité d'interagir immédiatement avec vos données. Il offre une expérience prête à l'emploi tout en restant totalement extensible et permet de commencer à interagir avec vos données immédiatement, sans configuration supplémentaire.</p><p>Vous pouvez interagir avec cette expérience directement dans Kibana par le biais d'une nouvelle expérience utilisateur de chat ou par le biais de l'API.</p><p>L'interrogation de l'agent par défaut via l'API ne nécessite qu'un seul appel :</p>POST kbn://api/agent_builder/converse
{
    "input": "what is our top portfolio account?"
}<p>Comme les conversations ont un état, vous pouvez continuer à interagir avec un agent à l'aide d'un numéro d'identification de la conversation ou récupérer l'historique complet de la conversation :</p>POST kbn://api/agent_builder/converse
{
    "input": "What about the second top?",
    "conversation_id": "ec757c6c-c3ed-4a83-8e2c-756238f008bb"
}

## get the full conversation
GET kbn://api/agent_builder/conversations/ec757c6c-c3ed-4a83-8e2c-756238f008bb<p><em>Agents des douanes</em></p><p>Les développeurs peuvent également créer leurs propres agents personnalisés grâce à des API simples. Les agents encapsulent les instructions, les outils et l'accès aux données, créant ainsi des moteurs de raisonnement sur mesure.</p><p>La création d'un agent personnalisé est aussi simple qu'un simple appel à l'API. L'exemple ci-dessous montre un exemple, le champ "configuration" contient tous les détails clés, tels que les instructions ou les outils disponibles :</p>POST kbn://api/agent_builder/agents
{
  "id": "custom_agent",
  "name": "My Custom Agent",
  "description": "Description of the custom agent",
  "configuration": {
      "instructions": "You are a log expert specialising in ...",
      "tools": 
...
   }
}<p>Une fois créé, l'agent peut être interrogé directement :</p>POST kbn://api/agent_builder/converse
{
    "input": "What news about DIA?",
    "agent_id": "custom_agent"
}<p>Cette approche transforme l'agent d'un système complexe à construire de toutes pièces en une unité simple et déclarative de logique d'entreprise, ce qui vous permet de mettre en place plus rapidement une automatisation intelligente.</p><p>Pour savoir comment créer un agent spécialisé à partir de zéro, consultez notre guide détaillé, étape par étape : <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">Votre premier agent Elastic : D'une simple requête à un chat alimenté par l'IA</a>.</p><h3>Outils</h3><p>Si les agents définissent <em>ce qu'il</em> faut accomplir, les outils définissent <em>comment.</em></p><p>Les outils exposent les capacités spécifiques du noyau Elastic pour que les agents puissent exécuter et récupérer des informations ou effectuer une action. Les outils peuvent inclure des fonctionnalités de base telles que l'obtention d'index ou de mappages, ou des fonctionnalités plus avancées telles que le langage naturel pour ES|QL.</p><p>Elasticsearch est livré avec un ensemble d'outils par défaut optimisés pour les besoins courants. Mais la véritable flexibilité réside dans la création de votre propre système. En définissant les outils, vous décidez exactement quelles requêtes, quels index et quels champs sont exposés à un agent avec ES|QL, ce qui vous permet de contrôler précisément la vitesse, la précision et la sécurité.</p><p>L'enregistrement d'un nouvel outil est aussi simple qu'un simple appel à l'API. Vous pouvez créer un outil qui exploite notre <a href="https://www.elastic.co/search-labs/blog/esql-timeline-of-improvements">ES|QL (Elasticsearch Query Language)</a> pour trouver des informations sur un actif financier spécifique :</p>POST kbn://api/agent_builder/tools
{
  "id": "news_on_asset",
  "type": "esql",
  "description": "Find news and reports about a particular asset where ...",
  "configuration": {
    "query": "FROM financial_news, financial_reports | where MATCH(company_symbol, ?symbol) OR MATCH(entities, ?symbol) | limit 5",
    "params": {
      "symbol": {
        "type": "keyword",
        "description": "The asset symbol"
      }
    }
  ...
  }
...
}<p>Une fois enregistré, vous pouvez attribuer le nouvel outil à vos agents personnalisés, en leur donnant un ensemble de capacités à raisonner et à invoquer chaque fois que cela est nécessaire.</p><p>Nous fournissons une plateforme pour créer des outils personnalisés pour vos besoins spécifiques, par exemple avec ES|QL qui transforme l'agent polyvalent en un expert spécifique à un domaine, fondé sur vos données uniques et votre domaine d'activité.</p><h3>Normes ouvertes et interopérabilité</h3><p>Les agents et outils Elasticsearch sont exposés via des API standard ouvertes, ce qui facilite leur intégration en tant que blocs fondamentaux dans l'écosystème plus large des cadres agentiques. Notre approche est simple : pas de boîte noire. Nous voulons que vous puissiez prendre la force principale d'Elastic en matière de recherche et l'associer à des capacités complémentaires et à d'autres systèmes agentiques.</p><p>Pour rendre cela possible, nous exposons nos capacités par le biais d'API, de protocoles émergents et de normes ouvertes.</p><p><em>Protocole de contexte de modèle (MCP)</em></p><p>Le <a href="https://www.elastic.co/search-labs/blog/model-context-protocol-elasticsearch">protocole MCP (Model Context Protocol)</a> est en passe de devenir la norme ouverte pour la connexion des outils entre les systèmes. En prenant en charge MCP, Elasticsearch peut connecter l'IA conversationnelle à vos bases de données, indices et API externes. Avec un serveur MCP distant intégré à la pile Elastic, tout client compatible MCP peut accéder aux outils d'Elastic et les utiliser comme éléments de construction dans vos flux de travail agentiques plus vastes.</p><p>Il ne s'agit pas d'une voie à sens unique. Vous pourrez également importer des outils à partir de serveurs MCP externes et les rendre disponibles dans Elasticsearch. Bientôt, les serveurs MCP seront probablement disponibles pour presque tout et seront bien plus complets que tout ce que nous pourrions créer nous-mêmes. Elastic fournit des fonctions de recherche et d'extraction à grande échelle, et vous pouvez les combiner avec des capacités spécialisées d'autres plateformes pour créer des agents efficaces.</p><p><em>Agent à agent (A2A)</em></p><p>Nous travaillons également sur la prise en charge des services d'agent à agent (A2A). Alors que le MCP concerne la connexion des outils, l'A2A concerne la connexion des agents. Avec un serveur A2A, les agents Elastic que vous créez pourront dialoguer directement avec des agents d'autres systèmes : partage de contexte, délégation de tâches et coordination de flux de travail.</p><p>Il s'agit d'une interopérabilité au niveau du raisonnement. Votre agent Elastic pourrait se charger de la recherche et de l'extraction, puis confier une tâche à un agent spécialisé dans l'assistance ou les technologies de l'information, et recevoir le résultat en retour de manière transparente. Il en résulte un écosystème d'agents coopérants, chacun faisant ce qu'il fait le mieux.</p><p>En fin de compte, l'adoption de MCP et d'A2A renforce notre engagement en faveur du rôle d'Elasticsearch en tant que citoyen de première classe, garantissant une intégration ouverte dans l'ensemble de l'écosystème agentique.</p><h3>Recherche et évaluation</h3><p>Au fur et à mesure que la recherche s'intègre aux agents, le défi d'une évaluation efficace devient crucial. Pour déployer en toute confiance des agents dans des environnements d'entreprise réels, vous devez avoir l'assurance qu'ils sont non seulement précis, mais aussi efficaces et fiables. Comment mesurer les performances, diagnostiquer une mauvaise réponse ou améliorer la situation de départ ? Tout commence par la visibilité.</p><p>C'est pourquoi nous avons conçu nos API pour la transparence dès le départ. Prenons l'exemple d'une simple interaction avec un agent :</p>POST kbn://api/agent_builder/converse
{
    "input": "what is our top portfolio account?"
}<p>La réponse comprend non seulement la réponse finale, mais aussi la trace complète de l'exécution, détaillant les outils sélectionnés par l'agent, les paramètres utilisés et les résultats de chaque étape.</p>{
  "conversation_id": "db5c0c8b-12bf-4928-a57e-d99129ad2fea",
  "steps": [
    {
      "type": "tool_call",
      "tool_call_id": "tooluse_Nfqr3mwtR92HTRIsTcGXZQ",
      "tool_id": ".index_explorer",
      "params": {
        "query": "indices containing portfolio data"
      },
      "results": [...]
    }
    // ... more steps ...
  ],
  "response": {
    "message": "Based on the information I've gathered...."
  }
}<p>Une traçabilité et une journalisation complètes sont essentielles pour une boucle d'amélioration continue, et bientôt, vous pourrez stocker et visualiser ces traces d'agents directement dans Elasticsearch. Mieux encore, ces traces sont construites sur le protocole OpenTelemetry, ce qui garantit qu'elles sont normalisées et portables pour l'intégration avec la plateforme d'observabilité de votre choix.</p><p>Ce niveau de détail est la base d'une véritable boucle d'amélioration continue. Il vous permet d'élaborer une suite complète de tests, de déboguer les échecs, d'identifier les modes de défaillance afin d'éviter les régressions et de capturer les modèles de réussite afin d'affiner les performances. En fin de compte, cette approche fondée sur les données est la clé de la transformation d'un prototype prometteur en un système d'IA fiable de qualité industrielle.</p><h3>Security</h3><p>Au fur et à mesure que les agents et les outils deviennent plus performants, la sécurité n'est plus facultative, elle est fondamentale. L'exposition des API, l'automatisation des tâches et des flux de travail exigent que les systèmes d'entreprise soient fiables. D'autant plus que les agents commencent à automatiser de plus en plus de flux de travail. Il est donc essentiel de pouvoir sécuriser ces flux et de s'assurer qu'ils répondent aux exigences de l'entreprise.</p><p>Les capacités ci-dessus héritent toutes des contrôles déjà disponibles dans Elastic aujourd'hui, y compris le <a href="https://www.elastic.co/search-labs/blog/rag-and-rbac-integration">contrôle d'accès basé sur les rôles (RBAC)</a> pour les appels d'API et la gestion des clés d'API. Nous étendons également les mêmes contrôles à de nouveaux protocoles tels que le MCP. Cela signifie la prise en charge de normes telles que OAuth, ainsi que la possibilité d'intégrer des mécanismes d'authentification personnalisés.</p><p>Notre objectif est de vous donner la flexibilité nécessaire pour expérimenter des agents et des outils, tout en maintenant le niveau de sécurité, de conformité et de gouvernance exigé par votre organisation.</p><h2>Ce qui vient ensuite</h2><p>Nous ne nous contentons pas d'ajouter des fonctionnalités, nous développons Elasticsearch pour l'ingénierie contextuelle agentique. Nous prévoyons de poursuivre notre développement sur la base de ces principes :</p><p>1. Engagement en faveur des normes Open Source &amp;</p><p>Notre engagement en faveur de l'open source et des normes ouvertes garantit que ces capacités restent interopérables avec les cadres agentiques externes. Vous serez toujours en mesure de connecter, d'étendre et de composer des agents à travers votre écosystème tout en gardant le contrôle de vos données et de vos flux de travail.</p><p>2. Valeur du contexte</p><p>Le contexte d'un agent d'intelligence artificielle est son plus grand atout. La gestion du contexte lorsque les agents effectuent des recherches et des opérations de flux de travail peut être une tâche difficile. Nous nous appuyons sur les points forts d'Elastic pour résoudre les problèmes d'ingénierie contextuelle, en veillant à ce que les informations les plus pertinentes soient toujours disponibles pour votre agent.</p><p>3. Focus sur les flux de données agentiques</p><p>À l'avenir, les agents constitueront une source de données de plus en plus importante, y compris les résultats des agents (documents générés, rapports, visualisations) et les traces d'exécution des agents (leur raisonnement, les appels d'outils, la mémoire/le contexte). Elastic est bien adapté au traitement de ce type de données, et nous travaillons sur la recherche concernant l'analyse, l'évaluation et l'amélioration automatisée de ces données.</p><p>4. Sécurité et sûreté dès la conception</p><p>Les agents d'intelligence artificielle posent de nouveaux défis en matière de sécurité et de sûreté. Elastic a toujours été un leader en matière de solutions sécurisées, et nous continuons à intégrer des garde-fous de niveau entreprise, des contrôles d'accès et les principes "zero-trust".</p><p>5. Intégré dans la plate-forme</p><p>Les capacités de création d'agents d'intelligence artificielle sont intégrées dans la plateforme Elasticsearch. Cela signifie que les capacités au niveau de la plateforme, telles que le traçage, l'évaluation, la visualisation et l'analyse, sont toutes applicables aux agents. Vous souhaitez développer des tableaux de bord basés sur les exécutions des agents - c'est intégré. Vous souhaitez évaluer les performances de l'agent d'IA à l'aide d'une analyse des sentiments - la plateforme le permet. Cela permet de construire un cycle de vie complet autour de vos expériences d'IA.</p><p>L'objectif d'Elastic est de vous donner les interfaces pour construire une IA conversationnelle et des flux de travail automatisés qui sont entièrement intégrés, extensibles et ancrés dans vos données. De plus amples détails techniques et des informations sur les progrès réalisés seront bientôt communiqués.</p><p>Agent Builder est disponible dès à présent en version privée. <a href="https://www.elastic.co/contact?pg=global&amp;plcmt=nav&amp;cta=205352">Connectez-vous avec nous</a> pour demander l'accès. Vous avez des questions ou des commentaires ? Connectez-vous avec notre communauté de développeurs dans notre <a href="https://elasticstack.slack.com/archives/C09GRHEQ4AG"><strong>espace de travail Slack</strong></a> ou sur notre <a href="https://discuss.elastic.co/c/search/84"><strong>forum de discussion.</strong></a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder</guid>
    <category><![CDATA[IA]]></category>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[À l'intérieur d'Elastic]]></category>
    <dc:creator><![CDATA[Anish Mathur,Dana Juratoni]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt16a3d8736bf086e0/6a17e1616864a45410b686c7/71876470119e02a45bcbfcbf27a3e110328bbd14-1020x654.png" length="0" type="image/png"/>
    <pubDate>Tue, 23 Sep 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[Connecter des agents à Elasticsearch avec Model Context Protocol]]></title>
    <description><![CDATA[Utilisons le serveur Model Context Protocol pour dialoguer avec vos données dans Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Et si l'interaction avec vos données était aussi facile que de discuter avec un collègue ? Imaginez que vous demandiez simplement : "Montrez-moi toutes les commandes de plus de 500 $ du mois dernier" ou "Quels sont les produits qui ont reçu le plus d'avis 5 étoiles ?" et que vous obteniez des réponses instantanées et précises, sans qu'aucune requête ne soit nécessaire.</p><p>Le protocole de contexte de modèle (MCP) rend cela possible. Il connecte de manière transparente l'IA conversationnelle avec vos bases de données et vos API externes, transformant les demandes complexes en conversations naturelles. Si les LLM modernes sont excellents pour comprendre le langage, leur véritable potentiel se révèle lorsqu'ils sont intégrés à des systèmes du monde réel. MCP comble le fossé qui les sépare, en rendant l'interaction des données plus intuitive et plus efficace.</p><p>Dans ce billet, nous allons explorer :</p><ul><li><p>Architecture MCP - Comment cela fonctionne-t-il sous le capot ?</p></li><li><p>Avantages d'un serveur MCP connecté à Elasticsearch</p></li><li><p>Construire un <a href="https://github.com/elastic/mcp-server-elasticsearch">serveur MCP alimenté par Elasticsearch</a></p></li></ul><p>Des moments passionnants nous attendent ! L'intégration de MCP avec votre pile Elastic transforme la façon dont vous interagissez avec l'information, rendant les requêtes complexes aussi intuitives qu'une conversation de tous les jours.</p><h2>Modèle Contexte Protocole</h2><p><a href="https://modelcontextprotocol.io/introduction">Model Context Protocol</a> (MCP), développé par Anthropic, est une norme ouverte qui connecte les modèles d'intelligence artificielle à des sources de données externes par le biais de canaux sécurisés et bidirectionnels. Il résout un problème majeur de l'IA : l'accès en temps réel à des systèmes externes tout en préservant le contexte de la conversation.</p><h3>Architecture MCP</h3><p>Modèle Contexte L'architecture du protocole se compose de deux éléments clés :</p><ul><li><p><strong>Clients MCP</strong> - Assistants IA et chatbots qui demandent des informations ou exécutent des tâches au nom des utilisateurs.</p></li><li><p><strong>Serveurs MCP</strong> - Référentiels de données, moteurs de recherche et API qui récupèrent les informations pertinentes ou effectuent les actions demandées (par exemple, appel d'API externes).</p></li></ul><p>Les serveurs MCP exposent quatre capacités principales aux clients :</p><ul><li><p><strong>Ressources</strong> - Données structurées, documents et contenu qui peuvent être récupérés et utilisés comme contexte pour les interactions LLM. Cela permet aux assistants d'IA d'accéder à des informations pertinentes à partir de bases de données, d'index de recherche ou d'autres sources.</p></li><li><p><strong>Outils</strong> - Fonctions exécutables qui permettent aux LLM d'interagir avec des systèmes externes, d'effectuer des calculs ou de prendre des mesures dans le monde réel. Ces outils étendent les capacités de l'IA au-delà de la génération de texte, en permettant aux assistants de déclencher des flux de travail, d'appeler des API ou de manipuler des données de manière dynamique.</p></li><li><p><strong>Invitations</strong> - Modèles d'invitations et flux de travail réutilisables pour normaliser et partager les interactions LLM communes.</p></li><li><p><strong>Échantillonnage</strong> - Demander des compléments LLM par l'intermédiaire du client pour permettre des comportements agentiques sophistiqués tout en maintenant la sécurité et la confidentialité.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfe82754551bb187a/6a17f7ec6864a43e71b6895d/bef5178133391e96e3d66ae634e41a85712a33a9-2345x1620.png" alt="Architecture du protocole de contexte de modèle (MCP)" /><h2>Serveur MCP + Elasticsearch</h2><p></p><p>Les systèmes traditionnels de récupération et de génération augmentée (RAG) récupèrent des documents sur la base des requêtes de l'utilisateur, mais le MCP va plus loin : il permet aux agents d'intelligence artificielle de construire et d'exécuter des tâches de manière dynamique et en temps réel. Cela permet aux utilisateurs de poser des questions en langage naturel, comme par exemple :</p><p></p><ul><li><p>"Affichez toutes les commandes de plus de 500 $ passées le mois dernier."</p></li><li><p>"Quels sont les produits qui ont reçu le plus d'avis 5 étoiles ?"</p></li></ul><p></p><p>Et obtenir des réponses instantanées et précises, sans avoir à rédiger la moindre requête.</p><p></p><p>MCP atteint cet objectif grâce à</p><ul><li><p>Sélection dynamique des outils - Les agents choisissent intelligemment les bons outils exposés via les serveurs MCP en fonction de l'intention de l'utilisateur. Les gestionnaires de programmes d'éducation et de formation tout au long de la vie "plus intelligents" sont généralement plus aptes à sélectionner les bons outils avec les arguments appropriés en fonction du contexte.</p></li><li><p>Communication bidirectionnelle - Les agents et les sources de données échangent des informations de manière fluide, en affinant les requêtes si nécessaire (par ex. d'abord le mappage de l'index de consultation, puis seulement la construction de la requête ES).</p></li><li><p>Orchestration multi-outils - Les flux de travail peuvent exploiter simultanément les outils de plusieurs serveurs MCP.</p></li><li><p>Contexte persistant - Les agents se souviennent des interactions précédentes, ce qui permet de maintenir une continuité entre les conversations.</p></li></ul><p>Un serveur MCP connecté à Elasticsearch débloque une puissante architecture de recherche en temps réel. Les agents d'intelligence artificielle peuvent explorer, interroger et analyser les données Elasticsearch à la demande. Vos données peuvent être recherchées par le biais d'une interface de chat simple.</p><p>Au-delà de la simple récupération de données, MCP permet d'agir. Il s'intègre à d'autres outils pour déclencher des flux de travail, automatiser des processus et alimenter des systèmes d'analyse. En séparant la recherche de l'exécution, MCP permet aux applications alimentées par l'IA de rester flexibles, à jour et intégrées de manière transparente dans les flux de travail des agents.</p><h2>Pratique : Serveur MCP pour dialoguer avec vos données Elasticsearch</h2><p>Pour interagir avec Elasticsearch via un serveur MCP, nous avons au moins besoin des fonctions suivantes :</p><ul><li><p>Récupérer les indices</p></li><li><p>Obtenir des correspondances</p></li><li><p>Effectuer des recherches à l'aide du DSL de requête d'Elasticsearch</p></li></ul><p>Notre serveur est écrit en TypeScript, et nous utiliserons le <a href="https://github.com/modelcontextprotocol/typescript-sdk">SDK TypeScript officiel</a> du MCP. Pour l'installation, nous recommandons d'installer l'application Claude Desktop (la version gratuite est suffisante) car elle comprend un client MCP intégré. Notre serveur MCP expose essentiellement le <a href="https://www.elastic.co/fr/guide/en/elasticsearch/client/javascript-api/current/index.html">client Elasticsearch JavaScript</a> officiel à travers les outils MCP.</p><p>Commençons par définir le client Elasticsearch et le serveur MCP :</p> const esClient = new Client({
    node: url,
    auth: {
      apiKey: apiKey,
    },
  });

  const server = new McpServer({
    name: "elasticsearch-mcp-server",
    version: "0.1.0",
  });<p>Nous utiliserons les outils de serveur MCP suivants qui peuvent interagir avec Elasticsearch :</p><ul><li><p><strong>Liste des index</strong> <a href="https://github.com/elastic/mcp-server-elasticsearch/blob/main/index.ts#L46">(list_indices</a>) : Cet outil récupère tous les index Elasticsearch disponibles, en fournissant des détails tels que le nom de l'index, l'état de santé et le nombre de documents.</p></li><li><p><strong>Obtenir des correspondances</strong> <a href="https://github.com/elastic/mcp-server-elasticsearch/blob/main/index.ts#L94">(get_mappings</a>) : Cet outil récupère les correspondances de champs pour un index Elasticsearch spécifié, aidant les utilisateurs à comprendre la structure et les types de données des documents stockés.</p></li><li><p><strong>Search</strong> <a href="https://github.com/elastic/mcp-server-elasticsearch/blob/main/index.ts#L147">(recherche</a>) : Cet outil exécute une recherche Elasticsearch à l'aide d'un DSL de requête fourni. Il active automatiquement les surlignages pour les champs de texte, ce qui facilite l'identification des résultats de recherche pertinents.</p></li></ul><p>L'implémentation complète du serveur MCP Elasticsearch est disponible dans le repo <a href="https://github.com/elastic/mcp-server-elasticsearch">elastic/mcp-server-elasticsearch</a>.</p><h4>Chat avec votre index</h4><p>Voyons comment configurer le serveur Elasticsearch MCP pour pouvoir poser des questions en langage naturel sur vos données, telles que "Trouver toutes les commandes de plus de 500 $ du mois dernier."</p><p><strong>Configurez votre application Claude Desktop</strong></p><ul><li><p>Ouvrir l'application Claude Desktop</p></li><li><p>Naviguer vers Settings &gt; Developer &gt; MCP Servers</p></li><li><p>Cliquez sur "Edit Config" et ajoutez cette configuration à votre <code>claude_desktop_config.json</code>:</p></li></ul>{
  "mcpServers": {
    "Elasticsearch MCP Server": {
      "command": "npx",
      "args": [
        "-y",
        "@elastic/mcp-server-elasticsearch"
      ],
      "env": {
        "ES_URL": "",
        "ES_API_KEY": ""
      }
    }
  }
}<p>Note : Cette configuration utilise le paquet <a href="https://www.npmjs.com/package/@elastic/mcp-server-elasticsearch">@elastic/mcp-server-elasticsearch</a> npm publié par Elastic. Si vous souhaitez développer localement, vous trouverez plus de détails sur l'installation du serveur Elasticsearch MCP <a href="https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md">ici.</a></p><p><strong>Remplir votre index Elasticseach</strong></p><ul><li><p>Vous pouvez utiliser nos <a href="https://gist.github.com/jedrazb/60e9400cbe40addfd9e4337749c28431">données d'exemple</a> pour remplir l'index "orders" pour cette démo.</p></li><li><p>Cela vous permettra d'essayer des requêtes telles que "Trouver toutes les commandes de plus de 500 $ du mois dernier."</p></li></ul><p><strong>Commencez à l'utiliser</strong></p><ul><li><p>Ouvrir une nouvelle conversation dans l'application Claude Desktop</p></li><li><p>Le serveur MCP se connecte automatiquement</p></li><li><p>Commencez à poser des questions sur vos données Elasticsearch !</p></li></ul><p>Regardez cette démo pour voir à quel point il est facile d'interroger vos données Elasticsearch en utilisant le langage naturel :</p><h4>Comment fonctionne-t-elle ?</h4><p>À la question "Trouver toutes les commandes de plus de 500 $ du mois dernier", le LLM reconnaît l'intention d'effectuer une recherche dans l'index Elasticsearch avec les contraintes spécifiées. Pour effectuer une recherche efficace, l'agent doit.. :</p><ul><li><p>Déterminez le nom de l'index : <code>orders</code></p></li><li><p>Comprendre les mappings de l'index <code>orders</code></p></li><li><p>Construire le DSL de requête compatible avec les mappages d'index et enfin exécuter la requête de recherche.</p></li></ul><p>Cette interaction peut être représentée comme suit :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt152f41bc8c3e9752/6a17f7ee6df73152df0a10cc/8875bc75745124be87deac0be666509446887de2-2345x1620.png" alt="Comment fonctionne le serveur MCP + Elasticsearch ?" /><h2>Conclusion</h2><p>Model Context Protocol améliore la façon dont vous interagissez avec les données Elasticsearch, en permettant des conversations en langage naturel au lieu de requêtes complexes. En associant les capacités de l'IA à vos données, MCP crée un flux de travail plus intuitif et plus efficace qui maintient le contexte tout au long de vos interactions.</p><p>Le serveur Elasticsearch MCP est disponible sous forme de paquetage npm public<a href="https://www.npmjs.com/package/@elastic/mcp-server-elasticsearch">(@elastic/mcp-server-elasticsearch</a>), ce qui facilite l'intégration pour les développeurs. Avec une configuration minimale, votre équipe peut commencer à explorer les données, à déclencher des flux de travail et à obtenir des informations par le biais de simples conversations.</p><p>Prêt à en faire l'expérience ? Essayez le <a href="https://github.com/elastic/mcp-server-elasticsearch">serveur Elasticsearch MCP</a> dès aujourd'hui et commencez à discuter avec vos données.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/model-context-protocol-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/model-context-protocol-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Jedr Blaszyk,Joe McElroy]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltce68a95c633809ae/6a17f7f0148009fa28b48915/65b378f644bd13e3edf2f108d48186f1889f546c-1200x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 28 Mar 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[L'agent IA pour gérer les projets Elasticsearch Serverless]]></title>
    <description><![CDATA[Un agent d'IA alimenté par le langage naturel qui gère sans effort les projets Elasticsearch Serverless, permettant la création, la suppression et la vérification de l'état des projets.]]></description>
    <content:encoded><![CDATA[<h2>Comment utiliser un agent d'IA pour gérer des projets Elasticsearch sans serveur ?</h2><ol><li><p><strong>Clonez le dépôt :</strong> Téléchargez le code de l'outil depuis GitHub en utilisant <code>git clone https://github.com/elastic/elasticsearch-labs/supporting-blog-content/serverless-ai-agent</code> <code>a</code>et naviguez dans le répertoire avec <code>cd serverless-ai-agent</code>.</p></li><li><p><strong>Configurer l'environnement : </strong>Créez un environnement virtuel (facultatif) avec <code>python -m venv venv</code> et activez-le (<code>source venv/bin/activate</code> ou <code>venv\Scripts\activate</code> sous Windows). Ensuite, installez les paquets Python nécessaires à l'aide de <code>pip install -r requirements.txt</code>.</p></li><li><p><strong>Configurer les informations d'identification : </strong>Créez un fichier <code>.env</code> à la racine du projet et remplissez-le avec l'URL de votre API Elasticsearch (<code>ES_URL</code>), la clé API (<code>API_KEY</code>), la région (<code>REGION</code>) et la clé API OpenAI (<code>OPENAI_API_KEY</code>).</p></li><li><p><strong>Exécutez l'outil : </strong>Exécutez l'outil en lançant <code>python main.py</code> dans votre terminal. Cela démarre l'agent d'intelligence artificielle et présente une invite pour vos commandes.</p></li><li><p><strong>Gérer les projets en langage naturel :</strong> Interagissez avec l'outil en utilisant des commandes en langage naturel comme "Créer un projet sans serveur nommé mon_projet", "Obtenir le statut du projet sans serveur nommé mon_projet", ou "Supprimer le projet sans serveur nommé mon_projet". L'IA interprétera vos commandes et exécutera les fonctions correspondantes.</p></li></ol><h2>Arrière-plan</h2><p>Ce petit outil en ligne de commande vous permet de gérer vos <a href="https://www.elastic.co/guide/en/serverless/current/intro.html">projets Serverless Elasticsearch</a> en anglais simple. Il s'adresse à une IA (dans ce cas, OpenAI) pour comprendre ce que vous voulez dire et appeler les bonnes fonctions à l'aide de LlamaIndex !</p><h3>Que peut faire l'agent Elasticsearch Serverless AI ?</h3><ul><li><p><strong>Créer un projet</strong>: Créez un nouveau projet Serverless Elasticsearch.</p></li><li><p><strong>Supprimer un projet</strong>: Supprimer un projet existant (oui, il nettoie après vous).</p></li><li><p><strong>Obtenir l'état d'avancement du projet</strong>: Vérifiez l'état d'avancement de votre projet.</p></li><li><p><strong>Obtenir les détails du projet</strong>: Obtenez tous les détails croustillants de votre projet.</p></li></ul><p>Consultez le code sur <a href="https://github.com/elastic/elasticsearch-labs/tree/a65f7bc1e4a041765d1c0a45ac44b9cd9fc1589f/supporting-blog-content/serverless-ai-agent">GitHub</a>.</p><h3>Fonctionnement de l'agent Elasticsearch Serverless AI</h3><p>Lorsque vous tapez quelque chose comme :</p><p><em>"Créer un projet sans serveur nommé mon_projet."</em></p><p>...voici ce qui se passe en coulisses :</p><ul><li><p><strong>Entrée de l'utilisateur &amp; contexte :</strong> Votre commande en langage naturel est envoyée à l'agent d'intelligence artificielle.</p></li><li><p><strong>Description des fonctions :</strong> L'agent IA connaît déjà quelques fonctions, telles que create_ess_project, delete_ess_project, get_ess_project_status et get_ess_project_details, parce que nous lui avons fourni des descriptions détaillées. Ces descriptions indiquent à l'IA le rôle de chaque fonction et les paramètres dont elle a besoin.</p></li><li><p><strong>Traitement par le LLM :</strong> Votre demande et les informations relatives à la fonction sont envoyées au LLM. Cela signifie que l'IA voit :</p><ul><li><p><strong>La requête de l'utilisateur</strong>: Votre instruction en langage clair.</p></li><li><p><strong>Fonctions disponibles &amp; descriptions</strong>: Détails sur les fonctions de chaque outil afin de pouvoir choisir le bon.</p></li><li><p><strong>Contexte/Info historique de la conversation</strong>: Comme il s'agit d'une conversation, il se souvient de ce qui a été dit auparavant.</p></li></ul></li><li><p><strong>Appel de fonction &amp; réponse :</strong> L'IA détermine quelle fonction appeler, transmet les bons paramètres (comme le nom de votre projet), puis la fonction est exécutée. La réponse vous est renvoyée dans un format convivial.</p></li></ul><p>En bref, nous envoyons à la fois votre requête en langage naturel et une liste de descriptions détaillées d'outils au mécanisme d'apprentissage tout au long de la vie afin qu'il puisse "comprendre" et choisir l'action appropriée à votre demande.</p><h3>Mise en place de l'agent d'intelligence artificielle</h3><h4>Prérequis :</h4><p>Avant d'exécuter l'agent AI, assurez-vous que les éléments suivants sont en place :</p><ol><li><p><strong>Python (v3.7 ou plus récent)</strong> installé.</p></li><li><p><strong>Compte Elasticsearch serverless</strong> configuré sur Elastic Cloud.</p></li><li><p><strong>Compte OpenAI</strong> pour interagir avec le modèle linguistique.</p></li></ol><h4>Les étapes :</h4><p><strong>1. Clonez le référentiel :</strong></p>git clone https://github.com/elastic/elasticsearch-labs/supporting-blog-content/serverless-ai-agent
cd serverless-ai-agent<p><strong>2. Créer un environnement virtuel (facultatif mais recommandé) :</strong> Si vous êtes confronté à des problèmes liés à l'environnement, vous pouvez créer un environnement virtuel pour l'isoler :</p>python -m venv venv
source venv/bin/activate  # On Windows, use venv\Scripts\activate<p><strong>3. Installez les dépendances :</strong> Assurez-vous que toutes les dépendances requises sont installées en exécutant le programme :</p>pip install -r requirements.txt<p><strong>4. Configurez votre environnement :</strong> Créez un fichier .env à la racine du projet avec les variables suivantes. Voici un exemple de fichier <code>.env.example</code> pour vous aider :</p>ES_URL=your_elasticsearch_api_url  # The base URL for your Elasticsearch service (e.g., https://your-cluster-id.es.region.aws.elastic-cloud.com)
API_KEY=your_elasticsearch_api_key  # Your API key for Elasticsearch
REGION=your_region  # Example: aws-eu-west-1
OPENAI_API_KEY=your_openai_api_key  # Your OpenAI API key<p>Assurez-vous que vous disposez des valeurs correctes pour <code>ES_URL</code>, <code>API_KEY</code>, et <code>OPENAI_API_KEY</code>. Vous trouverez vos clés API dans les tableaux de bord respectifs des services.</p><p><strong>5. Fichier de projets :</strong> l'outil utilise un fichier <code>projects.json</code> pour stocker vos correspondances de projets (noms de projets et détails). Ce fichier sera créé automatiquement s'il n'existe pas déjà.</p><h3>Exécution de l'agent d'intelligence artificielle</h3>python main.py<p>Vous verrez apparaître une invite comme celle-ci :</p>Welcome to the Serverless Project AI Agent Tool!
You can ask things like:
 - 'Create a serverless project named my_project'
 - 'Delete the serverless project named my_project'
 - 'Get the status of the serverless project named my_project'
 - 'Get the details of the serverless project named my_project'<p>Tapez votre commande et l'agent d'intelligence artificielle fera son travail ! Lorsque vous avez terminé, tapez <code>exit</code> ou <code>quit</code> pour partir.</p><h3>Quelques détails supplémentaires</h3><ul><li><p><strong>Intégration du LLM</strong>: Le LLM reçoit à la fois votre requête et des descriptions détaillées de chaque fonction disponible. Cela l'aide à comprendre le contexte et à décider, par exemple, s'il faut appeler <code>create_ess_project</code> ou <code>delete_ess_project</code>.</p></li><li><p><strong>Description des outils</strong>: Chaque outil de fonction (créé à l'aide de FunctionTool.from_defaults) a une description sympathique. Cette description est incluse dans l'invite envoyée au LLM afin qu'il "sache" quelles actions sont disponibles et ce que chaque action attend.</p></li><li><p><strong>Persistance</strong>: Vos projets et leurs détails sont enregistrés dans projects.json, afin de ne pas avoir à ressaisir les informations à chaque fois.</p></li><li><p><strong>Journalisation verbeuse</strong>: L'agent est configuré en mode verbeux, ce qui est idéal pour le débogage et pour voir comment vos instructions sont traduites en appels de fonction.</p></li></ul><h3>Exemple d'utilisation d'un agent IA Elasticsearch</h3>python main.py 

Welcome to the Serverless Project AI Agent Tool!

You can ask things like:
 - 'Create a serverless project named my_project'
 - 'Delete the serverless project named my_project'
 - 'Get the status of the serverless project named my_project'
 - 'Get the details of the serverless project named my_project'

User: Create a serverless project named my-february-test
Added user message to memory: Create a serverless project named my-february-test

=== Calling Function ===
Calling function: create_ess_project with args: {"project_name":"my-february-test"}
========================


Agent: The serverless Elasticsearch project named "my-february-test" has been created successfully. Here are the details:

- **Project ID:** &lt;&gt;&gt;
- **Elasticsearch Endpoint:** [https://my-february-test-ccc399.es.eu-west-1.aws.qa.elastic.cloud](https://my-february-test-ccc399.es.eu-west-1.aws.qa.elastic.cloud)
- **Kibana Endpoint:** [https://my-february-test-ccc399.kb.eu-west-1.aws.qa.elastic.cloud](https://my-february-test-ccc399.kb.eu-west-1.aws.qa.elastic.cloud)

User: get my-february-test status
Added user message to memory: get my-february-test status

=== Calling Function ===
Calling function: get_ess_project_status with args: {"project_name":"my-february-test"}
========================

Agent: The status of the "my-february-test" project is currently **initializing**.

User: get my-february-test info
Added user message to memory: get my-february-test info

=== Calling Function ===
Calling function: get_ess_project_details with args: {"project_name":"my-february-test"}
========================

Agent: Here are the details for the "my-february-test" project:

- **Project Name:** my-february-test
- **Alias:** my-february-test-ccc399
- **Cloud ID:** ""
- **Project ID:** ""
- **Region ID:** aws-eu-west-1
- **Created At:** 2025-02-12T15:42:00.530177619Z
- **Created By:** 571213384
- **Organization ID:** ""
- **Type:** Elasticsearch
- **Optimized For:** General Purpose
- **Search Lake:**
  - **Boost Window:** 7
  - **Search Power:** 100
- **Endpoints:**
  - **Elasticsearch:** https://my-february-test-ccc399.es.eu-west-1.aws.qa.elastic.cloud
  - **Kibana:** https://my-february-test-ccc399.kb.eu-west-1.aws.qa.elastic.cloud
- **Credentials:**
  - **Username:** ""
  - **Password:** ""

Please ensure to keep the credentials secure.

User: please delete the my-february-test project
Added user message to memory: please delete the my-february-test project

=== Calling Function ===
Calling function: delete_ess_project with args: {"project_name":"my-february-test"}
========================

Agent: The "my-february-test" project has been deleted successfully.<p></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/serverless-elasticsearch-ai-agent</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/serverless-elasticsearch-ai-agent</guid>
    <category><![CDATA[Elastic Cloud Serverless]]></category>
    <category><![CDATA[IA agentique]]></category>
    <dc:creator><![CDATA[Fram Souza]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt88526af16bafdb7c/6a17d7807f6f15825dc0998d/d11e1ba058784ec92b8953fb8db62e1bad21c210-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 04 Mar 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>