<?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/kr/search-labs/author/tomas-murua</link>
    </image>
    <link>https://www.elastic.co/kr/search-labs/author/tomas-murua</link>
    <atom:link href="https://www.elastic.co/kr/search-labs/rss/author/tomas-murua.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[kr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 12:38:41 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Elasticsearch로 ChatGPT 커넥터를 구축해 GitHub 문제 쿼리하기]]></title>
    <description><![CDATA[사용자 정의 ChatGPT 커넥터를 구축하고, 하이브리드 검색을 활용해 내부 GitHub 문제를 쿼리하는 Elasticsearch MCP 서버를 배포하는 방법을 알아보세요.]]></description>
    <content:encoded><![CDATA[<p>최근 OpenAI는 프로/비즈니스/엔터프라이즈 및 에듀 요금제에서 ChatGPT를 위한 <a href="https://help.openai.com/en/articles/11487775-connectors-in-chatgpt">사용자 정의 커넥터</a> 기능을 발표했습니다. Gmail, GitHub, 드롭박스 등에서 데이터를 활용하기 위한 기본 제공 커넥터 외에도 MCP 서버를 사용하여 사용자 정의 커넥터를 만들 수 있습니다.</p><p>맞춤형 커넥터를 사용하면 기존 ChatGPT 커넥터를 Elasticsearch와 같은 추가 데이터 소스와 결합하여 포괄적인 답변을 얻을 수 있습니다.</p><p>이문서에서는 내부 GitHub 문제와 풀 요청에 대한 정보를 포함하는 Elasticsearch 인덱스에 ChatGPT를 연결하는 <a href="https://modelcontextprotocol.io/docs/getting-started/intro">MCP</a> 서버를 구축합니다. 이 기능을 통해 Elasticsearch 데이터를 사용하여 자연어 쿼리에 응답할 수 있습니다.</p><p>Google Colab에서 <a href="https://gofastmcp.com/getting-started/welcome">FastMCP</a>를 사용하여 MCP 서버를 배포하고, ngrok을 통해 ChatGPT가 연결할 수 있는 공개 URL을 얻어 복잡한 인프라 설정을 간소화합니다.</p><p>MCP와 에코시스템에 대한 종합적인 개요는 <a href="https://www.elastic.co/search-labs/blog/mcp-current-state">MCP의 현재 상태</a>를 참조하세요.</p><h2>필수 구성 요소</h2><p>시작하려면 다음이 필요합니다.</p><ul><li><p>Elasticsearch 클러스터 (8.X 이상)</p></li><li><p>인덱스에 대한 읽기 권한이 있는 Elasticsearch API 키</p></li><li><p>Google 계정 (Google Colab용)</p></li><li><p>Ngrok 계정 (무료 요금제 사용 가능)</p></li><li><p>프로/엔터프라이즈/비즈니스 또는 에듀 요금제로 등록된 ChatGPT 계정</p></li></ul><h2>ChatGPT MCP 커넥터 요구사항 이해하기</h2><p>ChatGPT MCP 커넥터를 사용하려면 <code>search</code> 와 <code>fetch</code>, 두 가지를 구현해야 합니다. 자세한 내용은 <a href="https://platform.openai.com/docs/mcp#create-an-mcp-server">OpenAI 문서</a>를 참조하세요.</p><h3><a href="https://platform.openai.com/docs/mcp#search-tool">검색 툴</a></h3><p>사용자 쿼리를 기반으로 Elasticsearch 인덱스에서 관련 결과 목록을 반환합니다.</p><h4>수신 내용:</h4><ul><li><p>사용자의 자연어 쿼리가 포함된 단일 스트링입니다.</p></li><li><p>예: 'Elasticsearch 마이그레이션과 관련된 문제 찾기'</p></li></ul><h4>반환값: </h4><ul><li><p>결과 객체 배열을 포함하는 <code>result</code> 키를 가진 객체입니다. 각 결과에는 다음이 포함됩니다.</p><ul><li><p><code>id</code> - 고유 문서 식별자</p></li><li><p><code>title</code> - 이슈 또는 PR 제목</p></li><li><p><code>url</code> - 문제/PR에 대한 링크</p></li></ul></li></ul><h4>구현에서:</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">가져오기 도구</a></h3><p>특정 문서의 전체 내용을 가져옵니다.</p><h4>수신 내용:</h4><ul><li><p>검색 결과에서 Elasticsearch 문서 ID를 포함하는 단일 스트링</p></li><li><p>예: 'PR-578의 세부 정보를 가져와'</p></li></ul><h4>반환값:</h4><ul><li><p>다음 항목을 포함한 완전한 문서 객체입니다.</p><ul><li><p><code>id</code> - 고유 문서 식별자</p></li><li><p><code>title</code> - 이슈 또는 PR 제목</p></li><li><p><code>text</code> - 전체 문제/PR 설명 및 세부 정보</p></li><li><p><code>url</code> - 문제/PR에 대한 링크</p></li><li><p><code>type</code> - 문서 유형(문제, pull_request)</p></li><li><p><code>status</code> - 현재 상태(오픈, 진행 중, 해결 완료)</p></li><li><p><code>priority</code> - 우선순위 수준(낮음, 중간, 높음, 긴급)</p></li><li><p><code>assignee</code> - 문제/PR 담당자</p></li><li><p><code>created_date</code> - 생성된 시점</p></li><li><p><code>resolved_date</code> - 해결된 시점(해당되는 경우)</p></li><li><p><code>labels</code> - 문서에 연결된 태그</p></li><li><p><code>related_pr</code> - 관련 풀 요청 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>참고</strong>: 이 예에서는 모든 필드가 루트 레벨에 있는 플랫 구조를 사용합니다. OpenAI 요구 사항은 유연하며 중첩된 메타데이터 개체도 지원합니다.</p><h2>GitHub 이슈 및 PR 데이터 세트</h2><p>이 튜토리얼에서는 문제와 풀 요청이 포함된 내부 GitHub 데이터 집합을 사용합니다. 이는 ChatGPT를 통해 비공개 내부 데이터를 쿼리하는 시나리오입니다.</p><p>데이터 세트는 <a href="https://gist.github.com/TomasMurua/4e7bbdf7a7ebbdffaa663c43578d934a">여기</a>에서 찾을 수 있습니다. 그리고 <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk">벌크 API</a>를 사용해 데이터의 색인을 업데이트할 것입니다.</p><p>이 데이터 세트에는 다음이 포함되어 있습니다.</p><ul><li><p>설명, 상태, 우선순위 및 담당자와 관련된 문제</p></li><li><p>코드 변경, 리뷰, 배포 정보가 포함된 풀 요청</p></li><li><p>문제와 PR 간의 관계 (예: PR-578이 ISSUE-1889를 수정함)</p></li><li><p>라벨, 날짜 및 기타 메타데이터</p></li></ul><h3>인덱스 매핑</h3><p>인덱스는 <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">매핑</a>을 사용해 <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-elser">ELSER</a>와의 하이브리드 검색을 지원합니다. <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">text_semantic</a>은 시맨틱 검색에 사용되며, 다른 필드는 키워드 검색을 지원합니다.</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>MCP 서버 구축</h2><p>저희 MCP 서버는 더 나은 결과를 위해 하이브리드 검색을 사용하여 시맨틱과 텍스트 매칭을 결합하는 OpenAI 사양을 따르는 두 가지 도구를 구현합니다.</p><h3>검색 툴</h3><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">RRF</a>(상호 순위 융합)을 사용하여 의미론적 검색과 텍스트 매칭을 결합한 하이브리드 검색을 사용합니다.</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>주요 사항:</h3><ul><li><p><strong>RRF를 사용한 하이브리드 검색:</strong> 시맨틱 검색(ELSER)과 텍스트 검색(BM25)을 결합하여 더 나은 결과를 제공합니다.</p></li><li><p><strong>다중 일치 쿼리:</strong> 부스팅(title^3, text^2, assignee^2)을 사용하여 <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-multi-match-query">여러 필드에 걸쳐 검색합니다</a>. 캐럿 기호(^)는 관련성 점수를 곱하여 콘텐츠보다 제목의 일치 항목에 우선순위를 부여합니다.</p></li><li><p><strong>퍼지 매칭:</strong> <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/common-options#fuzziness"><code>fuzziness: AUTO</code></a>는 대략적인 매칭을 허용함으로써 오타와 맞춤법 오류를 처리합니다.</p></li><li><p><strong>상호 순위 결합(RRF) 파라미터 튜닝:</strong></p><ul><li><p><code>rank_window_size: 50</code> - 병합하기 전에 각 검색기(시맨틱 및 텍스트)에서 고려할 상위 결과의 수를 지정합니다.</p></li><li><p><code>rank_constant: 60</code> - 이 값은 개별 결과 집합의 문서가 최종 순위 결과에 미치는 영향을 결정합니다.</p></li></ul></li><li><p><strong>필수 필드만 반환: </strong> OpenAI 사양에 따라 <code>id</code>, <code>title</code>, <code>url</code> 만 반환되며, 불필요한 추가 필드를 노출하지 않습니다.</p></li></ul><h3>가져오기 도구</h3><p>문서가 있는 경우 문서 ID로 문서 세부 정보를 검색합니다.</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>주요 사항:</h3><ul><li><p><strong>문서 ID 필드로 검색:</strong> 사용자 정의 <code>id</code> 필드에서 용어 쿼리를 사용합니다.</p></li><li><p><strong>전체 문서 반환:</strong> 모든 콘텐츠가 포함된 전체 <code>text</code> 필드를 포함합니다.</p></li><li><p><strong>플랫 구조:</strong> 모든 필드가 루트 수준에 있으며, Elasticsearch의 문서 구조와 일치합니다.</p></li></ul><h2>Google Colab에 배포</h2><p>Google Colab을 사용하여 MCP 서버를 실행하고 ngrok을 사용해 외부에 공개함으로써 ChatGPT가 연결할 수 있도록 합니다.</p><h3>1단계: Google Colab 노트북 열기</h3><p>사전 구성된 <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-chatgpt-connector">Elasticsearch MCP for ChatGPT</a> 노트북에 액세스합니다.</p><h3>2단계: 자격 증명을 구성하세요</h3><p>세 가지 정보를 준비해야 합니다.</p><ul><li><p><strong>Elasticsearch URL:</strong> <a href="https://www.elastic.co/docs/deploy-manage/deploy/cloud-enterprise/connect-elasticsearch">Elasticsearch 클러스터 URL</a>입니다.</p></li><li><p><strong>Elasticsearch API 키:</strong> <a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">API 키</a>로 인덱스에 대한 읽기 액세스 권한을 부여합니다.</p></li><li><p><strong>Ngrok 인증 토큰:</strong> <a href="https://ngrok.com/">ngrok</a>에서 무료로 제공하는 토큰입니다. ngrok을 사용하여 MCP URL을 인터넷에 노출하여 ChatGPT가 연결할 수 있도록 합니다.</p></li></ul><h4>ngrok 토큰 받기</h4><ol><li><p><a href="https://ngrok.com/">ngrok</a>에서 무료 계정 가입</p></li><li><p><a href="https://dashboard.ngrok.com/">ngrok 대시보드</a>로 이동</p></li><li><p>인증 토큰을 복사하세요</p></li></ol><h4>Google Colab에 시크릿 추가</h4><p>Google Colab 노트북에서:</p><ol><li><p>왼쪽 사이드바에서 <strong>키 아이콘</strong>을 클릭하여 <strong>시크릿</strong>을 엽니다.</p></li><li><p>이 세 가지 시크릿을 추가합니다.</p></li></ol>ELASTICSEARCH_URL=https://your-cluster.elastic.com:443
ELASTICSEARCH_API_KEY=your-api-key
NGROK_TOKEN=your-ngrok-token<p>3. 각 시크릿에 대한 노트북 접근 활성화</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5acae97b386277f8/6a17f08f5ea30f74c964b6c2/d5dd6ac19fe816a562c6351fdb0f11369da0e877-609x321.jpg" alt="Google Colab에 시크릿 추가" /><h3>3단계: 노트북 실행</h3><ol><li><p><strong>런타임</strong>을 클릭한 다음 <strong>모두 실행</strong>을 클릭하여 모든 셀을 실행합니다.</p></li><li><p>서버가 시작될 때까지 기다립니다(약 30초).</p></li><li><p>공개 ngrok URL을 표시하는 출력을 찾습니다.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdd11aacf2deab67c/6a17f091e8fbce81f13a1a41/f185100e8869624bc9e1c7b2b4eb32785e2d89e7-1189x283.png" alt="" /><p>4. 출력은 다음과 같이 표시됩니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8891d917fdbaaf48/6a17f092abe0f208c7dfeaf6/e02e625e91ed9136454e4401b184575fb03a336e-1052x465.jpg" alt="Google Colab에서 노트북을 실행한 출력" /><h2>ChatGPT에 연결</h2><p>이제 MCP 서버를 ChatGPT 계정에 연결합니다.</p><ol><li><p>ChatGPT를 열고 <strong>설정</strong>으로 이동합니다.</p></li><li><p><strong>커넥터</strong>로 이동합니다.프로 계정을 사용하는 경우 커넥터에서 <a href="https://platform.openai.com/docs/guides/developer-mode">개발자 모드</a>를 사용 설정해야 합니다.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt95efdcb2c39307e7/6a17f094abe0f24d8edfeafa/32c02192912fc0e7e5a52e9399077ba7ae3b4901-739x715.png" alt="MPC 서버를 ChatGPT 계정에 연결하기" /><p><em>ChatGPT 엔터프라이즈 또는 비즈니스 버전을 사용하는 경우, 커넥터를 작업 환경에 게시해야 합니다.</em></p><p>3. <strong>만들기</strong>를 클릭합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4c8fc8dd6033918/6a17f095631730de19585b7b/15c53e5ccc381108a9dc0052cca05bf0fc97679a-755x683.png" alt="ChatGPT에 커넥터 추가" /><p><em><strong>참고</strong></em><em>: 비즈니스, 엔터프라이즈, 에듀 작업 공간에서는 작업 공간 소유자, 관리자 및 해당 설정이 활성화된 사용자(엔터프라이즈/에듀)만 사용자 정의 커넥터를 추가할 수 있습니다. 일반 회원 역할을 가진 사용자는 사용자 정의 커넥터를 직접 추가할 수 없습니다.</em></p><p><em>소유자 또는 관리자 사용자가 커넥터를 추가하고 활성화하면 작업 공간의 모든 구성원이 이를 사용할 수 있습니다.</em></p><p>4. 필요한 정보를 입력하고 <code>/sse/</code>로 끝나는 ngrok URL을 입력합니다. 'sse"' 뒤의 '/'에 주의하세요. 이것 없이는 작동하지 않습니다.</p><ul><li><p><strong>이름:</strong> Elasticsearch MCP</p></li><li><p><strong>설명: </strong>GitHub 내부 정보를 검색하고 가져오기 위한 사용자 정의 MCP입니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd716ad0beeeb1d35/6a17f09714d90c11cc79b6d7/162a85705cc8ac48a3f2f665551d513e0719f93d-479x684.png" alt="Elastic MCP 커넥터 생성 " /><p>5. <strong>생성</strong> 을 눌러 사용자 정의 MCP를 저장하세요.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857794237d7d3b5a/6a17f0983e03d729b74f2d54/97eb5fb0a32b86bfadfb35561f698616f217c049-913x629.png" alt="생성을 클릭하여 사용자 정의 MCP 커넥터 저장" /><p>서버가 실행 중이면 즉시 연결됩니다. Elasticsearch API 키가 서버에 구성되어 있으므로 추가 인증이 필요하지 않습니다.</p><h2>MCP 서버 테스트</h2><p>질문을 하기 전에 ChatGPT가 사용할 커넥터를 선택해야 합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd1602c48878dc7a9/6a17f09a6df731cca90a0fff/77a6fc1eb263a0eb16aac64f2ecaca5f4ac12ec2-966x568.gif" alt="ChatGPT에서 사용할 커넥터 선택" /><h3>프롬프트 1: 문제 검색</h3><p>질문: '<strong>Elasticsearch 마이그레이션과 관련된 문제를 찾아'</strong>라고 요청하고 작업 도구 호출을 확인하세요.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6c204ceacf897f61/6a17f09c9da390fb1de4657d/cfd781acbff8cd7c8095bbe29224f8b26d581f77-650x375.png" alt="ChatGPT에 'Elasticsearch 마이그레이션과 관련된 문제 찾기'를 요청하고 작업 도구 호출을 확인합니다." /><p>ChatGPT가 사용자의 쿼리를 사용하여 <code>search</code> 도구를 호출합니다. 사용 가능한 도구를 찾고 Elasticsearch 도구를 호출할 준비를 하며, 도구에 대해 조치를 취하기 전에 사용자에게 확인하는 것을 볼 수 있습니다.</p><h4>도구 호출 요청:</h4>{
  "query": "Elasticsearch migration issues"
}<h4>도구 응답:</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는 결과를 처리하여 자연스러운 대화 형식으로 표시합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1b4378e7d26b4ad0/6a17f09ddbb4ff4de1fb57bf/9d5b6cff85c7e54ccc2584b8ae96d45495fae8c1-923x1352.png" alt="ChatGPT가 도구 호출 요청 및 도구 호출 응답의 결과를 처리하는 방법" /><h3>비하인드 스토리</h3><h4>프롬프트: 'Elasticsearch 마이그레이션 관련 문제를 찾아'</h4><p>1. ChatGPT 호출 <code>search(“Elasticsearch migration”)</code></p><p>2. Elasticsearch가 하이브리드 검색 수행</p><ul><li><p><strong>시맨틱 검색</strong>은 '업그레이드' 및 '<em>버전 호환성</em>'과 같은 개념을 이해합니다.</p></li><li><p><strong>텍스트 검색</strong>은 '<em>Elasticsearch</em>' 및 '마이그레이션'과 정확히 일치하는 결과를 찾습니다.</p></li><li><p><strong>RRF</strong>는 두 가지 접근 방식의 결과를 결합하고 순위를 매깁니다.</p></li></ul><p>3. <code>id</code>, <code>title</code>와 일치하는 상위 10개의 이벤트를 반환합니다, <code>url</code></p><p>4. ChatGPT는 '<em>ISSUE-1712: Elasticsearch 7.x에서 8.x로 마이그레이션</em>'을 가장 관련성 있는 결과로 식별합니다</p><h3>프롬프트 2: 전체 세부 정보 확인</h3><p>문의: <em><strong>'ISSUE-1889의 세부 정보를 보여줘'</strong></em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d1a53db8bfe8326/6a17f09f445de966104d021a/5c0db5245535ce67a36056e61e135bddc97ce496-934x629.png" alt="ChatGPT는 사용자가 특정 문제에 대한 자세한 정보를 원한다는 것을 인식하고 가져오기 도구를 호출한 후, 도구에 대해 조치를 취하기 전에 사용자에게 확인합니다." /><p>ChatGPT는 사용자가 특정 문제에 대한 자세한 정보를 원한다는 것을 인식하고 <code>fetch</code> 도구를 호출한 후, 도구에 대해 조치를 취하기 전에 사용자에게 확인합니다.</p><h4>도구 호출 요청:</h4>{
  "id": "ISSUE-1889"
}<h4>도구 응답:</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는 정보를 종합하여 명확하게 제시합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt560958fa3bd212d0/6a17f0a0faa91355ba93c974/410f19f213e94fc4e3c47eeef6e04b69e0c86159-602x462.png" alt="ChatGPT가 정보를 종합하고 제시하는 방법 " /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcccf35a584e8373b/6a17f0a2505ac3471cad8c2e/54d8ffa117628a1e3afc317c3ab75d4f7731d7ab-767x1600.png" alt="ChatGPT가 정보를 제시하는 방법" /><h3>비하인드 스토리</h3><h4>프롬프트: 'ISSUE-1889의 세부 정보를 가져와'</h4><ol><li><p>ChatGPT 호출 <code>fetch(“ISSUE-1889”)</code></p></li><li><p>Elasticsearch가 전체 문서를 검색합니다.</p></li><li><p>모든 필드가 루트 수준에 포함된 전체 문서를 반환합니다.</p></li><li><p>ChatGPT는 정보를 종합하고 적절한 출처를 제시하며 응답합니다.</p></li></ol><h2>결론</h2><p>이 문서에서는 전용 <strong>검색</strong> 및 <strong>가져오기</strong> MCP 도구를 사용하여 ChatGPT를 Elasticsearch에 연결하고, 비공개 데이터에 대한 자연어 쿼리를 가능하게 하는 사용자 정의 MCP 서버를 구축했습니다.</p><p>이 MCP 패턴은 자연어로 쿼리하려는 모든 Elasticsearch 인덱스, 문서, 제품, 로그 또는 기타 데이터에 적용할 수 있습니다.</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[에이전틱 AI]]></category>
    <category><![CDATA[하이브리드 검색]]></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[Elastic 에이전트 빌더와 GPT-OSS로 HR용 AI 에이전트 구축하기]]></title>
    <description><![CDATA[Elastic 에이전트 빌더와 GPT-OSS를 사용해 직원 인사 데이터에 대한 자연어 쿼리에 답변할 수 있는 AI 에이전트를 구축하는 방법을 알아보세요.]]></description>
    <content:encoded><![CDATA[<h2>소개</h2><p>이 문서에서는 <a href="https://openai.com/index/introducing-gpt-oss/">GPT-OSS와</a> Elastic 에이전트 빌더를 사용해 HR용 AI 에이전트를 구축하는 방법을 설명합니다. 상담원은 OpenAI, Anthropic 또는 외부 서비스에 데이터를 보내지 않고도 질문에 답변할 수 있습니다.</p><p>LM Studio를 사용하여 GPT-OSS를 로컬로 서비스하고 이를 Elastic Agent Builder에 연결합니다.</p><p>이 글을 마치면 정보와 모델을 완벽하게 제어하면서 직원 데이터에 대한 자연어 질문에 답할 수 있는 맞춤형 AI 에이전트를 보유하게 됩니다.</p><h2>필수 구성 요소</h2><p>이 문서에는 다음이 필요합니다:</p><ul><li><p><a href="https://www.elastic.co/cloud">Elastic Cloud</a> 호스팅 9.2, 서버리스 또는 <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">로컬</a> 배포</p></li><li><p>32GB RAM이 장착된 머신 권장(GPT-OSS 20B의 경우 최소 16GB)</p></li><li><p><a href="https://lmstudio.ai/">LM Studio</a> 설치</p></li><li><p><a href="https://www.docker.com/products/docker-desktop/">도커 데스크톱</a> 설치</p></li></ul><h2>GPT-OSS를 사용하는 이유는 무엇인가요?</h2><p>로컬 LLM을 사용하면 자체 인프라에 배포하고 필요에 맞게 미세 조정할 수 있습니다. 이 모든 기능을 사용하면서 모델과 공유하는 데이터를 제어할 수 있으며, 물론 외부 제공업체에 라이선스 비용을 지불할 필요가 없습니다.</p><p>OpenAI는 개방형 모델 생태계를 위한 노력의 일환으로 2025년 8월 5일에 <a href="https://openai.com/index/introducing-gpt-oss/">GPT-OSS를 출시했습니다</a>.</p><p>20B 매개변수 모델은 다음을 제공합니다:</p><ul><li><p><strong>도구 사용 기능</strong></p></li><li><p><strong>효율적인 추론</strong></p></li><li><p><strong>OpenAI SDK 호환</strong></p></li><li><p><strong>에이전트 워크플로와 호환</strong></p></li></ul><p>벤치마크 비교:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt58fab956edb40412/6a170cfcb0367da43a72bd80/29160e3345352088e8213297630882f252b00c47-1600x680.png" alt="" /><h2>솔루션 아키텍처</h2><p>아키텍처는 전적으로 로컬 컴퓨터에서 실행됩니다. Elastic(Docker에서 실행)은 LM Studio를 통해 로컬 LLM과 직접 통신하며, Elastic 에이전트 빌더는 이 연결을 사용하여 직원 데이터를 쿼리할 수 있는 사용자 정의 AI 에이전트를 생성합니다.</p><p>자세한 내용은 이 <a href="https://www.elastic.co/docs/solutions/observability/connect-to-own-local-llm">문서를</a> 참조하세요.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80db5bb0a797f51b/6a170cfd0e2e492f2c41a16f/a4a886750ff25fa8bb7aefc7448161e52cf73ed3-1600x896.png" alt="" /><h2>HR용 AI 에이전트 구축: 단계</h2><p>구현을 5단계로 나눠서 설명하겠습니다:</p><ol><li><p>로컬 모델로 LM 스튜디오 구성</p></li><li><p>Docker로 로컬 Elastic 배포</p></li><li><p>Elastic에서 OpenAI 커넥터 생성</p></li><li><p>Elasticsearch에 직원 데이터 업로드</p></li><li><p>AI 에이전트 빌드 및 테스트</p></li></ol><h2>1단계: GPT-OSS 20B로 LM Studio 구성하기</h2><p>LM Studio는 컴퓨터에서 로컬로 대규모 언어 모델을 실행할 수 있는 사용자 친화적인 애플리케이션입니다. OpenAI 호환 API 서버를 제공하므로 복잡한 설정 과정 없이 Elastic과 같은 도구와 쉽게 통합할 수 있습니다. 자세한 내용은 <a href="https://lmstudio.ai/docs/app">LM Studio 문서를</a> 참조하세요.</p><p>먼저 공식 웹사이트에서 LM Studio를 다운로드하여 설치합니다. 설치가 완료되면 애플리케이션을 엽니다.</p><h3>LM Studio 인터페이스에서:</h3><ol><li><p>검색 탭으로 이동하여 "GPT-OSS"를 검색합니다.</p></li><li><p>OpenAI에서 <code>openai/gpt-oss-20b</code></p></li><li><p>다운로드를 클릭하세요.</p></li></ol><p>이 모델의 크기는 약 <strong>12.10GB입니다</strong>. 인터넷 연결 상태에 따라 다운로드하는 데 몇 분 정도 걸릴 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2dc341a6625e34b7/6a170cff839dfa2eb4dcff44/5d01bc4dcb377b5259fc6b521fe2425a31b90ca4-1312x872.png" alt="" /><h4>모델이 다운로드되면</h4><ol><li><p>로컬 서버 탭으로 이동합니다.</p></li><li><p>OPENAI/GPT-OSS-20B를 선택합니다.</p></li><li><p>기본 포트 1234 사용</p></li><li><p>오른쪽 패널에서 <strong>로드로 </strong>이동하여 컨텍스트 길이를 <strong>40K</strong> 이상으로 설정합니다.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3704ca1b28465cc4/6a170d00d7c022ed8fde64ef/e546033f916381647b876815b2c1f1ae2a08365f-326x337.png" alt="" /><p>5. 서버 시작을 클릭합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7b9170a4945ff857/6a170d0266c4f9ffadf8c0a6/28ee78a3caa84d14e04db3d42f30acbe4d4d005a-1312x872.png" alt="" /><p>서버가 실행 중이면 이 메시지가 표시되어야 합니다.</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>2단계: Docker로 로컬 Elastic 배포하기</h2><p>이제 Docker를 사용해 로컬에서 Elasticsearch와 Kibana를 설정하겠습니다. Elastic은 전체 설정 프로세스를 처리하는 편리한 스크립트를 제공합니다. 자세한 내용은 <a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">공식 문서를</a> 참조하세요.</p><h3>시작-로컬 스크립트 실행</h3><p>터미널에서 다음 명령을 실행합니다:</p>curl -fsSL https://elastic.co/start-local | sh<p>이 스크립트는</p><ul><li><p>Elasticsearch와 Kibana 다운로드 및 구성하기</p></li><li><p>Docker Compose를 사용하여 두 서비스 모두 시작</p></li><li><p>30일 플래티넘 평가판 라이선스 자동 활성화</p></li></ul><h3>예상 출력</h3><p>다음 메시지가 표시될 때까지 기다렸다가 표시된 비밀번호와 API 키를 저장하세요. 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>Kibana에 액세스</h3><p>브라우저를 열고 다음으로 이동합니다:</p>http://localhost:5601<p>터미널 출력에서 얻은 자격 증명을 사용하여 로그인합니다.</p><h3>상담원 빌더 사용</h3><p>Kibana에 로그인한 후, <strong>관리 </strong>&gt;<strong> AI </strong>&gt;<strong> 에이전트 빌더로 </strong>이동하여 에이전트 빌더를 활성화합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a934bd99fa6a0ce/6a170d046234e019c3db1a5a/92e104cb846c20d875865ded8a3d37f5c7daae9b-1491x1528.png" alt="" /><h2>3단계: Elastic에서 OpenAI 커넥터 만들기</h2><p>이제 로컬 LLM을 사용하도록 Elastic을 구성하겠습니다.</p><h3>액세스 커넥터</h3><ol><li><p>Kibana에서</p></li><li><p><strong>프로젝트 설정으로</strong> 이동 &gt; <strong>관리</strong></p></li><li><p><strong>알림 및 인사이트에서</strong> <strong>커넥터를</strong>선택합니다.</p></li><li><p>커넥터 만들기를 클릭합니다.</p></li></ol><h3>커넥터 구성</h3><p>커넥터 목록에서 <strong>OpenAI를</strong> 선택합니다. LM Studio는 OpenAI SDK를 사용하므로 호환성이 뛰어납니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt762023c39781eb78/6a170d06a29299a59ed01087/5ac87042e086c7a2bd47a8039e646ec831f0dcc6-923x974.png" alt="" /><p>이 값으로 필드를 채웁니다:</p><ul><li><p><strong>커넥터 이름: </strong>LM Studio - GPT-OSS 20B</p></li><li><p><strong>OpenAI 제공업체를 선택합니다: </strong>기타(OpenAI 호환 서비스)</p></li><li><p><strong>URL: </strong><code>http://host.docker.internal:1234/v1/chat/completions</code></p></li><li><p><strong>기본 모델: </strong>OPENAI/GPT-OSS-20B</p></li><li><p><strong>API 키:</strong> testkey-123(LM Studio 서버는 인증이 필요하지 않으므로 어떤 텍스트도 작동합니다.)</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt980e595f80e2be2e/6a170d086f7f0468a19148cc/2084ac32fcf1fb810c8b54ecab1c85a1e3e8905b-672x1302.png" alt="" /><p>구성을 완료하려면 <strong>저장 &amp; 테스트를</strong> 클릭합니다.</p><p><strong>중요:</strong> 상담원 빌더가 제대로 작동하려면 '<strong>네이티브 함수 호출 사용</strong>'을 켜야 합니다. 이 기능을 활성화하지 않으면 <strong><code>No tool calls found in the response</code></strong> 오류가 발생합니다.</p><h3>연결 테스트</h3><p>Elastic은 자동으로 연결을 테스트합니다. 모든 것이 올바르게 구성되면 다음과 같은 성공 메시지가 표시됩니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4d2e815dd558f881/6a170d090e2e49076541a177/f567d767f1969c4730c1daa92f651789dc3742ac-1042x812.png" alt="" /><p>대응:</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>4단계: 직원 데이터를 Elasticsearch에 업로드하기</h2><p>이제 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">HR 직원 데이터 세트를</a> 업로드하여 상담원이 민감한 데이터로 어떻게 작업하는지 보여드리겠습니다. 이 구조로 가상의 데이터 집합을 생성했습니다.</p><h3>데이터 세트 구조</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>매핑으로 인덱스 만들기</h3><p>먼저 적절한 매핑으로 인덱스를 생성합니다. 일부 주요 필드에 <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text">semantic_text</a> 필드를 사용하여 인덱스에 시맨틱 검색 기능을 사용할 수 있습니다.</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>대량 API로 색인 생성</h3><p><a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/gpt-oss-with-elasticsearch/hr-employees-bulk.json">데이터 세트를</a> 복사하여 Kibana의 개발 도구에 붙여넣고 실행합니다:</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>데이터 확인</h3><p>쿼리를 실행하여 확인합니다:</p>GET hr-employees/_search<h2>5단계: AI 에이전트 빌드 및 테스트</h2><p>모든 구성이 완료되었으면 이제 Elastic 에이전트 빌더를 사용해 사용자 정의 AI 에이전트를 빌드할 차례입니다. 자세한 내용은 <a href="https://www.elastic.co/docs/solutions/search/agent-builder/get-started">Elastic 설명서를</a> 참조하세요.</p><h3>커넥터 추가</h3><p>새 에이전트를 생성하기 전에, 기본 커넥터가 <a href="https://www.elastic.co/docs/reference/kibana/connectors-kibana/elastic-managed-llm">Elastic Managed LLM이므로</a> <code>LM Studio - GPT-OSS 20B</code> 이라는 사용자 정의 커넥터를 사용하도록 에이전트 빌더를 설정해야 합니다. 이를 위해 <strong>프로젝트 설정</strong> &gt; <strong>관리</strong> &gt; <strong>GenAI 설정으로</strong> 이동한 다음, 생성한 프로젝트를 선택하고 <strong>저장을</strong> 클릭합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc42f079c5e756057/6a170d0acf4f2501d9b2d1c7/11e830c3e2fb4c298b020c928fa5422f3397ba08-1600x1152.png" alt="" /><h3>에이전트 빌더 액세스</h3><ol><li><p><strong>상담원으로</strong>이동</p></li><li><p><strong>새 상담원 만들기를</strong>클릭합니다.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb8e734817c5a7c6a/6a170d0ca929cf867cae0a34/c1e60541563650163f972ac9088dc1ed1de759a7-1600x1054.png" alt="" /><h3>상담원 구성하기</h3><p>새 상담원을 만들 때 필수 필드는 <strong>상담원 ID</strong>, <strong>표시 이름</strong> 및 <strong>표시 지침입니다</strong>.</p><p>하지만 시스템 프롬프트와 비슷하지만 사용자 지정 상담원을 위해 상담원이 어떻게 행동하고 툴과 상호 작용할지 안내하는 사용자 지정 지침과 같은 더 많은 사용자 지정 옵션이 있습니다. 레이블은 상담원, 아바타 색상 및 아바타 심볼을 정리하는 데 도움이 됩니다.</p><p>데이터 집합을 기반으로 상담원에게 선택한 것은

<strong>상담원 ID입니다</strong>: <code>hr_assistant</code></p><p><strong>사용자 지정 지침:</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>
레이블: <code>Human Resources</code> 및 <code>GPT-OSS</code></p><p>표시 이름: <code>HR Analytics Assistant</code></p><p>설명을 표시합니다:</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>여기에 모든 데이터가 있으면 새 상담원 <strong>저장을</strong> 클릭할 수 있습니다.</p><h3>에이전트 테스트</h3><p>이제 직원 데이터에 대해 자연어 질문을 하면 GPT-OSS 20B가 의도를 파악하고 적절한 답변을 생성합니다.</p><h4>프롬프트:</h4>Which employee is the one with the highest salary in the hr-employees index?<h4>답변:</h4><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc0c52faacf63b583/6a170d0f0e2e497bfd41a17b/94ad19f80b96304028a59f60beca51dfc9aecc8a-899x631.png" alt="" /><p>에이전트 프로세스였습니다:</p><p>1. GPT-OSS 커넥터를 사용하여 질문 이해하기</p><p>2. (기본 제공 도구 또는 사용자 정의 <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL을</a> 사용하여) 적절한 Elasticsearch 쿼리를 생성합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte32a8a7e6363c7f2/6a170d115091680077e1bb44/6f2961d0d1b97475f6dda300acee84da540938e6-844x466.png" alt="" /><p>3. 일치하는 직원 기록 검색</p><p>4. 적절한 서식을 사용하여 자연어로 결과 표시</p><p>기존의 어휘 검색과 달리 GPT-OSS 기반 에이전트는 의도와 문맥을 이해하므로 정확한 필드 이름이나 쿼리 구문을 몰라도 정보를 쉽게 찾을 수 있습니다. 상담원의 사고 과정에 대한 자세한 내용은 이 <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance">문서를</a> 참조하세요.</p><h2>결론</h2><p>이 문서에서는 Elastic의 에이전트 빌더를 사용해 로컬에서 실행 중인 OpenAI GPT-OSS 모델에 연결하기 위해 사용자 정의 AI 에이전트를 구축했습니다. 이 아키텍처는 로컬 머신에 Elastic과 LLM을 모두 배포함으로써 외부 서비스로 정보를 전송하지 않고도 데이터를 완벽하게 제어하면서 생성형 AI 기능을 활용할 수 있게 해줍니다.</p><p>실험으로 GPT-OSS 20B를 사용했지만, 공식적으로 Elastic 에이전트 빌더에 권장되는 모델은 <a href="https://www.elastic.co/docs/solutions/search/agent-builder/models#recommended-models">여기를</a> 참조하세요. 고급 추론 기능이 필요한 경우, 로컬에서 실행하려면 더 높은 사양의 컴퓨터가 필요하지만 복잡한 시나리오에서 더 나은 성능을 발휘하는 <a href="https://huggingface.co/openai/gpt-oss-120b">120B 매개변수 변형도</a> 있습니다. 자세한 내용은 <a href="https://openai.com/open-models/">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[에이전틱 AI]]></category>
    <category><![CDATA[AI]]></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[AI 기반 대시보드: 비전에서 Kibana까지]]></title>
    <description><![CDATA[이미지를 처리하기 위해 LLM을 사용해 대시보드를 생성하고 이를 Kibana 대시보드로 전환합니다.
]]></description>
    <content:encoded><![CDATA[<p><a href="https://www.elastic.co/kibana/kibana-lens">Kibana Lens를</a> 사용하면 대시보드를 매우 간단하게 끌어서 놓을 수 있지만, 수십 개의 패널이 필요한 경우에는 클릭 수가 늘어납니다. 대시보드를 스케치하고 스크린샷을 찍어 LLM이 전체 프로세스를 완료하도록 할 수 있다면 어떨까요?</p><p>이 글에서는 이를 실현하는 방법에 대해 설명합니다. 대시보드의 이미지를 가져와서 매핑을 분석한 다음 Kibana를 전혀 건드리지 않고도 대시보드를 생성하는 애플리케이션을 만들어 보겠습니다!</p><p><strong>단계</strong>:</p><ol><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#background-&amp;-application-workflow">배경 &amp; 애플리케이션 워크플로</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#prepare-data">데이터 준비</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#llm-configuration">LLM 구성</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/ai-powered-dashboards#application-functions">애플리케이션 기능</a></p></li></ol><h2>배경 &amp; 애플리케이션 워크플로</h2><p>가장 먼저 떠오른 생각은 LLM이 전체 NDJSON 형식의 Kibana <a href="https://www.elastic.co/docs/explore-analyze/find-and-organize/saved-objects">저장 개체를</a> 생성한 다음 Kibana로 가져오도록 하는 것이었습니다.</p><p>몇 가지 모델을 사용해 보았습니다:</p><ul><li><p>Gemini 2.5 프로</p></li><li><p>GPT o3 / o4-미니 하이 / 4.1</p></li><li><p>클로드 4 소네트</p></li><li><p>Grok 3</p></li><li><p>딥씽크(딥씽크 R1)</p></li></ul><p>그리고 프롬프트는 간단하게 시작했습니다:</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>각 비주얼리제이션을 작성하는 방법에 대한 <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.">몇 가지 예시와</a> 자세한 설명을 살펴봤지만 운이 없었습니다. 이 실험에 관심이 있으시다면 <a href="https://gist.github.com/TomasMurua/a78dc283e115624731beffc98984b70b">여기에서</a> 자세한 내용을 확인할 수 있습니다.</p><p>이 접근 방식을 사용한 결과, LLM에서 생성된 파일을 Kibana에 업로드하려고 할 때 이러한 메시지가 표시되었습니다:</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>이는 생성된 JSON이 유효하지 않거나 형식이 잘못되었음을 의미합니다. 가장 흔한 문제는 불완전한 NDJSON을 생성하거나, 매개변수를 착각하거나, 아무리 강제 적용을 시도해도 NDJSON 대신 일반 JSON을 반환하는 LLM이었습니다.</p><p><a href="https://www.elastic.co/docs/solutions/search/search-templates">검색 템플릿이</a> LLM 프리스타일보다 더 효과적이었다는 <a href="https://www.elastic.co/search-labs/blog/llm-functions-elasticsearch-intelligent-query">이 글에서 영감을</a> 받아 전체 NDJSON 파일을 생성하도록 요청하는 대신 템플릿을 LLM에 제공하고 코드에서 LLM이 제공한 매개변수를 사용하여 적절한 시각화를 만들기로 결정했습니다. 이 접근 방식은 실망스럽지 않았고 예측 가능하고 확장 가능하며 이제 코드가 무거운 작업을 수행하므로 LLM이 아닌 코드가 작업을 수행하게 되었습니다.</p><p>애플리케이션 워크플로우는 다음과 같습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9f7738a4c7ddd0cd/6a1707d52b835f0a25f4b166/52c587cf0cf3517fdd4ee7ab95581dd4f2bce030-725x668.png" alt="" /><p></p><p><em>간단하게 설명하기 위해 일부 코드는 생략하지만, 전체 애플리케이션의 작업 코드는 </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>이</strong></em></a><em> 노트북에서</em>찾을 수 있습니다.</p><h2>필수 구성 요소</h2><p>개발을 시작하기 전에 다음이 필요합니다:</p><ol><li><p>Python 3.8 이상</p></li><li><p><a href="https://docs.python.org/3/library/venv.html">Venv</a> Python 환경</p></li><li><p>엔드포인트 및 API 키와 함께 실행 중인 Elasticsearch 인스턴스</p></li><li><p>환경 변수 이름 OPENAI_API_KEY에 저장된 OpenAI API 키입니다:</p></li></ol>export OPENAI_API_KEY="your-openai-api-key"<h2>데이터 준비</h2><p>데이터의 경우, 간단하게 유지하면서 Elastic 샘플 웹 로그를 사용하겠습니다. <a href="https://www.elastic.co/docs/manage-data/ingest/sample-data#add-sample-data-sets">여기에서</a> 해당 데이터를 클러스터로 가져오는 방법을 알아보세요.</p><p>각 문서에는 애플리케이션에 요청을 보낸 호스트에 대한 세부 정보와 함께 요청 자체 및 응답 상태에 대한 정보가 포함되어 있습니다. 아래는 문서 예시입니다:</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>이제 방금 로드한 인덱스( <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>나중에 로드할 이미지와 함께 매핑을 전달하겠습니다.</p><h2>LLM 구성</h2><p><a href="https://python.langchain.com/docs/concepts/structured_outputs/">구조화된 출력을</a> 사용하여 이미지를 입력하고 함수에 전달해야 하는 정보가 포함된 JSON을 수신하여 JSON 객체를 생성하도록 LLM을 구성해 보겠습니다.</p><p>종속성을 설치합니다:</p>pip install elasticsearch pydantic langchain langchain-openai -q<p>Elasticsearch는 <a href="https://www.elastic.co/docs/manage-data/data-store/mapping">인덱스 매핑을</a> 검색하는 데 도움이 됩니다. Pydantic을 사용하면 파이썬으로 스키마를 정의한 다음 LLM에 따르도록 요청할 수 있으며, <a href="https://www.elastic.co/search-labs/integrations/langchain">LangChain은</a> LLM과 AI 도구를 더 쉽게 호출할 수 있도록 도와주는 프레임워크입니다.</p><p>LLM에서 원하는 출력을 정의하기 위해 Pydantic 스키마를 생성합니다. 이미지에서 알아야 할 것은 차트 유형, 필드, 비주얼리제이션 제목 및 대시보드 제목입니다:</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>이미지 입력은 제가 방금 그린 대시보드를 보내드리겠습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7870f6421986d11d/6a1707d78b73cb3408189fa3/36441d7b5dc1f3ff2ac2a30710208d57ad41c716-1600x898.jpg" alt="" /><p>이제 LLM 모델 호출과 이미지 로딩을 선언합니다. 이 함수는 생성하려는 대시보드의 이미지와 Elasticsearch 인덱스의 매핑을 수신합니다.</p><p><code>with_structured_output</code> 을 사용하면 Pydantic <code>Dashboard</code> 스키마를 LLM이 생성할 응답 객체로 사용할 수 있습니다. <a href="https://docs.pydantic.dev/latest/">Pydantic을</a> 사용하면 유효성 검사를 통해 데이터 모델을 정의할 수 있으므로 LLM 출력이 예상 구조와 일치하는지 확인할 수 있습니다.</p><p>이미지를 base64로 변환하여 입력으로 보내려면 <a href="https://www.base64-image.de/">온라인 변환기를</a> 사용하거나 <a href="https://www.geeksforgeeks.org/python-convert-image-to-string-and-vice-versa/">코드로</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>LLM에는 이미 Kibana 대시보드에 대한 컨텍스트가 있으므로 프롬프트에서 모든 것을 설명할 필요는 없으며, Elasticsearch 및 Kibana와 함께 작동한다는 것을 잊지 않도록 하기 위한 몇 가지 세부 사항만 설명하면 됩니다.</p><p>프롬프트를 자세히 살펴 보겠습니다:</p><p>섹션</p><p>이유</p><p>귀하는 Kibana 버전 9.0.0의 이미지에서 Kibana 대시보드를 분석하는 전문가입니다.</p><p>이를 강화하는 것이 바로 Elasticsearch이며, Elasticsearch 버전은 LLM이 오래되거나 유효하지 않은 매개변수를 착각할 가능성을 줄여줍니다.</p><p>대시보드 이미지와 Elasticsearch 인덱스 매핑이 제공됩니다.</p><p>LLM의 잘못된 해석을 피하기 위해 이미지가 대시보드에 관한 것이라고 설명합니다.</p><p>다음은 대시보드의 기반이 되는 인덱스의 인덱스 매핑입니다. 이를 사용하여 데이터와 사용 가능한 필드를 이해하는 데 도움이 됩니다. 인덱스 매핑: {index_mappings}</p><p>LLM이 유효한 필드를 동적으로 선택할 수 있도록 매핑을 제공하는 것이 중요합니다. 그렇지 않으면 여기에 매핑을 하드 코딩하여 너무 딱딱하게 만들거나 올바른 필드 이름이 포함된 이미지에 의존할 수 있는데, 이는 신뢰할 수 없습니다.</p><p>이미지에 표시되는 내용에 따라 각 시각화와 관련된 필드만 포함합니다.</p><p>가끔 이미지와 관련이 없는 필드를 추가하려고 시도하기 때문에 이 기능을 추가해야 했습니다.</p><p>그러면 표시할 시각화 배열이 있는 객체가 반환됩니다:</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>LLM 응답 처리</h2><p>에서 샘플 2x2 패널 대시보드를 만든 다음 <a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-get-dashboards-dashboard">대시보드 가져오기 API를</a> 사용하여 JSON으로 내보낸 다음, 패널을 시각화 템플릿(파이, 막대, 메트릭)으로 저장하여 일부 매개 변수를 교체하여 질문에 따라 다른 필드로 새로운 시각화를 만들 수 있습니다.</p><p>템플릿 JSON 파일은 <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>여기에서</strong></a> 확인할 수 있습니다. 나중에 대체할 개체 값을 {<code>variable_name</code>}로 변경한 방법에 유의하세요.
</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc55d69d84a08e668/6a1707d8a2929903acd00fb8/ec7e1ac0cd8b470df13e60940162b56778acb386-315x234.png" alt="" /><p>LLM이 제공한 정보를 바탕으로 어떤 템플릿을 사용하고 어떤 값을 대체할지 결정할 수 있습니다.</p><p><code>fill_template_with_analysis</code> 는 시각화의 JSON 템플릿, 제목, 필드, 그리드에 있는 시각화의 좌표 등 단일 패널에 대한 매개변수를 받습니다.</p><p>그런 다음 템플릿의 값을 바꾸고 최종 JSON 시각화를 반환합니다.</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>간단하게 하기 위해 LLM이 생성하기로 결정한 패널에 정적 좌표를 할당하고 위 이미지와 같은 2x2 그리드 대시보드를 생성합니다.</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>LLM에서 결정한 시각화 유형에 따라 JSON 파일 템플릿을 선택하고 <code>fill_template_with_analysis</code> 을 사용하여 관련 정보를 바꾼 다음 새 패널을 나중에 대시보드를 만드는 데 사용할 배열에 추가합니다.</p><p>대시보드가 준비되면, <a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-post-dashboards-dashboard-id">대시보드 만들기 API를</a> 사용해 새 JSON 파일을 Kibana로 푸시하여 대시보드를 생성합니다:
</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>스크립트를 실행하고 대시보드를 생성하려면 콘솔에서 다음 명령을 실행합니다:</p>python &lt;file_name&gt;.py<p>최종 결과는 다음과 같습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5ceffed004153a4f/6a1707d9a929cf9147ae0901/e909afbf0e47d9a6e0f7bd07dfb2efcfa5cf06ac-921x715.png" alt="" /><h2>결론</h2><p>LLM은 텍스트를 코드로 변환하거나 이미지를 코드로 변환할 때 강력한 시각적 기능을 발휘합니다. 또한 대시보드 API를 사용하면 JSON 파일을 대시보드로 전환할 수 있으며, LLM과 몇 가지 코드를 사용하면 이미지를 Kibana 대시보드로 전환할 수 있습니다.</p><p>다음 단계는 다양한 그리드 설정, 대시보드 크기 및 위치를 사용하여 대시보드 시각적 요소의 유연성을 개선하는 것입니다. 또한 더 복잡한 시각화 및 시각화 유형에 대한 지원을 제공하면 이 애플리케이션에 유용한 추가 기능이 될 것입니다.</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[AI]]></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>