<?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[Intégrations - 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[Intégrations - 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/integrations</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/blog/category/integrations</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/category/integrations.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 16:08:20 GMT</lastBuildDate>
  <item>
    <title><![CDATA[API Kibana Dashboards : un contrat stable pour chaque type de panneau, testé par plus de 50 équipes avant DG]]></title>
    <description><![CDATA[Gérez les tableaux de bord Kibana sous forme de code : enregistrez-les dans Git, promouvez-les dans différents environnements et automatisez les déploiements avec l'API Kibana et Terraform.]]></description>
    <content:encoded><![CDATA[<p>Les<a href="https://dashboardsapispec.kibana.dev/dashboards#tag/Dashboards"> API Kibana Dashboards et de visualisation</a> sont prêtes pour la production dans Elastic 9.5 ; elles sont disponibles pour tous les niveaux d'abonnement et offrent une rétrocompatibilité totale. Définissez vos tableaux de bord au format JSON, validez-les dans Git, puis déployez-les dans différents environnements à l'aide de pipelines d'intégration et de déploiement continus (CI/CD), de <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_dashboard">Terraform</a> ou de tout autre outil que vous utilisez déjà. Plus de 50 équipes ont testé l'API lors de la <a href="https://www.elastic.co/search-labs/blog/kibana-dashboards-as-code-terraform-api">préversion technique 9.4</a>, certaines l'exploitant même déjà en production. La version 9.5 ajoute également de nouveaux points de terminaison (en préversion technique) pour le panneau <a href="https://dashboardsapispec.kibana.dev/tags.html">Tags</a>, avec des points de terminaison pour les panneaux <a href="https://dashboardsapispec.kibana.dev/markdowns.html"> Markdown</a> et<a href="https://dashboardsapispec.kibana.dev/links.html#tag/Links"> Links</a> disponibles dès maintenant dans Elastic Cloud Serverless et prochainement dans la version 9.6.</p><h2>Ce que la rétrocompatibilité implique pour l'API Kibana Dashboards</h2><p>Pendant la préversion technique, la forme de l'API pouvait changer d'une version à l'autre.[1] Ce n'est plus le cas. La disponibilité générale (DG) signifie :</p><ul><li><p><strong>Rétrocompatibilité totale.</strong> De nouveaux champs et types de panneaux seront ajoutés au fil du temps, mais les champs et comportements existants demeureront inchangés. Toute modification majeure susceptible de rompre la compatibilité sera examinée avec la plus grande attention et ne sera introduite que dans une nouvelle version majeure de la pile technologique.</p></li><li><p><strong>Prête pour la production avec compatibilité totale.</strong> L'API bénéficie des garanties de compatibilité complète d'Elastic. Vous pouvez l'utiliser en toute sécurité dans les environnements de production pour les déploiements automatisés, la promotion de l'environnement et la gestion programmatique des tableaux de bord.</p></li></ul><h2>Nouveaux points de terminaison de l'API Kibana pour les panneaux Tags, Markdown et Links</h2><p>Elastic 9.5 introduit également un nouveau point de terminaison autonome pour le panneau <a href="https://dashboardsapispec.kibana.dev/tags.html"><strong>Tags</strong></a>, qui vous permet de catégoriser et filtrer les tableaux de bord. Vous pouvez désormais les gérer par programmation via des points de terminaison CRUD dédiés, ce qui facilite leur organisation à grande échelle dans différents environnements.	</p><p>De nouveaux points de terminaison pour les panneaux <a href="https://dashboardsapispec.kibana.dev/markdowns.html"><strong>Markdown</strong></a> et <a href="https://dashboardsapispec.kibana.dev/links.html#tag/Links"><strong>Liens</strong></a> sont désormais disponibles dans Serverless et seront intégrés dans la prochaine version de la pile (9.6).</p><h2>Quels types de panneaux l'API Kibana Dashboards prend-elle en charge ?</h2><p>L'API Dashboards prend en charge tous les panneaux <em>par valeur</em> de la version 9.5 (ceux définis directement dans un tableau de bord, par opposition aux panneaux de bibliothèque enregistrés pour être réutilisés). Chaque type de panneau pris en charge dispose d'un schéma typé et validé.</p><p><strong>Type de panneau</strong></p><p><strong>État</strong></p><p>Graphiques XY</p><p>Compatibles</p><p>Métriques</p><p>Compatibles</p><p>Circulaires</p><p>Compatibles</p><p>Jauge</p><p>Compatibles</p><p>Carte thermique</p><p>Compatibles</p><p>Tables de données</p><p>Compatibles</p><p>Arborescence</p><p>Compatibles</p><p>Sessions Discover</p><p>Compatibles</p><p>Contrôles</p><p>Compatibles</p><p>Markdown</p><p>Compatibles</p><p>Liens</p><p>Compatibles</p><p>Panneaux ML</p><p>Compatibles</p><p>Panneaux Observability</p><p>Compatibles</p><p>Maps</p><p>Bientôt disponible</p><p>Vega</p><p>Bientôt disponible</p><h2>Comment gérer les tableaux de bord Kibana sous forme de code</h2><p>L'API Dashboards permet un workflow complet de tableaux de bord sous forme de code : exportez un tableau de bord au format JSON propre et facilement comparable, validez-le dans Git comme source de référence, examinez les modifications via des requêtes pull et déployez la même définition dans les environnements de développement, de préproduction et de production. Une fois qu'un tableau de bord est géré sous forme de code, considérez Git comme source de référence unique : les modifications effectuées directement dans l'interface utilisateur seront écrasées lors du prochain déploiement.</p><p>La principale difficulté lors du transfert d'un tableau de bord entre des espaces, des clusters ou des environnements est que les tableaux de bord font référence à des objets (data views ou visualisations de bibliothèques, par exemple) au moyen d'identifiants. Comme ces identifiants sont générés automatiquement et varient d'un environnement à l'autre, un tableau de bord exporté depuis un environnement peut pointer vers des objets inexistants dans un autre. Il existe trois méthodes pour gérer cette situation, présentées ici de la plus automatisée à la moins automatisée :</p><ul><li><p><strong>Utilisez Terraform.</strong> Le <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_dashboard">fournisseur Elastic Stack Terraform</a> suit chaque ressource et associe automatiquement les identifiants par environnement, afin que les références restent cohérentes lorsque vous faites passer un tableau de bord de l'environnement de développement à l'environnement de production.</p></li><li><p><strong>Définissez par valeur les </strong><a href="https://www.elastic.co/docs/explore-analyze/visualize/esorql"><strong>panneaux Elasticsearch Query Language (ES|QL)</strong></a><strong>.</strong> La méthode la plus portable pour créer un panneau consiste à définir sa visualisation à l'aide d'ES|QL directement dans le tableau de bord. Une requête <a href="https://www.elastic.co/docs/explore-analyze/query-filter/languages/esql-kibana">ES|QL</a> lit les données à partir des index qui y sont spécifiés ; le panneau ne contient donc aucune référence externe à des data views ou à des objets de bibliothèque. On obtient ainsi un tableau de bord entièrement autonome et portable.</p></li><li><p><strong>Attribuer les identifiants correspondants.</strong> Si vous référencez des objets enregistrés, tels que des data views ou des visualisations de bibliothèque, créez-les avec un identifiant spécifique en utilisant la méthode PUT (upsert) plutôt que POST (qui génère automatiquement un identifiant). Utilisez des identifiants explicites et lisibles, comme logs-prod, afin qu'ils soient faciles à reconnaître et à réutiliser d'un environnement à l'autre.</p></li></ul><p>Pour une présentation détaillée de ces modèles de portabilité et du workflow complet des tableaux de bord sous forme de code, consultez la documentation <a href="https://www.elastic.co/docs/explore-analyze/dashboards/manage-dashboards-as-code#dashboards-as-code-portability">Gérer les tableaux de bord sous forme de code</a>.</p><h3>Création d'un tableau de bord Kibana avec l'API Dashboards en utilisant PUT</h3><p>Voici un exemple rapide de création d'un tableau de bord avec un panneau de métriques, utilisant la méthode PUT au lieu de POST pour attribuer un identifiant personnalisé basé sur le nom du tableau de bord (service-health-overview). La même logique s'applique à la création de visualisations autonomes enregistrées dans la bibliothèque.</p>PUT kbn:/api/dashboards/service-health-overview
{
  "title": "Service health overview",
  "description": "Key service metrics — managed via API",
  "tags": [
    "production",
    "sre-team"
  ],
  "panels": [
    {
      "type": "vis",
      "grid": {
        "x": 0,
        "y": 0,
        "w": 12,
        "h": 8
      },
      "config": {
        "title": "Error rate (5xx)",
        "type": "metric",
        "data_source": {
          "type": "esql",
          "query": "FROM logs-* | WHERE http.response.status_code &gt;= 500 | STATS error_rate=count(*) BY host.name"
        },
        "metrics": [
          {
            "type": "primary",
            "column": "count"
          }
        ]
      }
    }
  ]
}<h2>Roadmap de l'API Kibana Dashboards : Maps, Vega et points de terminaison autonomes</h2><p>Nous travaillons activement à étendre la surface de l'API. La prise en charge des panneaux Maps et Vega est la prochaine étape, avec ajout de schémas typés. Nous développons également des points de terminaison CRUD autonomes pour les sessions Discover (au-delà de leur prise en charge actuelle en tant que panneaux de tableau de bord), les panneaux Vega, Maps et les Annotations, le tout dissocié du cycle de vie des tableaux de bord.</p><p>Pour les définitions complètes des schémas, consultez la <a href="https://dashboardsapispec.kibana.dev/dashboards#tag/Dashboards">documentation de l'API Dashboards</a>. Pour les utilisateurs de Terraform, le <a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_dashboard">fournisseur Elastic Stack Terraform</a> prend en charge l'API Dashboards en DG.</p><h2>Remarque</h2><ol><li><p>Les points de terminaison principaux restent inchangés par rapport à la préversion technique. Si vous avez développé des intégrations pour la version 9.4, elles fonctionneront avec la version 9.5. Les seuls changements entraînant une rupture de compatibilité sont deux modifications mineures concernant la liste des tableaux de bord et les formats d'unité de durée ; elles sont documentées <a href="https://www.elastic.co/docs/release-notes/kibana/breaking-changes">ici</a>.</p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/dashboards-as-code-kibana-api</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/dashboards-as-code-kibana-api</guid>
    <category><![CDATA[Kibana]]></category>
    <category><![CDATA[Expérience développeur]]></category>
    <category><![CDATA[Intégrations]]></category>
    <dc:creator><![CDATA[Teresa Alvarez Soler]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ed7e33de291f255/6a730619c8b7ac02b251f9d3/image1.png" length="0" type="image/png"/>
    <pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[On-prem en moins de 5 minutes : modèles d'embedding Jina maintenant disponibles pour un déploiement sur site]]></title>
    <description><![CDATA[Les 28 modèles de Jina AI, y compris les modèles de reclassement, sont disponibles sous forme de conteneurs Docker prêts à être déployés, sans télémétrie ni serveur de licence. Ils sont directement compatibles avec les API d'OpenAI, de Cohere, de Voyage AI et d'Elastic Inference Service.]]></description>
    <content:encoded><![CDATA[<p>Les 28 modèles d'embedding et de reclassement Jina AI sont désormais proposés sous forme de conteneurs Docker entièrement hors ligne pour un déploiement sur site, y compris <a href="https://www.elastic.co/fr/search-labs/blog/jina-embeddings-v5-omni-all-media-one-index">jina-embeddings-v5-omni</a><a href="https://www.elastic.co/fr/search-labs/blog/jina-embeddings-v5-omni-all-media-one-index"> </a>et <a href="https://www.elastic.co/fr/search-labs/tutorials/jina-tutorial/jina-reranker-v3">jina-reranker-v3</a>. Il suffit d'en télécharger un et de le transférer vers un système sur site air gap ou protégé par un pare-feu pour que l'inférence locale soit opérationnelle en moins de cinq minutes. Ces conteneurs sont totalement autonomes et n'établissent aucune connexion externe ; ils ne font appel ni à Hugging Face ni à un quelconque registre de modèles, et ne nécessitent ni serveur de licence, ni télémétrie, ni points de terminaison de logging. Pour les secteurs réglementés, les environnements soumis à des exigences de souveraineté des données ou les situations où l'accès à Internet est instable voire inexistant, cette solution élimine la dépendance vis-à-vis de services d'IA tiers. Jina On-Prem prend en charge les schémas d'Elastic Inference Service (EIS), d'OpenAI, de Cohere, de Voyage AI et de l'API Gemini ; les applications existantes fonctionnent donc sans modification du code.</p><p>Les modèles d'IA les plus puissants fonctionnent sur des infrastructures cloud distantes accessibles via une API web ; vous devez donc faire confiance à votre fournisseur de services d'IA pour garantir la sécurité, la disponibilité du service et la stabilité des tarifs. Il est difficile de concilier des exigences légitimes en matière de fiabilité, de confidentialité, de maîtrise des coûts et de bonne gouvernance des données avec une utilisation de l'IA toujours plus puissante, sophistiquée et gourmande en ressources.</p><p>Les réglementations gouvernementales, les décisions de justice et les décisions commerciales prises dans l'intérêt de tiers ont récemment conduit à restreindre l'accès à certains services. Or, même s'il est possible de se tourner vers d'autres solutions, les modèles d'IA ne sont pas des composants que l'on peut remplacer au gré de ses envies. Les applications qui exploitent les embeddings sémantiques nécessitent l'accès aux mêmes modèles lors de l'interrogation que lors de l'ingestion des données ; perdre l'accès à votre modèle d'embedding revient donc à paralyser votre système de recherche.</p><p>Les modèles de tarification de l'IA accentuent ce risque. Les récentes informations financières communiquées par les principaux fournisseurs d'IA donnent aux clients de bonnes raisons de s'inquiéter d'éventuelles hausses de prix. Le recours à des produits aux coûts imprévisibles accroît encore les risques associés à des investissements massifs dans l'IA, dont le retour sur investissement peut s'avérer aléatoire.</p><p>Jina On-Prem est la réponse d'Elastic à ces défis.</p><h2>Qui a besoin d'une IA sur site ?</h2><p>L'hébergement local et le contrôle direct de vos modèles d'IA répondent à diverses contraintes techniques, exigences sectorielles et impératifs commerciaux.</p><p>Une installation locale réduit les frais payés à vos fournisseurs de services d'IA, mais elle fait peser sur votre organisation les coûts liés au matériel et à la fiabilité de l'accès. Selon votre volume d'utilisation, cette option peut s'avérer plus économique. Toutefois, d'autres contraintes justifient d'envisager l'exploitation de votre propre système d'IA. Si l'un des problèmes décrits ci-dessous concerne votre entreprise, envisagez une solution d'IA locale telle que Jina On-Prem. Cette liste n'est pas exhaustive.</p><p>Cas d'utilisation</p><p>Pourquoi sur site</p><p>Exemple</p><p>Air gap/haute sécurité</p><p>Aucune transmission de données sortante ; isolation complète du réseau</p><p>Défense, renseignement, recherche classifiée</p><p>Conformité réglementaire</p><p>Souveraineté des données ; aucune transmission transfrontalière ni exposition à des tiers</p><p>Santé (Health Insurance Portability and Accountability Act [HIPAA]), finance, entreprises de l'UE (Règlement général sur la protection des données [RGPD])</p><p>Sensible à la latence</p><p>Dépendance réseau nulle ; aucune tolérance aux échecs de connexion</p><p>Robotique, edge computing, véhicules, navires</p><p>Prévisibilité des coûts</p><p>Coût d'infrastructure fixe vs tarification au jeton avec des tarifs futurs incertains</p><p>Charges de travail d'inférence continue à fort volume</p><p>Réduction de la responsabilité</p><p>Aucune exposition de données de tiers ; préservation de la confidentialité des communications et du devoir de diligence</p><p>Cabinets d'avocats, organismes publics</p><h3>Pourquoi les systèmes air gap et protégés par pare-feu ont besoin d'une IA sur site</h3><p>Les systèmes air gap et protégés par un pare-feu ne peuvent pas utiliser d'API d'IA externes. Jina On-Prem s'exécute entièrement au sein de votre infrastructure, sans aucune connexion sortante.</p><p>Pour les organisations qui gèrent des données particulièrement sensibles, les questions de sécurité et de confidentialité sont primordiales. Il est peu utile d'investir dans la protection de vos données sensibles si vous les confiez aussitôt à un tiers distant dont les mesures de sécurité pourraient être insuffisantes ou qui pourrait être soumis aux exigences d'un gouvernement étranger.</p><p>Les employés des organisations qui manipulent des données sensibles reçoivent souvent une formation sur la gestion sécurisée de ces données. Toutefois, cette mesure perd de son efficacité dès lors qu'ils disposent de navigateurs web susceptibles d'accéder à n'importe quelle page d'Internet pendant qu'ils traitent ces informations. L'isolation constitue la mesure de sécurité la plus efficace, qu'elle soit assurée par une séparation physique totale ou par des pare-feux très restrictifs, mais elle entrave considérablement l'utilisation de services externes, quels qu'ils soient.</p><h3>IA sur site pour les systèmes sensibles à la latence et à haute disponibilité</h3><p>Le logiciel en tant que service (SaaS) et le cloud computing constituent un compromis entre le coût lié à l'hébergement de services hautement accessibles et fiables sur vos propres infrastructures et le choix de confier cette tâche à un tiers. Toutefois, ces solutions s'accompagnent d'une latence variable, d'interruptions de service et d'une perte totale de contrôle en cas de dysfonctionnement. Les services d'IA ne font pas exception à la règle : si votre système de recherche devient indisponible parce que vous ne pouvez plus accéder à votre modèle d'embedding, ce compromis pourrait apparaître bien moins avantageux.</p><p>Par ailleurs, le recours à une IA externe comporte toujours des risques difficiles à anticiper ou à gérer. L'accès à Internet et la latence du réseau peuvent se dégrader sans préavis, sous l'effet d'événements politiques, d'intempéries ou du passage d'ancres de navires sur des câbles sous-marins à fibre optique. Les gouvernements peuvent, et l'ont fait récemment, recourir à des interdictions d'exportation pour bloquer soudainement l'accès à des modèles d'IA. Les fournisseurs de services d'IA retirent parfois certains modèles pour inciter les utilisateurs à adopter des versions plus récentes. Il convient donc de mettre en balance la flexibilité et la maîtrise des coûts qu'offrent les services externes avec les risques de dépendance qu'ils engendrent.</p><h3>IA sur site pour le respect des exigences du RGPD, de la loi HIPAA et de souveraineté des données</h3><p>Les organisations qui collectent des données personnelles sont soumises à des réglementations de plus en plus strictes qui diffèrent souvent d'une juridiction à l'autre et peuvent imposer des exigences contradictoires. Ainsi, les <a href="https://www.hhs.gov/hipaa/for-professionals/privacy/laws-regulations/index.html">règles HIPAA</a> imposent des protections des données très strictes aux prestataires de santé américains, et des législations strictes sur la protection générale des données au <a href="https://laws-lois.justice.gc.ca/eng/acts/p-8.6/">Canada</a>, dans l'<a href="https://gdpr-info.eu/">Union européenne</a> et dans de <a href="https://www.japaneselawtranslation.go.jp/en/laws/view/4241">nombreuses juridictions asiatiques</a> exigent que toutes les entreprises qui traitent des informations personnelles le fassent de manière sécurisée et limitent la transmission de ces données à des tiers ou à d'autres juridictions. Ces règles peuvent même imposer des obligations à des entités étrangères si elles comptent des clients dans ces juridictions. Les institutions financières sont souvent soumises à des règles encore plus strictes et assument, en matière de sécurité de l'information, la même responsabilité directe que celle qui leur incombe pour se prémunir contre d'autres formes d'activités criminelles.</p><p>La conformité réglementaire peut être incompatible avec les services d'IA tiers, en particulier si leur utilisation implique un transfert de données transfrontalier.</p><p>En outre, des événements récents montrent que les règles restreignant la localisation physique des espaces de stockage de données ne constituent pas nécessairement une garantie de protection fiable lorsque les fournisseurs internationaux de services cloud sont soumis à des pressions de la part de gouvernements étrangers. Les législations locales peuvent présenter des divergences d'une juridiction à l'autre, ce qui impose le stockage et le traitement des données au niveau local et rend impossible le recours à des services tiers. Dans certains cas, la seule solution consiste à internaliser l'ensemble de vos processus, y compris vos systèmes d'IA.</p><h3>Risques de responsabilité liés à la transmission de données à des tiers dans le cadre de l'IA</h3><p>Les lois sur la protection des données et les obligations de vigilance reconnues concernant les données sensibles entraînent régulièrement des conséquences en matière de responsabilité, parfois très lourdes. Vous pouvez être tenu pour responsable de la manière dont des prestataires de services tiers traitent vos données. Si les tribunaux et les procédures judiciaires peuvent offrir certaines protections a posteriori face à des prestataires peu fiables, ces recours ne sont ni disponibles ni généralement efficaces contre les acteurs de la sécurité nationale, les forces de l'ordre ou les cybercriminels.</p><p>Pour les gouvernements, des cas ont déjà été signalés où des fournisseurs de services cloud transfrontaliers ont divulgué des informations sensibles de l'État à des acteurs étrangers.</p><p>Toutefois, même si vous ne craignez ni les gouvernements étrangers ni les pirates informatiques, et que vos prestataires externes de services d'IA sont eux-mêmes sécurisés, le simple fait qu'ils soient externes peut engendrer des risques de responsabilité.</p><p>Par exemple, dans la plupart des juridictions, les communications entre avocats et clients bénéficient de protections juridiques spécifiques, et les cabinets d'avocats sont soumis à des obligations strictes concernant l'enregistrement ou le stockage de ces informations. Aux États-Unis, cette confidentialité des communications est si célèbre qu'il constitue un élément central de nombreux scénarios de films et de séries télévisées. Or, ce privilège peut être perdu si des informations sont communiquées à une personne n'étant pas couverte par ce secret ; des évolutions récentes suggèrent que les prestataires externes de services d'IA pourraient entrer dans cette catégorie.</p><p>Il est possible, du moins aux États-Unis, que le simple recours à des services d'IA tiers via une API Internet, comme l'intégration de modèles assurant des services d'indexation, enfreigne des règles de confidentialité essentielles. Un cabinet d'avocats pourrait faire l'objet de poursuites, de sanctions disciplinaires ou d'une radiation du barreau pour la simple utilisation d'un logiciel hébergé en externe, même en l'absence de toute faille de sécurité.</p><h3>IA sur site pour les systèmes hors ligne, en périphérie et physiquement isolés</h3><p>Les systèmes informatiques ne sont pas isolés uniquement pour des raisons de sécurité. Par exemple, les véhicules en déplacement ne peuvent pas dépendre d'un accès à Internet pour assurer des fonctions essentielles. Les navires et les aéronefs sont dotés de systèmes informatiques embarqués très complets qui doivent fonctionner sans connexion Internet et ne peuvent donc pas recourir à des services d'IA externes. Les plateformes offshore, les installations isolées en pleine nature, ainsi que les services informatiques situés dans l'Arctique, l'Antarctique ou sur de petites îles dépourvues de liaisons physiques adéquates avec les réseaux mondiaux, sont autant d'exemples d'installations qui tirent parti de l'hébergement local de tous les services dont elles ont besoin. À mesure que l'IA prend de l'importance dans l'informatique d'entreprise, il devient crucial de prendre en compte ces contraintes.</p><p>Les applications émergentes de l'IA aux systèmes physiques (robotique et autres cas d'utilisation confinés à un espace donné ou axés sur le monde extérieur, tels que les systèmes de gestion logistique ou même les caisses de supermarché) peuvent être connectées à l'Internet mondial, mais elles ne tolèrent ni les interruptions de connexion ni les pics de latence. Si leur fonctionnement repose sur un système d'IA, celui-ci doit être aussi local et fiable que possible.</p><h2>Qui n'a pas besoin d'une IA sur site ?</h2><p>Les services logiciels à distance et l'IA externalisée présentent des avantages. L'exécution de modèles d'IA peut nécessiter des processeurs coûteux et énergivores, dont la durée de vie est notoirement courte. L'accès à du matériel de haute qualité est particulièrement difficile à l'heure actuelle en raison de facteurs liés au marché et de chocs économiques externes. Dans ce contexte, il peut être judicieux de payer au jeton consommé pour utiliser une API externe, plutôt que de supporter les lourds investissements initiaux qu'implique une IA locale.</p><p>Les API externes constituent la solution la plus pertinente pour les utilisateurs occasionnels. Si vous exploitez des modèles d'IA principalement pour le traitement de données par lots à des fins d'analyse plutôt que pour faire fonctionner un système de recherche devant rester disponible en permanence, il est peu judicieux d'investir dans du matériel coûteux et des installations locales.</p><p>De plus, lorsque vos processus de traitement de données reposent déjà sur le cloud (comme c'est le cas, par exemple, d'un site e-commerce hébergé dans le cloud pour des raisons de fiabilité et d'accessibilité), le recours à des services d'IA intégrés à cette même infrastructure peut s'avérer plus rentable que de déployer votre propre modèle d'IA sous licence. Dans la mesure où vous dépendez déjà de votre fournisseur de services cloud, dépendre également de ses services d'IA n'ajoute pas de risque significatif.</p><p>Si votre cas d'utilisation correspond à cette description, les modèles Jina AI sont disponibles sur <a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/eis">EIS</a>, <a href="https://aws.amazon.com/marketplace/seller-profile?id=seller-stch2ludm6vgy">AWS Marketplace</a> et <a href="https://console.cloud.google.com/marketplace/browse?q=jina">Google Cloud Platform</a> spécifiquement pour répondre à vos besoins.</p><p>Le tableau ci-dessous résume les facteurs clés. Votre réponse dépend de vos données, de votre infrastructure et de votre modèle d'utilisation.</p><p>Facteur</p><p>Sur site privilégié</p><p>API Cloud privilégiée</p><p>Modèle d'utilisation</p><p>Inférence continue ou à volume élevé</p><p>Traitement intermittent ou par lots</p><p>Sensibilité des données</p><p>Réglementées, souveraines ou classifiées</p><p>Aucune restriction transfrontalière ou liée à des tiers</p><p>Environnement réseau</p><p>Air gap, protégé par un pare-feu ou peu fiable</p><p>Internet stable et permanent</p><p>Infrastructure existante</p><p>Disposer de matériel GPU ou pouvoir s'en procurer</p><p>Déjà hébergé dans le cloud avec une IA en colocation</p><p>Modèle de coût</p><p>Matériel fixe + licence ; prévisible à grande échelle</p><p>Au jeton ; plus faible au départ, variable à long terme</p><p>Tolérance à la latence</p><p>Aucune (robotique, périphérie, temps réel)</p><p>La variabilité du réseau est acceptable</p><p>Responsabilité opérationnelle</p><p>Votre équipe gère le matériel et la disponibilité</p><p>Le fournisseur gère le matériel et les mises à jour ; vous gérez l'intégration</p><p>Vous devez évaluer les coûts et les avantages au regard de votre situation et de vos cas d'utilisation spécifiques, en tenant compte des points soulevés dans la section précédente qui vous concernent. Cette analyse coûts-avantages évoluera sans aucun doute avec le temps. Il est impossible de prédire l'avenir du secteur de l'IA ou l'évolution des prix du matériel, même à court terme.</p><h2>Présentation de Jina On-Prem</h2><p>Pour les utilisateurs pouvant tirer parti de services d'IA locaux, nous lançons <a href="https://github.com/jina-ai/jina-on-prem/wiki/">Jina On-Prem</a>, une suite d'installation entièrement autonome pour les modèles haute performance de Jina AI.</p><p>Les modèles de Jina AI égalent la précision de modèles d'embedding <a href="https://mteb-leaderboard.hf.space/benchmark/MTEB(Multilingual%2C%20v2)">bien plus volumineux</a>, tout en réduisant les coûts de calcul, l'empreinte mémoire et les besoins matériels. Ils sont ainsi le choix idéal pour les utilisateurs qui souhaitent ou doivent héberger leur IA sur site. Des licences commerciales sont disponibles avec des solutions scalables dont le tarif est proportionnel à l'utilisation afin de répondre aux cas d'utilisation de toute envergure.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt190865fb3ebde472/6a6a33d0065b162508701ff9/02559ceca556a26c53eb703ae87d421452b27251-1374x1400.png" alt="MMTEB Multilingual v2 leaderboard showing Jina AI embedding model rankings: jina-embeddings-v5-omni-small and jina-embeddings-v5-text-small ranked 13th, jina-embeddings-v5-omni-nano and jina-embeddings-v5-text-nano ranked 19th, competing against models from Microsoft, Google, Tencent, NVIDIA and Qwen" /><h3>Quels schémas d'API Jina On-Prem prend-il en charge ?</h3><ul><li><p>Disponibles sous la forme d'une collection complète de dépendances pour une installation locale ou d'un <a href="https://www.docker.com/">conteneur Docker</a> que vous pouvez installer et exécuter en quelques minutes.</p></li><li><p>Les installations Jina On-Prem <em>ne font pas</em> appel à des systèmes externes.</p><ul><li><p>Aucun appel au hub Hugging Face ni à aucun registre de modèles (HF_HUB_OFFLINE=1 et TRANSFORMERS_OFFLINE=1 sont intégrés).</p></li><li><p>Pas de serveur de licence.</p></li><li><p>Pas de points de terminaison de télémétrie ou de logging.</p></li></ul></li><li><p>Compatibles avec le matériel basé sur processeur et sur GPU, avec détection automatique du GPU.</p></li><li><p>Les 28 modèles Jina AI sont tous disponibles, y compris les derniers modèles d'embeddings multimodaux <a href="https://www.elastic.co/fr/search-labs/blog/jina-embeddings-v5-omni-all-media-one-index">jina-embeddings-v5-omni</a> et <a href="https://www.elastic.co/fr/search-labs/tutorials/jina-tutorial/jina-reranker-v3">jina-reranker-v3</a>.</p></li><li><p>Accès via des schémas API d'IA standards : <a href="https://jina.ai/api-dashboard">API Jina</a>, OpenAI, Cohere, Voyage AI et Gemini. Jina On-Prem est une solution clé en main pour les applications conçues sur ces schémas.</p></li><li><p>Remplacement direct pour les modèles servis par <a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/eis">EIS</a>. Jina On-Prem s'intègre directement aux <a href="https://www.elastic.co/fr/blog/deploy-elastic-air-gapped-disconnected-environments">déploiements Elastic air gap</a>.</p></li></ul><h2>Configuration matérielle requise pour les modèles sur site Jina AI</h2><p>Les exigences matérielles varient selon les modèles Jina. Le tableau ci-dessous présente les recommandations pour les modèles les plus récents utilisant des GPU. Il n'est pas nécessaire de disposer d'une puissance supérieure à celle d'un GPU NVIDIA L4, bien qu'un modèle A100 soit recommandé pour les modèles d'embedding v5. Notre modèle d'embedding le plus récent nécessite actuellement un minimum de 8 Go de VRAM.</p><p>Modèle</p><p>VRAM minimum</p><p>GPU recommandé</p><p>jina-embeddings-v5-text-nano</p><p>2 Go</p><p>T4/L4</p><p>jina-embeddings-v5-text-small</p><p>3 Go</p><p>L4/A10G</p><p>jina-embeddings-v5-omni-small</p><p>8 Go</p><p>L4/A10G/A100</p><p>jina-reranker-v3</p><p>3 Go</p><p>L4</p><p>jina-clip-v2</p><p>4 Go</p><p>L4</p><p>jina-code-embeddings-1.5b</p><p>4 Go</p><p>L4</p><p>ReaderLM-v2</p><p>4 Go</p><p>L4</p><p>Si vous utilisez plus d'un modèle à la fois, les besoins en VRAM augmenteront. Pour plus d'informations, veuillez consulter la page <a href="https://github.com/jina-ai/jina-on-prem/wiki/Sizing-And-Hardware">Dimensionnement et matériel</a>.</p><h2>Comment installer Jina On-Prem avec Docker</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt20265d09e2d8d0f4/6a6a33d1065b162105701ffd/ada9881af407168298b1940f8537ad71a5411c89-1999x1200.png" alt="" /><p>Le moyen le plus rapide de démarrer est d'<a href="https://www.docker.com/get-started/">installer Docker</a> (si ce n'est pas déjà fait) et de suivre les instructions sur la page <a href="https://github.com/jina-ai/jina-on-prem/wiki/QuickStart">Démarrage rapide de Jina On-Prem</a>.</p><p>Des conteneurs Docker préconfigurés sont disponibles pour les 28 modèles Jina. Il vous suffit d'en télécharger un et de le transférer vers votre environnement cible pour faire fonctionner les modèles Jina AI en moins de cinq minutes.</p><p>Pour les builds multimodaux ou personnalisés, ou pour télécharger l'ensemble complet des dépendances pour une installation en dehors d'un conteneur, suivez les étapes indiquées dans le <a href="https://github.com/jina-ai/jina-on-prem/wiki/Bundling-Guide">guide de regroupement</a>.</p><p>Votre installation Jina On-Prem prend en charge l'ensemble des fonctionnalités de l'API Jina et d'EIS ainsi que la génération d'embeddings via les API OpenAI, Cohere, Voyage AI et Gemini, afin de pouvoir s'intégrer dans des applications préexistantes à l'aide d'interfaces standard. Consultez la <a href="https://github.com/jina-ai/jina-on-prem/wiki/API-Reference">documentation de l'API</a> pour plus d'informations.</p><p>Les modèles Jina, y compris les modèles installés avec Jina On-Prem, sont disponibles selon diverses conditions de licence, les derniers modèles étant gratuits pour un usage non commercial sous licence <a href="https://creativecommons.org/licenses/by-nc/4.0/deed.en">CC BY-NC 4.0</a>. Pour obtenir une licence Jina On-Prem à des fins commerciales, veuillez contacter <a href="https://www.elastic.co/fr/contact">Elastic Sales</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/on-prem-ai-jina-embedding-models</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/on-prem-ai-jina-embedding-models</guid>
    <category><![CDATA[Jina AI]]></category>
    <category><![CDATA[Intégrations]]></category>
    <dc:creator><![CDATA[Scott Martens]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt17731ab0c6ec66f6/6a6a33d140a4941014ca5c9a/09bc6dac4e6a86c7877f8ed78d68f5d581aeffa9-1999x1200.png" length="0" type="image/png"/>
    <pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Apporter du dynamisme à Elasticsearch : intégration de la prise en charge native de l’API Prometheus]]></title>
    <description><![CDATA[Interrogez Elasticsearch directement depuis des clients compatibles Prometheus via les points de terminaison natifs PromQL, de découverte et de métadonnées. Envoyez des données à Elasticsearch avec Prometheus Remote Write.]]></description>
    <content:encoded><![CDATA[<p>Dirigez n’importe quel client compatible avec Prometheus vers Elasticsearch et exécutez PromQL directement sur vos métriques existantes. Elasticsearch ajoute des endpoints natifs pour les requêtes, la découverte et les métadonnées Prometheus sous forme de prévisualisation technique qui fonctionnent sur des métriques ingérées via Prometheus Remote Write, OpenTelemetry ou l’API Bulk. L’API fonctionne sur les flux de données temporelles (TSDS) d’Elasticsearch, il n’y a donc pas de couche de stockage spécifique à Prometheus distincte à gérer.</p><p>Cet article explique comment les endpoints de requête, de découverte et de métadonnées s’appuient sur les travaux d’ingestion et de requête antérieurs pour former cette surface API. Les articles connexes vont plus loin sur les éléments spécifiques :</p><ul><li><p><a href="https://www.elastic.co/observability-labs/blog/elasticsearch-supports-promql">La prise en charge native de PromQL dans ES|QL</a> couvre la manière dont les requêtes PromQL sont traduites en plans d’exécution ES|QL.</p></li><li><p><a href="https://www.elastic.co/observability-labs/blog/prometheus-remote-write-elasticsearch">Transférer des métriques Prometheus à Elasticsearch avec Remote Write</a> couvre la configuration de l’ingestion.</p></li><li><p><a href="https://www.elastic.co/observability-labs/blog/prometheus-remote-write-elasticsearch-architecture">Comment fonctionne l'ingestion d'écriture à distance de Prometheus dans Elasticsearch</a> couvre les aspects internes de l'écriture à distance.</p></li></ul><p>Ce travail est encore en cours. Les sections ci-dessous indiquent ce qui est actuellement pris en charge et quelles parties évoluent encore.</p><h2>La surface de l'API</h2><p>Aujourd’hui, les interfaces API compatibles avec Prometheus se répartissent en trois catégories.</p><h3>Endpoints de requête</h3><p>Les endpoints de requête permettent aux clients compatibles avec Prometheus d’évaluer les expressions PromQL :</p><ul><li><p><code>GET /_prometheus/api/v1/query_range</code> évalue une expression PromQL sur une fenêtre de temps (résultats matriciels).</p></li><li><p><code>GET /_prometheus/api/v1/query</code> évalue à un instant donné (résultats vectoriels). Actuellement implémenté en tant que requête à courte portée qui renvoie le dernier échantillon.</p></li></ul><p>Seul GET est pris en charge pour les endpoints de requête actuellement. Certains clients utilisent par défaut la méthode POST. Vous devrez peut-être les configurer pour utiliser la méthode GET. La convention Prometheus POST utilise des corps <code>application/x-www-form-urlencoded</code>, que la couche HTTP d’Elasticsearch rejette comme protection CSRF avant que la requête n’atteigne le gestionnaire.</p><p>Pour connaître l’état complet de la couverture de PromQL, consultez <a href="https://www.elastic.co/observability-labs/blog/elasticsearch-supports-promql">l’article connexe sur PromQL dans ES|QL</a>.</p><h3>Points de terminaison des métadonnées</h3><p>Les endpoints de métadonnées fournissent les informations de découverte dont les clients ont besoin pour l’autocomplétion, les listes déroulantes de variables et la navigation dans les métriques.</p><p>Les endpoints des séries, des étiquettes et des valeurs d’étiquette acceptent tous les sélecteurs <code>match[]</code> et une plage de temps (<code>start</code>/<code>end</code>). Le paramètre <code>match[]</code> prend un sélecteur de série Prometheus comme <code>http_requests_total{job="api"}</code> et limite la réponse aux séries temporelles qui correspondent. Les réponses restent ainsi rapides et pertinentes sur les clusters comportant un grand nombre de métriques. Par exemple :</p>GET /_prometheus/api/v1/series?match[]=http_requests_total{job="api"}GET /_prometheus/api/v1/labels?match[]=http_requests_totalGET /_prometheus/api/v1/label/instance/values?match[]=http_requests_total{job="api"}<p>La première renvoie toutes les séries pour <code>http_requests_total</code> où <code>job="api"</code>, avec leurs ensembles d’étiquettes complets. La seconde renvoie uniquement les noms des étiquettes qui existent sur les séries <code>http_requests_total</code>. Le troisième renvoie uniquement les valeurs de <code>instance</code> qui apparaissent sur les séries correspondantes.</p><p><code>GET /_prometheus/api/v1/metadata</code> est différent : il retourne le type et l’unité pour chaque métrique, éventuellement filtrés par nom via un paramètre <code>metric</code>.</p>GET /_prometheus/api/v1/metadata?metric=http_requests_total<p>Il n’accepte pas les sélecteurs <code>match[]</code> ni aucune plage horaire. Dans Prometheus, les métadonnées sont collectées à partir de cibles de scrape actives (les lignes <code>HELP</code>, <code>TYPE</code> et <code>UNIT</code> qu’elles exposent). La réponse n’implique donc pas de scan des données. Elasticsearch ne dispose pas d’un dépôt dédié de métadonnées comme celui-ci, donc l’implémentation actuelle découvre les métadonnées des métriques en visitant les données temporelles des dernières 24 heures. Cela permet de maintenir la rapidité de la requête sans nécessiter un balayage complet de l’index. Cette analyse en 24 heures est aujourd’hui corrigée : l’API de métadonnées Prometheus ne divulgue pas les paramètres <code>start</code> ni <code>end</code> qu’Elasticsearch pourrait utiliser pour la rendre ajustable par l’utilisateur.</p><p>Le fonctionnement des endpoints des métadonnées, y compris les commandes <code>TS_INFO</code> et <code>METRICS_INFO</code> qui les alimentent, est expliqué <a href="https://www.elastic.co/search-labs/blog//elasticsearch-native-prometheus-api#ts-info-and-metrics-info">ci-dessous</a>.</p><h3>Index de pré-filtrage</h3><p>Tous les endpoints de requête et de métadonnées acceptent un segment de chemin <code>{index}</code> optionnel après <code>/_prometheus/</code> :</p>GET /_prometheus/metrics-prod-*/api/v1/query_range?query=up&amp;start=...&amp;end=...<p>Il limite les index Elasticsearch sur lesquels la requête est en exécution avant le début de toute évaluation d’expression. Sur les clusters comportant de nombreux flux de données entre équipes ou environnements, cela évite de scanner des index non pertinents et peut réduire de manière significative la latence des requêtes. Vous pouvez configurer des sources de données distinctes par modèle d’indexation afin de fournir aux équipes un accès limité à leurs propres métriques.</p><h3>Remarque sur Remote Write</h3><p>Pour l’ingestion, Elasticsearch expose également l’endpoint standard Prometheus Remote Write :</p><ul><li><p><code>POST /_prometheus/api/v1/write</code> ingère des séries temporelles via le protocole Prometheus Remote Write v1. v2 n’est pas encore pris en charge.</p></li></ul><p>Remote Write écrit dans les flux de données temporelles existants d’Elasticsearch (TSDS), et non dans une couche de stockage spécifique à Prometheus. Les étiquettes Prometheus deviennent des dimensions TSDS, et les noms des métriques deviennent des champs dans le mapping des index. <a href="https://www.elastic.co/observability-labs/blog/prometheus-remote-write-elasticsearch-architecture">L’article sur l’architecture de l’écriture à distance</a> couvre le mapping complet en détail, notamment comment les types de métriques sont déduits et comment les étiquettes sont stockées avec un préfixe <code>labels.</code>.</p><h3>Fonctionnement</h3><p>En interne, tous les endpoints fonctionnent de la même manière : ils analysent les paramètres HTTP entrants, construisent un plan de requête ES|QL, l’exécutent sur des flux de données temporelles et convertissent le résultat en colonnes au format JSON attendu par les clients Prometheus.</p><h2>TS_INFO et METRICS_INFO</h2><p>Les endpoints des métadonnées doivent répondre à des questions telles que « quelles étiquettes existent ? » ou « quels types de métriques sont définis ? » sur des millions de séries temporelles, sans analyser chaque point de données.</p><p>En interne, les endpoints de métadonnées Prometheus répondent à ces questions en construisant des plans ES|QL autour de deux nouvelles commandes de traitement : <code>METRICS_INFO</code> et <code>TS_INFO</code>. Vous n’avez pas besoin d’utiliser ces commandes directement pour utiliser l’API Prometheus, mais elles constituent les primitives d’exécution fondamentales qui sous-tendent les réponses aux métadonnées. Toutes deux fonctionnent en ne visitant qu’un seul document par série temporelle pour extraire ses métadonnées, plutôt que de parcourir tous les échantillons. Cela signifie que leur coût évolue avec le nombre de séries temporelles distinctes, et non en fonction du nombre de points de données.</p><p><code>METRICS_INFO</code> renvoie une ligne par métrique distincte avec son nom, son type, son unité et ses champs de dimension associés. <code>TS_INFO</code> est plus granulaire : une ligne par combinaison (métrique, série temporelle), incluant les valeurs réelles des dimensions en tant qu'objet JSON.</p><p>Un article de blog dédié à <code>TS_INFO</code> et <code>METRICS_INFO</code> sera bientôt publié, abordant le modèle d’exécution en deux phases, la façon dont ils s’adaptent et la façon de les utiliser directement dans les requêtes ES|QL au-delà de l’API Prometheus.</p><h3>Comment les points de terminaison des métadonnées les utilisent</h3><p>Chaque endpoint des métadonnées construit un plan ES|QL avec l’une de ces commandes à son noyau.</p><p><code>/api/v1/labels</code> et <code>/api/v1/series</code> utilisent <code>TS_INFO</code>, car ils ont besoin de détails par série temporelle (quelles étiquettes existent, quelles valeurs de dimension identifient chaque série). <code>/api/v1/metadata</code> et <code>/api/v1/label/__name__/values</code> utilisent <code>METRICS_INFO</code>, car ils n’ont besoin que d’informations métriques (noms, types et unités métriques).</p><p><code>/api/v1/label/{name}/values</code> pour les étiquettes ordinaires (autres que <code>__name__</code>), n’utilisez aucune des deux commandes. Les étiquettes régulières comme <code>job</code> ou <code>instance</code> sont de véritables champs de dimensions dans l’index, de sorte que l’endpoint peut les interroger directement avec une agrégation group-by. Lorsque des sélecteurs <code>match[]</code> sont fournis, ils sont traduits en une clause <code>WHERE</code> qui filtre la série temporelle avant l’exécution de l’agrégation.</p><p>Le label <code>__name__</code> nécessite une stratégie différente car il n’est pas toujours présent sous forme de champ de dimension. Prometheus Remote Write stocke <code>labels.__name__</code>, mais les mesures ingérées par d’autres voies (OpenTelemetry, l’API Bulk) ne les contiennent pas. Le nom de la métrique est encodé dans le nom même du champ (par exemple, <code>metrics.http_requests_total</code>). Vous pourriez consulter les correspondances d’index pour énumérer les noms des champs, mais les correspondances seules ne vous indiquent pas quelle métrique a quelles dimensions, et elles ne peuvent pas être filtrées par les valeurs d’étiquettes d’un sélecteur <code>match[]</code>. <code>METRICS_INFO</code> peut faire les deux : il énumère les noms des métriques dans les index tout en respectant les filtres <code>WHERE</code> en amont.</p><p>Dans tous les cas, la couche API gère la conversion vers les conventions Prometheus : elle supprime les préfixes de stockage <code>labels.</code> et <code>metrics.</code>, et synthétise <code>__name__</code> pour les métriques non-Prometheus qui en sont dépourvues.</p><h2>Conclusion</h2><p>Résultat : tout client compatible avec Prometheus peut interroger et explorer les métriques Elasticsearch par le biais d’endpoints qu’il comprend déjà. Les mesures d’écriture à distance, les mesures OpenTelemetry et les mesures indexées par d’autres chemins sont toutes affichées avec la même API et les mêmes index TSDS.</p><p>Toutes les API Prometheus mentionnées ici sont désormais disponibles en préversion technique dans Elasticsearch Serverless. Pour les clusters autogérés et les déploiements hébergés par Elastic Cloud Hosted, disponibles en préversion technique dans Elasticsearch 9.4, à l’exception de <code>GET /_prometheus/api/v1/metadata</code>. Pour expérimenter localement, utilisez <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">start-local</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-native-prometheus-api</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-native-prometheus-api</guid>
    <category><![CDATA[Intégrations]]></category>
    <dc:creator><![CDATA[Felix Barnsteiner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt12b4e100d5bbb7f0/6a16f7a22b835ff747f4afdd/c7b333bd73e8a1f4e18486b2d692ba742788dcfd-1376x768.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 11 May 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[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[Présentation des modèles Jina, de leurs fonctionnalités et de leurs cas d’usage dans Elasticsearch]]></title>
    <description><![CDATA[Explorez les embeddings multimodaux Jina, Reranker v3 et les modèles d'embedding sémantique, et découvrez comment les utiliser en mode natif dans Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Jina, développé par Elastic, propose des modèles fondamentaux pour la recherche, adaptés aux applications et à l’automatisation des processus métier. Ces modèles fournissent des fonctionnalités essentielles pour intégrer l’IA dans des applications Elasticsearch ou des projets d’IA innovants.</p><p>Les modèles Jina se répartissent en trois grandes catégories, conçues pour faciliter le traitement, l’organisation et la recherche d’informations :</p><ul><li><p>Modèles d’embedding sémantique</p></li><li><p>Modèles de reclassification</p></li><li><p>Petits modèles de langage génératif</p></li></ul><h2>Modèles d’embedding sémantique</h2><p>L’idée derrière les embeddings sémantiques est qu’un modèle d’IA peut apprendre à représenter certains aspects du sens d’une entrée en s’appuyant sur la géométrie d’espaces à très grande dimension.</p><p>On peut considérer un embedding sémantique comme un point (techniquement un <em>vecteur</em>) dans un espace à plusieurs dimensions. Un modèle d’embedding est un réseau de neurones qui reçoit des données numériques en entrée (souvent du texte ou une image) et renvoie l’emplacement du point correspondant dans un espace multidimensionnel, sous forme de coordonnées numériques. Si le modèle est efficace, la distance entre deux embeddings sémantiques est proportionnelle à la similarité de sens des objets correspondants.</p><p>Pour comprendre l’intérêt de cette approche dans les applications de recherche, imaginez les embeddings des mots « chien » et « chat » comme des points dans l’espace :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbad74e5d8292a60e/6a17db73abe0f2114edfe8d2/802cf9bbcb82180d3fc91009f9f62027eee8f031-615x615.png" alt="" /><p>Un bon modèle d’embedding générera une représentation du mot « félin » bien plus proche de « chat » que de « chien », tandis que « canidé » sera plus proche de « chien » que de « chat », car ces mots partagent un sens très proche :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb2b25691801a881/6a17db747b54f946d28b37a5/bce49daf9a31b8fb7ce1c6ef7ae4e8117a4e8b33-615x615.png" alt="" /><p>Si un modèle est multilingue, nous nous attendrions à la même chose pour les traductions de « chat » et « chien » :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt976ba40be7776449/6a17db75be6086c2bd0045f2/ce4d030385324526cbd7539140e0e634d939371c-615x615.png" alt="" /><p>Les modèles d’embedding traduisent la similarité ou la différence de sens entre des éléments en relations spatiales entre leurs représentations vectorielles. Les illustrations ci-dessus sont en deux dimensions pour faciliter la visualisation, mais les modèles d’embedding produisent des vecteurs comportant des dizaines, voire des milliers de dimensions. Cela leur permet de capturer les subtilités du sens dans des textes entiers, en leur associant un point dans un espace comportant des centaines, voire des milliers de dimensions, pour des documents pouvant contenir des milliers de mots.</p><h2>Embeddings multimodaux</h2><p>Les modèles multimodaux étendent le principe des embeddings sémantiques à d’autres types de contenu que le texte – notamment les images. On s’attend donc à ce qu’un embedding d’image soit proche de celui d’une description fidèle de cette image :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt66dc8895485734ec/6a17db77b1e11318d279f155/1ac6aef5b1423e5fe4853e8a547a74e66b0885c2-615x615.png" alt="" /><p>Les embeddings sémantiques offrent de nombreux cas d’usage. Ils peuvent notamment servir à créer des classificateurs efficaces, à regrouper les données (data clustering), ou encore à effectuer des tâches comme la déduplication ou l’analyse de la diversité des données – des fonctionnalités clés dans les environnements big data où les volumes à traiter sont trop importants pour être gérés manuellement.</p><p>L’usage principal des embeddings concerne la recherche d’informations. Elasticsearch peut stocker des objets de récupération avec des embeddings comme clés. Les requêtes sont converties en vecteurs d’embedding, et une recherche renvoie les objets stockés dont les clés sont les plus proches du vecteur d’embedding de la requête.</p><p>Là où la <em>recherche vectorielle</em> traditionnelle (par vecteur unique ou <em>vecteur clairsemé</em>) utilise des vecteurs basés sur les mots ou les métadonnées dans les documents et les requêtes, la <em>recherche par embeddings</em> (ou <em>vecteurs denses</em>) utilise des significations évaluées par l’IA plutôt que des mots. Cela les rend en général plus flexibles et plus précis que les méthodes de recherche classiques.</p><h2>Apprentissage par représentation de type matriochka</h2><p>Le nombre de dimensions d’un embedding et la précision des valeurs qu’il contient ont un impact significatif sur les performances. Les espaces très dimensionnels et les nombres de très grande précision permettent de représenter des informations très complexes et détaillées, mais nécessitent des modèles d’IA plus coûteux à entraîner et à exécuter. Les vecteurs générés occupent également plus d’espace de stockage et nécessitent davantage de ressources de calcul pour mesurer les distances entre eux. L’utilisation de modèles d’embedding sémantique implique donc un compromis important entre précision et consommation de ressources.</p><p>Pour maximiser la flexibilité côté utilisateur, les modèles Jina sont entraînés avec une technique appelée <a href="https://arxiv.org/abs/2205.13147">Matryoshka Representation Learning</a>. Cette méthode pousse le modèle à prioriser les distinctions sémantiques importantes dans les premières dimensions du vecteur, ce qui permet ensuite de tronquer les dimensions les plus élevées sans perte significative de performance.</p><p>Concrètement, cela signifie que les utilisateurs des modèles Jina peuvent choisir le nombre de dimensions qu’ils souhaitent attribuer à leurs embeddings. Réduire le nombre de dimensions entraîne une perte de précision, mais la dégradation des performances reste mineure. Pour la plupart des tâches, les performances des modèles Jina diminuent d’environ 1 à 2 % chaque fois que l’on réduit la taille des embeddings de 50 %, jusqu’à une réduction d’environ 95 %.</p><h2>Récupération asymétrique</h2><p>La similarité sémantique est généralement mesurée de façon symétrique. La valeur obtenue en comparant « chat » à « chien » est la même que celle obtenue en comparant « chien » à « chat ». Mais lorsqu’on utilise des embeddings pour la recherche d’informations, les résultats sont meilleurs si l’on casse cette symétrie et qu’on encode les requêtes différemment des objets à retrouver.</p><p>Cela tient à la façon dont les modèles d’embedding sont entraînés. Les données d’entraînement contiennent des éléments similaires, comme des mots, dans des contextes variés, et les modèles apprennent à en déduire le sens en comparant les similitudes et les différences contextuelles entre ces éléments.</p><p>Ainsi, il se peut par exemple que le mot « animal » apparaisse rarement dans les mêmes contextes que « chat » ou « chien », et que l’embedding du mot « animal » ne soit donc pas particulièrement proche de ceux de « chat » ou « chien ».</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf219074e18a6290a/6a17db78be6086cf060045f6/9a33163405af6c71ee7f4ba8ebc86af39e295a69-615x615.png" alt="" /><p>Cela réduit la probabilité qu’une requête sur le mot « animal » retourne des documents traitant de chats et de chiens — ce qui est précisément l’effet inverse de l’objectif recherché. On encode donc le mot « animal » différemment selon qu’il s’agit d’une requête ou d’un objet cible à retrouver :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt33438b4964001467/6a17db79b1e113101c79f159/363992d4f0affba7937c0c8a9f82c9a531fcd3ba-615x615.png" alt="" /><p>La <em>recherche asymétrique</em> consiste à utiliser un modèle différent pour les requêtes, ou à entraîner un modèle d’embedding de façon spécifique pour encoder différemment les éléments selon qu’ils sont stockés pour la recherche ou utilisés comme requêtes.</p><h2>Embeddings multi-vecteurs</h2><p>Les embeddings simples sont efficaces pour la recherche d’informations car ils s’intègrent bien au fonctionnement d’une base indexée : les objets à retrouver sont stockés avec un unique vecteur d’embedding utilisé comme clé de recherche. Lorsque les utilisateurs interrogent le magasin de documents, leurs requêtes sont converties en vecteurs d’embedding, et les documents dont la clé est la plus proche de celle de la requête (dans l’espace vectoriel de haute dimension) sont retournés comme correspondances candidates.</p><p>Les embeddings multi-vecteurs fonctionnent différemment. Au lieu de générer un vecteur de longueur fixe pour représenter une requête ou un objet stocké, ils produisent une séquence d’embeddings représentant des parties plus petites de ces éléments. Ces parties sont généralement des jetons ou mots pour les textes, ou des fragments d’image pour les données visuelles. Ces embeddings traduisent le sens de chaque élément dans son contexte.</p><p>Par exemple, prenons ces phrases:</p><ul><li><p>She had a heart of gold.</p></li><li><p>She had a change of heart.</p></li><li><p>She had a heart attack.</p></li></ul><p>En apparence, ces phrases sont très similaires, mais un modèle multi-vecteur générerait probablement des embeddings très différents pour chaque occurrence du mot « heart », car son sens varie dans le contexte de chaque phrase:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5c81f089771e6029/6a17db7b7f6f157601c099ec/a33e60c8d8ee3d312bca8375ca2a8b0a0cd40ba9-615x615.png" alt="" /><p>Comparer deux objets à l’aide de leurs embeddings multi-vecteurs revient souvent à calculer leur distance de Chamfer : on compare chaque élément d’un embedding avec ceux de l’autre, puis on additionne les distances minimales. D’autres systèmes, y compris les modules de reclassification Jina présentés plus bas, transmettent ces données à un modèle d’IA spécifiquement entraîné à évaluer leur similarité. Ces deux approches offrent généralement une précision supérieure à la simple comparaison de vecteurs uniques, car les embeddings multi-vecteurs capturent beaucoup plus d’informations contextuelles.</p><p>Toutefois, les embeddings multivecteurs sont peu adaptés à l’indexation. Ils sont souvent utilisés dans les tâches de reclassification, comme illustré dans le modèle <code>jina-colbert-v2</code> présenté dans la section suivante.</p><h2>Modèles d’embedding Jina</h2><h3>Jina Embeddings v4</h3><p><a href="https://jina.ai/news/jina-embeddings-v4-universal-embeddings-for-multimodal-multilingual-retrieval/"><strong>jina-embeddings-v4</strong></a> est un modèle multilingue et multimodal de 3,8 milliards de paramètres (3,8 × 10⁹), compatible avec des textes dans une grande diversité de langues. Il repose sur une architecture innovante qui exploite les connaissances visuelles et linguistiques pour améliorer les performances dans les deux domaines, en particulier dans les tâches de recherche d’images — notamment la <a href="https://huggingface.co/tasks/visual-document-retrieval">recherche de documents visuels</a>. Cela signifie qu’il est capable de traiter des images comme des graphiques, des présentations, des captures d’écran, des pages scannées ou des schémas — des types d’images courants contenant souvent du texte embarqué, en dehors du champ des modèles de vision entraînés sur des scènes du monde réel.</p><p>Nous avons optimisé ce modèle pour différentes tâches à l’aide d’adaptateurs compacts LoRA (<a href="https://huggingface.co/docs/peft/en/package_reference/lora">Low-Rank Adaptation</a>). Cette approche nous permet d’entraîner un modèle unique capable de se spécialiser dans plusieurs tâches sans perte de performance, pour un coût mémoire ou calculatoire minimal.</p><p>Principales fonctionnalités :</p><ul><li><p>Des performances de pointe en recherche de documents visuels, avec en plus une excellente prise en charge du texte multilingue et des images classiques — surpassant des modèles bien plus volumineux.</p></li><li><p>Prise en charge de contextes d’entrée étendus : 32 768 jetons correspondent à environ 80 pages de texte en anglais double interligne, et 20 mégapixels équivalent à une image de 4 500 × 4 500 pixels.</p></li><li><p>Taille des embeddings sélectionnée par l’utilisateur, allant de 2048 dimensions au maximum jusqu’à 128 dimensions. Nous avons constaté empiriquement une forte dégradation des performances en dessous de ce seuil.</p></li><li><p>Compatibilité avec les embeddings simples et multi-vecteurs. Pour le texte, la sortie multivecteur se compose d’un embedding de 128 dimensions pour chaque jeton d’entrée. Pour les images, un embedding de 128 dimensions est généré pour chaque bloc de 28 × 28 pixels nécessaires à la couverture de l’image.</p></li><li><p>Optimisation pour la recherche asymétrique grâce à une paire d’adaptateurs LoRA spécialement entraînés à cet effet.</p></li><li><p>Un adaptateur LoRA optimisé pour le calcul de similarité sémantique.</p></li><li><p>Prise en charge spécifique des langages de programmation et des frameworks IT, également via un adaptateur LoRA.</p></li></ul><p>Nous avons développé <code>jina-embeddings-v4</code> comme outil polyvalent pour toute une gamme de tâches : recherche, compréhension du langage naturel et analyse basée sur l’IA. C’est un modèle relativement compact au vu de ses capacités, mais qui demande tout de même des ressources importantes pour être déployé, et convient mieux à une utilisation via une API cloud ou dans un environnement haute performance.</p><h3>Jina Embeddings v3</h3><p><a href="https://jina.ai/news/jina-embeddings-v3-a-frontier-multilingual-embedding-model/"><strong>jina-embeddings-v3</strong></a> est un modèle d’embedding multilingue, léger, performant, axé sur le texte, avec moins de 600 millions de paramètres. Il prend en charge jusqu’à 8 192 jetons de texte en entrée et génère des embeddings vectoriels simples, avec des tailles personnalisables (de 1 024 à 64 dimensions).</p><p>Nous avons entraîner<code>jina-embeddings-v3</code> non seulement pour la recherche d’informations et la similarité sémantique, mais aussi pour des tâches de classification, comme l’analyse de sentiments, la modération de contenu, le clustering, l’agrégation de nouvelles et la recommandation. Comme <code>jina-embeddings-v4</code>, ce modèle utilise des adaptateurs LoRA spécialisés pour les cas d’usage suivants :</p><ul><li><p>Récupération asymétrique</p></li><li><p>Similarité sémantique</p></li><li><p>Classification</p></li><li><p>Clustering</p></li></ul><p><code>jina-embeddings-v3</code> est un modèle beaucoup plus compact que <code>jina-embeddings-v4</code> , avec une taille de contexte en entrée considérablement réduite, mais qui est aussi moins coûteux à exécuter. Malgré cela, il offre des performances très compétitives (bien qu’uniquement sur du texte) et représente un choix pertinent pour de nombreux cas d’usage.</p><h3>Embeddings de code Jina</h3><p>Les modèles Jina spécialisés pour l’embedding de code — <a href="https://jina.ai/models/jina-code-embeddings-1.5b"><strong>jina-code-embeddings</strong></a> (0,5 Md et 1,5 Md de paramètres) — prennent en charge 15 langages de programmation ainsi que des textes en anglais dans le domaine de l’informatique et des technologies de l’information. Ce sont des modèles compacts, avec respectivement 500 millions et 1,5 milliard de paramètres. Les deux modèles acceptent jusqu’à 32 768 jetons en entrée et permettent à l’utilisateur de définir la taille des embeddings générés : de 896 à 64 dimensions pour le plus petit, et de 1 536 à 128 pour le plus grand.</p><p>Ces modèles prennent en charge la recherche asymétrique, pour cinq spécialisations par type de tâche, en utilisant une méthode de <a href="https://arxiv.org/abs/2101.00190">réglage par préfixe</a> plutôt que des adaptateurs LoRA :</p><ul><li><p><strong>Code vers code.</strong> Récupère du code similaire entre différents langages de programmation. Utilisé pour l’alignement de code, l’élimination des doublons, la migration et le refactoring.</p></li><li><p><strong>Langage naturel vers code.</strong> Permet de retrouver du code correspondant à une requête en langage naturel, un commentaire ou une description.</p></li><li><p><strong>Code vers langage naturel. </strong>Associe du code source à de la documentation ou à d’autres textes en langage naturel.</p></li><li><p><strong>Complétion de code à partir de code.</strong> Suggère du code pertinent pour compléter ou améliorer un extrait existant.</p></li><li><p><strong>Questions-réponses techniques.</strong> Fournit des réponses en langage naturel sur des sujets technologiques, idéal pour des cas d’usage liés à l’assistance technique.</p></li></ul><p>Ces modèles offrent des performances supérieures pour les tâches portant sur la documentation technique et les ressources de développement, à un coût computationnel relativement faible. Ils s’intègrent facilement dans les environnements de développement et les assistants de programmation.</p><h3>Jina ColBERT v2</h3><p><a href="https://jina.ai/models/jina-colbert-v2"><strong>jina-colbert-v2</strong></a> est un modèle d’embedding multivecteur de 560 millions de paramètres. Il est multilingue, entraîné à partir de données couvrant 89 langues, et prend en charge les tailles d’embedding variables et la recherche asymétrique.</p><p>Comme mentionné précédemment, les plongements multivecteurs sont peu adaptés à l’indexation mais sont très utiles pour augmenter la précision des résultats d’autres stratégies de recherche. En utilisant <code>jina-colbert-v2</code><strong>,</strong> vous pouvez calculer à l’avance les embeddings multivecteurs, puis les utiliser pour reclasser les candidats lors de la recherche, au moment de la requête. Cette méthode est moins précise que l’utilisation directe d’un modèle de reclassification, mais beaucoup plus efficace, car elle consiste uniquement à comparer les embeddings multivecteurs déjà stockés, sans faire appel au modèle d’IA à chaque requête ou comparaison de candidats. Elle est particulièrement adaptée aux cas d’usage où la latence et le coût de calcul d’un modèle de reclassification seraient trop élevés, ou lorsque le nombre de documents candidats est trop important.</p><p>Ce modèle produit une séquence d’embeddings, un par jeton d’entrée, et les utilisateurs peuvent choisir des embeddings de 128, 96 ou 64 dimensions. Les correspondances candidates sont limitées à 8 192 jetons. Les requêtes sont encodées de manière asymétrique, ce qui impose à l’utilisateur de spécifier si un texte est une requête ou une correspondance candidate, et de limiter la requête à 32 jetons.</p><h3>Jina CLIP v2</h3><p><a href="https://jina.ai/news/jina-clip-v2-multilingual-multimodal-embeddings-for-text-and-images/"><strong>jina-clip-v2</strong></a> est un modèle d’embedding multimodal de 900 millions de paramètres, entraîné pour produire des embeddings proches entre un texte et une image décrivant le même contenu. Son usage principal est la recherche d’images à partir de requêtes textuelles, mais c’est aussi un modèle textuel performant. Il permet de réduire les coûts liés à la gestion de modèles distincts pour la recherche texte-texte et texte-image.</p><p>Ce modèle prend en charge un contexte d’entrée textuel de 8 192 jetons, et les images sont redimensionnées à 512 × 512 pixels avant génération des embeddings.</p><p>Les architectures CLIP (Contrastive Language–Image Pretraining) sont simples à entraîner, produisent des modèles compacts, mais présentent des limites structurelles importantes. Elles ne permettent pas de transférer la connaissance d’un support à un autre pour améliorer les performances. Elles ne peuvent pas utiliser un support pour améliorer leurs performances sur un autre. Ainsi, même si le modèle sait que les mots « chien » et « chat » sont plus proches en sens que ne l’est « voiture », il ne saura pas forcément qu’une image de chien est plus proche d’une image de chat qu’elle ne l’est d’une image de voiture.</p><p>Cependant, ce modèle souffre également d’un problème connu sous le nom de <em>décalage de modalité</em> : par exemple, un texte sur les chiens pourrait être plus proche, en termes d’embedding, d’un texte sur les chats que d’une image de chien. À cause de cette limitation, nous recommandons d’utiliser CLIP soit pour la recherche texte-image, soit comme modèle textuel seul, mais pas pour combiner les deux dans une même requête.</p><h2>Modèles de reclassification</h2><p>Les modèles de reclassification prennent une ou plusieurs correspondances candidates, ainsi qu’une requête en entrée, et les comparent directement, produisant ainsi des correspondances beaucoup plus précises.</p><p>En théorie, on pourrait utiliser un reranker directement pour la recherche d’informations, en comparant chaque requête à chaque document stocké, mais cela serait extrêmement coûteux en calcul et peu réaliste, sauf pour de très petites collections. En pratique, les rerankers sont donc surtout utilisés pour réévaluer des listes restreintes de correspondances candidates identifiées par d’autres moyens, comme une recherche par embeddings ou d’autres algorithmes de recherche. Les modèles de reclassification conviennent parfaitement aux architectures de recherche hybrides ou fédérées, où une requête peut être envoyée à plusieurs systèmes de recherche distincts, chacun interrogeant ses propres ensembles de données et retournant des résultats différents. Ils sont très efficaces pour fusionner des résultats hétérogènes en une seule réponse de haute qualité.</p><p>La recherche basée sur des embeddings peut représenter un engagement important : elle implique de réindexer toutes vos données stockées et de revoir les attentes des utilisateurs sur les résultats. L’ajout d’un reranker à une solution de recherche existante permet de bénéficier des avantages de l’IA sans avoir à réarchitecturer toute la solution.</p><h2>Modèles de reclassification Jina</h2><h3>Jina Reranker m0</h3><p><a href="https://jina.ai/models/jina-reranker-m0/"><strong>jina-reranker-m0</strong></a> est un reclassificateur multimodal de 2,4 milliards de paramètres, qui prend en charge des requêtes textuelles et des candidats textuels et/ou visuels. C’est le modèle de référence pour la recherche documentaire visuelle, idéal pour interroger des bases contenant des PDF, captures d’écran, images modifiées ou documents semi-structurés, qu’ils soient textuels, visuels ou mixtes.</p><p>Ce modèle prend une requête et une correspondance candidate, et retourne un score. Lorsque la même requête est utilisée avec différents candidats, les scores sont comparables et peuvent être utilisés pour les classer. Il prend en charge une taille d’entrée totale allant jusqu’à 10 240 jetons, incluant la requête et le texte ou l’image candidat(e). Chaque bloc d’image de 28 × 28 pixels utilisé pour couvrir l’image compte comme un jeton pour le calcul de la taille d’entrée.</p><h3>Jina Reranker v3</h3><p><a href="https://jina.ai/models/jina-reranker-v3/"><strong>jina-reranker-v3</strong></a> est un reclassificateur textuel de 600 millions de paramètres avec des performances de pointe pour sa taille. Contrairement à <code>jina-reranker-m0</code>, il traite une requête unique et une liste pouvant aller jusqu’à 64 candidats, puis renvoie leur ordre de classement. Il prend en charge un contexte d’entrée de 131  000 jetons, incluant la requête et tous les candidats.</p><h3>Jina Reranker v2</h3><p><a href="https://jina.ai/models/jina-reranker-v2"><strong>jina-reranker-v2-base-multilingual</strong></a> est un modèle compact et polyvalent, intégrant des fonctionnalités supplémentaires comme le support de l’appel de fonction et des requêtes SQL. Pesant moins de 300 millions de paramètres, ce modèle offre un reclassement multilingue rapide, efficace et précis, avec un support supplémentaire pour la sélection de tables SQL et de fonctions externes associées aux requêtes textuelles, ce qui le rend adapté aux cas d’usage orientés agent.</p><h2>Petits modèles de langage génératif</h2><p>Les modèles de langage génératif sont des modèles comme ChatGPT d’OpenAI, Google Gemini et Claude d’Anthropic, qui acceptent des entrées textuelles ou multimédias et renvoient des sorties textuelles. Il n’existe pas de frontière claire entre les <em>grands</em> modèles de langage (LLM) et les <em>petits</em> modèles de langage (SLM), mais les difficultés pratiques liées au développement, à l’exploitation et à l’usage de LLM de pointe sont bien connues. Les modèles les plus connus ne sont pas distribués publiquement, donc nous ne pouvons qu’estimer leur taille : ChatGPT, Gemini et Claude seraient dans la fourchette des 1 à 3 milliards de milliards de paramètres (1–3×10¹²).</p><p>Exécuter ces modèles, même lorsqu’ils sont en accès libre, dépasse largement les capacités du matériel conventionnel et requiert les puces les plus avancées, organisées en réseaux massivement parallèles. Il est possible d’utiliser des LLM via des API payantes, mais cela implique des coûts importants, une forte latence, et pose des défis en matière de protection des données, de souveraineté numérique et de rapatriement hors du cloud. En outre, les coûts liés à l’entraînement et à la personnalisation de modèles de cette taille peuvent être conséquents.</p><p>C’est pourquoi de nombreuses recherches portent sur le développement de modèles plus petits qui, bien qu’ils n’offrent pas toutes les capacités des plus grands LLM, peuvent exécuter certaines tâches spécifiques avec une qualité équivalente et à moindre coût. Les entreprises déploient généralement des logiciels pour répondre à des besoins spécifiques, et les logiciels d’IA n’échappent pas à cette règle : les solutions basées sur des SLM sont souvent préférées aux LLM. Ils peuvent généralement être exécutés sur du matériel standard, sont plus rapides, consomment moins d’énergie et sont beaucoup plus faciles à personnaliser.</p><p>L’offre SLM de Jina se développe à mesure que nous cherchons à intégrer l’IA dans des solutions de recherche concrètes.</p><h2>Jina SLMs</h2><h3>ReaderLM v2</h3><p><a href="https://jina.ai/models/ReaderLM-v2"><strong>ReaderLM-v2</strong></a> est un modèle de langage génératif capable de convertir du HTML en Markdown ou en JSON, selon des schémas JSON fournis par l’utilisateur et des instructions en langage naturel.</p><p>Le prétraitement et la normalisation des données sont des étapes clés dans le développement de solutions de recherche performantes pour les données numériques, mais les données issues du web sont souvent désordonnées, et les stratégies simples de conversion montrent vite leurs limites. Au contraire, <code>ReaderLM-v2</code> propose une solution d’IA intelligente, capable de comprendre le chaos d’un arbre DOM brut issu d’une page web, et d’identifier avec robustesse les éléments utiles.</p><p>Avec 1,5 milliard de paramètres (1,5 × 10⁹), ils sont mille fois plus compacts que les LLM de dernière génération tout en offrant des performances comparables sur des tâches ciblées.</p><h3>Jina VLM</h3><p><a href="https://jina.ai/models/jina-vlm"><strong>jina-vlm</strong></a> est un modèle de langage génératif de 2,4 milliards de paramètres (2,4×10⁹), conçu pour répondre à des questions en langage naturel à propos d’images. Il offre un excellent support pour l’analyse de documents visuels, c’est-à-dire la réponse à des questions sur des captures d’écran, des présentations, des schémas ou d’autres images non naturelles.</p><p>Par exemple :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt124b9932e01dcd40/6a17db7d4202291eca29f4bc/adfa1420d079ca4fd5582eef4349b1265b378e76-950x500.png" alt="" /><p>Ils sont également très performants pour la lecture de texte dans des images:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1a862a9c9a0e42ce/6a17db7fb1e1133a2979f15d/ea3956e7ad86f8e171841cab2c28c8b3498da1d4-1002x500.png" alt="" /><p>Mais là où <code>jina-vlm</code> excelle vraiment, c'est dans la compréhension du contenu des images informatives et artificielles :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt761cf621ea32e4ae/6a17db8163baff7730741b26/f68606f9d2d99e2cd616d4ff81db3574dc4e26a5-1020x700.png" alt="" /><p>Ou :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4df4d31e574df7e3/6a17db82e3179134e02d56e9/297e85e7e78f296388a02301e1e08fed70827423-1000x500.png" alt="" /><p><code>jina-vlm</code> Ils conviennent parfaitement pour la génération automatique de légendes, les descriptions de produits, les balises alt pour les images, et les applications d’accessibilité pour les personnes malvoyantes. Ils ouvrent aussi la voie à des systèmes RAG (retrieval-augmented generation) capables d’utiliser des données visuelles et de permettre à des agents d’IA de traiter des images sans intervention humaine.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/jina-models-elasticsearch-guide</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/jina-models-elasticsearch-guide</guid>
    <category><![CDATA[Intégrations]]></category>
    <category><![CDATA[Jina AI]]></category>
    <dc:creator><![CDATA[Scott Martens]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta03919124faf767a/6a17db84ec0f89b8fe5a64d8/407b4c862b51ebdfc7f26db4e25950a65caf1673-656x442.png" length="0" type="image/png"/>
    <pubDate>Thu, 01 Jan 2026 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>
  </channel>
</rss>