<?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[Tomás Murúa - 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[Tomás Murúa - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/fr/search-labs/author/tomas-murua</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/author/tomas-murua</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/author/tomas-murua.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Tue, 29 Sep 2026 10:24:17 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Créer un connecteur ChatGPT avec Elasticsearch pour interroger les issues GitHub]]></title>
    <description><![CDATA[Découvrez comment créer un connecteur ChatGPT personnalisé et déployer un serveur MCP Elasticsearch qui utilise la rechercher hybride pour interroger les issues GitHub internes.]]></description>
    <content:encoded><![CDATA[<p>OpenAI a récemment annoncé la fonctionnalité <a href="https://help.openai.com/en/articles/11487775-connectors-in-chatgpt">connecteurs personnalisés</a> pour ChatGPT sur les plans Pro/Business/Entreprise et Edu. En plus des connecteurs prêts à l'emploi pour accéder aux données sur Gmail, GitHub, Dropbox, etc., il est possible de créer des connecteurs personnalisés en utilisant des serveurs MCP.</p><p>Les connecteurs personnalisés vous donnent la possibilité de combiner vos connecteurs ChatGPT existants avec des sources de données supplémentaires comme Elasticsearch pour obtenir des réponses complètes.</p><p>Dans cet article, nous allons créer un serveur <a href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a> qui connecte ChatGPT à un index Elasticsearch contenant des informations sur les issues GitHub internes et les requêtes pull. Cela permet de répondre aux requêtes en langage naturel en utilisant vos données Elasticsearch.</p><p>Nous déploierons le serveur MCP en utilisant <a href="https://gofastmcp.com/getting-started/welcome">FastMCP</a> sur Google Colab avec ngrok pour obtenir une URL publique à laquelle ChatGPT peut se connecter, éliminant ainsi le besoin d'une configuration complexe de l'infrastructure.</p><p>Pour un aperçu complet de MCP et de son écosystème, reportez-vous à la section <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">État actuel du MCP</a>.</p><h2>Prérequis</h2><p>Avant de commencer, vous aurez besoin des éléments suivants :</p><ul><li><p>Cluster Elasticsearch (8.X ou supérieur)</p></li><li><p>Clé API Elasticsearch avec accès en lecture à votre index</p></li><li><p>Compte Google (pour Google Colab)</p></li><li><p>Compte ngrok (fonctionne avec le niveau gratuit)</p></li><li><p>Compte ChatGPT avec un forfait Pro/Entreprise/Business ou Edu</p></li></ul><h2>Comprendre les exigences du connecteur ChatGPT MCP</h2><p>Les connecteurs ChatGPT MCP nécessitent l'implémentation de deux outils : <code>search</code> et <code>fetch</code>. Pour plus de détails, consultez <a href="https://platform.openai.com/docs/mcp#create-an-mcp-server">OpenAI Docs</a>.</p><h3><a href="https://platform.openai.com/docs/mcp#search-tool">Outil de recherche</a></h3><p>Renvoie une liste de résultats pertinents depuis votre index Elasticsearch en fonction d'une requête utilisateur.</p><h4>Ce qu'il reçoit :</h4><ul><li><p>Une chaîne unique contenant la requête en langage naturel de l'utilisateur.</p></li><li><p>Exemple : "Recherchez les issues liées à la migration d'Elasticsearch."</p></li></ul><h4>Ce qu'il renvoie : </h4><ul><li><p>Un objet avec une clé <code>result</code> contenant un tableau d'objets de résultats. Chaque résultat inclut :</p><ul><li><p><code>id</code> - Identifiant de document unique</p></li><li><p><code>title</code> - Titre de l'issue ou de la PR</p></li><li><p><code>url</code> - Lien vers l'issue/la PR</p></li></ul></li></ul><h4>Dans notre implémentation :</h4>return {
    "results": [
        {
            "id": "PR-612",
            "title": "Fix memory leak in WebSocket notification service",
            "url": "https://internal-git.techcorp.com/pulls/612"
        },
        # ... more results
    ]
}<h3><a href="https://platform.openai.com/docs/mcp#fetch-tool">Outil de récupération</a></h3><p>Récupère le contenu complet d'un document spécifique.</p><h4>Ce qu'il reçoit :</h4><ul><li><p>Chaîne unique contenant l'ID du document Elasticsearch extrait du résultat de la recherche</p></li><li><p>Exemple : "Donnez-moi les détails de la PR-578."</p></li></ul><h4>Ce qu'il renvoie :</h4><ul><li><p>Objet de document complet contenant :</p><ul><li><p><code>id</code> - Identifiant de document unique</p></li><li><p><code>title</code> - Titre de l'issue ou de la PR</p></li><li><p><code>text</code> - Description complète du problème/PR et détails</p></li><li><p><code>url</code> - Lien vers l'issue/la PR</p></li><li><p><code>type</code> - Type de document (issue, pull_request)</p></li><li><p><code>status</code> - Statut actuel (ouvert, en cours, résolu)</p></li><li><p><code>priority</code> - Niveau de priorité (faible, moyen, élevé, critique)</p></li><li><p><code>assignee</code> - Personne en charge de l'issue/la PR</p></li><li><p><code>created_date</code> - Date de création</p></li><li><p><code>resolved_date</code> - Date de résolution (le cas échéant)</p></li><li><p><code>labels</code> - Balises associées au document</p></li><li><p><code>related_pr</code> - ID de la requête pull associée</p></li></ul></li></ul>return {
    "id": "PR-578",
    "title": "Security hotfix: Patch SQL injection vulnerabilities",
    "text": "Description: CRITICAL SECURITY FIX for ISSUE-1889. Patches SQL...",
    "url": "https://internal-git.techcorp.com/pulls/578",
    "type": "pull_request",
    "status": "closed",
    "priority": "critical",
    "assignee": "sarah_dev",
    "created_date": "2025-09-19",
    "resolved_date": "2025-09-19",
    "labels": "security, hotfix, sql",
    "related_pr": null
}<p><strong>Remarque</strong> : Cet exemple utilise une structure plate où tous les champs se trouvent au niveau racine. Les exigences d'OpenAI sont flexibles et prennent également en charge les objets de métadonnées imbriqués.</p><h2>Issues GitHub et ensemble de données de PR</h2><p>Pour ce tutoriel, nous allons utiliser un ensemble de données interne de GitHub contenant des issues et des requêtes pull. Ceci représente un scénario dans lequel vous souhaitez interroger des données privées et internes via ChatGPT.</p><p>L'ensemble de données est accessible <a href="https://gist.github.com/TomasMurua/4e7bbdf7a7ebbdffaa663c43578d934a">ici</a>. Et nous mettrons à jour l'index des données à l'aide de l'<a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk">API Bulk</a>.</p><p>Cet ensemble de données comprend :</p><ul><li><p>Issues avec description, état, niveau de priorité et personnes en charge</p></li><li><p>Requêtes pull avec modifications de code, révisions et informations de déploiement</p></li><li><p>Relations entre les issues et les PR (p. ex., la PR-578 corrige l'ISSUE-1889)</p></li><li><p>Étiquettes, dates et autres métadonnées</p></li></ul><h3>Mappings de l'index</h3><p>L'index utilise les <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">mappings</a> suivants pour prendre en charge la recherche hybride avec <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-elser">ELSER</a>. Le champ <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">text_semantic</a> est utilisé pour la recherche sémantique, tandis que les autres champs permettent la recherche par mot-clé.</p>{
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword"
      },
      "title": {
        "type": "text"
      },
      "text": {
        "type": "text"
      },
      "text_semantic": {
        "type": "semantic_text",
        "inference_id": ".elser-2-elasticsearch"
      },
      "url": {
        "type": "keyword"
      },
      "type": {
        "type": "keyword"
      },
      "status": {
        "type": "keyword"
      },
      "priority": {
        "type": "keyword"
      },
      "assignee": {
        "type": "keyword"
      },
      "created_date": {
        "type": "date",
        "format": "iso8601"
      },
      "resolved_date": {
        "type": "date",
        "format": "iso8601"
      },
      "labels": {
        "type": "keyword"
      },
      "related_pr": {
        "type": "keyword"
      }
    }
  }
}<h2>Créer le serveur MCP</h2><p>Notre serveur MCP implémente deux outils conformes aux spécifications d'OpenAI qui utilisent la recherche hybride pour combiner la sémantique et la correspondance de texte pour de meilleurs résultats.</p><h3>Outil de recherche</h3><p>Utilise la recherche hybride avec <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">RRF</a> (fusion des rangs réciproques) qui combine la recherche sémantique avec la correspondance de texte :</p>@mcp.tool()
    async def search(query: str) -&gt; Dict[str, List[Dict[str, Any]]]:
        """
        Search for internal issues and PRs using hybrid search (semantic + text with RRF).
        Returns list with id, title, and url per OpenAI spec.
        """
        if not query or not query.strip():
            return {"results": []}

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

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

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

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

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

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

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

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

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

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

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

        except Exception as e:
            logger.error(f"Fetch error: {e}")
            raise ValueError(f"Failed to fetch '{id}': {str(e)}")<h3>Points clés :</h3><ul><li><p><strong>Recherche par champ d'ID de document</strong> : utilise une requête de terme sur le champ personnalisé <code>id</code></p></li><li><p><strong>Renvoie le document complet</strong> : inclut le champ complet <code>text</code> avec tout le contenu</p></li><li><p><strong>Structure plate</strong> : tous les champs au niveau racine, correspondant à la structure de document d'Elasticsearch.</p></li></ul><h2>Déployer sur Google Colab</h2><p>Nous utiliserons Google Colab pour exécuter notre serveur MCP et ngrok pour l'exposer publiquement afin que ChatGPT puisse s'y connecter.</p><h3>Étape 1 : Ouvrir le notebook Google Colab</h3><p>Accédez à notre notebook préconfiguré <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-chatgpt-connector">Elasticsearch MCP pour ChatGPT</a>.</p><h3>Étape 2 : Configurer vos identifiants</h3><p>Vous aurez besoin de trois informations :</p><ul><li><p><strong>URL Elasticsearch</strong> : l'<a href="https://www.elastic.co/docs/deploy-manage/deploy/cloud-enterprise/connect-elasticsearch">URL de votre cluster Elasticsearch</a>.</p></li><li><p><strong>Clé API Elasticsearch</strong> : <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">clé API</a> avec accès en lecture à votre index.</p></li><li><p><strong>Jeton d'authentification ngrok</strong> : jeton gratuit fourni par <a href="https://ngrok.com/">ngrok</a>. Nous utiliserons ngrok pour exposer l'URL du MCP à l'Internet afin que ChatGPT puisse s'y connecter.</p></li></ul><h4>Obtenir votre token ngrok</h4><ol><li><p>Créez un compte gratuit sur <a href="https://ngrok.com/">ngrok</a></p></li><li><p>Accédez à votre <a href="https://dashboard.ngrok.com/">tableau de bord ngrok</a></p></li><li><p>Copier votre jeton d'authentification</p></li></ol><h4>Ajouter des secrets à Google Colab</h4><p>Dans le notebook Google Colab :</p><ol><li><p>Cliquez sur l'<strong>icône clé</strong> dans la barre latérale gauche pour ouvrir <strong>Secrets</strong>.</p></li><li><p>Ajoutez ces trois secrets :</p></li></ol>ELASTICSEARCH_URL=https://your-cluster.elastic.com:443
ELASTICSEARCH_API_KEY=your-api-key
NGROK_TOKEN=your-ngrok-token<p>3. Activer l'accès aux notebooks pour chaque secret</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5acae97b386277f8/6a17f08f5ea30f74c964b6c2/d5dd6ac19fe816a562c6351fdb0f11369da0e877-609x321.jpg" alt="Ajouter des secrets à Google Colab" /><h3>Étape 3 : Exécuter le notebook</h3><ol><li><p>Cliquez sur <strong>Runtime</strong> (Exécution) puis sur <strong>Run all</strong> (Tout exécuter) pour exécuter toutes les cellules</p></li><li><p>Attendez que le serveur démarre (environ 30 secondes)</p></li><li><p>Recherchez l'URL publique de ngrok dans la sortie</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdd11aacf2deab67c/6a17f091e8fbce81f13a1a41/f185100e8869624bc9e1c7b2b4eb32785e2d89e7-1189x283.png" alt="" /><p>4. La sortie affichera quelque chose comme :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8891d917fdbaaf48/6a17f092abe0f208c7dfeaf6/e02e625e91ed9136454e4401b184575fb03a336e-1052x465.jpg" alt="La sortie de l'exécution d'un notebook dans Google Colab" /><h2>Se connecter à ChatGPT</h2><p>Nous allons maintenant connecter le serveur MCP à votre compte ChatGPT.</p><ol><li><p>Ouvrez ChatGPT et accédez aux <strong>Paramètres</strong>.</p></li><li><p>Accédez à <strong>Connectors</strong> (Connecteurs).Si vous utilisez un compte Pro, vous devez activer le <a href="https://platform.openai.com/docs/guides/developer-mode">mode développeur</a> dans les connecteurs.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt95efdcb2c39307e7/6a17f094abe0f24d8edfeafa/32c02192912fc0e7e5a52e9399077ba7ae3b4901-739x715.png" alt="Connexion du serveur MPC à un compte ChatGPT" /><p><em>Si vous utilisez ChatGPT Enterprise ou Business, vous devez publier le connecteur sur votre espace de travail.</em></p><p>3. Cliquez sur <strong>Create</strong> (Créer).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4c8fc8dd6033918/6a17f095631730de19585b7b/15c53e5ccc381108a9dc0052cca05bf0fc97679a-755x683.png" alt="Ajouter un connecteur à ChatGPT" /><p><em><strong>Remarque</strong></em><em> : Dans les espaces de travail Business, Entreprise et Edu, seuls les propriétaires, les administrateurs et les utilisateurs ayant activé l'option correspondante (pour Entreprise/Edu) peuvent ajouter des connecteurs personnalisés. Les utilisateurs ayant un rôle de membre standard ne peuvent pas ajouter de connecteurs personnalisés eux-mêmes.</em></p><p><em>Une fois qu'un connecteur est ajouté et activé par un propriétaire ou un utilisateur administrateur, il devient accessible à tous les membres de l'espace de travail.</em></p><p>4. Saisissez les informations requises et votre URL ngrok se terminant par <code>/sse/</code>. Notez le "/" après "sse". Cela ne fonctionnera pas sans cet élément :</p><ul><li><p><strong>Nom :</strong> Elasticsearch MCP</p></li><li><p><strong>Description</strong> : MCP personnalisé pour la recherche et la récupération d'informations GitHub internes.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd716ad0beeeb1d35/6a17f09714d90c11cc79b6d7/162a85705cc8ac48a3f2f665551d513e0719f93d-479x684.png" alt="Créer un connecteur MCP Elastic " /><p>5. Appuyez sur <strong>Créer</strong> pour enregistrer le MCP personnalisé.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857794237d7d3b5a/6a17f0983e03d729b74f2d54/97eb5fb0a32b86bfadfb35561f698616f217c049-913x629.png" alt="Sauvegarder le connecteur MCP personnalisé en cliquant sur Créer" /><p>La connexion est instantanée si votre serveur est en cours d'exécution. Aucune authentification supplémentaire n'est requise, car la clé API Elasticsearch est configurée sur votre serveur.</p><h2>Tester le serveur MCP</h2><p>Avant de poser des questions, vous devez sélectionner le connecteur que ChatGPT doit utiliser.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" alt="Sélection du connecteur que ChatGPT doit utiliser" /><h3>Prompt 1 : Recherchez les issues</h3><p>Demandez : "<strong>Recherchez les issues liées à la migration d'Elasticsearch</strong>", puis confirmez l'appel à l'outil d'action.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6c204ceacf897f61/6a17f09c9da390fb1de4657d/cfd781acbff8cd7c8095bbe29224f8b26d581f77-650x375.png" alt="Demandez à ChatGPT « Trouve les problèmes liés à la migration d'Elasticsearch » et confirmez l'appel de l'outil Actions." /><p>ChatGPT appellera l'outil <code>search</code> avec votre requête. Vous pouvez voir qu'il recherche des outils disponibles et se prépare à appeler l'outil Elasticsearch, et confirme auprès de l'utilisateur avant de prendre toute action sur l'outil.</p><h4>Demande d'appel d'outil :</h4>{
  "query": "Elasticsearch migration issues"
}<h4>Réponse de l'outil :</h4>{
  "results": [
    {
      "id": "PR-598",
      "title": "Elasticsearch 8.x migration - Application code changes",
      "url": "https://internal-git.techcorp.com/pulls/598"
    },
    {
      "id": "ISSUE-1712",
      "title": "Migrate from Elasticsearch 7.x to 8.x",
      "url": "https://internal-git.techcorp.com/issues/1712"
    },
    {
      "id": "RFC-045",
      "title": "Design Proposal: Microservices Migration Architecture",
      "url": "https://internal-git.techcorp.com/rfcs/045"
    }
    // ... 7 more results
  ]
}<p>ChatGPT traite les résultats et les présente dans un format conversationnel naturel.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b4378e7d26b4ad0/6a17f09ddbb4ff4de1fb57bf/9d5b6cff85c7e54ccc2584b8ae96d45495fae8c1-923x1352.png" alt="Comment ChatGPT traite les résultats de la demande d'appel d'outil et de la réponse de l'outil" /><h3>En coulisses</h3><h4>Prompt : "Recherchez les issues liées à la migration d'Elasticsearch"</h4><p>1. Appels de ChatGPT <code>search(“Elasticsearch migration”)</code></p><p>2. Elasticsearch effectue une recherche hybride.</p><ul><li><p>La <strong>recherche sémantique</strong> comprend des concepts tels que "mise à niveau" et "<em>compatibilité des versions</em>".</p></li><li><p>La <strong>recherche de texte</strong> trouve des correspondances exactes pour "<em>Elasticsearch</em>" et "migration".</p></li><li><p><strong>RRF</strong> combine et classe les résultats des deux approches</p></li></ul><p>3. Renvoie les 10 événements les plus pertinents avec <code>id</code>, <code>title</code>, <code>url</code></p><p>4. ChatGPT identifie "<em>ISSUE-1712: migrate from Elasticsearch 7.x to 8.x</em>" (Migrer d'Elasticsearch 7.x vers 8.x) comme résultat le plus pertinent.</p><h3>Prompt 2 : Obtenez tous les détails</h3><p>Demandez : <em><strong>"Donnez-moi les détails de l'ISSUE-1889"</strong></em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d1a53db8bfe8326/6a17f09f445de966104d021a/5c0db5245535ce67a36056e61e135bddc97ce496-934x629.png" alt="ChatGPT comprend que vous souhaitez obtenir des informations détaillées sur un problème spécifique, appelle l'outil fetch et confirme auprès de l'utilisateur avant d'entreprendre toute action sur l'outil." /><p>ChatGPT comprend que vous souhaitez obtenir des informations détaillées sur un problème spécifique, appelle l'outil <code>fetch</code> et confirme auprès de l'utilisateur avant d'entreprendre des actions sur l'outil.</p><h4>Demande d'appel d'outil :</h4>{
  "id": "ISSUE-1889"
}<h4>Réponse de l'outil :</h4>{
  "id": "ISSUE-1889",
  "title": "SQL injection vulnerability in search endpoint",
  "text": "Description: Security audit identified SQL injection vulnerability in /api/v1/search endpoint. User input from query parameter is not properly sanitized before being used in raw SQL query. Severity: HIGH - Immediate action required Affected Code: - File: services/search/query_builder.py - Line: 145-152 - Issue: String concatenation used instead of parameterized queries Investigation: - @security_team_alice: Confirmed exploitable with UNION-based injection - @sarah_dev: Checking all other endpoints for similar patterns - @john_backend: Found 3 more instances in legacy codebase Remediation: - Rewrite using SQLAlchemy ORM or parameterized queries - Add input validation and sanitization - Implement WAF rules as additional layer - Security regression tests Comments: - @tech_lead_mike: Stop all other work, this is P0 - @sarah_dev: PR-578 ready with fixes for all 4 vulnerable endpoints - @alex_devops: Deployed hotfix to production 2025-09-19 at 14:30 UTC - @security_team_alice: Verified fix, conducting full pentest next week Resolution: All vulnerable endpoints patched. Added pre-commit hooks to catch raw SQL queries. Security training scheduled for team.",
  "url": "https://internal-git.techcorp.com/issues/1889",
  "type": "issue",
  "status": "closed",
  "priority": "critical",
  "assignee": "sarah_dev",
  "created_date": "2025-09-18",
  "resolved_date": "2025-09-19",
  "labels": "security, vulnerability, bug, sql",
  "related_pr": "PR-578"
}<p>ChatGPT synthétise les informations et les présente clairement.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt560958fa3bd212d0/6a17f0a0faa91355ba93c974/410f19f213e94fc4e3c47eeef6e04b69e0c86159-602x462.png" alt="Comment ChatGPT synthétise les informations et les présente " /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcccf35a584e8373b/6a17f0a2505ac3471cad8c2e/54d8ffa117628a1e3afc317c3ab75d4f7731d7ab-767x1600.png" alt="Comment ChatGPT présente les informations" /><h3>En coulisses</h3><h4>Prompt : "Donnez-moi les détails de l'ISSUE-1889"</h4><ol><li><p>Appels ChatGPT <code>fetch(“ISSUE-1889”)</code></p></li><li><p>Elasticsearch extrait le document complet</p></li><li><p>Retourne un document complet avec tous les champs au niveau racine</p></li><li><p>ChatGPT synthétise les informations et répond avec les citations appropriées.</p></li></ol><h2>Conclusion</h2><p>Dans cet article, nous avons créé un serveur MCP personnalisé qui connecte ChatGPT à Elasticsearch à l'aide d'outils MCP de <strong>recherche</strong> et de <strong>récupération</strong> dédiés, permettant de lancer des requêtes en langage naturel sur des données privées.</p><p>Ce modèle MCP fonctionne pour n'importe quel index Elasticsearch, documentation, produit, log ou toute autre donnée que vous souhaitez interroger en langage naturel.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/chatgpt-connector-mcp-server-github-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/chatgpt-connector-mcp-server-github-elasticsearch</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[Recherche hybride]]></category>
    <dc:creator><![CDATA[Tomás Murúa]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" length="0" type="image/gif"/>
    <pubDate>Mon, 01 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Construire un agent d'IA pour les RH avec Elastic Agent Builder et GPT-OSS]]></title>
    <description><![CDATA[Découvrez comment créer un agent d'intelligence artificielle capable de répondre à des requêtes en langage naturel sur les données RH de vos employés en utilisant Elastic Agent Builder et GPT-OSS.]]></description>
    <content:encoded><![CDATA[<h2>Introduction</h2><p>Cet article vous montrera comment construire un agent d'IA pour les RH en utilisant <a href="https://openai.com/index/introducing-gpt-oss/">GPT-OSS</a> et Elastic Agent Builder. L'agent peut répondre à vos questions sans envoyer de données à OpenAI, Anthropic ou tout autre service externe.</p><p>Nous allons utiliser LM Studio pour servir GPT-OSS localement et le connecter à Elastic Agent Builder.</p><p>À la fin de cet article, vous disposerez d'un agent d'IA personnalisé capable de répondre à des questions en langage naturel sur les données de vos employés, tout en conservant un contrôle total sur vos informations et votre modèle.</p><h2>Produits requis</h2><p>Pour cet article, vous avez besoin de :</p><ul><li><p><a href="https://www.elastic.co/cloud">Elastic Cloud</a> hébergé 9.2, déploiement sans serveur ou <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">local</a>.</p></li><li><p>Machine avec 32 Go de RAM recommandée (minimum 16 Go pour GPT-OSS 20B)</p></li><li><p><a href="https://lmstudio.ai/">LM Studio</a> installé</p></li><li><p><a href="https://www.docker.com/products/docker-desktop/">Docker Desktop</a> installé</p></li></ul><h2>Pourquoi utiliser GPT-OSS ?</h2><p>Avec un LLM local, vous avez la possibilité de le déployer dans votre propre infrastructure et de l'adapter à vos besoins. Tout cela en gardant le contrôle sur les données que vous partagez avec le modèle et, bien sûr, sans avoir à payer de licence à un fournisseur externe.</p><p>OpenAI <a href="https://openai.com/index/introducing-gpt-oss/">a publié GPT-OSS</a> le 5 août 2025, dans le cadre de son engagement envers l'écosystème des modèles ouverts.</p><p>Le modèle de paramètres 20B offre :</p><ul><li><p><strong>Capacités d'utilisation des outils</strong></p></li><li><p><strong>Inférence efficace</strong></p></li><li><p><strong>Compatible avec le SDK OpenAI</strong></p></li><li><p><strong>Compatible avec les flux de travail agentiques</strong></p></li></ul><p>Comparaison des points de repère :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt58fab956edb40412/6a170cfcb0367da43a72bd80/29160e3345352088e8213297630882f252b00c47-1600x680.png" alt="" /><h2>Architecture de la solution</h2><p>L'architecture fonctionne entièrement sur votre machine locale. Elastic (exécuté dans Docker) communique directement avec votre LLM local via LM Studio, et Elastic Agent Builder utilise cette connexion pour créer des agents d'IA personnalisés qui peuvent interroger les données de vos employés.</p><p>Pour plus de détails, consultez cette <a href="https://www.elastic.co/docs/solutions/observability/connect-to-own-local-llm">documentation</a>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80db5bb0a797f51b/6a170cfd0e2e492f2c41a16f/a4a886750ff25fa8bb7aefc7448161e52cf73ed3-1600x896.png" alt="" /><h2>Construire un agent d'IA pour les RH : étapes</h2><p>Nous diviserons la mise en œuvre en 5 étapes :</p><ol><li><p>Configurer LM studio avec un modèle local</p></li><li><p>Déployer Elastic local avec Docker</p></li><li><p>Créer le connecteur OpenAI dans Elastic</p></li><li><p>Téléchargement des données des employés vers Elasticsearch</p></li><li><p>Créez et testez votre agent d'intelligence artificielle</p></li></ol><h2>Étape 1 : Configurer LM Studio avec GPT-OSS 20B</h2><p>LM Studio est une application conviviale qui vous permet d'exécuter localement de grands modèles linguistiques sur votre ordinateur. Il fournit un serveur d'API compatible avec OpenAI, ce qui facilite l'intégration avec des outils tels qu'Elastic sans processus de configuration complexe. Pour plus de détails, reportez-vous à la <a href="https://lmstudio.ai/docs/app">documentation de LM Studio</a>.</p><p>Tout d'abord, téléchargez et installez LM Studio depuis le site officiel. Une fois installée, ouvrez l'application.</p><h3>Dans l'interface de LM Studio :</h3><ol><li><p>Allez dans l'onglet recherche et cherchez "GPT-OSS"</p></li><li><p>Sélectionnez le site <code>openai/gpt-oss-20b</code> à partir d'OpenAI</p></li><li><p>Cliquez sur télécharger</p></li></ol><p>La taille de ce modèle devrait être d'environ <strong>12,10 Go.</strong> Le téléchargement peut prendre quelques minutes, en fonction de votre connexion internet.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2dc341a6625e34b7/6a170cff839dfa2eb4dcff44/5d01bc4dcb377b5259fc6b521fe2425a31b90ca4-1312x872.png" alt="" /><h4>Une fois le modèle téléchargé :</h4><ol><li><p>Aller dans l'onglet du serveur local</p></li><li><p>Sélectionner l'openai/gpt-oss-20b</p></li><li><p>Utiliser le port par défaut 1234</p></li><li><p>Dans le panneau de droite, cliquez sur <strong>Charger </strong>et réglez la longueur du contexte sur <strong>40K</strong> ou plus.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3704ca1b28465cc4/6a170d00d7c022ed8fde64ef/e546033f916381647b876815b2c1f1ae2a08365f-326x337.png" alt="" /><p>5. Cliquez sur démarrer le serveur</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7b9170a4945ff857/6a170d0266c4f9ffadf8c0a6/28ee78a3caa84d14e04db3d42f30acbe4d4d005a-1312x872.png" alt="" /><p>Vous devriez voir ceci si le serveur est en cours d'exécution.</p>[LM STUDIO SERVER] Success! HTTP server listening on port 1234
[LM STUDIO SERVER] Supported endpoints:
[LM STUDIO SERVER] -&gt;	GET  http://localhost:1234/v1/models
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/responses
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/chat/completions
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/completions
[LM STUDIO SERVER] -&gt;	POST http://localhost:1234/v1/embeddings
Server started.<h2>Étape 2 : Déployer Elastic local avec Docker</h2><p>Nous allons maintenant configurer Elasticsearch et Kibana localement à l'aide de Docker. Elastic fournit un script pratique qui gère l'ensemble du processus d'installation. Pour plus de détails, voir la <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">documentation officielle</a>.</p><h3>Exécuter le script start-local</h3><p>Exécutez la commande suivante dans votre terminal :</p>curl -fsSL https://elastic.co/start-local | sh<p>Ce script va :</p><ul><li><p>Télécharger et configurer Elasticsearch et Kibana</p></li><li><p>Démarrer les deux services à l'aide de Docker Compose</p></li><li><p>Activation automatique d'une licence d'essai Platinum de 30 jours</p></li></ul><h3>Résultats attendus</h3><p>Attendez le message suivant et enregistrez le mot de passe et la clé API indiqués ; vous en aurez besoin pour accéder à Kibana :</p>🎉 Congrats, Elasticsearch and Kibana are installed and running in Docker!
🌐 Open your browser at http://localhost:5601
   Username: elastic
   Password: KSUlOMNr
🔌 Elasticsearch API endpoint: http://localhost:9200
🔑 API key: cnJGX0pwb0JhOG00cmNJVklUNXg6cnNJdXZWMnM4bncwMllpQlFlUTlWdw==
Learn more at https://github.com/elastic/start-local<h3>Accéder à Kibana</h3><p>Ouvrez votre navigateur et naviguez vers :</p>http://localhost:5601<p>Connectez-vous en utilisant les informations d'identification obtenues dans la sortie du terminal.</p><h3>Activer le constructeur d'agents</h3><p>Une fois connecté à Kibana, naviguez vers <strong>Management </strong>&gt;<strong> AI </strong>&gt;<strong> Agent Builder </strong>et activez l'Agent Builder.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a934bd99fa6a0ce/6a170d046234e019c3db1a5a/92e104cb846c20d875865ded8a3d37f5c7daae9b-1491x1528.png" alt="" /><h2>Étape 3 : Créer le connecteur OpenAI dans Elastic</h2><p>Nous allons maintenant configurer Elastic pour qu'il utilise votre LLM local.</p><h3>Connecteurs d'accès</h3><ol><li><p>Dans Kibana</p></li><li><p>Allez dans <strong>Paramètres du projet</strong> &gt; <strong>Gestion</strong></p></li><li><p>Sous <strong>Alertes et aperçus</strong>, sélectionnez <strong>Connecteurs</strong></p></li><li><p>Cliquez sur Créer un connecteur</p></li></ol><h3>Configurer le connecteur</h3><p>Sélectionnez <strong>OpenAI</strong> dans la liste des connecteurs. LM Studio utilise le SDK OpenAI, ce qui le rend compatible.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt762023c39781eb78/6a170d06a29299a59ed01087/5ac87042e086c7a2bd47a8039e646ec831f0dcc6-923x974.png" alt="" /><p>Remplissez les champs avec ces valeurs :</p><ul><li><p><strong>Nom du connecteur : </strong>LM Studio - GPT-OSS 20B</p></li><li><p><strong>Sélectionnez un fournisseur OpenAI : </strong>Autre (Service compatible avec l'OpenAI)</p></li><li><p><strong>URL : </strong><code>http://host.docker.internal:1234/v1/chat/completions</code></p></li><li><p><strong>Modèle par défaut : </strong>openai/gpt-oss-20b</p></li><li><p><strong>Clé API :</strong> testkey-123 (n'importe quel texte fonctionne, car le serveur LM Studio ne nécessite pas d'authentification).</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt980e595f80e2be2e/6a170d086f7f0468a19148cc/2084ac32fcf1fb810c8b54ecab1c85a1e3e8905b-672x1302.png" alt="" /><p>Pour terminer la configuration, cliquez sur <strong>Save &amp; test.</strong></p><p><strong>Important :</strong> Activez l'option "<strong>Enable native function calling</strong>" (activer l'appel de fonctions natives) ; cette option est nécessaire pour que l'Agent Builder fonctionne correctement. Si vous ne l'activez pas, vous obtiendrez une erreur <strong><code>No tool calls found in the response</code></strong>.</p><h3>Tester la connexion</h3><p>Elastic devrait automatiquement tester la connexion. Si tout est configuré correctement, vous obtiendrez un message de réussite comme celui-ci :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4d2e815dd558f881/6a170d090e2e49076541a177/f567d767f1969c4730c1daa92f651789dc3742ac-1042x812.png" alt="" /><p>Réponse :</p>{
  "status": "ok",
  "data": {
    "id": "chatcmpl-flj9h0hy4wcx4bfson00an",
    "object": "chat.completion",
    "created": 1761189456,
    "model": "openai/gpt-oss-20b",
    "choices": [
      {
        "index": 0,
        "message": {
          "role": "assistant",
          "content": "Hello! 👋 How can I assist you today?",
          "reasoning": "Just greet.",
          "tool_calls": []
        },
        "logprobs": null,
        "finish_reason": "stop"
      }
    ],
    "usage": {
      "prompt_tokens": 69,
      "completion_tokens": 23,
      "total_tokens": 92
    },
    "stats": {},
    "system_fingerprint": "openai/gpt-oss-20b"
  },
  "actionId": "ee1c3aaf-bad0-4ada-8149-118f52dad757"
}<h2>Étape 4 : Téléchargement des données des employés vers Elasticsearch</h2><p>Nous allons maintenant télécharger l'<a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">ensemble de données relatives aux employés des RH</a> afin de montrer comment l'agent travaille avec des données sensibles. J'ai généré un ensemble de données fictives avec cette structure.</p><h3>Structure de l'ensemble de données</h3>{
  "employee_id": "0f4dce68-2a09-4cb1-b2af-6bcb4821539b",
  "full_name": "Daffi Stiebler",
  "email": "lscutchings0@huffingtonpost.com",
  "date_of_birth": "1975-06-20T15:39:36Z",
  "hire_date": "2025-07-28T00:10:45Z",
  "job_title": "Physical Therapy Assistant",
  "department": "HR",
  "salary": "108455",
  "performance_rating": "Needs Improvement",
  "years_of_experience": 2,
  "skills": "Java",
  "education_level": "Master's Degree",
  "manager": "Carl MacGibbon",
  "emergency_contact": "Leigha Scutchings",
  "home_address": "5571 6th Park"
}<h3>Créer l'index avec les correspondances</h3><p>Tout d'abord, créez l'index avec les correspondances appropriées. Notez que nous utilisons des champs <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">semantic_text</a> pour certains champs clés ; cela permet des capacités de recherche sémantique pour notre index.</p>​​PUT hr-employees
{
  "mappings": {
    "properties": {
      "@timestamp": {
        "type": "date"
      },
      "employee_id": {
        "type": "keyword"
      },
      "full_name": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "email": {
        "type": "keyword"
      },
      "date_of_birth": {
        "type": "date",
        "format": "iso8601"
      },
      "hire_date": {
        "type": "date",
        "format": "iso8601"
      },
      "job_title": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "department": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "salary": {
        "type": "double"
      },
      "performance_rating": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "years_of_experience": {
        "type": "long"
      },
      "skills": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "education_level": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "manager": {
        "type": "text",
        "copy_to": "employee_semantic"
      },
      "emergency_contact": {
        "type": "keyword"
      },
      "home_address": {
        "type": "keyword"
      },
      "employee_semantic": {
        "type": "semantic_text"
      }
    }
  }
}<h3>Index avec Bulk API</h3><p>Copiez et collez le <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">jeu de données</a> dans votre Dev Tools dans Kibana et exécutez-le :</p>POST hr-employees/_bulk
{"index": {}}
{"employee_id": "57728b91-e5d7-4fa8-954a-2384040d3886", "full_name": "Filide Gane", "email": "vhallahan1@booking.com", "job_title": "Business Systems Development Analyst", "department": "Marketing", "salary": "$52330.27", "performance_rating": "Meets Expectations", "years_of_experience": 12, "skills": "Java", "education_level": "Bachelor's Degree", "date_of_birth": "2000-02-07T16:49:32Z", "hire_date": "2023-11-07T13:03:16Z", "manager": "Freedman Kings", "emergency_contact": "Vilhelmina Hallahan", "home_address": "75 Dennis Junction"}
{"index": {}}
{"employee_id": "...", ...}<h3>Vérifier les données</h3><p>Exécutez une requête pour vérifier :</p>GET hr-employees/_search<h2>Étape 5 : Créer et tester votre agent d'intelligence artificielle</h2><p>Une fois tout configuré, il est temps de créer un agent d'IA personnalisé à l'aide d'Elastic Agent Builder. Pour plus de détails, voir la <a href="https://www.elastic.co/docs/solutions/search/agent-builder/get-started">documentation Elastic</a>.</p><h3>Ajouter le connecteur</h3><p>Avant de pouvoir créer notre nouvel agent, nous devons configurer notre Agent builder pour qu'il utilise notre connecteur personnalisé appelé <code>LM Studio - GPT-OSS 20B</code>, car le connecteur par défaut est <a href="https://www.elastic.co/docs/reference/kibana/connectors-kibana/elastic-managed-llm">Elastic Managed LLM</a>. Pour cela, nous devons aller dans <strong>Project Setting</strong> &gt; <strong>Management</strong> &gt; <strong>GenAI Settings</strong>; nous sélectionnons alors celui que nous avons créé et cliquons sur <strong>Save.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc42f079c5e756057/6a170d0acf4f2501d9b2d1c7/11e830c3e2fb4c298b020c928fa5422f3397ba08-1600x1152.png" alt="" /><h3>Agent d'accès Constructeur</h3><ol><li><p>Aller aux <strong>agents</strong></p></li><li><p>Cliquez sur <strong>Créer un nouvel agent</strong></p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb8e734817c5a7c6a/6a170d0ca929cf867cae0a34/c1e60541563650163f972ac9088dc1ed1de759a7-1600x1054.png" alt="" /><h3>Configurer l'agent</h3><p>Pour créer un nouvel agent, les champs obligatoires sont l'<strong>identifiant de l'agent</strong>, le <strong>nom d'affichage</strong> et les <strong>instructions d'affichage.</strong></p><p>Mais il existe d'autres options de personnalisation, comme les instructions personnalisées qui indiquent comment votre agent va se comporter et interagir avec vos outils, à la manière d'une invite système, mais pour notre agent personnalisé. Les étiquettes permettent d'organiser les agents, la couleur de l'avatar et le symbole de l'avatar.</p><p>Ceux que j'ai choisis pour notre agent sur la base de l'ensemble des données sont les suivants :

<strong>Agent ID :</strong> <code>hr_assistant</code></p><p><strong>Instructions personnalisées :</strong></p>You are an HR Analytics Assistant that helps answer questions about employee data.
When responding to queries:
- Provide clear, concise answers
- Include relevant employee details (name, department, salary, skills)
- Format monetary values with currency symbols
- Be professional and maintain data confidentiality<p>
Étiquettes : <code>Human Resources</code> et <code>GPT-OSS</code></p><p>Nom d'affichage : <code>HR Analytics Assistant</code></p><p>Description de l'affichage :</p>A specialized AI assistant for Human Resources that helps analyze employee data, compensation, performance metrics, and talent management. Ask questions about employees, departments, salaries, or performance analytics.<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt23fb011e5b4f4d49/6a170d0e7d8d67f47a70e77f/f94bb2bf08497e5e756ca76b30a3a51f42927756-1424x1217.png" alt="" /><p>Une fois toutes les données saisies, nous pouvons cliquer sur <strong>Enregistrer</strong> notre nouvel agent.</p><h3>Tester l'agent</h3><p>Vous pouvez désormais poser des questions en langage naturel sur les données de vos employés, et GPT-OSS 20B comprendra l'intention et générera une réponse appropriée.</p><h4>Prompt :</h4>Which employee is the one with the highest salary in the hr-employees index?<h4>Réponse :</h4><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc0c52faacf63b583/6a170d0f0e2e497bfd41a17b/94ad19f80b96304028a59f60beca51dfc9aecc8a-899x631.png" alt="" /><p>Le processus de l'agent a été le suivant :</p><p>1. Comprendre votre question à l'aide du connecteur GPT-OSS</p><p>2. Générer la requête Elasticsearch appropriée (à l'aide des outils intégrés ou d'<a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> personnalisés)</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte32a8a7e6363c7f2/6a170d115091680077e1bb44/6f2961d0d1b97475f6dda300acee84da540938e6-844x466.png" alt="" /><p>3. Récupérer les enregistrements des salariés correspondants</p><p>4. Présenter les résultats en langage naturel avec un formatage approprié</p><p>Contrairement à la recherche lexicale traditionnelle, l'agent alimenté par GPT-OSS comprend l'intention et le contexte, ce qui facilite la recherche d'informations sans connaître les noms exacts des champs ou la syntaxe de la requête. Pour plus de détails sur le processus de réflexion de l'agent, voir cet <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance">article</a>.</p><h2>Conclusion</h2><p>Dans cet article, nous avons construit un agent d'IA personnalisé à l'aide de l'Agent Builder d'Elastic pour se connecter au modèle OpenAI GPT-OSS fonctionnant localement. En déployant à la fois Elastic et le LLM sur votre machine locale, cette architecture vous permet de tirer parti des capacités d'IA générative tout en conservant un contrôle total sur vos données, le tout sans envoyer d'informations à des services externes.</p><p>Nous avons utilisé GPT-OSS 20B à titre expérimental, mais les modèles officiellement recommandés pour Elastic Agent Builder sont référencés <a href="https://www.elastic.co/docs/solutions/search/agent-builder/models#recommended-models">ici.</a> Si vous avez besoin de capacités de raisonnement plus avancées, il existe également la <a href="https://huggingface.co/openai/gpt-oss-120b">variante de paramètre 120B</a> qui est plus performante pour les scénarios complexes, bien qu'elle nécessite une machine plus sophistiquée pour fonctionner localement. Pour plus de détails, consultez la <a href="https://openai.com/open-models/">documentation officielle d'OpenAI</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/build-an-ai-agent-hr-elastic-agent-builder-gpt-oss</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/build-an-ai-agent-hr-elastic-agent-builder-gpt-oss</guid>
    <category><![CDATA[IA agentique]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Tomás Murúa]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt664f490053e46e6b/6a170d13b0367d2d7e72bd84/05d2d0513fff67d975f9223d75108aa9f50646bc-1600x914.png" length="0" type="image/png"/>
    <pubDate>Wed, 26 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Tableaux de bord alimentés par l'IA : D'une vision à Kibana]]></title>
    <description><![CDATA[Générer un tableau de bord en utilisant un LLM pour traiter une image et la transformer en tableau de bord Kibana.
]]></description>
    <content:encoded><![CDATA[<p><a href="https://www.elastic.co/kibana/kibana-lens">Kibana Lens</a> simplifie le glisser-déposer des tableaux de bord, mais lorsque vous avez besoin de dizaines de panneaux, les clics s'accumulent. Et si vous pouviez dessiner un tableau de bord, en faire une capture d'écran et laisser un LLM terminer tout le processus à votre place ?</p><p>Dans cet article, nous allons y parvenir. Nous allons créer une application qui prend une image d'un tableau de bord, analyse nos mappings et génère un tableau de bord sans que nous ayons à toucher à Kibana !</p><p><strong>Les étapes</strong>:</p><ol><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#background-&amp;-application-workflow">Contexte &amp; flux de travail de l'application</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#prepare-data">Préparer les données</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#llm-configuration">Configuration LLM</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#application-functions">Fonctions d'application</a></p></li></ol><h2>Contexte &amp; flux de travail de l'application</h2><p>La première idée qui m'est venue à l'esprit a été de laisser le LLM générer l'ensemble des <a href="https://www.elastic.co/docs/explore-analyze/find-and-organize/saved-objects">objets sauvegardés au</a> format NDJSON dans Kibana, puis de les importer dans Kibana.</p><p>Nous avons essayé une poignée de modèles :</p><ul><li><p>Gemini 2.5 pro</p></li><li><p>GPT o3 / o4-mini-high / 4.1</p></li><li><p>Sonnet de Claude 4</p></li><li><p>Grok 3</p></li><li><p>Deepseek (Deepthink R1)</p></li></ul><p>En ce qui concerne les messages-guides, nous avons commencé par une phrase simple :</p>You are an Elasticsearch Saved-Object generator (Kibana 9.0).
INPUTS
=====
1. PNG screenshot of a 4-panel dashboard (attached).
2. Index mapping (below) – trimmed down to only the fields present in the screenshot.
3. Example NDJSON of *one* metric visualization (below) for reference.

TASK
====
Return **only** a valid NDJSON array that recreates the dashboard exactly:
* 2 metric panels (Visits, Unique Visitors)
* 1 pie chart (Most used OS)
* 1 vertical bar chart (State Geo Dest)
* Use index pattern `kibana_sample_data_logs`.
* Preserve roughly the same layout (2×2 grid).
* Use `panelIndex` values 1-4 and random `id` strings.
* Kibana version: 9.0<p>Bien que nous ayons parcouru des <a href="https://www.elastic.co/search-labs/blog/function-calling-with-elastic#:~:text=Few%2Dshot%20prompting%20involves%20providing%20examples%20of%20the%20types%20of%20queries%20you%20want%20it%20to%20return%2C%20which%20helps%20in%20increasing%20consistency.">exemples en quelques images</a> et des explications détaillées sur la manière de construire chaque visualisation, nous n'avons pas eu de chance. Si vous êtes intéressé par cette expérimentation, vous pouvez trouver des détails <a href="https://gist.github.com/TomasMurua/a78dc283e115624731beffc98984b70b">ici.</a></p><p>Le résultat de cette approche était l'apparition de ces messages lorsque l'on essayait de télécharger vers Kibana les fichiers produits par le LLM :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9ea005966a783057/6a1707d266c4f90e4ef8bf88/2b599443b5613c9f0fc3235581614add5b4b3900-891x98.png" alt="" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5e5632d6d95b998c/6a1707d3a6c2b9441de79661/d87ccfc033bc00ee8188c5cae18043fbca22784c-741x233.png" alt="" /><p>Cela signifie que le JSON généré est invalide ou mal formaté. Les problèmes les plus fréquents étaient que le LLM produisait des NDJSON incomplets, des paramètres hallucinants ou retournait du JSON normal au lieu de NDJSON, même si nous essayions de faire en sorte qu'il en soit autrement.</p><p>Inspirés par <a href="https://www.elastic.co/search-labs/blog/llm-functions-elasticsearch-intelligent-query">cet article</a> - où les <a href="https://www.elastic.co/docs/solutions/search/search-templates">modèles de recherche</a> ont mieux fonctionné que le LLM freestyle - nous avons décidé de donner des modèles au LLM au lieu de demander de générer le fichier NDJSON complet et ensuite nous, dans le code, utilisons les paramètres donnés par le LLM pour créer les visualisations appropriées.</p><p>Le processus de candidature sera le suivant :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9f7738a4c7ddd0cd/6a1707d52b835f0a25f4b166/52c587cf0cf3517fdd4ee7ab95581dd4f2bce030-725x668.png" alt="" /><p></p><p><em>Nous omettons une partie du code pour des raisons de simplicité, mais vous pouvez trouver le code de travail de l'application complète sur </em><a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/from-image-idea-to-kibana-dashboard-using-ai/from-image-idea-to-kibana-dashboard-using-ai.ipynb"><em><strong>ce</strong></em></a><em> carnet.</em></p><h2>Produits requis</h2><p>Avant de commencer à développer, vous aurez besoin des éléments suivants :</p><ol><li><p>Python 3.8 ou supérieur</p></li><li><p>Un environnement <a href="https://docs.python.org/3/library/venv.html">Venv</a> Python</p></li><li><p>Une instance Elasticsearch en cours d'exécution, ainsi que son point d'accès et sa clé API</p></li><li><p>Une clé d'API OpenAI stockée dans la variable d'environnement OPENAI_API_KEY :</p></li></ol>export OPENAI_API_KEY="your-openai-api-key"<h2>Préparer les données</h2><p>Pour les données, nous resterons simples et utiliserons les journaux web de l'échantillon Elastic. Pour savoir comment importer ces données dans votre cluster <a href="https://www.elastic.co/docs/manage-data/ingest/sample-data#add-sample-data-sets">, cliquez ici.</a></p><p>Chaque document contient des informations sur l'hôte qui a envoyé des demandes à l'application, ainsi que des informations sur la demande elle-même et l'état de sa réponse. Vous trouverez ci-dessous un exemple de document :</p>{
    "agent": "Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24",
    "bytes": 8509,
    "clientip": "70.133.115.149",
    "extension": "css",
    "geo": {
        "srcdest": "US:IT",
        "src": "US",
        "dest": "IT",
        "coordinates": {
            "lat": 38.05134111,
            "lon": -103.5106908
        }
    },
    "host": "cdn.elastic-elastic-elastic.org",
    "index": "kibana_sample_data_logs",
    "ip": "70.133.115.149",
    "machine": {
        "ram": 5368709120,
        "os": "osx"
    },
    "memory": null,
    "message": "70.133.115.149 - - [2018-08-30T23:35:31.492Z] \"GET /styles/semantic-ui.css HTTP/1.1\" 200 8509 \"-\" \"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24\"",
    "phpmemory": null,
    "referer": "http://twitter.com/error/john-phillips",
    "request": "/styles/semantic-ui.css",
    "response": 200,
    "tags": [
        "success",
        "info"
    ],
    "@timestamp": "2025-07-03T23:35:31.492Z",
    "url": "https://cdn.elastic-elastic-elastic.org/styles/semantic-ui.css",
    "utc_time": "2025-07-03T23:35:31.492Z",
    "event": {
        "dataset": "sample_web_logs"
    },
    "bytes_gauge": 8509,
    "bytes_counter": 51201128
}<p>Prenons maintenant les mappings de l'index que nous venons de charger, <code>kibana_sample_data_logs</code>:</p>INDEX_NAME = "kibana_sample_data_logs"

es_client = Elasticsearch(
    [os.getenv("ELASTICSEARCH_URL")],
    api_key=os.getenv("ELASTICSEARCH_API_KEY"),
)

result = es_client.indices.get_mapping(index=INDEX_NAME)
index_mappings = result[list(result.keys())[0]]["mappings"]["properties"]<p>Nous allons transmettre les mappings avec l'image que nous chargerons plus tard.</p><h2>Configuration LLM</h2><p>Configurons le LLM pour qu'il utilise la <a href="https://python.langchain.com/docs/concepts/structured_outputs/">sortie structurée</a> afin d'entrer une image et de recevoir un JSON contenant les informations que nous devons transmettre à notre fonction pour produire les objets JSON.</p><p>Nous installons les dépendances :</p>pip install elasticsearch pydantic langchain langchain-openai -q<p>Elasticsearch nous aidera à récupérer les <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">mappages d'index</a>. Pydantic nous permet de définir des schémas en Python pour demander au LLM de les suivre, et <a href="https://www.elastic.co/search-labs/integrations/langchain">LangChain</a> est le cadre qui facilite l'appel aux LLM et aux outils d'IA.</p><p>Nous allons créer un schéma pydantique pour définir les résultats que nous voulons obtenir du LLM. Ce que nous devons savoir à partir de l'image, c'est le type de graphique, le champ, le titre de la visualisation et le titre du tableau de bord :</p>class Visualization(BaseModel):
    title: str = Field(description="The dashboard title")
    type: List[Literal["pie", "bar", "metric"]]
    field: str = Field(
        description="The field that this visualization use based on the provided mappings"
    )


class Dashboard(BaseModel):
    title: str = Field(description="The dashboard title")
    visualizations: List[Visualization]<p>Pour la saisie de l'image, nous enverrons un tableau de bord que je viens de dessiner :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7870f6421986d11d/6a1707d78b73cb3408189fa3/36441d7b5dc1f3ff2ac2a30710208d57ad41c716-1600x898.jpg" alt="" /><p>Nous déclarons maintenant l'appel au modèle LLM et le chargement de l'image. Cette fonction recevra les mappings de l'index Elasticsearch et une image du tableau de bord que nous voulons générer.</p><p>Avec <code>with_structured_output</code>, nous pouvons utiliser notre schéma Pydantic <code>Dashboard</code> comme objet de réponse que le LLM produira. Avec <a href="https://docs.pydantic.dev/latest/">Pydantic</a>, nous pouvons définir des modèles de données avec validation, ce qui garantit que la sortie LLM correspond à la structure attendue.</p><p>Pour convertir l'image en base64 et l'envoyer en entrée, vous pouvez utiliser un <a href="https://www.base64-image.de/">convertisseur en ligne</a> ou le faire <a href="https://www.geeksforgeeks.org/python-convert-image-to-string-and-vice-versa/">en code</a>.</p>prompt = f"""
    You are an expert in analyzing Kibana dashboards from images for the version 9.0.0 of Kibana.

    You will be given a dashboard image and an Elasticsearch index mapping.

    Below are the index mappings for the index that the dashboard is based on.
    Use this to help you understand the data and the fields that are available.

    Index Mappings:
    {index_mappings}

    Only include the fields that are relevant for each visualization, based on what is visible in the image.
    """

message = [
    {
        "role": "user",
        "content": [
            {"type": "text", "text": prompt},
            {
                "type": "image",
                "source_type": "base64",
                "data": image_base64,
                "mime_type": "image/png",
            },
        ],
    }
]


try:
    llm = init_chat_model("gpt-4.1-mini")
    llm = llm.with_structured_output(Dashboard)
    dashboard_values = llm.invoke(message)

    print("Dashboard values generated by the LLM successfully")
    print(dashboard_values)
except Exception as e:
    print(f"Failed to analyze image and match fields: {str(e)}")<p>Le LLM connaît déjà le contexte des tableaux de bord Kibana, nous n'avons donc pas besoin de tout expliquer dans l'invite, juste quelques détails pour s'assurer qu'il n'oublie pas qu'il travaille avec Elasticsearch et Kibana.</p><p>Décortiquons l'invitation :</p><p>Section</p><p>Raison</p><p>Vous êtes un expert en analyse de tableaux de bord Kibana à partir d'images pour la version 9.0.0 de Kibana.</p><p>En insistant sur le fait qu'il s'agit d'Elasticsearch et de la version d'Elasticsearch, nous réduisons la probabilité que le LLM hallucine des paramètres anciens/invalides.</p><p>Vous recevrez une image de tableau de bord et un mappage d'index Elasticsearch.</p><p>Nous expliquons que l'image concerne les tableaux de bord afin d'éviter toute interprétation erronée de la part du LLM.</p><p>Vous trouverez ci-dessous les correspondances d'index pour l'index sur lequel le tableau de bord est basé, ce qui vous aidera à comprendre les données et les champs disponibles. Mappages d'index : {index_mappings}</p><p>Il est essentiel de fournir les correspondances afin que le LLM puisse sélectionner les champs valides de manière dynamique. Sinon, nous pourrions coder en dur les correspondances ici, ce qui est trop rigide, ou compter sur le fait que l'image contienne les bons noms de champs, ce qui n'est pas fiable.</p><p>N'incluez que les champs pertinents pour chaque visualisation, en fonction de ce qui est visible dans l'image.</p><p>Nous avons dû ajouter ce renforcement parce qu'il arrive que l'on essaie d'ajouter des champs qui ne sont pas pertinents pour l'image.</p><p>Cela renvoie un objet contenant un tableau de visualisations à afficher :</p>"Dashboard values generated by the LLM successfully
title=""Client, Extension, OS, and Response Keyword Analysis""visualizations="[
   "Visualization(title=""Count of Client IP",
   "type="[
      "metric"
   ],
   "field=""clientip"")",
   "Visualization(title=""Extension Keyword Distribution",
   "type="[
      "pie"
   ],
   "field=""extension.keyword"")",
   "Visualization(title=""Most Used OS",
   "type="[
      "bar"
   ],
   "field=""machine.os.keyword"")",
   "Visualization(title=""Response Keyword Distribution",
   "type="[
      "bar"
   ],
   "field=""response.keyword"")"
]<h2>Traitement de la réponse au mécanisme d'apprentissage tout au long de la vie</h2><p>Nous avons créé un exemple de tableau de bord 2x2 panneaux à l'adresseet l'avons exporté en JSON à l'aide de l'<a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-get-dashboards-dashboard">API Get a dashboard</a>, puis nous avons stocké les panneaux en tant que modèles de visualisation (camembert, barre, métrique) dans lesquels nous pouvons remplacer certains paramètres pour créer de nouvelles visualisations avec différents champs en fonction de la question.</p><p>Vous pouvez consulter les fichiers JSON du modèle <a href="https://github.com/Delacrobix/elasticsearch-labs/tree/supporting-blog-content/from-image-idea-to-kibana-dashboard-using-ai/supporting-blog-content/from-image-idea-to-kibana-dashboard-using-ai/templates"><strong>ici.</strong></a> Notez que nous avons modifié les valeurs de l'objet que nous voulons remplacer plus tard par {<code>variable_name</code>}
</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc55d69d84a08e668/6a1707d8a2929903acd00fb8/ec7e1ac0cd8b470df13e60940162b56778acb386-315x234.png" alt="" /><p>Grâce aux informations fournies par le mécanisme d'apprentissage tout au long de la vie, nous pouvons décider du modèle à utiliser et des valeurs à remplacer.</p><p><code>fill_template_with_analysis</code> recevra les paramètres pour un seul panneau, y compris le modèle JSON de la visualisation, un titre, un champ et les coordonnées de la visualisation sur la grille.</p><p>Ensuite, il remplacera les valeurs du modèle et renverra la visualisation JSON finale.</p>def fill_template_with_analysis(
    template: Dict[str, Any],
    visualization: Visualization,
    grid_data: Dict[str, Any],
):
    template_str = json.dumps(template)
    replacements = {
	 "{visualization_id}": str(uuid.uuid4()),
        "{title}": visualization.title,
        "{x}": grid_data["x"],
        "{y}": grid_data["y"],
    }

    if visualization.field:
        replacements["{field}"] = visualization.field

    for placeholder, value in replacements.items():
        template_str = template_str.replace(placeholder, str(value))

    return json.loads(template_str)<p>Pour faire simple, nous aurons des coordonnées statiques que nous assignerons aux panneaux que le LLM décidera de créer et nous produirons un tableau de bord à grille 2x2 comme l'image ci-dessus.</p># Filling templates fields
panels = []    
grid_data = [
    {"x": 0, "y": 0},
    {"x": 12, "y": 0},
    {"x": 0, "y": 12},
    {"x": 12, "y": 12},
]


i = 0

for vis in dashboard_values.visualizations:
    for vis_type in vis.type:
        template = templates.get(vis_type, templates.get("bar", {}))
        filled_panel = fill_template_with_analysis(template, vis, grid_data[i])
        panels.append(filled_panel)
        i += 1<p>En fonction du type de visualisation décidé par le LLM, nous choisirons un modèle de fichier JSON et remplacerons les informations pertinentes à l'aide de <code>fill_template_with_analysis</code> , puis nous ajouterons le nouveau panneau à un tableau que nous utiliserons ultérieurement pour créer le tableau de bord.</p><p>Lorsque le tableau de bord est prêt, nous utilisons l'<a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-post-dashboards-dashboard-id">API Create a dashboard</a> pour envoyer le nouveau fichier JSON à Kibana afin de générer le tableau de bord :
</p>try:
    dashboard_id = str(uuid.uuid4())

    # post request to create the dashboard endpoint
    url = f"{os.getenv('KIBANA_URL')}/api/dashboards/dashboard/{dashboard_id}"

    dashboard_config = {
        "attributes": {
            "title": dashboard_values.title,
            "description": "Generated by AI",
            "timeRestore": True,
            "panels": panels,  # Visualizations with the values generated by the LLM
            "timeFrom": "now-7d/d",
            "timeTo": "now",
        },
    }

    headers = {
        "Content-Type": "application/json",
        "kbn-xsrf": "true",
        "Authorization": f"ApiKey {os.getenv('ELASTICSEARCH_API_KEY')}",
    }

    requests.post(
        url,
        headers=headers,
        json=dashboard_config,
    )

    # Url to the generated dashboard
    dashboard_url = f"{os.getenv('KIBANA_URL')}/app/dashboards#/view/{dashboard_id}"

    print("Dashboard URL: ", dashboard_url)
    print("Dashboard ID: ", dashboard_id)

except Exception as e:
    print(f"Failed to create dashboard: {str(e)}")<p>Pour exécuter le script et générer le tableau de bord, exécutez la commande suivante dans la console :</p>python &lt;file_name&gt;.py<p>Le résultat final sera le suivant :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5ceffed004153a4f/6a1707d9a929cf9147ae0901/e909afbf0e47d9a6e0f7bd07dfb2efcfa5cf06ac-921x715.png" alt="" /><h2>Conclusion</h2><p>Les LLM démontrent leurs fortes capacités visuelles lorsqu'ils transforment du texte en code ou des images en code. L'API des tableaux de bord permet également de transformer des fichiers JSON en tableaux de bord, et avec un LLM et un peu de code, nous pouvons transformer des images en tableau de bord Kibana.</p><p>L'étape suivante consiste à améliorer la flexibilité des visuels des tableaux de bord en utilisant différents paramètres de grille, différentes tailles de tableau de bord et différentes positions. De plus, la prise en charge de visualisations et de types de visualisation plus complexes serait un ajout utile à cette application.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-powered-dashboards</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-powered-dashboards</guid>
    <category><![CDATA[Kibana]]></category>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Jeffrey Rengifo,Tomás Murúa]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt41727cbee6155a68/6a1707dbb0367dd2fd72bc86/eb60ceb2fbc3941745b21ae3357cbb6ea8fab18c-1443x811.png" length="0" type="image/png"/>
    <pubDate>Wed, 16 Jul 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>