<?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/de/search-labs/author/tomas-murua</link>
    </image>
    <link>https://www.elastic.co/de/search-labs/author/tomas-murua</link>
    <atom:link href="https://www.elastic.co/de/search-labs/rss/author/tomas-murua.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[de]]></language>
    <lastBuildDate>Fri, 16 Oct 2026 23:46:13 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Erstellung eines ChatGPT-Konnektors mit Elasticsearch zur Abfrage von GitHub-Issues]]></title>
    <description><![CDATA[Erfahren Sie, wie Sie einen benutzerdefinierten ChatGPT-Konnektor erstellen und einen Elasticsearch MCP-Server bereitstellen, der die hybride Suche verwendet, um interne GitHub Issues abzufragen.]]></description>
    <content:encoded><![CDATA[<p>Kürzlich hat OpenAI <a href="https://help.openai.com/en/articles/11487775-connectors-in-chatgpt">benutzerdefinierte Konnektoren</a> für ChatGPT für Pro-, Business-, Enterprise- und Edu-Abos angekündigt. Sie ergänzen die vorkonfigurierten Konnektoren zum Abrufen von Daten auf Gmail, GitHub, Dropbox usw. Es ist möglich, mithilfe von MCP-Servern benutzerdefinierte Konnektoren zu erstellen.</p><p>Benutzerdefinierte Konnektoren ermöglichen es Ihnen, Ihre vorhandenen ChatGPT-Konnektoren mit zusätzlichen Datenquellen wie Elasticsearch zu kombinieren, um umfassende Antworten zu erhalten.</p><p>In diesem Artikel werden wir einen <a href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a>-Server erstellen, der ChatGPT mit einem Elasticsearch-Index verbindet, der Informationen zu internen GitHub Issues und Pull Requests enthält. So können Abfragen in natürlicher Sprache mit Ihren Elasticsearch-Daten beantwortet werden.</p><p>Wir werden den MCP-Server mithilfe von <a href="https://gofastmcp.com/getting-started/welcome">FastMCP</a> auf Google Colab mit ngrok bereitstellen, um eine öffentliche URL zu erhalten, mit der ChatGPT eine Verbindung herstellen kann. Dadurch entfällt die Notwendigkeit einer komplexen Infrastruktureinrichtung.</p><p>Einen umfassenden Überblick über MCP und sein Ökosystem finden Sie unter <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">„Der aktuelle Stand von MCP“</a>.</p><h2>Voraussetzungen</h2><p>Vor Beginn benötigen Sie Folgendes:</p><ul><li><p>Elasticsearch-Cluster (8.X oder höher)</p></li><li><p>Elasticsearch-API-Schlüssel mit Lesezugriff auf Ihren Index</p></li><li><p>Google-Konto (für Google Colab)</p></li><li><p>Ngrok-Konto (das kostenlose Abo genügt)</p></li><li><p>ChatGPT-Konto mit Pro-, Enterprise-, Business- oder Edu-Plan</p></li></ul><h2>Die Anforderungen für ChatGPT MCP-Konnektoren verstehen</h2><p>Für die ChatGPT MCP-Konnektoren müssen zwei Tools implementiert werden: <code>search</code> und <code>fetch</code>. Weitere Einzelheiten finden Sie in den <a href="https://platform.openai.com/docs/mcp#create-an-mcp-server">OpenAI Dokumenten</a>.</p><h3><a href="https://platform.openai.com/docs/mcp#search-tool">Suchtool</a></h3><p>Gibt eine Liste relevanter Ergebnisse aus Ihrem Elasticsearch-Index auf der Grundlage einer Benutzerabfrage zurück.</p><h4>Das erhält es:</h4><ul><li><p>Eine einzelne Zeichenfolge mit der Anfrage des Benutzers in natürlicher Sprache.</p></li><li><p>Beispiel: „Finde Probleme im Zusammenhang mit der Elasticsearch-Migration.“</p></li></ul><h4>Was es zurückgibt: </h4><ul><li><p>Ein Objekt mit einem <code>result</code>-Schlüssel, der ein Array von result-Objekten enthält. Jedes Ergebnis umfasst:</p><ul><li><p><code>id</code> - Eindeutige Dokumentkennung</p></li><li><p><code>title</code> - Titel eines Issues oder Pull Requests (PR)</p></li><li><p><code>url</code> - Link zum Issue/PR</p></li></ul></li></ul><h4>In unserer Implementierung:</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">Abrufwerkzeug</a></h3><p>Ruft den vollständigen Inhalt eines bestimmten Dokuments ab.</p><h4>Das erhält es:</h4><ul><li><p>Eine einzelne Zeichenfolge mit der Elasticsearch-Dokument-ID aus dem Suchergebnis</p></li><li><p>Beispiel: „Nenne mir die Details zum PR-578.“</p></li></ul><h4>Was es zurückgibt:</h4><ul><li><p>Ein vollständiges Dokumentobjekt mit:</p><ul><li><p><code>id</code> - Eindeutige Dokumentkennung</p></li><li><p><code>title</code> - Titel eines Issues oder Pull Requests (PR)</p></li><li><p><code>text</code> - Vollständige Beschreibung und Details des Problems/PR</p></li><li><p><code>url</code> - Link zum Issue/PR</p></li><li><p><code>type</code> - Dokumenttyp (Issue, Pull-Request)</p></li><li><p><code>status</code> - Aktueller Status (offen, in Bearbeitung, abgeschlossen)</p></li><li><p><code>priority</code> - Prioritätsstufe (niedrig, mittel, hoch, kritisch)</p></li><li><p><code>assignee</code> - Person, der das Issue/der PR zugewiesen wurde</p></li><li><p><code>created_date</code> - Erstellungsdatum</p></li><li><p><code>resolved_date</code> - Wann das Issue gelöst wurde (falls zutreffend)</p></li><li><p><code>labels</code> - Mit dem Dokument verbundene Tags</p></li><li><p><code>related_pr</code> - Verwandte Pull-Request-ID</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>Hinweis</strong>: In diesem Beispiel wird eine flache Struktur verwendet, bei der sich alle Felder auf der Stammebene befinden. Die Anforderungen von OpenAI sind flexibel und unterstützen auch verschachtelte Metadatenobjekte.</p><h2>Datensatz zu GitHub Issues und Pull Requests</h2><p>Für dieses Tutorial verwenden wir einen internen GitHub Datensatz mit Issues und Pull Requests. Dies stellt ein Szenario dar, in dem Sie private, interne Daten über ChatGPT abfragen möchten.</p><p>Den Datensätze finden Sie <a href="https://gist.github.com/TomasMurua/4e7bbdf7a7ebbdffaa663c43578d934a">hier</a>. Wir werden außerdem den Index der Daten mit der <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk">Bulk-API</a> aktualisieren.</p><p>Dieser Datensatz umfasst:</p><ul><li><p>Issues mit Beschreibungen, Status, Priorität und Zuweisungen</p></li><li><p>Pull-Requests mit Codeänderungen, Bewertungen und Deployment-Informationen</p></li><li><p>Beziehungen zwischen Issues und PRs (z. B. PR-578 behebt ISSUE-1889)</p></li><li><p>Labels, Daten und andere Metadaten</p></li></ul><h3>Index-Mappings</h3><p>Der Index verwendet die folgenden <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">Mappings</a>, um die hybride Suche mit <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-elser">ELSER</a> zu unterstützen. Das <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">text_semantic</a> wird für die semantische Suche verwendet, während andere Felder die Schlüsselwortsuchen ermöglichen.</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>Den MCP-Server erstellen</h2><p>Unser MCP-Server implementiert zwei Tools gemäß den OpenAI Spezifikationen und verwendet die hybride Suche, um den semantischen und den textbasierten Abgleich für bessere Ergebnisse zu kombinieren.</p><h3>Suchtool</h3><p>Nutzt hybride Suche mit <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">RRF</a> (Reciprocal Rank Fusion), die semantische Suche mit Textabgleich kombiniert:</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>Wichtige Punkte:</h3><ul><li><p><strong>Hybride Suche mit RRF:</strong> Kombiniert semantische Suche (ELSER) und Text-Suche (BM25) für bessere Ergebnisse.</p></li><li><p><strong>Multi-Match-Abfrage:</strong> <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-multi-match-query">Sucht über mehrere Felder hinweg</a> mit Boosting (title^3, text^2, assignee^2). Das Caret-Symbol (^) multipliziert die Relevanzwerte und priorisiert dabei Treffer in Titeln gegenüber solchen im Inhalt.</p></li><li><p><strong>Fuzzy-Matching:</strong> <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/common-options#fuzziness"><code>fuzziness: AUTO</code></a> behebt Tippfehler und Rechtschreibfehler, indem es ungefähre Übereinstimmungen erlaubt.</p></li><li><p><strong>RRF-Parameterabstimmung:</strong></p><ul><li><p><code>rank_window_size: 50</code> - Legt fest, wie viele Top-Ergebnisse von jedem Retriever (semantische und textbasierte) vor dem Zusammenführen berücksichtigt werden.</p></li><li><p><code>rank_constant: 60</code> - Dieser Wert bestimmt, wie viel Einfluss Dokumente in einzelnen Ergebnismengen auf das endgültige Ranking haben.</p></li></ul></li><li><p><strong>Gibt nur die erforderlichen Felder zurück:</strong> <code>id</code>, <code>title</code>, <code>url</code> gemäß OpenAI-Spezifikation, und vermeidet das unnötige Freilegen zusätzlicher Felder.</p></li></ul><h3>Abrufwerkzeug</h3><p>Ruft Dokumentdetails anhand der Dokumenten-ID ab, sofern vorhanden:</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>Wichtige Punkte:</h3><ul><li><p><strong>Suchen nach Dokumenten-ID-Feld:</strong> Verwendet eine Begriffsabfrage im benutzerdefinierten <code>id</code>-Feld.</p></li><li><p><strong>Vollständige Rückgabe des Dokuments:</strong> Mit vollständigem <code>text</code>-Feld mit allen Inhalten</p></li><li><p><strong>Flache Struktur:</strong> Alle Felder auf der Wurzelebene, entsprechend der Dokumentstruktur von Elasticsearch.</p></li></ul><h2>Bereitstellung auf Google Colab</h2><p>Wir nutzen Google Colab, um unseren MCP-Server zu betreiben, und ngrok, um ihn öffentlich zugänglich zu machen, damit ChatGPT eine Verbindung herstellen kann.</p><h3>Schritt 1: Öffnen Sie das Google Colab Notebook</h3><p>Greifen Sie auf unser vorkonfiguriertes Notebook <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-chatgpt-connector">Elasticsearch MCP für ChatGPT</a> zu.</p><h3>Schritt 2: Konfigurieren Sie Ihre Anmeldeinformationen</h3><p>Sie benötigen drei Informationen:</p><ul><li><p><strong>Elasticsearch URL:</strong> Ihre <a href="https://www.elastic.co/docs/deploy-manage/deploy/cloud-enterprise/connect-elasticsearch">Elasticsearch-Cluster-URL</a>.</p></li><li><p><strong>Elasticsearch API-Schlüssel:</strong> <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">API-Schlüssel</a> mit Lesezugriff auf Ihren Index.</p></li><li><p><strong>Ngrok-Auth-Token:</strong> Kostenloses Token von <a href="https://ngrok.com/">ngrok</a>. Wir nutzen ngrok, um die MCP-URL im Internet sichtbar zu machen, damit ChatGPT sich damit verbinden kann.</p></li></ul><h4>So erhalten Sie Ihr ngrok-Token</h4><ol><li><p>Registrieren Sie sich für ein kostenloses Konto bei <a href="https://ngrok.com/">ngrok</a></p></li><li><p>Gehe zu Ihrem <a href="https://dashboard.ngrok.com/">Dashboard</a></p></li><li><p>Kopieren Sie Ihr Authentifizierungs-Token</p></li></ol><h4>Secrets zu Google Colab hinzufügen</h4><p>Im Google Colab-Notizbuch:</p><ol><li><p>Klicken Sie auf das <strong>Schlüsselsymbol </strong>in der linken Seitenleiste, um <strong>Secrets</strong> zu öffnen.</p></li><li><p>Fügen Sie diese drei Secrets hinzu:</p></li></ol>ELASTICSEARCH_URL=https://your-cluster.elastic.com:443
ELASTICSEARCH_API_KEY=your-api-key
NGROK_TOKEN=your-ngrok-token<p>3. Aktivieren Sie den Notebook-Zugriff für jedes Secret.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5acae97b386277f8/6a17f08f5ea30f74c964b6c2/d5dd6ac19fe816a562c6351fdb0f11369da0e877-609x321.jpg" alt="Hinzufügen von Geheimnissen zu Google Collab" /><h3>Schritt 3: Führen Sie das Notebook aus</h3><ol><li><p>Klicken Sie auf <strong>Runtime</strong> und dann auf <strong>alle ausführen</strong>, um alle Zellen auszuführen.</p></li><li><p>Warten Sie, bis der Server startet (etwa 30 Sekunden)</p></li><li><p>Suchen Sie nach der Ausgabe, die Ihre öffentliche ngrok-URL anzeigt.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdd11aacf2deab67c/6a17f091e8fbce81f13a1a41/f185100e8869624bc9e1c7b2b4eb32785e2d89e7-1189x283.png" alt="" /><p>4. Die Ausgabe sieht in etwa so aus:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8891d917fdbaaf48/6a17f092abe0f208c7dfeaf6/e02e625e91ed9136454e4401b184575fb03a336e-1052x465.jpg" alt="Die Ausgabe der Ausführung eines Notebooks in Google Collab" /><h2>Mit ChatGPT verbinden</h2><p>Nun verbinden wir den MCP-Server mit Ihrem ChatGPT-Konto.</p><ol><li><p>Öffnen Sie ChatGPT und gehen Sie zu <strong>Einstellungen</strong>.</p></li><li><p>Navigieren Sie zu <strong>Konnektoren. </strong>Wenn Sie ein Pro-Konto nutzen, müssen Sie den <a href="https://platform.openai.com/docs/guides/developer-mode">Entwicklermodus</a> in den Konnektoren aktivieren.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt95efdcb2c39307e7/6a17f094abe0f24d8edfeafa/32c02192912fc0e7e5a52e9399077ba7ae3b4901-739x715.png" alt="Verbindung des MPC-Servers mit einem ChatGPT-Konto" /><p><em>Wenn Sie ChatGPT Enterprise oder Business verwenden, müssen Sie den Konnektor an Ihrem Workspace veröffentlichen.</em></p><p>3. Klicken Sie auf <strong>Erstellen.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4c8fc8dd6033918/6a17f095631730de19585b7b/15c53e5ccc381108a9dc0052cca05bf0fc97679a-755x683.png" alt="Hinzufügen eines Konnektors zu ChatGPT" /><p><em><strong>Hinweis</strong></em><em>: In Business-, Enterprise- und Edu-Workspaces können nur Workspace-Inhaber, Administratoren sowie Benutzer, bei denen die entsprechende Einstellung aktiviert ist (für Enterprise/Edu), benutzerdefinierte Konnektoren hinzufügen. Benutzer mit der regulären Mitgliederrolle sind nicht berechtigt, selbst benutzerdefinierte Konnektoren hinzuzufügen.</em></p><p><em>Sobald ein Konnektor von einem Benutzer mit der Inhaber- oder Admin-Rolle hinzugefügt und aktiviert wurde, kann er von allen Mitgliedern des Workspaces verwendet werden.</em></p><p>4. Geben Sie die erforderlichen Informationen ein sowie Ihre ngrok-URL, die mit <code>/sse/</code> endet. Beachten Sie den „/“ nach „sse“. Ohne diesen funktioniert es nicht:</p><ul><li><p><strong>Name:</strong> Elasticsearch MCP</p></li><li><p><strong>Beschreibung: </strong>Benutzerdefiniertes MCP zum Suchen und Abrufen von internen GitHub-Informationen.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd716ad0beeeb1d35/6a17f09714d90c11cc79b6d7/162a85705cc8ac48a3f2f665551d513e0719f93d-479x684.png" alt="Erstellen eines elastischen MCP-Steckers " /><p>5. Klicken Sie auf <strong>Erstellen</strong>, um das benutzerdefinierte MCP zu speichern.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857794237d7d3b5a/6a17f0983e03d729b74f2d54/97eb5fb0a32b86bfadfb35561f698616f217c049-913x629.png" alt="Speichern des benutzerdefinierten MCP-Konnektors durch Klicken auf „Erstellen“." /><p>Die Verbindung ist sofort hergestellt, wenn Ihr Server läuft. Keine zusätzliche Authentifizierung ist erforderlich, da der Elasticsearch-API-Schlüssel auf Ihrem Server konfiguriert ist.</p><h2>Teste den MCP-Server</h2><p>Bevor Sie Fragen stellen, müssen Sie auswählen, welchen Konnektor ChatGPT verwenden soll.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" alt="Auswahl des Konnektors, den ChatGPT verwenden soll" /><h3>Aufforderung 1: Nach Problemen suchen</h3><p>Anfrage: „<strong>Finde Probleme im Zusammenhang mit der Elasticsearch-Migration“ </strong>und bestätigen Sie die Aktionen des aufgerufenen Tools.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6c204ceacf897f61/6a17f09c9da390fb1de4657d/cfd781acbff8cd7c8095bbe29224f8b26d581f77-650x375.png" alt="ChatGPT wird aufgefordert, „Probleme im Zusammenhang mit der Elasticsearch-Migration zu finden“, und die Aktionen des aufgerufenen Tools werden bestätigt." /><p>ChatGPT wird das Tool <code>search</code> mit Ihrer Abfrage aufrufen. Sie können sehen, dass es nach verfügbaren Tools sucht, sich darauf vorbereitet, das Elasticsearch-Tool aufzurufen. Vor jeglichen Aktionen gegenüber dem Tool wird die Bestätigung des Benutzers eingeholt.</p><h4>Anfrage zum Aufruf des Tools:</h4>{
  "query": "Elasticsearch migration issues"
}<h4>Reaktion des Tools:</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 verarbeitet die Ergebnisse und präsentiert sie in einem natürlichen, gesprächsorientierten Format.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b4378e7d26b4ad0/6a17f09ddbb4ff4de1fb57bf/9d5b6cff85c7e54ccc2584b8ae96d45495fae8c1-923x1352.png" alt="Wie ChatGPT die Ergebnisse der Tool-Aufrufanfrage und der Tool-Aufrufantwort verarbeitet" /><h3>Hinter den Kulissen</h3><h4>Prompt: „Finde Probleme im Zusammenhang mit der Elasticsearch-Migration.“</h4><p>1. ChatGPT-Anrufe <code>search(“Elasticsearch migration”)</code></p><p>2. Elasticsearch führt eine hybride Suche durch.</p><ul><li><p>Die <strong>semantische Suche</strong> versteht Konzepte wie „Upgrade“ und „<em>Versionskompatibilität“.</em></p></li><li><p><strong>Die Textsuche</strong> findet exakte Treffer für „<em>Elasticsearch</em>“ und „Migration“.</p></li><li><p><strong>RRF</strong> kombiniert und bewertet Ergebnisse beider Ansätze</p></li></ul><p>3. Sie gibt die 10 am besten mit <code>id</code>, <code>title</code>, übereinstimmenden Ergebnisse zurück <code>url</code></p><p>4. ChatGPT identifiziert „<em>ISSUE-1712: Migration von Elasticsearch 7.x auf 8.x</em>“ als relevantestes Ergebnis.</p><h3>Prompt 2: Nenne mir die vollständigen Details</h3><p>Anfrage: <em><strong>„Nenne mir die Details zu ISSUE-1889“</strong></em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d1a53db8bfe8326/6a17f09f445de966104d021a/5c0db5245535ce67a36056e61e135bddc97ce496-934x629.png" alt="ChatGPT erkennt, dass Sie detaillierte Informationen zu einem bestimmten Problem wünschen, und ruft das entsprechende Tool auf, um sich vor der Durchführung von Aktionen mit dem Benutzer abzustimmen." /><p>ChatGPT erkennt, dass Sie detaillierte Informationen zu einem bestimmten Problem wünschen, ruft das Tool <code>fetch</code> auf holt beim Benutzer die Bestätigung ein, bevor Maßnahmen gegen das Tool ergriffen werden.</p><h4>Anfrage zum Aufruf des Tools:</h4>{
  "id": "ISSUE-1889"
}<h4>Reaktion des Tools:</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 fasst die Informationen zusammen und präsentiert sie übersichtlich.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt560958fa3bd212d0/6a17f0a0faa91355ba93c974/410f19f213e94fc4e3c47eeef6e04b69e0c86159-602x462.png" alt="Wie ChatGPT die Informationen synthetisiert und präsentiert " /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcccf35a584e8373b/6a17f0a2505ac3471cad8c2e/54d8ffa117628a1e3afc317c3ab75d4f7731d7ab-767x1600.png" alt="Wie ChatGPT die Informationen präsentiert" /><h3>Hinter den Kulissen</h3><h4>Prompt: „Nenne mir die Details von ISSUE-1889“</h4><ol><li><p>ChatGPT-Anrufe <code>fetch(“ISSUE-1889”)</code></p></li><li><p>Elasticsearch ruft das vollständige Dokument ab</p></li><li><p>Gibt ein vollständiges Dokument mit allen Feldern auf der Stammebene zurück</p></li><li><p>ChatGPT synthetisiert die Informationen und antwortet mit korrekten Zitaten.</p></li></ol><h2>Fazit</h2><p>In diesem Artikel haben wir einen maßgeschneiderten MCP-Server erstellt, der ChatGPT mit Elasticsearch über spezielle <strong>Such-</strong> und <strong>Abruf-</strong>-MCP-Tools verbindet und so natürliche Sprachanfragen zu privaten Daten ermöglicht.</p><p>Dieses MCP-Muster funktioniert für jeden Elasticsearch-Index, jede Dokumentation, jedes Produkt, jedes Log oder andere Daten, die Sie über natürliche Sprache abfragen möchten.</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[Agentische KI]]></category>
    <category><![CDATA[Hybride Suche]]></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[Entwicklung eines KI-Agenten für die Personalabteilung mit Elastic Agent Builder und GPT-OSS]]></title>
    <description><![CDATA[Erfahren Sie, wie Sie mit Elastic Agent Builder und GPT-OSS einen KI-Agenten erstellen, der in natürlicher Sprache Anfragen zu Ihren Mitarbeiter-HR-Daten beantworten kann.]]></description>
    <content:encoded><![CDATA[<h2>Einleitung</h2><p>Dieser Artikel zeigt Ihnen, wie Sie mit <a href="https://openai.com/index/introducing-gpt-oss/">GPT-OSS</a> und Elastic Agent Builder einen KI-Agenten für HR erstellen. Der Agent kann Ihre Fragen beantworten, ohne Daten an OpenAI, Anthropic oder einen externen Dienst zu senden.</p><p>Wir werden LM Studio verwenden, um GPT-OSS lokal bereitzustellen und es mit dem Elastic Agent Builder zu verbinden.</p><p>Am Ende dieses Artikels verfügen Sie über einen individuell angepassten KI-Agenten, der Fragen in natürlicher Sprache zu Ihren Mitarbeiterdaten beantworten kann und gleichzeitig die volle Kontrolle über Ihre Informationen und Ihr Modell behält.</p><h2>Voraussetzungen</h2><p>Für diesen Artikel benötigen Sie:</p><ul><li><p><a href="https://www.elastic.co/cloud">Elastic Cloud-</a> gehostete Version 9.2, serverlose oder <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">lokale</a> Bereitstellung</p></li><li><p>Empfohlen wird ein Rechner mit 32 GB RAM (mindestens 16 GB für GPT-OSS 20B).</p></li><li><p><a href="https://lmstudio.ai/">LM Studio</a> installiert</p></li><li><p><a href="https://www.docker.com/products/docker-desktop/">Docker Desktop</a> installiert</p></li></ul><h2>Warum GPT-OSS verwenden?</h2><p>Mit einem lokalen LLM haben Sie die Kontrolle, es in Ihrer eigenen Infrastruktur einzusetzen und es genau an Ihre Bedürfnisse anzupassen. All dies, während Sie die Kontrolle über die Daten behalten, die Sie mit dem Modell teilen, und natürlich müssen Sie keine Lizenzgebühr an einen externen Anbieter zahlen.</p><p>OpenAI <a href="https://openai.com/index/introducing-gpt-oss/">veröffentlichte GPT-OSS</a> am 5. August 2025 als Teil seines Engagements für das offene Ökosystem von Computermodellen.</p><p>Das Parametermodell 20B bietet:</p><ul><li><p><strong>Werkzeugnutzungsfähigkeiten</strong></p></li><li><p><strong>Effiziente Schlussfolgerung</strong></p></li><li><p><strong>OpenAI SDK-kompatibel</strong></p></li><li><p><strong>Kompatibel mit agentenbasierten Workflows</strong></p></li></ul><p>Vergleich der Benchmarks:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt58fab956edb40412/6a170cfcb0367da43a72bd80/29160e3345352088e8213297630882f252b00c47-1600x680.png" alt="" /><h2>Lösungsarchitektur</h2><p>Die Architektur läuft vollständig auf Ihrem lokalen Rechner. Elastic (läuft in Docker) kommuniziert direkt mit Ihrem lokalen LLM über LM Studio, und der Elastic Agent Builder nutzt diese Verbindung, um benutzerdefinierte KI-Agenten zu erstellen, die Ihre Mitarbeiterdaten abfragen können.</p><p>Weitere Einzelheiten entnehmen Sie bitte dieser <a href="https://www.elastic.co/docs/solutions/observability/connect-to-own-local-llm">Dokumentation</a>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80db5bb0a797f51b/6a170cfd0e2e492f2c41a16f/a4a886750ff25fa8bb7aefc7448161e52cf73ed3-1600x896.png" alt="" /><h2>Entwicklung eines KI-Agenten für die Personalabteilung: Schritte</h2><p>Wir werden die Implementierung in 5 Schritte unterteilen:</p><ol><li><p>Konfigurieren Sie LM Studio mit einem lokalen Modell</p></li><li><p>Lokalen Elastic-Speicher mit Docker bereitstellen</p></li><li><p>Erstellen Sie den OpenAI-Konnektor in Elastic</p></li><li><p>Mitarbeiterdaten in Elasticsearch hochladen</p></li><li><p>Erstellen und testen Sie Ihren KI-Agenten</p></li></ol><h2>Schritt 1: LM Studio mit GPT-OSS 20B konfigurieren</h2><p>LM Studio ist eine benutzerfreundliche Anwendung, mit der Sie große Sprachmodelle lokal auf Ihrem Computer ausführen können. Es bietet einen OpenAI-kompatiblen API-Server, wodurch die Integration mit Tools wie Elastic ohne komplexen Einrichtungsprozess vereinfacht wird. Weitere Details finden Sie in der <a href="https://lmstudio.ai/docs/app">LM Studio-Dokumentation</a>.</p><p>Laden Sie zunächst LM Studio von der offiziellen Website herunter und installieren Sie es. Nach der Installation öffnen Sie die Anwendung.</p><h3>In der LM Studio-Oberfläche:</h3><ol><li><p>Gehen Sie zum Suchfeld und suchen Sie nach „GPT-OSS“.</p></li><li><p>Wählen Sie <code>openai/gpt-oss-20b</code> aus OpenAI aus.</p></li><li><p>Klicken Sie auf „Herunterladen“.</p></li></ol><p>Die Größe dieses Modells sollte ungefähr <strong>12,10 GB</strong> betragen. Der Download kann je nach Ihrer Internetverbindung einige Minuten dauern.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2dc341a6625e34b7/6a170cff839dfa2eb4dcff44/5d01bc4dcb377b5259fc6b521fe2425a31b90ca4-1312x872.png" alt="" /><h4>Sobald das Modell heruntergeladen ist:</h4><ol><li><p>Wechseln Sie zur Registerkarte „Lokaler Server“.</p></li><li><p>Wählen Sie openai/gpt-oss-20b aus.</p></li><li><p>Verwenden Sie den Standardport 1234.</p></li><li><p>Gehen Sie im rechten Bereich auf <strong>„Laden“</strong>und stellen Sie die Kontextlänge auf <strong>40 KB</strong> oder höher ein.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3704ca1b28465cc4/6a170d00d7c022ed8fde64ef/e546033f916381647b876815b2c1f1ae2a08365f-326x337.png" alt="" /><p>5. Klicken Sie auf „Server starten“.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7b9170a4945ff857/6a170d0266c4f9ffadf8c0a6/28ee78a3caa84d14e04db3d42f30acbe4d4d005a-1312x872.png" alt="" /><p>Dies sollte Ihnen angezeigt werden, wenn der Server läuft.</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>Schritt 2: Lokalen Elastic-Speicher mit Docker bereitstellen</h2><p>Nun richten wir Elasticsearch und Kibana lokal mit Docker ein. Elastic stellt ein praktisches Skript zur Verfügung, das den gesamten Einrichtungsprozess übernimmt. Für weitere Einzelheiten verweisen wir auf die <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">offizielle Dokumentation</a>.</p><h3>Führen Sie das Start-Lokal-Skript aus</h3><p>Führen Sie folgenden Befehl in Ihrem Terminal aus:</p>curl -fsSL https://elastic.co/start-local | sh<p>Dieses Skript wird:</p><ul><li><p>Elasticsearch und Kibana herunterladen und konfigurieren</p></li><li><p>Starten Sie beide Dienste mit Docker Compose.</p></li><li><p>Automatische Aktivierung einer 30-tägigen Platinum-Testlizenz</p></li></ul><h3>Erwartete Ausgabe</h3><p>Warten Sie einfach auf die folgende Meldung und speichern Sie das angezeigte Passwort und den API-Schlüssel; Sie benötigen diese für den Zugriff auf 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>Zugriff auf Kibana</h3><p>Öffnen Sie Ihren Browser und navigieren Sie zu:</p>http://localhost:5601<p>Melden Sie sich mit den Anmeldeinformationen an, die Sie in der Terminalausgabe erhalten haben.</p><h3>Agent Builder aktivieren</h3><p>Nach dem Einloggen in Kibana navigieren Sie zu <strong>Management </strong>&gt;<strong> AI </strong>&gt;<strong> Agent Builder </strong>und aktivieren den Agent Builder.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a934bd99fa6a0ce/6a170d046234e019c3db1a5a/92e104cb846c20d875865ded8a3d37f5c7daae9b-1491x1528.png" alt="" /><h2>Schritt 3: Erstellen Sie den OpenAI-Konnektor in Elastic</h2><p>Nun konfigurieren wir Elastic so, dass es Ihr lokales LLM verwendet.</p><h3>Zugangsanschlüsse</h3><ol><li><p>In Kibana</p></li><li><p>Gehen Sie zu <strong>Projekteinstellungen</strong> &gt; <strong>Verwaltung</strong></p></li><li><p>Unter <strong>„Warnungen und Einblicke“</strong> wählen Sie <strong>„Konnektoren“</strong>aus.</p></li><li><p>Klicken Sie auf „Connector erstellen“.</p></li></ol><h3>Konfigurieren Sie den Anschluss</h3><p>Wählen Sie <strong>OpenAI</strong> aus der Liste der Konnektoren aus. LM Studio nutzt das OpenAI SDK und ist daher kompatibel.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt762023c39781eb78/6a170d06a29299a59ed01087/5ac87042e086c7a2bd47a8039e646ec831f0dcc6-923x974.png" alt="" /><p>Füllen Sie die Felder mit diesen Werten aus:</p><ul><li><p><strong>Anschlussname: </strong>LM Studio - GPT-OSS 20B</p></li><li><p><strong>Wählen Sie einen OpenAI-Anbieter: </strong>Andere (OpenAI-kompatibler Dienst)</p></li><li><p><strong>URL: </strong><code>http://host.docker.internal:1234/v1/chat/completions</code></p></li><li><p><strong>Standardmodell: </strong>openai/gpt-oss-20b</p></li><li><p><strong>API-Schlüssel:</strong> testkey-123 (Jeder beliebige Text funktioniert, da LM Studio Server keine Authentifizierung erfordert.)</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt980e595f80e2be2e/6a170d086f7f0468a19148cc/2084ac32fcf1fb810c8b54ecab1c85a1e3e8905b-672x1302.png" alt="" /><p>Klicken Sie zum Abschluss der Konfiguration auf <strong>Speichern &amp; Testen</strong>.</p><p><strong>Wichtig:</strong> Aktivieren Sie die Option „ <strong>Native Funktionsaufrufe aktivieren</strong>“; dies ist erforderlich, damit der Agent Builder ordnungsgemäß funktioniert. Wenn Sie dies nicht aktivieren, erhalten Sie einen <strong><code>No tool calls found in the response</code></strong> -Fehler.</p><h3>Testen Sie die Verbindung</h3><p>Elastic sollte die Verbindung automatisch testen. Wenn alles korrekt konfiguriert ist, wird eine Erfolgsmeldung wie diese angezeigt:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4d2e815dd558f881/6a170d090e2e49076541a177/f567d767f1969c4730c1daa92f651789dc3742ac-1042x812.png" alt="" /><p>Abwehr:</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>Schritt 4: Mitarbeiterdaten in Elasticsearch hochladen</h2><p>Nun laden wir den <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">HR-Mitarbeiterdatensatz</a> hoch, um zu demonstrieren, wie der Agent mit sensiblen Daten arbeitet. Ich habe einen fiktiven Datensatz mit dieser Struktur generiert.</p><h3>Struktur des Datensatzes</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>Erstellen Sie den Index mit Zuordnungen</h3><p>Zuerst muss der Index mit den entsprechenden Zuordnungen erstellt werden. Beachten Sie, dass wir für einige Schlüsselfelder <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">semantische</a> Textfelder verwenden; dies ermöglicht semantische Suchfunktionen für unseren 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>Indexierung mit Bulk-API</h3><p>Kopieren Sie den <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">Datensatz</a> in Ihre Entwicklertools in Kibana und führen Sie ihn aus:</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>Überprüfen Sie die Daten.</h3><p>Führen Sie eine Abfrage zur Überprüfung durch:</p>GET hr-employees/_search<h2>Schritt 5: KI-Agent erstellen und testen</h2><p>Nachdem alles konfiguriert ist, ist es nun an der Zeit, mit dem Elastic Agent Builder einen benutzerdefinierten KI-Agenten zu erstellen. Weitere Details finden Sie in der <a href="https://www.elastic.co/docs/solutions/search/agent-builder/get-started">Elastic-Dokumentation</a>.</p><h3>Fügen Sie den Verbinder hinzu.</h3><p>Bevor wir unseren neuen Agenten erstellen können, müssen wir unseren Agent Builder so einstellen, dass er unseren benutzerdefinierten Konnektor mit der Bezeichnung <code>LM Studio - GPT-OSS 20B</code> verwendet, da der Standardkonnektor <a href="https://www.elastic.co/docs/reference/kibana/connectors-kibana/elastic-managed-llm">Elastic Managed LLM</a> ist. Dazu müssen wir zu <strong>Projekteinstellungen</strong> &gt; <strong>Verwaltung</strong> &gt; <strong>GenAI-Einstellungen</strong> gehen; jetzt wählen wir die von uns erstellte Einstellung aus und klicken auf <strong>Speichern</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc42f079c5e756057/6a170d0acf4f2501d9b2d1c7/11e830c3e2fb4c298b020c928fa5422f3397ba08-1600x1152.png" alt="" /><h3>Zugriffsagenten-Generator</h3><ol><li><p>Gehen Sie zu <strong>den Agenten.</strong></p></li><li><p>Klicken Sie auf <strong>„Neuen Agenten erstellen“.</strong></p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb8e734817c5a7c6a/6a170d0ca929cf867cae0a34/c1e60541563650163f972ac9088dc1ed1de759a7-1600x1054.png" alt="" /><h3>Konfigurieren Sie den Agenten</h3><p>Zum Anlegen eines neuen Agenten sind die Felder <strong>Agenten-ID</strong>, <strong>Anzeigename</strong> und <strong>Anzeigeanweisungen</strong> erforderlich.</p><p>Es gibt aber noch weitere Anpassungsmöglichkeiten, wie zum Beispiel die benutzerdefinierten Anweisungen, die vorgeben, wie sich Ihr Agent verhalten und mit Ihren Tools interagieren soll, ähnlich einer Systemaufforderung, aber für unseren benutzerdefinierten Agenten. Mithilfe von Labels lassen sich Agenten, Avatarfarben und Avatarsymbole organisieren.</p><p>Diejenigen, die ich anhand des Datensatzes für unseren Agenten ausgewählt habe, sind:

<strong>Agenten-ID:</strong> <code>hr_assistant</code></p><p><strong>Benutzerdefinierte Anweisungen:</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>
Labels: <code>Human Resources</code> und <code>GPT-OSS</code></p><p>Anzeigename: <code>HR Analytics Assistant</code></p><p>Anzeigebeschreibung:</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>Nachdem alle Daten eingegeben wurden, können wir auf „Unseren neuen Agenten <strong>speichern</strong> “ klicken.</p><h3>Testen Sie den Agenten</h3><p>Sie können nun Fragen in natürlicher Sprache zu Ihren Mitarbeiterdaten stellen, und GPT-OSS 20B versteht die Absicht und generiert eine angemessene Antwort.</p><h4>Prompt:</h4>Which employee is the one with the highest salary in the hr-employees index?<h4>Antwort:</h4><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc0c52faacf63b583/6a170d0f0e2e497bfd41a17b/94ad19f80b96304028a59f60beca51dfc9aecc8a-899x631.png" alt="" /><p>Der Agentenprozess war wie folgt:</p><p>1. Verstehen Sie Ihre Frage mithilfe des GPT-OSS-Connectors.</p><p>2. Generieren Sie die entsprechende Elasticsearch-Abfrage (mithilfe der integrierten Tools oder einer benutzerdefinierten <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL-</a> Abfrage).</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte32a8a7e6363c7f2/6a170d115091680077e1bb44/6f2961d0d1b97475f6dda300acee84da540938e6-844x466.png" alt="" /><p>3. Abrufen passender Mitarbeiterdatensätze</p><p>4. Die Ergebnisse in natürlicher Sprache und mit geeigneter Formatierung präsentieren</p><p>Im Gegensatz zur herkömmlichen lexikalischen Suche versteht der von GPT-OSS unterstützte Agent Absicht und Kontext, wodurch es einfacher wird, Informationen zu finden, ohne die genauen Feldnamen oder die Abfragesyntax kennen zu müssen. Weitere Einzelheiten zum Denkprozess des Agenten finden Sie in diesem <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance">Artikel</a>.</p><h2>Fazit</h2><p>In diesem Artikel haben wir mithilfe des Agent Builders von Elastic einen benutzerdefinierten KI-Agenten erstellt, um eine Verbindung zum lokal laufenden OpenAI GPT-OSS-Modell herzustellen. Durch die Bereitstellung von Elastic und LLM auf Ihrem lokalen Rechner ermöglicht Ihnen diese Architektur die Nutzung generativer KI-Funktionen bei gleichzeitiger vollständiger Kontrolle über Ihre Daten, ohne dass Informationen an externe Dienste gesendet werden müssen.</p><p>Wir haben GPT-OSS 20B als Experiment verwendet, aber die offiziell empfohlenen Modelle für Elastic Agent Builder sind <a href="https://www.elastic.co/docs/solutions/search/agent-builder/models#recommended-models">hier</a> aufgeführt. Falls Sie fortgeschrittenere Schlussfolgerungsfähigkeiten benötigen, gibt es auch die <a href="https://huggingface.co/openai/gpt-oss-120b">120B-Parametervariante</a> , die bei komplexen Szenarien besser abschneidet, allerdings ist für die lokale Ausführung ein leistungsstärkerer Rechner erforderlich. Weitere Einzelheiten finden Sie in der <a href="https://openai.com/open-models/">offiziellen OpenAI-Dokumentation</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[Agentische KI]]></category>
    <category><![CDATA[KI]]></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[KI-gestützte Dashboards: Von der Vision zu Kibana]]></title>
    <description><![CDATA[Generieren Sie ein Dashboard mithilfe eines LLM, um ein Bild zu verarbeiten und in ein Kibana-Dashboard umzuwandeln.
]]></description>
    <content:encoded><![CDATA[<p><a href="https://www.elastic.co/kibana/kibana-lens">Kibana Lens</a> macht das Erstellen von Dashboards per Drag &amp; Drop sehr einfach, aber wenn man Dutzende von Panels benötigt, summieren sich die Klicks. Was wäre, wenn Sie ein Dashboard skizzieren, einen Screenshot davon machen und einen LLM den gesamten Prozess für Sie abschließen lassen könnten?</p><p>In diesem Artikel werden wir genau das tun. Wir werden eine Anwendung erstellen, die ein Bild eines Dashboards aufnimmt, unsere Mappings analysiert und anschließend ein Dashboard generiert, ohne dass wir Kibana überhaupt berühren müssen!</p><p><strong>Schritte</strong>:</p><ol><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#background-&amp;-application-workflow">Hintergrund und Anwendungsablauf</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#prepare-data">Daten vorbereiten</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#llm-configuration">LLM-Konfiguration</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#application-functions">Anwendungsfunktionen</a></p></li></ol><h2>Hintergrund und Anwendungsablauf</h2><p>Mein erster Gedanke war, den LLM das gesamte NDJSON-Format der in Kibana <a href="https://www.elastic.co/docs/explore-analyze/find-and-organize/saved-objects">gespeicherten Objekte</a> generieren zu lassen und sie dann in Kibana zu importieren.</p><p>Wir haben eine Handvoll Modelle ausprobiert:</p><ul><li><p>Gemini 2.5 Pro</p></li><li><p>GPT o3 / o4-mini-hoch / 4.1</p></li><li><p>Claude 4 Sonett</p></li><li><p>Grok 3</p></li><li><p>Deepseek (Deepthink R1)</p></li></ul><p>Und als Anregungen begannen wir mit ganz einfachen Dingen:</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>Trotz der Durchsicht <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.">einiger weniger Beispiele</a> und detaillierter Erklärungen zum Aufbau der einzelnen Visualisierungen hatten wir keinen Erfolg. Wenn Sie an diesem Experiment interessiert sind, finden Sie <a href="https://gist.github.com/TomasMurua/a78dc283e115624731beffc98984b70b">hier</a> weitere Informationen.</p><p>Das Ergebnis dieser Vorgehensweise war, dass beim Versuch, die vom LLM erzeugten Dateien in Kibana hochzuladen, diese Meldungen angezeigt wurden:</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>Das bedeutet, dass das generierte JSON ungültig oder schlecht formatiert ist. Die häufigsten Probleme waren, dass der LLM unvollständiges NDJSON erzeugte, Parameter falsch interpretierte oder normales JSON anstelle von NDJSON zurückgab, egal wie sehr wir uns bemühten, das Gegenteil zu erzwingen.</p><p>Inspiriert von <a href="https://www.elastic.co/search-labs/blog/llm-functions-elasticsearch-intelligent-query">diesem Artikel</a> – in dem <a href="https://www.elastic.co/docs/solutions/search/search-templates">Suchvorlagen</a> besser funktionierten als LLM Freestyle – entschieden wir uns, dem LLM Vorlagen zu übergeben, anstatt die vollständige NDJSON-Datei generieren zu lassen und anschließend im Code die vom LLM bereitgestellten Parameter zur Erstellung der Visualisierungen zu verwenden. Dieser Ansatz hat sich bewährt und ist vorhersehbar und erweiterbar, da nun der Code und nicht mehr das LLM die Hauptarbeit übernimmt.</p><p>Der Bewerbungsprozess wird wie folgt ablaufen:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9f7738a4c7ddd0cd/6a1707d52b835f0a25f4b166/52c587cf0cf3517fdd4ee7ab95581dd4f2bce030-725x668.png" alt="" /><p></p><p><em>Der Einfachheit halber lassen wir einige Codeabschnitte weg, aber den vollständigen, lauffähigen Code der Anwendung finden Sie in </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>diesem</strong></em></a><em> Notebook.</em></p><h2>Voraussetzungen</h2><p>Bevor Sie mit der Entwicklung beginnen, benötigen Sie Folgendes:</p><ol><li><p>Python 3.8 oder höher</p></li><li><p>Eine <a href="https://docs.python.org/3/library/venv.html">Venv</a> Python-Umgebung</p></li><li><p>Eine laufende Elasticsearch-Instanz, zusammen mit ihrem Endpunkt und API-Schlüssel</p></li><li><p>Ein OpenAI-API-Schlüssel, der unter dem Umgebungsvariablennamen OPENAI_API_KEY gespeichert ist:</p></li></ol>export OPENAI_API_KEY="your-openai-api-key"<h2>Daten vorbereiten</h2><p>Für die Daten halten wir es einfach und verwenden Elastic-Beispiel-Weblogs. <a href="https://www.elastic.co/docs/manage-data/ingest/sample-data#add-sample-data-sets">Hier</a> erfahren Sie, wie Sie diese Daten in Ihren Cluster importieren.</p><p>Jedes Dokument enthält Angaben zum Host, der die Anfragen an die Anwendung gestellt hat, sowie Informationen zur Anfrage selbst und deren Antwortstatus. Nachfolgend finden Sie ein Beispieldokument:</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>Nun holen wir uns die Zuordnungen des soeben geladenen Index, <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>Wir werden die Zuordnungen zusammen mit dem Bild übergeben, das wir später laden werden.</p><h2>LLM-Konfiguration</h2><p>Konfigurieren wir das LLM so, dass es <a href="https://python.langchain.com/docs/concepts/structured_outputs/">strukturierte Ausgabe</a> verwendet, um ein Bild einzugeben und ein JSON mit den Informationen zu erhalten, die wir an unsere Funktion übergeben müssen, um die JSON-Objekte zu erzeugen.</p><p>Wir installieren die Abhängigkeiten:</p>pip install elasticsearch pydantic langchain langchain-openai -q<p>Elasticsearch wird uns dabei helfen, die <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">Indexzuordnungen</a> abzurufen. Pydantic ermöglicht es uns, Schemata in Python zu definieren, denen der LLM dann folgen soll, und <a href="https://www.elastic.co/search-labs/integrations/langchain">LangChain</a> ist das Framework, das den Aufruf von LLMs und KI-Tools vereinfacht.</p><p>Wir werden ein Pydantic-Schema erstellen, um die gewünschte Ausgabe des LLM zu definieren. Aus dem Bild müssen wir den Diagrammtyp, das Feld, den Visualisierungstitel und den Dashboard-Titel ablesen:</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>Als Bildeingabe senden wir ein Dashboard, das ich gerade gezeichnet habe:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7870f6421986d11d/6a1707d78b73cb3408189fa3/36441d7b5dc1f3ff2ac2a30710208d57ad41c716-1600x898.jpg" alt="" /><p>Nun deklarieren wir den LLM-Modellaufruf und das Laden des Bildes. Diese Funktion erhält die Zuordnungen des Elasticsearch-Index und ein Bild des Dashboards, das wir generieren möchten.</p><p>Mit <code>with_structured_output</code> können wir unser Pydantic <code>Dashboard</code> Schema als Antwortobjekt verwenden, das der LLM erzeugen wird. Mit <a href="https://docs.pydantic.dev/latest/">Pydantic</a> können wir Datenmodelle mit Validierung definieren, wodurch sichergestellt wird, dass die LLM-Ausgabe der erwarteten Struktur entspricht.</p><p>Um das Bild in Base64 zu konvertieren und als Eingabe zu senden, können Sie einen <a href="https://www.base64-image.de/">Online-Konverter</a> verwenden oder dies <a href="https://www.geeksforgeeks.org/python-convert-image-to-string-and-vice-versa/">im Code</a> erledigen.</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>Der LLM verfügt bereits über Kontextinformationen zu Kibana-Dashboards, daher müssen wir nicht alles in der Eingabeaufforderung erklären, sondern nur einige Details, um sicherzustellen, dass er nicht vergisst, dass er mit Elasticsearch und Kibana arbeitet.</p><p>Lassen Sie uns die Aufgabenstellung aufschlüsseln:</p><p>Abschnitt</p><p>Grund</p><p>Sie sind Experte in der Analyse von Kibana-Dashboards anhand von Images für die Version 9.0.0 von Kibana.</p><p>Durch die Verstärkung dieser Funktion wird Elasticsearch und die Verwendung der Elasticsearch-Version unterstützt, wodurch die Wahrscheinlichkeit verringert wird, dass das LLM alte/ungültige Parameter fälschlicherweise annimmt.</p><p>Sie erhalten ein Dashboard-Bild und eine Elasticsearch-Indexzuordnung.</p><p>Wir erklären, dass es sich bei dem Bild um Dashboards handelt, um Fehlinterpretationen seitens des LLM zu vermeiden.</p><p>Nachfolgend finden Sie die Indexzuordnungen für den Index, auf dem das Dashboard basiert. Nutzen Sie diese, um die Daten und die verfügbaren Felder besser zu verstehen. Indexzuordnungen: {index_mappings}</p><p>Es ist entscheidend, die Zuordnungen bereitzustellen, damit das LLM dynamisch gültige Felder auswählen kann. Andernfalls könnten wir die Zuordnungen hier fest codieren, was zu starr wäre, oder uns darauf verlassen, dass das Bild die richtigen Feldnamen enthält, was nicht zuverlässig ist.</p><p>Beschränken Sie sich auf die Felder, die für die jeweilige Visualisierung relevant sind, basierend auf dem, was im Bild sichtbar ist.</p><p>Wir mussten diese Verstärkung hinzufügen, weil manchmal versucht wird, Felder hinzuzufügen, die nicht zum Bild gehören.</p><p>Dies gibt ein Objekt mit einem Array von anzuzeigenden Visualisierungen zurück:</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>Verarbeitung der LLM-Antwort</h2><p>WirWir haben ein Beispiel-Dashboard mit 2x2-Panels erstellt und es dann mithilfe der <a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-get-dashboards-dashboard">Get a dashboard API</a> im JSON-Format exportiert. Anschließend haben wir die Panels als Visualisierungsvorlagen (Kreisdiagramm, Balkendiagramm, Metrikdiagramm) gespeichert, in denen wir einige der Parameter ersetzen können, um je nach Fragestellung neue Visualisierungen mit anderen Feldern zu erstellen.</p><p>Die JSON-Vorlagedateien können Sie <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>hier</strong></a> einsehen. Beachten Sie, wie wir die Objektwerte, die wir später ersetzen möchten, durch {<code>variable_name</code>}ersetzt haben.
</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc55d69d84a08e668/6a1707d8a2929903acd00fb8/ec7e1ac0cd8b470df13e60940162b56778acb386-315x234.png" alt="" /><p>Anhand der von LLM bereitgestellten Informationen können wir entscheiden, welche Vorlage wir verwenden und welche Werte wir ersetzen.</p><p><code>fill_template_with_analysis</code> empfängt die Parameter für ein einzelnes Panel, einschließlich der JSON-Vorlage der Visualisierung, eines Titels, eines Feldes und der Koordinaten der Visualisierung im Raster.</p><p>Anschließend werden die Werte der Vorlage ersetzt und die endgültige JSON-Visualisierung zurückgegeben.</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>Um es einfach zu halten, verwenden wir statische Koordinaten, die wir den vom LLM erstellten Panels zuweisen, und erzeugen so ein 2x2-Raster-Dashboard wie in der obigen Abbildung dargestellt.</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>Je nach dem vom LLM festgelegten Visualisierungstyp wählen wir eine JSON-Dateivorlage aus und ersetzen die relevanten Informationen durch <code>fill_template_with_analysis</code> . Anschließend fügen wir das neue Panel einem Array hinzu, das wir später zum Erstellen des Dashboards verwenden.</p><p>Sobald das Dashboard fertig ist, verwenden wir die <a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-post-dashboards-dashboard-id">„Create a dashboard“-API</a> , um die neue JSON-Datei an Kibana zu übertragen und das Dashboard zu generieren:
</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>Um das Skript auszuführen und das Dashboard zu generieren, führen Sie folgenden Befehl in der Konsole aus:</p>python &lt;file_name&gt;.py<p>Das Endergebnis wird folgendermaßen aussehen:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5ceffed004153a4f/6a1707d9a929cf9147ae0901/e909afbf0e47d9a6e0f7bd07dfb2efcfa5cf06ac-921x715.png" alt="" /><h2>Fazit</h2><p>LLMs zeigen ihre ausgeprägten visuellen Fähigkeiten bei der Umwandlung von Text in Code oder der Umwandlung von Bildern in Code. Die Dashboards-API ermöglicht es auch, JSON-Dateien in Dashboards umzuwandeln, und mit einem LLM und etwas Code können wir Bilder in ein Kibana-Dashboard umwandeln.</p><p>Der nächste Schritt besteht darin, die Flexibilität der Dashboard-Visualisierungen durch die Verwendung unterschiedlicher Rastereinstellungen, Dashboard-Größen und -Positionen zu verbessern. Darüber hinaus wäre die Unterstützung komplexerer Visualisierungen und Visualisierungstypen eine sinnvolle Ergänzung dieser Anwendung.</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[KI]]></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>