<?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[統合 - 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[統合 - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/jp/search-labs/blog/category/integrations</link>
    </image>
    <link>https://www.elastic.co/jp/search-labs/blog/category/integrations</link>
    <atom:link href="https://www.elastic.co/jp/search-labs/rss/category/integrations.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[jp]]></language>
    <lastBuildDate>Tue, 29 Sep 2026 14:29:05 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Kibana Dashboards API：GA前に50以上のチームでテストされた、あらゆるパネルタイプに対応する安定した仕様]]></title>
    <description><![CDATA[Kibanaのダッシュボードをコードとして管理：Kibana APIとTerraformを使ってGitにコミットし、環境間で展開し、導入を自動化します。]]></description>
    <content:encoded><![CDATA[<p><a href="https://dashboardsapispec.kibana.dev/dashboards#tag/Dashboards">KibanaのDashboards APIとVisualizations API</a>は、Elastic 9.5で本番環境に対応しており、すべてのサブスクリプションティアで利用可能で、完全な下位互換性も備えています。ダッシュボードをJSONとして定義してGitにコミットし、継続的インテグレーションと継続的デプロイメント（CI/CD）パイプライン、<a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_dashboard">Terraform</a>、またはすでにお持ちのツールを使って環境全体にデプロイします。<a href="https://www.elastic.co/search-labs/blog/kibana-dashboards-as-code-terraform-api">9.4のテクニカルプレビュー</a>期間中に50以上のチームがAPIをテストし、中には既に本番環境で運用しているチームもあります。バージョン9.5では<a href="https://dashboardsapispec.kibana.dev/tags.html">タグ</a>用の新しいエンドポイント（テクニカルプレビュー中）が追加され、<a href="https://dashboardsapispec.kibana.dev/markdowns.html">マークダウン</a>および<a href="https://dashboardsapispec.kibana.dev/links.html#tag/Links">リンク</a>パネルエンドポイントはElastic Cloud Serverlessで利用可能となり、9.6でリリース予定です。</p><h2>Kibana Dashboards APIにおける後方互換性の意味</h2><p>テクニカルプレビュー中はリリース間でAPIの仕様が変更される可能性があります。[1]現在はこれは該当しません。一般提供（GA）開始とは、以下のことを意味します。</p><ul><li><p><strong>完全な後方互換性。</strong>新しいフィールドやパネルの種類は今後追加されますが、既存のフィールドや動作は変更されません。今後、互換性を損なうような変更を行う場合は、非常に慎重に検討し、新しいメジャーバージョンでのみ導入します。</p></li><li><p><strong>本番環境での利用に対応し、完全にサポートさ。</strong>このAPIには、Elasticの完全なサポート保証が付いています。本番環境では、自動化された導入、環境の昇格、およびプログラムによるダッシュボード管理に安全にご利用いただけます。</p></li></ul><h2>タグ、マークダウン、リンクパネル用の新しいKibana APIエンドポイント</h2><p>Elastic 9.5では、<a href="https://dashboardsapispec.kibana.dev/tags.html"><strong>タグ</strong></a>用の新しいスタンドアロンエンドポイントも導入され、ダッシュボードの分類やフィルタリングが可能になりました。専用のCRUDエンドポイントによりプログラムによる管理が可能になり、複数の環境にわたって大規模にダッシュボードを整理しやすくなりました。	</p><p>新しい<a href="https://dashboardsapispec.kibana.dev/markdowns.html"><strong>マークダウン</strong></a>および<a href="https://dashboardsapispec.kibana.dev/links.html#tag/Links"><strong>リンク</strong></a>パネルエンドポイントは現在Serverlessで利用可能で、次回のスタックリリース（9.6）に搭載される予定です。</p><h2>Kibana Dashboards APIはどのようなパネル型をサポートしていますか？</h2><p>Dashboards APIは、9.5のすべての<em>値渡し</em>パネル（再利用のために保存されたライブラリパネルとは対照的に、ダッシュボードで直接定義されたもの）をサポートしています。サポートされているすべてのパネル型には、型指定され検証済みのスキーマがあります。</p><p><strong>パネル型</strong></p><p><strong>ステータス</strong></p><p>XYチャート</p><p>サポートあり</p><p>メトリクス</p><p>サポートあり</p><p>円グラフ</p><p>サポートあり</p><p>ゲージ</p><p>サポートあり</p><p>ヒートマップ</p><p>サポートあり</p><p>データ表</p><p>サポートあり</p><p>ツリーマップ</p><p>サポートあり</p><p>Discoverセッション</p><p>サポートあり</p><p>コントロール</p><p>サポートあり</p><p>マークダウン</p><p>サポートあり</p><p>リンク</p><p>サポートあり</p><p>MLパネル</p><p>サポートあり</p><p>オブザーバビリティパネル</p><p>サポートあり</p><p>マップ</p><p>まもなくリリース</p><p>Vega</p><p>まもなくリリース</p><h2>Kibanaのダッシュボードをコードとして管理する方法</h2><p>Dashboards APIを使用すると、完全なダッシュボード・アズ・コードのワークフローが実現できます。ダッシュボードをクリーンで差分比較可能なJSONとしてエクスポートし、それをGitにコミットして真の情報源とし、プルリクエストで変更内容を確認し、開発環境、ステージング環境、本番環境に同じ定義をデプロイできます。ダッシュボードをコードとして管理するようになったら、Gitを唯一の信頼できる情報源として扱います。UIで直接行った変更は、次回デプロイ時に上書きされます。</p><p>ダッシュボードをスペース、クラスター、またはステージ間で移動する際の主な課題は、ダッシュボードがデータビューやライブラリの視覚化などのオブジェクトをIDで参照することです。これらのIDは自動生成され、環境ごとに異なるため、ある環境からエクスポートされたダッシュボードが、別の環境には存在しないオブジェクトを指し示すことがあります。この問題を解決するには3つの方法があり、自動化の度合いが高い順に以下に示します。</p><ul><li><p><strong>Terraformを使用する。</strong><a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_dashboard">Elastic Stack Terraformプロバイダー</a>は各リソースを追跡し、環境ごとにIDを自動マッピングするため、開発から本番環境へダッシュボードを移行する際に参照が一貫して保たれます。</p></li><li><p><strong>値渡しの</strong><a href="https://www.elastic.co/docs/explore-analyze/visualize/esorql"><strong>Elasticsearchクエリ言語（ES|QL）パネル</strong></a><strong>を定義する。</strong>パネルを構築する最もポータブルな方法は、ES|QLを使用してダッシュボードで直接可視化を定義することです。<a href="https://www.elastic.co/docs/explore-analyze/query-filter/languages/esql-kibana">ES|QL</a>クエリは、クエリ内で指定したインデックスからデータを読み取るため、パネルにはData viewやライブラリオブジェクトへの外部参照は含まれません。その結果、完全に自己完結型のポータブルダッシュボードとなります。</p></li><li><p><strong>一致するIDを割り当てる。</strong>Data viewやライブラリの視覚化など、保存済みのオブジェクトを参照する場合は、POST（IDを自動生成）ではなく、PUT（アップサート）を使用して、選択したIDでオブジェクトを作成してください。「logs-prod」のような人間が読みやすいIDを使うことで、環境を超えて再利用・認識しやすくなります。</p></li></ul><p>これらの移植性パターンとダッシュボード・アズ・コードのワークフロー全体に関する詳細な説明については、<a href="https://www.elastic.co/docs/explore-analyze/dashboards/manage-dashboards-as-code#dashboards-as-code-portability">「ダッシュボードをコードとして管理する」</a>ドキュメントをご覧ください。</p><h3>PUTメソッドを使用してDashboards APIでKibanaダッシュボードを作成</h3><p>ここでは、ダッシュボード名（service-health-overview）を使用してカスタムIDを割り当てるために、POSTではなくPUTを使用してメトリックパネルを含むダッシュボードを作成する簡単な例を示します。ライブラリに保存されたスタンドアロンの可視化を作成する場合も、同じロジックが適用されます。</p>PUT kbn:/api/dashboards/service-health-overview
{
  "title": "Service health overview",
  "description": "Key service metrics — managed via API",
  "tags": [
    "production",
    "sre-team"
  ],
  "panels": [
    {
      "type": "vis",
      "grid": {
        "x": 0,
        "y": 0,
        "w": 12,
        "h": 8
      },
      "config": {
        "title": "Error rate (5xx)",
        "type": "metric",
        "data_source": {
          "type": "esql",
          "query": "FROM logs-* | WHERE http.response.status_code &gt;= 500 | STATS error_rate=count(*) BY host.name"
        },
        "metrics": [
          {
            "type": "primary",
            "column": "count"
          }
        ]
      }
    }
  ]
}<h2>Kibana Dashboards APIロードマップ：マップ、Vega、スタンドアロンのエンドポイント</h2><p>APIの展開範囲を積極的に拡大していきます。次に、マップとVegaパネルのサポートを進め、それらに型付きスキーマを追加します。また、ダッシュボードのライフサイクルから切り離したDiscoverセッション（既存のダッシュボードパネルのサポートを超えて）、Vega、マップ、Annotations向けのスタンドアロンCRUDエンドポイントも構築しています。</p><p>スキーマ定義の詳細は、<a href="https://dashboardsapispec.kibana.dev/dashboards#tag/Dashboards">Dashboards APIドキュメント</a>をご覧ください。Terraformユーザー向けには<a href="https://registry.terraform.io/providers/elastic/elasticstack/latest/docs/resources/kibana_dashboard">Elastic Stack Terraformプロバイダー</a>が一般提供のDashboards APIをサポートしています。</p><h2>注</h2><ol><li><p>コアエンドポイントはテクニカルプレビュー版から変更されていません。9.4向けに構築した統合機能は、9.5でも動作します。唯一の破壊的変更は、ダッシュボード一覧と所要時間単位のフォーマットに影響を与える2つの小さな変更で、<a href="https://www.elastic.co/docs/release-notes/kibana/breaking-changes">こちら</a>に記載されています。</p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/dashboards-as-code-kibana-api</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/dashboards-as-code-kibana-api</guid>
    <category><![CDATA[Kibana]]></category>
    <category><![CDATA[開発者エクスペリエンス]]></category>
    <category><![CDATA[統合]]></category>
    <dc:creator><![CDATA[Teresa Alvarez Soler]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ed7e33de291f255/6a730619c8b7ac02b251f9d3/image1.png" length="0" type="image/png"/>
    <pubDate>Wed, 05 Aug 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[5分未満でオンプレミスに：Jina埋め込みモデルがオンプレミス導入に対応]]></title>
    <description><![CDATA[リランカーを含む全28種類のJina AIモデルを、テレメトリなし、ライセンスサーバーなしで、すぐにデプロイ可能なDockerコンテナーとして利用できます。OpenAI、Cohere、Voyage AI、Elastic Inference ServiceのAPIとドロップイン互換です。]]></description>
    <content:encoded><![CDATA[<p>Jina AIの28種類の埋め込みモデルおよび再ランク付けモデルはすべて、<a href="https://www.elastic.co/jp/search-labs/blog/jina-embeddings-v5-omni-all-media-one-index">jina-embeddings-v5-omni</a><a href="https://www.elastic.co/jp/search-labs/blog/jina-embeddings-v5-omni-all-media-one-index"> </a>や<a href="https://www.elastic.co/jp/search-labs/tutorials/jina-tutorial/jina-reranker-v3">jina-reranker-v3</a>を含め、オンプレミス導入用の完全オフラインのDockerコンテナーとして提供されるようになりました。1つダウンロードしてオンプレミスのエアギャップ環境やファイアウォールで保護されたシステムに転送するだけで、5分未満でローカル推論を実行できます。コンテナーは完全に自己完結型であり、外部接続を一切行いません。Hugging Faceやモデルレジストリへの呼び出しは発生しません。ライセンスサーバー、テレメトリ、ログエンドポイントも一切存在しません。これにより、規制対象の業界、データ主権要件、またはインターネットアクセスが不安定あるいはまったく利用できない環境において、サードパーティのAIサービスへの依存を解消できます。Jina On-Premは、Elastic Inference Service（EIS）、OpenAI、Cohere、Voyage AI、GeminiのAPIスキーマをサポートしているため、既存のアプリケーションをコード変更なしで動作させることができます。</p><p>最も強力なAIモデルはWeb API経由でアクセスするリモートのクラウド環境で実行されるため、セキュリティ、サービスの可用性、および安定した価格に関してAIサービスプロバイダーを信頼する必要があります。信頼性、プライバシー、管理可能なコスト、優れたデータガバナンスに対する合理的な要求と、ますます強力で高度かつ多くのリソースを必要とするAIの利用を簡単に両立させることはできません。</p><p>政府の規制、裁判所の決定、他者の利益を考慮したビジネス上の判断はいずれも、最近、特定のサービスへのアクセスを制限する結果となっています。また、他のサービスに切り替えることができたとしても、AIモデルはいつでも好きなときに簡単に交換できるようなコンポーネントではありません。セマンティック埋め込みを使用するアプリケーションは、データインジェスト時と同じモデルにクエリ時にもアクセスできることに依存しています。埋め込みモデルへのアクセスを失うことは、検索システムが停止することを意味します。</p><p>AI価格設定モデルはそのリスクをさらに増大させます。主要なAIベンダーによる最近の財務情報開示は、顧客が潜在的な値上げを懸念する十分な理由となっています。予測不能なコストを伴う製品への依存は、明確なリターンを生み出さない可能性がある資本集約的なAI投資に、さらなるリスクをもたらします。</p><p>Jina On-Premは、これらの課題に対するElasticの解決策です。</p><h2>オンプレミスAIを必要とするのは誰でしょうか？</h2><p>ローカルホスティングとAIモデルの直接制御により、さまざまな技術的要求、業界の要件、ビジネス上のニーズに対応できます。</p><p>ローカルにインストールすることで、AIサービスプロバイダーに支払う費用は削減できますが、ハードウェアや信頼性の高いアクセスのコストは組織が負担することになります。利用量によっては、単純にその方が安くなる場合もあります。しかし、自社でAIを実行することを検討すべき差し迫った理由は他にもあります。以下で説明する課題のいずれかが貴社に関係する場合は、Jina On-PremのようなローカルAIソリューションをご検討ください。このリストはすべてを網羅したものではありません。</p><p>ユースケース</p><p>なぜオンプレミスなのか</p><p>例</p><p>エアギャップ/高セキュリティ</p><p>アウトバウンドデータ送信なし、完全なネットワーク分離</p><p>防衛、インテリジェンス、機密研究</p><p>規制遵守</p><p>データ主権、国境を越えた送信やサードパーティへの露出なし</p><p>ヘルスケア（医療保険の相互運用性と説明責任に関する法律［HIPAA］）、金融、EU企業（一般データ保護規制［GDPR］）</p><p>レイテンシが重要</p><p>ネットワーク依存なし、接続障害は許容されない</p><p>ロボティクス、エッジコンピューティング、車両、船舶</p><p>コストの予測可能性</p><p>固定インフラコスト vs. 将来の料金が不確実なトークンごとの価格設定</p><p>大容量かつ継続的な推論ワークロード</p><p>責任の軽減</p><p>サードパーティへのデータ露出なし、法的特権と注意義務を維持</p><p>法律事務所、政府機関</p><h3>エアギャップ環境やファイアウォールで保護されたシステムにオンプレミスAIが必要な理由</h3><p>エアギャップ環境やファイアウォールで保護されたシステムでは、外部のAI APIを使用できません。Jina On-Premは、外部接続なしでお客様のインフラ上で完全に実行されます。</p><p>特に機密性の高いデータを管理する組織にとって、セキュリティとプライバシーへの配慮は最重要課題です。十分なセキュリティ対策が講じられていなかったり、外国政府の要求に従う可能性があったりする外部のサードパーティに機密データをすぐに渡してしまうのであれば、その保護に投資してもほとんど意味がありません。</p><p>機密データを扱う組織の従業員は、安全なデータ処理に関するトレーニングを受けることがよくありますが、そのデータを扱っている最中にインターネット上のあらゆるページを開くことができるWebブラウザーを全員が使用している場合、このトレーニングはあまり効果的ではありません。エアギャップや非常に厳格なファイアウォールによる分離は、利用可能な最も効果的なセキュリティ対策ですが、それによってあらゆる種類の外部サービスを利用することが困難になります。</p><h3>レイテンシの影響を受けやすいシステムや高可用性システム向けのオンプレミスAI</h3><p>サービスとしてのソフトウェア（SaaS）やクラウドコンピューティングは、自前のコンピューターでアクセス性と信頼性の高いサービスを提供するコストと、問題を他社にアウトソーシングすることとの間の妥協案です。しかし、これらにはレイテンシの変動や障害が伴い、問題が発生した際にコントロールを完全に失うことになります。AIサービスも例外ではありません。埋め込みモデルにアクセスできないときに検索システムがオフラインになるのであれば、それはもはや優れた妥協案とは言えないかもしれません。</p><p>さらに、外部のAIに依存すると、簡単に予測や管理ができないリスクが常に伴います。政治的出来事、悪天候、または海底光ファイバーケーブルにアンカーを引っ掛ける船舶などが原因で、インターネットアクセスやネットワークのレイテンシーは予告なく悪化する可能性があります。政府機関は、AIモデルへのアクセスを突然ブロックするために輸出禁止措置を使用することがあり、実際、近年そのような事例が発生しています。AIサービスプロバイダーは、より新しいモデルへの切り替えを促すために、モデルの提供を終了することがあります。外部サービスの柔軟性と管理可能なコストは、依存に伴うリスクとのバランスを取る必要があります。</p><h3>GDPR、HIPAA、データ主権のコンプライアンスに対応するオンプレミスAI</h3><p>個人データを収集する組織は、管轄区域によって異なり、相反する要件が課されることもある、ますます厳格な規制の対象となります。特に、<a href="https://www.hhs.gov/hipaa/for-professionals/privacy/laws-regulations/index.html">HIPAAの規則</a>は米国の医療提供者に非常に厳格なデータ保護を課しており、また<a href="https://laws-lois.justice.gc.ca/eng/acts/p-8.6/">カナダ</a>、<a href="https://gdpr-info.eu/">欧州連合</a>、および<a href="https://www.japaneselawtranslation.go.jp/en/laws/view/4241">多くのアジアの管轄区域</a>における厳格な一般データ保護法では、個人情報を扱うすべての企業に対して、安全な方法で処理を行うこと、およびそのデータの他の当事者や他の管轄区域への転送を制限することが義務付けられています。これらの規則は、外国の事業者がそれらの管轄区域内に顧客を持っている場合、その事業者に対しても義務を課すことがあります。金融機関は、多くの場合、さらに厳格な規則の対象となり、他の形態の犯罪行為に対して負うのと同様に、情報セキュリティに対しても直接的な責任を負います。</p><p>規制への準拠は、特にサードパーティのAIサービスの使用に国境を越えたデータ送信が伴う場合、それらのサービスと両立しない可能性があります。</p><p>さらに、最近の出来事が示しているように、国際的なクラウド事業者が外国政府からの圧力を受けた場合、データストアの物理的な場所を制限する規則は信頼できる保護手段とならない可能性があります。国内法が管轄区域間で抵触し、ローカルでのデータストレージと処理が義務付けられ、サードパーティサービスの利用が不可能になる場合があります。場合によっては、AIシステムを含め、プロセスのすべての部分をインハウス化することだけが唯一のソリューションとなることもあります。</p><h3>サードパーティのデータ送信によるAIの法的責任リスク</h3><p>データ保護法や機密データの取り扱いに関する注意義務は、通常、法的責任を伴い、時には非常に重大なものとなることがあります。サードパーティのサービス提供業者によるデータの取り扱いについて、お客様が法的責任を負う可能性があります。裁判所や法的手続きによって、安全でないサービス提供業者からある程度事後的な保護が得られる場合もありますが、そうした救済措置は、国家安全保障機関、法執行機関、あるいは犯罪的なハッカーに対しては利用できないか、一般的にも有効ではありません。</p><p>政府に関しては、国境を越えてサービスを提供するクラウドサービスプロバイダーが、機密性の高い国家情報を外国の関係者に開示した事例がすでに発生しています。</p><p>しかし、外国の政府やハッカーについて心配しておらず、外部のAIサービスプロバイダー自体が安全である場合であっても、それらが外部にあるという事実だけで法的責任が生じる可能性があります。</p><p>例えば、ほとんどの管轄区域において、弁護士とクライアントとのコミュニケーションは特別な法的保護を受けており、法律事務所がこの情報を記録または格納する際には厳格な法的責任を負います。米国では、この「弁護士・クライアント間の秘匿特権」は非常に有名で、映画やテレビ番組のプロットの中心にもなっています。しかし、その秘匿特権が失われる理由の1つとして、特権を有しない人物と情報を共有することが挙げられ、最近の動向からは、外部のAIサービスプロバイダーがそのような人物に該当する可能性があることが示唆されています。</p><p>少なくともアメリカ合衆国においては、インデキシングサービスを提供する埋め込みモデルなど、サードパーティのAIサービスをインターネットAPI経由で利用するだけでも、重大な機密保持規則に違反する可能性があります。法律事務所は、セキュリティ侵害が発生しなかったとしても、外部でホストされているソフトウェアを使用しているというだけで、訴訟を起こされたり、懲戒処分を受けたり、弁護士資格を剥奪されたりする可能性があります。</p><h3>オフライン、エッジ、および物理的に隔離されたシステム向けのオンプレミスAI</h3><p>コンピューターシステムが分離される理由は、セキュリティ上の理由だけではありません。例えば、移動する車両は、不可欠な機能においてインターネット接続に頼ることはできません。船舶や航空機には非常に大規模なオンボードコンピューターシステムが搭載されており、インターネット接続なしで機能する必要があるため、外部のAIサービスを使用することはできません。海洋プラットフォーム、僻地にあるリモート施設、北極や南極、グローバルネットワークへの適切な物理接続がない小さな島々にあるコンピューターサービスはすべて、必要なすべてのサービスをローカルでホストすることでメリットを得られる設備の例です。エンタープライズコンピューティングにおけるAIの役割が大きくなるにつれ、これらの制限に対処することがより重要になります。</p><p>物理システムへのAIの新たな応用（ロボティクスや、物流管理システム、さらにはスーパーマーケットのレジなどの、限られた空間内で動作する、または現実世界を対象とするその他のユースケース）は、グローバルインターネットに接続されている可能性がありますが、接続障害やレイテンシーの急増を許容することはできません。運用のためにAIシステムに依存している場合、そのAIシステムは可能な限りローカルで、信頼性が高くなければなりません。</p><h2>オンプレミスAIを必要としないのは誰でしょうか？</h2><p>リモートソフトウェアサービスやオフサイトAIには、確かにメリットがあります。AIモデルの実行には、寿命が短いことで知られる、高価で消費電力の大きいプロセッサーが必要になる場合があります。市場要因や外部の経済ショックにより、現在、高品質なハードウェアの入手は特に困難になっています。このような状況下では、ローカルAIの高額な資本コストを負担する代わりに、外部APIを使用してトークン単位で支払う方が理にかなっている場合があります。</p><p>外部APIは、断続的に利用するユーザーに最も適しています。AIモデルを主に分析のためのデータのバッチ処理に使用し、常時オンラインで稼働させる必要のある検索システムを実行しない場合、多額の資本を要するハードウェアやローカル環境への投資はほとんど意味がありません。</p><p>さらに、信頼性やアクセシビリティの理由からクラウドでホストされているEC Webサイトなど、データ処理がすでにクラウドベースである場合、同じクラウドインフラ内にあるAIサービスを使用する方が、独自にライセンスを取得したAIモデルを導入するよりも費用対効果が高くなる可能性があります。すでにクラウドサービスプロバイダーに依存しているため、そのAIサービスに依存してもリスクが大幅に増えることはありません。</p><p>お客様のユースケースがこの説明に当てはまる場合は、お客様のニーズに対応するため、<a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/eis">EIS</a>、<a href="https://aws.amazon.com/marketplace/seller-profile?id=seller-stch2ludm6vgy">AWS Marketplace</a>、<a href="https://console.cloud.google.com/marketplace/browse?q=jina">Google Cloud Platform</a>でJina AIモデルをご利用いただけます。</p><p>以下の表は、主な要素をまとめたものです。どちらが適しているかは、お客様のデータ、インフラ、使用パターンによって異なります。</p><p>要因</p><p>オンプレミスを優先</p><p>Cloud APIを優先</p><p>使用パターン</p><p>継続的または大量の推論</p><p>断続的な処理またはバッチ処理</p><p>データの機密性</p><p>規制対象、データ主権の対象、または機密</p><p>国境を越えたデータ移転や第三者への提供に関する制限なし</p><p>ネットワーク環境</p><p>エアギャップ、ファイアウォール保護、または不安定な環境</p><p>安定した常時接続のインターネット</p><p>既存のインフラ</p><p>GPUハードウェアを所有している、または調達できる</p><p>AIと同じ場所ですでにクラウドホストされている</p><p>コストモデル</p><p>固定ハードウェア + ライセンス、大規模でも予測可能</p><p>トークン単位；初期費用は低く、長期的には変動</p><p>レイテンシー許容度</p><p>なし（ロボティクス、エッジ、リアルタイム）</p><p>ネットワークの変動を許容可能</p><p>運用責任</p><p>お客様のチームがハードウェアと可用性を管理</p><p>プロバイダーがハードウェアとアップデートを管理し、お客様側で統合を管理</p><p>前出のセクションで取り上げた問題のうちお客様に該当するものを踏まえ、個別の状況やユースケースに照らして費用対効果を検討する必要があります。費用対効果分析は、時間の経過とともに変化することは間違いありません。短期的であっても、AI業界の未来やハードウェアの価格を予測することはできません。</p><h2>Jina On-Premのご紹介</h2><p>ローカルAIサービスを活用できるユーザー向けに、Jina AIの高性能モデルを完全に自己完結した形で導入するためのインストールスイートである<a href="https://github.com/jina-ai/jina-on-prem/wiki/">Jina On-Prem</a>をご紹介します。</p><p>Jina AIのモデルは、<a href="https://mteb-leaderboard.hf.space/benchmark/MTEB(Multilingual%2C%20v2)">何倍も大きな</a>埋め込みモデルと同等の精度を誇り、計算コスト、メモリ使用量、ハードウェア要件を削減します。そのため、AIをオンプレミスで維持したい、あるいは維持する必要があるユーザーにとって最適な選択肢となります。商用ライセンスは、あらゆる規模のユースケースに対応する、拡張性がある規模に応じた価格設定のソリューションとして提供されています。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt190865fb3ebde472/6a6a33d0065b162508701ff9/02559ceca556a26c53eb703ae87d421452b27251-1374x1400.png" alt="MMTEB Multilingual v2 leaderboard showing Jina AI embedding model rankings: jina-embeddings-v5-omni-small and jina-embeddings-v5-text-small ranked 13th, jina-embeddings-v5-omni-nano and jina-embeddings-v5-text-nano ranked 19th, competing against models from Microsoft, Google, Tencent, NVIDIA and Qwen" /><h3>JinaオンプレミスはどのAPIスキーマをサポートしていますか？</h3><ul><li><p>ローカルインストール用の依存関係一式として、あるいは数分でインストールして実行できる<a href="https://www.docker.com/">Dockerコンテナー</a>として利用できます。</p></li><li><p>Jina On-Premインストールは、外部システムを<em>呼び出しません</em>。</p><ul><li><p>Hugging Face Hubやモデルレジストリへの呼び出しは行われません（HF_HUB_OFFLINE=1およびTRANSFORMERS_OFFLINE=1が組み込まれています）。</p></li><li><p>ライセンスサーバーはありません。</p></li><li><p>テレメトリまたはログのエンドポイントはありません。</p></li></ul></li><li><p>CPUとGPUの両方のハードウェアをサポートしており、GPUの自動検出に対応しています。</p></li><li><p>最新の<a href="https://www.elastic.co/jp/search-labs/blog/jina-embeddings-v5-omni-all-media-one-index">jina-embeddings-v5-omni</a>マルチモーダル埋め込みモデルおよび<a href="https://www.elastic.co/jp/search-labs/tutorials/jina-tutorial/jina-reranker-v3">jina-reranker-v3</a>を含む、全28種類のJina AIモデルが利用可能です。</p></li><li><p>標準的なAI APIスキーマ（<a href="https://jina.ai/api-dashboard">Jina API</a>、OpenAI、Cohere、Voyage AI、Gemini）経由でアクセスできます。Jina On-Premは、それらのスキーマ上に構築されたアプリケーション向けのドロップインソリューションです。</p></li><li><p><a href="https://www.elastic.co/docs/explore-analyze/elastic-inference/eis">EIS</a>で提供されるモデルのドロップイン代替として使用できます。Jina On-Premは、<a href="https://www.elastic.co/jp/blog/deploy-elastic-air-gapped-disconnected-environments">エアギャップ環境に導入されたElastic</a>と直接統合されます。</p></li></ul><h2>Jina AIオンプレミスモデルのハードウェア要件</h2><p>ハードウェア要件はJinaモデルによって異なります。以下の表は、GPUを使用する場合の最新モデルの推奨事項を示しています。NVIDIA L4 GPUを上回る性能は必要ありませんが、v5埋め込みモデルにはA100が推奨されます。当社の最新の埋め込みモデルには、現在最低8GBのVRAMが必要です。</p><p>モデル</p><p>最低VRAM</p><p>推奨GPU</p><p>jina-embeddings-v5-text-nano</p><p>2GB</p><p>T4 / L4</p><p>jina-embeddings-v5-text-small</p><p>3GB</p><p>L4 / A10G</p><p>jina-embeddings-v5-omni-small</p><p>8GB</p><p>L4 / A10G / A100</p><p>jina-reranker-v3</p><p>3GB</p><p>L4</p><p>jina-clip-v2</p><p>4GB</p><p>L4</p><p>jina-code-embeddings-1.5b</p><p>4GB</p><p>L4</p><p>ReaderLM-v2</p><p>4GB</p><p>L4</p><p>一度に複数のモデルを使用する場合、必要なVRAM容量が増大します。詳細については、<a href="https://github.com/jina-ai/jina-on-prem/wiki/Sizing-And-Hardware">サイジングとハードウェアのページ</a>をご参照ください。</p><h2>DockerでJina On-Premをインストールする方法</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt20265d09e2d8d0f4/6a6a33d1065b162105701ffd/ada9881af407168298b1940f8537ad71a5411c89-1999x1200.png" alt="" /><p>最もすばやく利用を開始するには、（まだインストールしていない場合は）<a href="https://www.docker.com/get-started/">Dockerをインストール</a>して、<a href="https://github.com/jina-ai/jina-on-prem/wiki/QuickStart">Jina On-Premクイックスタート</a>ページの手順に従います。</p><p>全28種類のJinaモデル向けに、あらかじめ構築されたDockerコンテナーが用意されています。1つをダウンロードしてインストール先に転送すれば、5分足らずでJina AIモデルを稼働させることができます。</p><p>マルチモーダルまたはカスタムビルドの場合、あるいはコンテナー外にインストールするために依存関係一式をダウンロードする場合は、<a href="https://github.com/jina-ai/jina-on-prem/wiki/Bundling-Guide">バンドルガイド</a>に記載されている手順に従ってください。</p><p>Jina On-Premインストールは、すべてのJina APIおよびEIS機能、ならびにOpenAI、Cohere、Voyage AI、Gemini APIを介した埋め込み生成をサポートしているため、標準的なインターフェースを使用して既存のアプリケーションに統合できます。詳細については、<a href="https://github.com/jina-ai/jina-on-prem/wiki/API-Reference">APIドキュメント</a>をご参照ください。</p><p>Jina On-Premでインストールされたモデルを含むJinaモデルは、さまざまなライセンス条件で利用でき、最新モデルは<a href="https://creativecommons.org/licenses/by-nc/4.0/deed.en">CC BY-NC 4.0</a>ライセンスの下で非商用目的に無料で利用できます。Jina On-Premを商用利用するためにライセンスを取得する場合は、<a href="https://www.elastic.co/jp/contact">Elastic営業担当</a>までお問い合わせください。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/on-prem-ai-jina-embedding-models</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/on-prem-ai-jina-embedding-models</guid>
    <category><![CDATA[Jina AI]]></category>
    <category><![CDATA[統合]]></category>
    <dc:creator><![CDATA[Scott Martens]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt17731ab0c6ec66f6/6a6a33d140a4941014ca5c9a/09bc6dac4e6a86c7877f8ed78d68f5d581aeffa9-1999x1200.png" length="0" type="image/png"/>
    <pubDate>Thu, 23 Jul 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elasticsearchに火を灯す：Prometheus APIのネイティブサポートを追加]]></title>
    <description><![CDATA[Prometheus互換のクライアントから、ネイティブのPromQL、ディスカバリー、メタデータエンドポイント経由でElasticsearchに直接クエリを実行できます。Prometheus Remote WriteでElasticsearchにデータを送信します。]]></description>
    <content:encoded><![CDATA[<p>Prometheusと互換性のある任意のクライアントをElasticsearchに向け、既存のメトリックに対してPromQLを直接実行します。Elasticsearchは、Prometheusのリモート書き込み、OpenTelemetry、またはBulk APIを通じて取り込まれたメトリックで動作するネイティブのPrometheusクエリ、検出、およびメタデータのエンドポイントをテクニカルプレビューとして追加しています。APIはElasticsearchの時系列データストリーム（TSDS）上で動作するので、Prometheus固有のストレージレイヤーを個別に運用する必要はありません。</p><p>この記事では、クエリ、検出、メタデータのエンドポイントが、以前の取り込みとクエリの作業に基づいてどのように構築され、APIサーフェスを形成するのかを説明します。関連記事では、個々のトピックについてさらに詳しく掘り下げています。</p><ul><li><p><a href="https://www.elastic.co/observability-labs/blog/elasticsearch-supports-promql">ES|QLのネイティブPromQLサポート</a>では、PromQLクエリがES|QL実行プランに変換される仕組みについて説明します。</p></li><li><p><a href="https://www.elastic.co/observability-labs/blog/prometheus-remote-write-elasticsearch">Prometheus MetricsをRemote WriteでElasticsearchに送信する</a>手順では、取り込み設定について説明します。</p></li><li><p><a href="https://www.elastic.co/observability-labs/blog/prometheus-remote-write-elasticsearch-architecture">ElasticsearchにおけるPrometheus Remote Writeインジェストの仕組み</a>では、リモート書き込みの内部構造を説明しています。</p></li></ul><p>これはまだ開発途中の機能です。以下のセクションでは、現在サポートされている機能と、まだ開発中の部分について記載しています。</p><h2>APIサーフェス</h2><p>現在、Prometheus互換APIサーフェスは3つのグループに分かれます。</p><h3>クエリエンドポイント</h3><p>クエリエンドポイントを使用すると、Prometheus互換クライアントはPromQL式を評価できます。</p><ul><li><p><code>GET /_prometheus/api/v1/query_range</code> は時間ウィンドウ内でPromQL式を評価します（マトリクス結果）。</p></li><li><p><code>GET /_prometheus/api/v1/query</code> は単一の時点で評価します（ベクトル結果）。現在は、最後のサンプルを返す短範囲クエリとして実装されています。</p></li></ul><p>現在、クエリエンドポイントでサポートされているのはGETのみです。一部のクライアントはデフォルトでPOSTを使用するため、GETを使用するように設定する必要があります。PrometheusのPOST規約では<code>application/x-www-form-urlencoded</code>本文を使用しますが、ElasticsearchのHTTPレイヤーは、リクエストがハンドラーに到達する前にCSRF対策として拒否します。</p><p>PromQLの完全なカバレッジ状況については、<a href="https://www.elastic.co/observability-labs/blog/elasticsearch-supports-promql">ES|QLにおけるPromQLに関する関連記事</a>をご覧ください。</p><h3>メタデータエンドポイント</h3><p>メタデータエンドポイントは、クライアントがオートコンプリート、変数のドロップダウン、およびメトリックのブラウジングに必要な検出情報を提供します。</p><p>シリーズ、ラベル、およびラベル値のエンドポイントはすべて <code>match[]</code> セレクターと時間範囲 (<code>start</code>/<code>end</code>) を受け入れます。<code>match[]</code>パラメーターは<code>http_requests_total{job="api"}</code>のようなPrometheusシリーズセレクターを取り、一致する時系列に対応を制限します。これにより、多数のメトリクスを持つクラスター上で対応を迅速かつ関連性の高いものに保ちます。例：</p>GET /_prometheus/api/v1/series?match[]=http_requests_total{job="api"}GET /_prometheus/api/v1/labels?match[]=http_requests_totalGET /_prometheus/api/v1/label/instance/values?match[]=http_requests_total{job="api"}<p>最初の関数は、 <code>http_requests_total</code>かつ<code>job="api"</code>であるすべての系列を、完全なラベルセットとともに返します。2番目は、 <code>http_requests_total</code>シリーズに存在するラベル名のみを返します。3番目の結果は、マッチングするシリーズに現れる <code>instance</code> 値のみを返します。</p><p><code>GET /_prometheus/api/v1/metadata</code> は異なります。各メトリックのタイプと単位を返し、オプションで<code>metric</code>パラメーターを使用して名前でフィルタリングできます。</p>GET /_prometheus/api/v1/metadata?metric=http_requests_total<p><code>match[]</code>セレクターや時間範囲は受け付けません。Prometheusでは、メタデータはアクティブなスクレイピングターゲット（それらが公開する<code>HELP</code>、 <code>TYPE</code>、 <code>UNIT</code>行）から収集されるため、応答にはデータスキャンは含まれません。Elasticsearchにはそのような専用のメタデータストアがないため、現在の実装では過去24時間の時系列データを参照することでメトリックメタデータを検出しています。これにより、インデックス全体のスキャンを必要とせずにクエリの高速性を維持できます。その24時間遡及は現在本日に固定されています。PrometheusメタデータAPIは、Elasticsearchがユーザー調整可能にするために使用できる<code>start</code>または<code>end</code>パラメーターを公開していません。</p><p>メタデータエンドポイントがどのように機能するかについては、<code>TS_INFO</code> と <code>METRICS_INFO</code> コマンドを含め、<a href="https://www.elastic.co/search-labs/blog//elasticsearch-native-prometheus-api#ts-info-and-metrics-info">以下で</a>説明します。</p><h3>インデックスの事前フィルタリング</h3><p>すべてのクエリとメタデータエンドポイントは、<code>/_prometheus/</code> の後にオプションの <code>{index}</code> パスセグメントを受け入れます。</p>GET /_prometheus/metrics-prod-*/api/v1/query_range?query=up&amp;start=...&amp;end=...<p>これは、式の評価を開始する前に、どのElasticsearchインデックスに対してクエリを実行するかを制限します。複数のチームや環境にわたる多くのデータストリームを持つクラスターでは、無関係なインデックスのスキャンを避けることで、クエリのレイテンシを大幅に削減できます。チームごとに独自のメトリクスへのスコープ付きアクセスを提供するために、インデックスパターンごとに個別のデータソースを設定できます。</p><h3>リモート書き込みに関する注意事項</h3><p>インジェストのために、Elasticsearchは標準のPrometheus Remote Writeエンドポイントを公開しています。</p><ul><li><p><code>POST /_prometheus/api/v1/write</code> Prometheus Remote Write v1プロトコルを介して時系列データを取り込みます。v2はまだサポートされていません。</p></li></ul><p>Remote Writeは、Prometheus専用のストレージレイヤーではなく、Elasticsearchの既存の時系列データストリーム（TSDS）に書き込みます。PrometheusのラベルはTSDSディメンションになり、メトリック名はインデックスマッピングのフィールドになります。<a href="https://www.elastic.co/observability-labs/blog/prometheus-remote-write-elasticsearch-architecture">リモート書き込みアーキテクチャの記事</a>では、メトリックタイプがどのように推論され、ラベルが<code>labels.</code>プレフィックスでどのように格納されるかを含む、マッピングの詳細を網羅しています。</p><h3>プログラム概要</h3><p>内部的には、すべてのエンドポイントは同じように動作します。受信したHTTPパラメーターを解析し、ES|QLクエリプランを作成し、時系列データストリームに対してそれを実行し、列形式の結果をPrometheusクライアントが期待するJSON形式に変換します。</p><h2>TS_INFOとMETRICS_INFO</h2><p>メタデータエンドポイントは、すべてのデータポイントをスキャンすることなく、数百万もの時系列データに対して、「どのようなラベルが存在するか？」や「どのようなメトリックタイプが定義されているか？」といった質問に答える必要があります。</p><p>内部的には、Prometheusのメタデータエンドポイントは、2つの新しい処理コマンド<code>METRICS_INFO</code>と<code>TS_INFO</code>を中心にES|QLプランを構築することで、これらの質問に答えます。Prometheus APIを使用するためにこれらのコマンドを直接使用する必要はありませんが、これらはメタデータ応答の背後にあるコアとなる実行プリミティブです。どちらも、すべてのサンプルをスキャンするのではなく、時系列ごとに1つの文書にのみアクセスしてメタデータを抽出します。これは、コストがデータポイントの数ではなく、個別の時系列の数に応じてスケールすることを意味します。</p><p><code>METRICS_INFO</code> 1行ごとに、その名前、タイプ、単位、および関連するディメンションフィールドを持つ固有のメトリックを返します。<code>TS_INFO</code>はより詳細な情報を提供します。メトリック、時系列の組み合わせごとに1行が含まれ、実際のディメンション値がJSONオブジェクトとして含まれます。</p><p><code>TS_INFO</code>と<code>METRICS_INFO</code>に関する専用のブログ記事がまもなく公開されます。二段階実行モデル、それらのスケール方法、そしてPrometheus APIを超えてES|QLクエリで直接使用する方法について詳しく解説します。</p><h3>メタデータエンドポイントがこれらを使用する方法</h3><p>各メタデータエンドポイントは、これらのコマンドのいずれかをコアとしてES|QLプランを構築します。</p><p><code>/api/v1/labels</code> また、<code>/api/v1/series</code>は<code>TS_INFO</code>を使用します。これは、時系列ごとの詳細情報（どのラベルが存在するか、どのディメンション値が各系列を識別するか）が必要なためです。<code>/api/v1/metadata</code>と<code>/api/v1/label/__name__/values</code>は、メトリクス名、型、単位などの各メトリクス情報のみを必要とするため、<code>METRICS_INFO</code>を使用します。</p><p><code>/api/v1/label/{name}/values</code> 通常のラベル（<code>__name__</code>以外）の場合は、どちらのコマンドも使用しません。通常のラベル <code>job</code> や <code>instance</code> は、インデックス内の実際のディメンションフィールドなので、エンドポイントはグループ分けアグリゲーションで直接クエリできます。<code>match[]</code> 個のセレクターが提供されると、それらは時系列をフィルタリングする <code>WHERE</code> 句に変換され、アグリゲーションが実行される前に適用されます。</p><p><code>__name__</code>ラベルは、ディメンションフィールドとして常に存在するとは限らないため、別の戦略が必要です。Prometheus Remote Writeは<code>labels.__name__</code> を保存しますが、他の経路（OpenTelemetry、Bulk API）で取り込まれたメトリクスには保存されません。メトリック名はフィールド名自体にエンコードされています（例： <code>metrics.http_requests_total</code> ）。インデックスマッピングを見てフィールド名を列挙することはできますが、マッピングだけではどのメトリックがどのディメンションを持っているかはわかりませんし、 <code>match[]</code>セレクターからのラベル値でフィルタリングすることもできません。<code>METRICS_INFO</code>は両方を行うことができます。インデックス全体でメトリック名を列挙しながら、上流の<code>WHERE</code>フィルターを尊重します。</p><p>すべての場合において、APIレイヤーはPrometheusの規則に戻す変換を処理します。<code>labels.</code>と<code>metrics.</code>のストレージプレフィックスを除去し、<code>__name__</code>をPrometheus以外のメトリクスに対して合成します。</p><h2>まとめ</h2><p>その結果、Prometheusと互換性のあるクライアントであれば、すでに理解しているエンドポイントを利用してElasticsearchをクエリし、調査することができます。リモート書き込みメトリック、OpenTelemetryメトリック、およびその他の経路でインデックスされたメトリックはすべて、同じTSDSインデックスによって支えられた同じAPIを通じて表示されます。</p><p>ここで紹介したすべてのPrometheus APIは、現在Elasticsearch Serverlessのテクニカルプレビューとして利用可能です。セルフマネージドクラスターおよびElastic Cloud Hostedの導入は、<code>GET /_prometheus/api/v1/metadata</code>を除いて、Elasticsearch 9.4でテクニカルプレビューとして利用可能です。ローカルで実験するには<a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart">start-local</a>を使用します。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-native-prometheus-api</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-native-prometheus-api</guid>
    <category><![CDATA[統合]]></category>
    <dc:creator><![CDATA[Felix Barnsteiner]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt12b4e100d5bbb7f0/6a16f7a22b835ff747f4afdd/c7b333bd73e8a1f4e18486b2d692ba742788dcfd-1376x768.jpg" length="0" type="image/jpeg"/>
    <pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[TypeScriptを使用したElasticsearch MCPサーバーの作成]]></title>
    <description><![CDATA[TypeScriptとClaude Desktopを使用してElasticsearch MCPサーバーを作成する方法を学びます。]]></description>
    <content:encoded><![CDATA[<p>Elasticsearchで大規模なナレッジベースを扱う場合、情報を見つけるだけでは片手落ちです。エンジニアは複数の文書から結果を統合し、要約を作成し、回答を情報源にたどる必要があることが多いです。モデルコンテキストプロトコル（MCP）は、Elasticsearchと大規模言語モデル（LLM）アプリケーションを接続するための標準化された方法を提供します。ElasticはElastic Agent Builder（<a href="https://www.elastic.co/docs/solutions/search/agent-builder/mcp-server">MCPエンドポイントを</a>機能の一つに含む）のような公式ソリューションを提供していますが、カスタムMCPサーバーを構築することで、検索ロジック、結果のフォーマット、取得したコンテンツをLLMに渡して合成、要約、引用を行う方法などを完全に制御できます。</p><p>この記事では、カスタムElasticsearch MCPサーバーを構築するメリットを探り、ElasticsearchをLLM対応アプリケーションに接続するサーバーをTypeScriptで作成する方法を紹介します。</p><h2>カスタムのElasticsearch MCPサーバーを構築する理由</h2><p>Elasticは<a href="https://www.elastic.co/docs/solutions/search/mcp">MCPサーバー</a>のいくつかの代替手段を提供しています。</p><ul><li><p><a href="https://www.elastic.co/docs/solutions/search/agent-builder/mcp-server">Elasticsearch 9.2+用Elastic Agent Builder MCPサーバー</a></p></li><li><p><a href="https://github.com/elastic/mcp-server-elasticsearch?tab=readme-ov-file#elasticsearch-mcp-server">旧バージョン向けのElasticsearch MCPサーバー（Python）</a></p></li></ul><p>MCPサーバーとElasticsearchの連携方法をより細かく制御したい場合は、独自のカスタムサーバーを構築することで、ニーズに合わせて柔軟にカスタマイズできます。例えば、Agent BuilderのMCPエンドポイントはElasticsearchクエリ言語（ES|QL）クエリに限定されていますが、カスタムサーバーでは完全なクエリDSLを使用できます。また、LLMに渡される前に結果をどのようにフォーマットするかを制御でき、このチュートリアルで実装するOpenAIを利用した要約など、追加の処理ステップを統合することもできます。</p><p>この記事を読み終える頃には、Elasticsearchインデックスに保存されている情報を検索し、要約し、引用を提供するTypeScriptで記述されたMCPサーバーが完成しているでしょう。Elasticsearchを使用して情報を検索し、OpenAIの<code>gpt-4o-mini</code>モデルを用いて要約と引用を生成し、Claude DesktopをMCPクライアントおよびUIとして活用してユーザーのクエリを受け取り、応答を提供します。最終的には、エンジニアが組織内の技術文書全体からベストプラクティスを発見し、統合するのに役立つ内部ナレッジアシスタントが完成します。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltad9133cb083ad352/6a170c19b0367d411e72bd5b/ec5771a874cf9740d4cac6888622cbe8cd6aede7-1999x1133.png" alt="TypeScriptとClaude Desktopを使用してElastic MCPサーバーを作成します。" /><h2>要件：</h2><ul><li><p>Node.js 20 +</p></li><li><p>Elasticsearch</p></li><li><p>OpenAI APIキー</p></li><li><p>Claude Desktop</p></li></ul><h3>MCPとは何ですか？</h3><p><a href="https://www.elastic.co/what-is/mcp">MCP</a>は<a href="https://www.anthropic.com/news/model-context-protocol">Anthropic</a>によって作成されたオープンスタンダードで、LLMとElasticsearchのような外部システムとの間で安全かつ双方向の接続を提供します。MCP の現状については<a href="https://www.elastic.co/search-labs/blog/mcp-current-state">この記事</a>で詳しく読むことができます。</p><p>MCPの環境は<a href="https://www.elastic.co/search-labs/blog/mcp-current-state#mcp-project-updates:-transport,-elicitation,-and-structured-tooling">日々進化</a>しており、多様なユースケースに対応したサーバーが利用可能です。さらに、この記事でご紹介するように、独自のカスタムMCPサーバーを簡単に構築することもできます。</p><h3>MCPクライアント</h3><p><a href="https://modelcontextprotocol.io/clients">利用可能なMCPクライアント</a>は多数あり、それぞれに特徴や制限があります。簡便性と普及度を考慮し、今回はMCPクライアントとして<a href="https://claude.ai/download">Claude Desktop</a>を使用します。これは、ユーザーが自然言語で質問できるチャットインターフェースとして機能し、MCPサーバーが公開しているツールを自動的に呼び出して、文書を検索し、要約を生成します。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt06fd7a02042094e1/6a170c1b14b2700024e3c651/66eb0b11473347b6cf2d85718251eeac38d6249d-1999x1491.png" alt="「Coffee and Claude time? How can I help you today?」というメモが表示されたClaude 4.5 Sonnetのページ" /><h2>Elasticsearch MCPサーバーの作成</h2><p><a href="https://github.com/modelcontextprotocol/typescript-sdk">TypeScript SDK</a>を使えば、ユーザーのクエリ入力に基づいてElasticsearchデータのクエリ方法を理解するサーバーを簡単に作成できます。</p><p>この記事では、Elasticsearch MCPサーバーとClaude Desktopクライアントを統合するための手順を説明します。</p><ol><li><p><a href="https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude#configure-mcp-server-for-elasticsearch">Elasticsearch 用の MCP サーバーを設定してください。</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude#load-the-mcp-server-into-claude-desktop">MCPサーバーをClaude Desktopにロード</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude#test-it-out">試してみてください。</a></p></li></ol><h3>Elasticsearch MCPサーバーを設定してください</h3><p>まず、Nodeアプリケーションを初期化します。</p>npm init -y<p>これで <code>package.json</code>ファイルが作成され、このアプリケーションに必要な依存関係のインストールを開始できます。</p>npm install @elastic/elasticsearch @modelcontextprotocol/sdk openai zod &amp;&amp; npm install --save-dev ts-node @types/node typescript<ul><li><p><strong>@elastic/elasticsearch</strong> はElasticsearchのNode.jsライブラリにアクセスするためのものです。</p></li><li><p><strong>@modelcontextprotocol/sdk</strong>は、MCPサーバーの作成と管理、ツールの登録、MCPクライアントとの通信処理を行うためのコアツールを提供します。</p></li><li><p><strong>openai</strong>は、OpenAIのモデルと対話し、要約や自然言語による対応を生成することができます。</p></li><li><p><a href="https://zod.dev/"><strong>zod</strong></a>は、各ツールの入出力データの構造化スキーマの定義と検証に役立ちます。</p></li></ul><p><code>ts-node</code>、<code>@types/node</code>、 <code>typescript</code>は開発中にコードの入力やスクリプトのコンパイルに使用されます。</p><h4>データセットを設定</h4><p>Claude DesktopがMCPサーバーを使用してクエリできるデータを提供するために、<a href="https://github.com/Delacrobix/typescript-elasticsearch-mcp/blob/main/dataset.json">内部の模擬ナレッジベースデータセット</a>を使用します。このデータセットから作成される文書は以下のような形式になります。</p>{
    "id": 5,
    "title": "Logging Standards for Microservices",
    "content": "Consistent logging across microservices helps with debugging and tracing. Use structured JSON logs and include request IDs and timestamps. Avoid logging sensitive information. Centralize logs in Elasticsearch or a similar system. Configure log rotation to prevent storage issues and ensure logs are searchable for at least 30 days.",
    "tags": ["logging", "microservices", "standards"]
}<p>データを取り込むために、Elasticsearchにインデックスを作成し、そこにデータセットをロードするスクリプトを用意しました。<a href="https://github.com/Delacrobix/typescript-elasticsearch-mcp/blob/main/setup.ts">こちらで</a>ご覧いただけます。</p><h4>MCPサーバー</h4><p><a href="https://github.com/Delacrobix/typescript-elasticsearch-mcp/blob/main/index.ts"><code>index.ts</code></a>というファイルを作成し、依存関係をインポートして環境変数を処理するための以下のコードを追加します。</p>// index.ts
import { z } from "zod";
import { Client } from "@elastic/elasticsearch";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import OpenAI from "openai";

const ELASTICSEARCH_ENDPOINT =
  process.env.ELASTICSEARCH_ENDPOINT ?? "http://localhost:9200";
const ELASTICSEARCH_API_KEY = process.env.ELASTICSEARCH_API_KEY ?? "";
const OPENAI_API_KEY = process.env.OPENAI_API_KEY ?? "";
const INDEX = "documents";<p>また、ElasticsearchとOpenAIの呼び出しを処理するようにクライアントを初期化します。</p>const openai = new OpenAI({
  apiKey: OPENAI_API_KEY,
});

const _client = new Client({
  node: ELASTICSEARCH_ENDPOINT,
  auth: {
    apiKey: ELASTICSEARCH_API_KEY,
  },
});<p>実装をより堅牢にし、構造化された入出力を保証するために、 <a href="https://zod.dev/"><code>zod</code></a>を使用してスキーマを定義します。これにより、ランタイムでデータを検証し、エラーを早期に捕捉し、ツールの対応をプログラムで処理しやすくすることができます。</p>const DocumentSchema = z.object({
  id: z.number(),
  title: z.string(),
  content: z.string(),
  tags: z.array(z.string()),
});

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

type Document = z.infer&lt;typeof DocumentSchema&gt;;
type SearchResult = z.infer&lt;typeof SearchResultSchema&gt;;<p>構造化出力の詳細については、<a href="https://www.elastic.co/search-labs/blog/structured-outputs-elasticsearch-guide">こちらを</a>ご覧ください。</p><p>それでは、MCPサーバーを初期化しましょう。</p>const server = new McpServer({
  name: "Elasticsearch RAG MCP",
  description:
    "A RAG server using Elasticsearch. Provides tools for document search, result summarization, and source citation.",
  version: "1.0.0",
});<h4>MCPツールの定義</h4><p>すべての設定が完了したので、MCPサーバーによって公開されるツールの作成を開始できます。このサーバーは2つのツールを公開します。</p><ul><li><p><strong><code>search_docs</code></strong><strong>：</strong>Elasticsearchで文書を全文検索で検索します。</p></li><li><p><strong><code>summarize_and_cite</code></strong><strong>：</strong>以前に取得した文書から情報を要約・統合し、ユーザーの質問に答えます。このツールは、出典となる文書を参照する引用も追加します。</p></li></ul><p>これらのツールを組み合わせることで、シンプルな「検索してから要約」ワークフローが構築されます。一方のツールが関連文書を取得し、もう一方のツールがその文書を使用して要約と引用を含む回答を生成します。</p><h4>ツールの応答形式</h4><p>各ツールは任意の入力パラメータを受け入れることができますが、以下の構造で応答する必要があります。</p><ul><li><p><strong>Content：</strong> これは非構造化形式でのツールの応答です。このフィールドは通常、テキスト、画像、音声、リンク、または埋め込みを返すために使用されます。この用途では、ツールによって生成された情報を含む整形済みテキストを返すために使用されます。</p></li><li><p><strong>structuredContent：</strong>これは、各ツールの結果を構造化された形式で提供するために使用されるオプションの戻り値です。これはプログラム上の目的に役立ちます。このMCPサーバーでは使用されていませんが、他のツールを開発したり、結果をプログラムで処理したりする場合に便利です。</p></li></ul><p>その構造を念頭に置いて、各ツールについて詳しく見ていきましょう。</p><h4>Search_docsツール</h4><p>このツールは、Elasticsearchインデックスで<a href="https://www.elastic.co/docs/solutions/search/full-text">全文検索</a>を実行し、ユーザークエリに基づいて最も関連性の高いドキュメントを取得します。主要な一致をハイライトし、関連性スコアを素早くまとめてくれます。</p>server.registerTool(
  "search_docs",
  {
    title: "Search Documents",
    description:
      "Search for documents in Elasticsearch using full-text search. Returns the most relevant documents with their content, title, tags, and relevance score.",
    inputSchema: {
      query: z
        .string()
        .describe("The search query terms to find relevant documents"),
      max_results: z
        .number()
        .optional()
        .default(5)
        .describe("Maximum number of results to return"),
    },
    outputSchema: {
      results: z.array(SearchResultSchema),
      total: z.number(),
    },
  },
  async ({ query, max_results }) =&gt; {
    if (!query) {
      return {
        content: [
          {
            type: "text",
            text: "Query parameter is required",
          },
        ],
        isError: true,
      };
    }

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

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

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

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

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

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

      return {
        content: [
          {
            type: "text",
            text: `Error searching documents: ${error.message}`,
          },
        ],
        isError: true,
      };
    }
  }
);<p><a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-fuzzy-query"><em><code>fuzziness</code></em></a><em><code>: “AUTO”</code></em> は <em> 分析対象のトークンの長さに応じて誤字許容度を調整するように設定しています。また </em>、<em> タイトルフィールドで一致が発生したドキュメントのスコアを上げるtitle^2も設定しました。</em>。</p><h4>summarize_and_citeツール</h4><p>このツールは、前回の検索で取得したドキュメントに基づいて要約を生成します。OpenAIの <code>gpt-4o-mini</code>モデルを使用して、ユーザーの質問に答えるために最も関連性の高い情報を統合し、検索結果に直接基づく回答を提供します。要約に加えて、使用したソースドキュメントの引用情報（メタデータ）も返します。</p>server.registerTool(
  "summarize_and_cite",
  {
    title: "Summarize and Cite",
    description:
      "Summarize the provided search results to answer a question and return citation metadata for the sources used.",
    inputSchema: {
      results: z
        .array(SearchResultSchema)
        .describe("Array of search results from search_docs"),
      question: z.string().describe("The question to answer"),
      max_length: z
        .number()
        .optional()
        .default(500)
        .describe("Maximum length of the summary in characters"),
      max_docs: z
        .number()
        .optional()
        .default(5)
        .describe("Maximum number of documents to include in the context"),
    },
    outputSchema: {
      summary: z.string(),
      sources_used: z.number(),
      citations: z.array(
        z.object({
          id: z.number(),
          title: z.string(),
          tags: z.array(z.string()),
          relevance_score: z.number(),
        })
      ),
    },
  },
  async ({ results, question, max_length, max_docs }) =&gt; {
    if (!results || results.length === 0 || !question) {
      return {
        content: [
          {
            type: "text",
            text: "Both results and question parameters are required, and results must not be empty",
          },
        ],
        isError: true,
      };
    }

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

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

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

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

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

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

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

      return {
        content: [
          {
            type: "text",
            text: combinedText,
          },
        ],
        structuredContent: {
          summary: summaryText,
          sources_used: citations.length,
          citations: citations,
        },
      };
    } catch (error: any) {
      return {
        content: [
          {
            type: "text",
            text: `Error generating summary and citations: ${error.message}`,
          },
        ],
        isError: true,
      };
    }
  }
);<p>最後に、<a href="https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#stdio">stdio</a>を使用してサーバーを起動する必要があります。つまり、MCPクライアントは、標準の入出力ストリームを読み書きすることでサーバーと通信します。stdioは最もシンプルな転送オプションで、クライアントによってサブプロセスとして立ち上げられるローカルMCPサーバーに適しています。ファイルの最後に以下のコードを追加します。</p>const transport = new StdioServerTransport();
server.connect(transport);<p>次に、以下のコマンドを使用してプロジェクトをコンパイルします。</p>npx tsc index.ts --target ES2022 --module node16 --moduleResolution node16 --outDir ./dist --strict --esModuleInterop<p>これにより<code>dist</code>フォルダが作成され、その中に<code>index.js</code>ファイルが作成されます。</p><h3>MCPサーバーをClaude Desktopにロード</h3><p>Claude DesktopでMCPサーバーを設定するには、<a href="https://modelcontextprotocol.io/docs/develop/connect-local-servers">このガイド</a>に従ってください。Claudeの設定ファイルでは、以下の値を設定する必要があります:</p>{
  "mcpServers": {
    "elasticsearch-rag-mcp": {
      "command": "node",
      "args": [   "/Users/user-name/app-dir/dist/index.js"
      ],
      "env": {
        "ELASTICSEARCH_ENDPOINT": "your-endpoint-here",
        "ELASTICSEARCH_API_KEY": "your-api-key-here",
        "OPENAI_API_KEY": "your-openai-key-here"
      }
    }
  }
}<p><code>args</code>値は、 <code>dist</code>フォルダ内のコンパイル済みファイルを指す必要があります。また、設定ファイル内の環境変数も、コード内で定義されているものと全く同じ名前で設定する必要があります。</p><h3>試してみる</h3><p>各ツールを実行する前に、「<strong>検索とツール</strong>」をクリックして、ツールが有効になっていることを確認します。ここでは、それぞれを有効または無効にすることもできます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt395a7337021f9820/6a170c1c67045bb74d45c228/172981c2a54adabc70d5819013c3007670935605-1999x1002.png" alt="「Good afternoon, Jeff. How can I help you today?」というメモが表示されたClaude 4.5 Sonnetのページ" /><p>最後に、Claude DesktopのチャットからMCPサーバーをテストして、質問を始めましょう。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf4ac458dc0206271/6a170c1e66c4f91328f8c072/03654c0f8c53c714f801fba8b25747071179209b-1999x1353.png" alt="ユーザーがClaude Desktopチャットで、認証方法と役割ベースのアクセス制御に関するドキュメントを検索するようリクエストし、それに対するClaudeの回答。" /><p>「<strong>認証方法とRBACに関する文書を検索する</strong>」という質問に対して、<code>search_docs</code> ツールが実行され、以下の結果が返されます。</p>Most Relevant Documents:
Access Control and Role Management (highest relevance) - This document covers role-based access control (RBAC) principles, including ensuring users only have necessary permissions, regular auditing of user roles, revoking inactive accounts, and implementing just-in-time access for sensitive operations.
User Authentication with OAuth 2.0 - This document explains OAuth 2.0 authentication, which enables secure delegated access without credential sharing. It covers configuring identity providers, token management with limited scope and lifetime, and secure storage of refresh tokens.
Container Security Guidelines - While primarily about container security, this document touches on access control aspects like running containers as non-root users and avoiding embedded credentials.
Incident Response Playbook - This mentions role assignment during incidents (incident commander, communications lead, etc.), which relates to access control in emergency scenarios.
Logging Standards for Microservices - This document includes guidance on avoiding logging sensitive information, which is relevant to authentication security.<p>回答は「素晴らしい！認証方法とロールベースのアクセス制御に関する関連文書を5件見つけました。見つかった内容は以下のとおりです。」</p><p>ツール呼び出しは、対応ペイロードの一部としてソース文書を返します。これらの文書は、後に引用を生成するために使用されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbaf48a9468770ce2/6a170c21509168bffee1bb14/25ff4c7e9563d99752f95540dafdc7fd211a66e3-800x530.gif" alt="Claude 4.5 Sonnetのページ。認証方法とRBACに関する5つの関連文書がスクロールして表示されます。" /><p>また、複数のツールを一度のインタラクションで連結することも可能です。この場合、Claude Desktopはユーザーの質問を分析し、まず<code>search_docs</code>を呼び出して関連文書を取得し、次にその結果を<code>summarize_and_cite</code>に渡して最終的な回答を生成する必要があると判断します。これらすべては、ユーザーからの個別のプロンプトを必要とせずに実行されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta46ff45274e64192/6a170c230c4857a91501aac1/e6a8a46acb4236e77058f18bcd2f0737b5882c05-1999x1101.png" alt="Claude Desktopチャットに、「Jeff returns」というメモと、新しいユーザーからの質問「What are the main recommendations to improve authentication and access control across our systems? Include references.」が添えられている。" /><p>この場合、「<strong>システム全体の認証とアクセス制御を改善するための主な推奨事項は何ですか？参考文献を含めてください。</strong>」というクエリに対して、以下の結果が得られました。</p>Based on the documentation, here are the main recommendations to improve authentication and access control across your systems:

Key Recommendations

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

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

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

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

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

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

Access Control and Role Management (Tags: security, access-control)
User Authentication with OAuth 2.0 (Tags: authentication, oauth)
These recommendations work together to create a defense-in-depth approach, where multiple security layers protect your systems from unauthorized access.<p>前のステップと同様に、この質問に対する各ツールの回答を確認できます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8f633c518e708a99/6a170c25ab7f082991db9ed6/cb606d356b2f7d5e4878a5eff71bc881869ac0ee-800x585.gif" alt="Claude Desktopチャットページ、スクロールテキストには各ツールからの対応が含まれ、システム全体の認証とアクセス制御を改善するための主な推奨事項に関する質問への回答が含まれている。" /><p><em>注：各ツールの使用を承認するかを確認するサブメニューが表示された場合は、</em><em><strong>「常に許可」</strong></em><em>または</em><em><strong>「一度だけ許可」</strong></em><em>を選択します。</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6627ee0bff1862df/6a170c266f7f040f6f91488c/aea942ba9b0037526ea215bec65690f1a5c3099c-1522x250.png" alt="ユーザーが選択できるClaude Desktop「常に許可」と「一度だけ許可」のオプション。" /><h2>まとめ</h2><p>MCPサーバーは、ローカルとリモートの両方のアプリケーションのLLMツールの標準化に向けた重要な一歩です。完全な互換性の実現にはまだ取り組んでいますが、その方向へ急速に進んでいます。</p><p>この記事では、ElasticsearchをLLM搭載アプリケーションに接続するカスタムMCPサーバーをTypeScriptで構築する方法を学びました。当サーバーは2つのツールを提供しています。1つはQuery DSLを使用して関連文書を取得するためのツール<code>search_docs</code>、もう1つはOpenAIモデルとクライアントUIとしてのClaude Desktopを使用して引用付きの要約を生成するためのツール<code>summarize_and_cite</code>です。</p><p>異なるクライアントとサーバープロバイダー間の互換性の将来は有望に見えます。次のステップは、エージェントにより多くの機能と柔軟性を加えることです。実用的な<a href="https://www.elastic.co/search-labs/blog/llm-functions-elasticsearch-intelligent-query">記事</a>で、検索テンプレートを使用してクエリをパラメーター化し、精度と柔軟性を得る方法を学ぶことができます。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elastic-mcp-server-typescript-claude</guid>
    <category><![CDATA[エージェント型AI]]></category>
    <category><![CDATA[統合]]></category>
    <dc:creator><![CDATA[Jeffrey Rengifo]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5600198cb47666a5/6a170c28509168ce3ae1bb18/0bb24c05fff391f42070c2883182ea6fe9cb9680-1280x720.png" length="0" type="image/png"/>
    <pubDate>Fri, 27 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elasticsearch Inference APIとHugging Faceモデルを組み合わせて使用]]></title>
    <description><![CDATA[推論エンドポイントを使用してElasticsearchをHugging Faceモデルに接続する方法と、セマンティック検索とチャット補完機能を備えた多言語ブログ推奨システムを構築する方法を学びましょう。]]></description>
    <content:encoded><![CDATA[<p>最近のアップデートで、Elasticsearchは<a href="https://endpoints.huggingface.co/">Hugging Face Inference Service</a>でホストされているモデルに接続するためのネイティブ統合機能を導入しました。この記事では、この統合を構成し、大規模言語モデル（LLM）を使用して簡単なAPI呼び出しを通じて推論を実行する方法を探ります。リソース使用量と解答品質のバランスが取れた軽量汎用モデルである<a href="https://huggingface.co/HuggingFaceTB/SmolLM3-3B">SmolLM3-3B</a>を使用します。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9094997548bd70f8/6a170d6a839dfa0ad6dcff54/7ddadf1976421a860a7d62087239adb9150d808b-1999x1388.png" alt="複数の小規模言語モデルを、x軸にモデルサイズ（数十億個のパラメータ）、y軸に勝率（パーセント）でプロットした散布図。SmolLM3-3Bは効率性の傾向において上位に位置し、同規模の他のモデルよりも高い勝率を示しています。" /><h2>要件</h2><ul><li><p><strong>Elasticsearch 9.3またはElastic Cloud Serverless：</strong><a href="https://www.elastic.co/search-labs/tutorials/install-elasticsearch/elastic-cloud">これらの指示に従って</a>クラウド導入を作成することもできますし、<a href="https://www.elastic.co/docs/deploy-manage/deploy/self-managed/local-development-installation-quickstart#local-dev-quick-start"><code>start-local</code></a>クイックスタートを使うこともできます。</p></li><li><p><strong>Python 3.12：</strong>Pythonは<a href="https://www.python.org/">こちら</a>からダウンロードしてください。</p></li><li><p><strong>Hugging Face</strong><a href="https://huggingface.co/docs/hub/en/security-tokens">アクセストークン</a>。</p></li></ul><h2>Hugging Face推論エンドポイントを使用したチャットの完了</h2><p>まず、ElasticsearchをHugging Faceの<a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put">推論エンドポイント</a>に接続し、ブログ記事のコレクションからAIを活用したレコメンデーションを生成する実践的な例を作成します。アプリのナレッジベースには、会社のブログ記事のデータセットを使用します。これには価値のある情報が含まれていますが、多くの場合、見つけるのが困難です。</p><p>このエンドポイントでは、<a href="https://www.elastic.co/docs/solutions/search/semantic-search">セマンティック検索</a>が指定されたクエリに対して最も関連性の高い記事を取得し、Hugging Face LLMがそれらの結果に基づいて短いコンテキスト推奨を生成します。</p><p>これから構築する情報フローの概要を見ていきましょう。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf217b7b7db4e1e6c/6a170d6ca929cf8022ae0a3b/1dfbc2323438feaaa42e13ab242dd1f7166f74aa-1200x676.png" alt="Elasticsearchインデックスがセマンティック検索結果を推論エンドポイントに送り込み、そこから記事のレコメンデーション結果が返されるフロー図。" /><p>この記事では、コンパクトなサイズと強力な多言語推論能力・ツール呼び出し能力を組み合わせた<strong>SmolLM3-3B</strong>の性能を検証します。検索クエリに基づいて、一致するすべてのコンテンツ（英語とスペイン語）をLLMに送信し、検索クエリと結果に基づいたカスタムメイドの説明を含むおすすめ記事のリストを生成します。</p><p>AIによる推奨生成システムを備えた記事サイトのUIは次のようになります。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt20e69b9a06fecd65/6a170d6e839dfa6f97dcff58/8d3b86b212f28ff279f2da67a33e6134039f0e4e-1999x949.png" alt="AIによるおすすめ生成システムを備えた記事サイトのUI。3つの例がリストされており、テキストは英語、タイトルは英語またはスペイン語のいずれかで表示される。" /><p>このアプリケーションの完全な実装は、リンク先の<a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/elasticsearch-inference-api-and-hugging-face/notebook.ipynb">ノートブック</a>で確認できます。</p><h3>Elasticsearch推論エンドポイントの構成</h3><p>Elasticsearch <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-hugging-face">Hugging Face推論エンドポイント</a>を使用するには、2つの重要な要素（Hugging Face APIキーと実行中のHugging FaceエンドポイントURL）が必要です。下の画像のように表示されるはずです。</p>PUT _inference/chat_completions/hugging-face-smollm3-3b
{
    "service": "hugging_face",
    "service_settings": {
        "api_key": "hugging-face-access-token", 
        "url": "url-endpoint" 
    }
}<p>Hugging FaceのElasticsearchにおける推論エンドポイントは、 <code>text_embedding</code>, <code>completion</code>, <code>chat_completion</code>, と <code>rerank</code>の異なるタスクタイプをサポートしています。このブログ記事では、検索結果とシステムプロンプトに基づいて会話形式のレコメンデーションをモデルに生成させる必要があるため、<code>chat_completion</code> を使用します。このエンドポイントを使用すると、Elasticsearch APIを使用してElasticsearchから直接チャットの完了を簡単に実行できます。</p>POST _inference/chat_completion/hugging-face-smollm3-3b/_stream
{
  "messages": [
      { "role": "user", "content": "&lt;user prompt&gt;" }
  ]
}<p>これはアプリケーションのコアとして機能し、モデルを通過するプロンプトと検索結果を受け取ります。理論について説明したので、アプリケーションの実装を始めましょう。</p><h4>Hugging Faceでの推論エンドポイントの設定</h4><p>Hugging Faceモデルをデプロイするために、モデルのエンドポイントをデプロイするための簡単で高速なサービス<a href="https://huggingface.co/inference-endpoints/dedicated">Hugging Faceワンクリック導入</a>を使用します。これは有料サービスであり、利用には追加料金が発生する可能性があることにご注意ください。このステップでは、記事の推奨を生成するために使うモデルインスタンスが作成されます。</p><p>ワンクリックカタログからモデルを選択できます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta7bdfa43d6766324/6a170d6fb339d59e5476a039/b816e9fba1fe172687bf58f5143fb1f838c1077f-549x331.png" alt="「smoll3」にフィルタリングされたモデルカタログのインターフェースビュー。テキスト生成「smollm3‑3b」という名前の1つのモデル、vLLM、GPU 1× NVIDIA L4、定価$ 0.8 と、すべての Hugging Faceモデルに検索を拡張する提案のメモが表示。" /><p><strong>SmolLM3-3B</strong>モデルを選択します。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb0a2e6ffd7deb20/6a170d710c48574b7401aafc/610d3aba0429f3666c2df3616d513eb6a4397c0c-502x478.png" alt="SmolLM3-3Bモデルのエンドポイントを作成するためのインターフェース。モデル名、「Hugging Faceによって検証済み」という注記、エンドポイント名フィールド、実行中のレプリカ1つあたり1時間0.80ドルのコスト、cURLオプション、および「エンドポイントの作成」ボタンが表示。" /><p>ここから、Hugging FaceのエンドポイントURLを取得します。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt25714021711ed6ff/6a170d72c1e8a54853f88336/025094ddb2cfbd1f0f216a5ec4e119b0f4fa2c42-646x328.png" alt="「smollm3-3b-pnz」という名前のHugging Face推論エンドポイントのダッシュボードビュー。緑色の実行ステータス、アクティブなレプリカ1つ、過去1時間のリクエスト数0、ナビゲーションタブ、表示されているエンドポイントURLが表示。" /><p>Elasticsearch <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-hugging-face">Hugging Faceの推論エンドポイントのドキュメント</a>で述べられているように、テキスト生成にはOpenAI APIと互換性のあるモデルが必要です。そのため、<code>/v1/chat/completions</code>のサブパスをHugging FaceのエンドポイントURLに追加する必要があります。最終的な結果は次のようになります。</p>https://j2g31h0futopfkli.us-east-1.aws.endpoints.huggingface.cloud/v1/chat/completions<p>これで準備が整いましたので、Pythonノートブックでコーディングを開始できます。</p><h4>Hugging Face APIキーの生成</h4><p><a href="https://huggingface.co/join">Hugging Faceアカウント</a>を作成し、<a href="https://huggingface.co/docs/hub/en/security-tokens#user-access-tokens">以下の指示</a>に従ってAPIトークンを取得してください。トークンの種類は、<em>fine-grained</em>（本番環境に推奨。特定のリソースへのアクセスのみを提供）、<em>read</em>（読み取り専用アクセス用）、<em>write</em>（読み取りおよび書き込みアクセス用）の3つから選択できます。このチュートリアルでは、推論エンドポイントを呼び出すだけでよいので、readトークンで十分です。次のステップのために、このキーを保存しておいてください。</p><h4>Elasticsearch推論エンドポイントの設定</h4><p>まず、Elasticsearch Pythonクライアントを宣言します。</p>os.environ["ELASTICSEARCH_API_KEY"] = "your-elasticsearch-api-key"
os.environ["ELASTICSEARCH_URL"] = "https://xxxx.us-central1.gcp.cloud.es.io:443"

es_client = Elasticsearch(
    os.environ["ELASTICSEARCH_URL"], api_key=os.environ["ELASTICSEARCH_API_KEY"]
)<p>次に、Hugging Faceモデルを使用するElasticsearch推論エンドポイントを作成します。このエンドポイントを使用すると、ブログ記事とモデルに渡されたプロンプトに基づいて応答を生成できます。</p>INFERENCE_ENDPOINT_ID = "smollm3-3b-pnz"

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

resp = es_client.inference.put(
        task_type="chat_completion",
        inference_id=INFERENCE_ENDPOINT_ID,
        body={
            "service": "hugging_face",
            "service_settings": {
                "api_key": os.environ["HUGGING_FACE_API_KEY"],
                "url": os.environ["HUGGING_FACE_INFERENCE_ENDPOINT_URL"],
            },
        },
    )<h3>データセット</h3><p>このデータセットには、クエリの対象となる<a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/elasticsearch-inference-api-and-hugging-face/dataset.json">ブログ記事</a>が含まれており、ワークフロー全体で使用される多言語コンテンツセットを表しています。</p>// Articles dataset document example: 
{
    "id": "6",
    "title": "Complete guide to the new API: Endpoints and examples",
    "author": "Tomas Hernandez",
    "date": "2025-11-06",
    "category": "tutorial",
    "content": "This guide describes in detail all endpoints of the new API v2. It includes code examples in Python, JavaScript, and cURL for each endpoint. We cover authentication, resource creation, queries, updates, and deletion. We also explain error handling, rate limiting, and best practices. Complete documentation is available on our developer portal."
  }<h4>Elasticsearch マッピング</h4><p>データセットが定義されたので、ブログ記事の構造に適切にフィットするデータスキーマを作成する必要があります。Elasticsearchにデータを格納するために以下の<a href="https://www.elastic.co/docs/manage-data/data-store/mapping">インデックスマッピング</a>が使用されます。</p>INDEX_NAME = "blog-posts"

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


es_client.indices.create(index=INDEX_NAME, body=mapping)<p>ここで、データがどのように構造化されているかをより明確に見ることができます。セマンティック検索を使用して自然言語に基づいて結果を取得し、<a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/copy-to"><code>copy_to</code></a>プロパティを使用してフィールドの内容を<a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/semantic-text"><code>semantic_text</code></a>フィールドにコピーします。さらに、<code>title</code>フィールドには2つのサブフィールドが含まれています。<code>original</code>サブフィールドは、記事の元の言語に応じて英語またはスペイン語でタイトルを格納し、<code>translated_title</code>サブフィールドはスペイン語の記事にのみ存在し、元のタイトルの英語訳が含まれています。</p><h3>データの取り込み</h3><p>以下のコードスニペットは<a href="https://www.elastic.co/docs/reference/elasticsearch/clients/javascript/bulk_examples">bulk API</a>を使用してブログ投稿データセットをElasticsearchに取り込みます。</p>def build_data(json_file, index_name):
    with open(json_file, "r") as f:
        data = json.load(f)

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


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

    if failed:
        print(f"Errors: {failed}")
except Exception as e:
    print(f"Error: {str(e)}")<p>Elasticsearchに記事を取り込んだので、次に<code>semantic_text</code>フィールドに対して検索できる関数を作成する必要があります:</p>def perform_semantic_search(query_text, index_name=INDEX_NAME, size=5):
    try:
        query = {
            "query": {
                "match": {
                    "semantic_field": {
                        "query": query_text,
                    }
                }
            },
            "size": size,
        }

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

        return hits
    except Exception as e:
        print(f"Semantic search error: {str(e)}")
        return []<p>推論エンドポイントを呼び出す関数も必要です。この場合、<strong><code>chat_completion</code></strong>タスクタイプを使用してエンドポイントを呼び出し、ストリーミング応答を取得します。</p>def stream_chat_completion(messages: list, inference_id: str = INFERENCE_ENDPOINT_ID):
    url = f"{ELASTICSEARCH_URL}/_inference/chat_completion/{inference_id}/_stream"
    payload = {"messages": messages}
    headers = {
        "Authorization": f"ApiKey {ELASTICSEARCH_API_KEY}",
        "Content-Type": "application/json",
    }

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

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

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

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

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

                    try:
                        chunk_data = json.loads(data_content)

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

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

    except requests.exceptions.RequestException as e:
        yield f"Error: {str(e)}"<p>ここで、 <code>chat_completions</code> 推論エンドポイントと推薦エンドポイントを合わせてセマンティック検索関数を呼び出し、カードに割り当てられるデータを生成する関数を書くことができます。</p>def recommend_articles(search_query, index_name=INDEX_NAME, max_articles=5):
    print(f"\n{'='*80}")
    print(f"🔍 Search Query: {search_query}")
    print(f"{'='*80}\n")

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

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

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

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

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

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


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

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

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

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

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

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

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

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

    full_response = ""

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

    return context, articles, full_response<p>最後に、情報を抽出して出力できるようにフォーマットする必要があります。</p>def display_recommendation_cards(articles, recommendations_text):
    print("\n" + "=" * 100)
    print("📇 RECOMMENDED ARTICLES".center(100))
    print("=" * 100 + "\n")

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

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

        parsed = json.loads(cleaned_text)

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

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

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

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

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

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

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

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

        # Card bottom
        print("└" + "─" * 98 + "┘")<p>セキュリティブログの投稿について質問して、これをテストしてみましょう。</p>search_query = "Security and vulnerabilities"

context, articles, recommendations = recommend_articles(search_query)

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

# Display visual cards
display_recommendation_cards(articles, recommendations)<p>ここでは、ワークフローによって生成されたコンソール内のカードを確認できます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4aa221a08a51aeb3/6a170d7460084be1413c45d6/730d35212594bb3db30447c3ea7e2a92857287b7-1999x1515.png" alt="セクションタイトル「Recommended Articles」。認証システムの脆弱性、移行リスク、REST API v2のパフォーマンスと認証の改善、通知システムの変更、新しいAPIの完全ガイドなど、5つの記事の要約がボックスで表示。" /><p>すべてのヒットとLLMの対応を含む完全な結果を<a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/elasticsearch-inference-api-and-hugging-face/results.md">このファイル</a>でご覧いただけます。</p><p>「Security and vulnerabilities」に関連する記事をクエリしています。この質問は、Elasticsearchに保存されているドキュメントに対する検索クエリとして使用されます。取得された結果はモデルに渡され、モデルはその内容に基づいてレコメンデーションを生成します。ご覧の通り、このモデルは読者がクリックする動機付けとなる魅力的な短いテキストを非常にうまく生成しています。</p><h2>まとめ</h2><p>この例では、ElasticsearchとHugging Faceを組み合わせて、AIアプリケーション向けの高速で効率的な集中型システムを構築する方法を示します。Hugging Faceの豊富なモデルカタログにより、このアプローチでは手作業を削減し、柔軟性を確保できます。特にSmolLM3-3Bを使用すると、コンパクトな多言語モデルでも、セマンティック検索と組み合わせることで有意義な推論とコンテンツ生成を実現できることがわかります。これらのツールを組み合わせることで、インテリジェントなコンテンツ分析と多言語アプリケーションを構築するための、拡張性が高く効果的な基盤を提供できます。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hugging-face-elasticsearch-inference-api</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hugging-face-elasticsearch-inference-api</guid>
    <category><![CDATA[エージェント型AI]]></category>
    <category><![CDATA[統合]]></category>
    <dc:creator><![CDATA[Jeffrey Rengifo]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5f961af4cb26ec97/6a170d767d8d6790c770e790/1417d6ff033712206c9bd4bcc22074ee3437ce96-1999x1125.png" length="0" type="image/png"/>
    <pubDate>Mon, 23 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[ElasticsearchのGemini CLI拡張機能（ツールとスキル付き）]]></title>
    <description><![CDATA[GoogleのGemini CLIでElasticsearchのデータを検索、取得、分析するためのElasticの拡張機能（開発者およびエージェントのワークフロー向け）をご紹介します。
]]></description>
    <content:encoded><![CDATA[<p>GoogleのGemini CLI用のElastic拡張機能のリリースを発表できることを嬉しく思います。これにより、<a href="https://www.elastic.co/elasticsearch">Elasticsearch</a>と<a href="https://www.elastic.co/elasticsearch/agent-builder">Elastic Agent Builder</a>のパワーを、AI開発ワークフローに直接組み込むことができます。この拡張機能には、Elasticsearchを操作するための最近開発されたエージェントスキルもいくつか用意されています。</p><p>この拡張機能はオープンソースプロジェクトとして<a href="https://github.com/elastic/gemini-cli-elasticsearch">こちら</a>から利用できます。</p><h2>Gemini CLIの概要とインストール方法</h2><p><a href="https://geminicli.com/">Gemini CLI</a> は、GoogleのGeminiモデルを直接コマンドラインに取り込むオープンソースのAIエージェントです。ターミナルからAIと対話することで、コードの生成、ファイルの編集、シェルコマンドの実行、ウェブからの情報の取得などのタスクを実行できます。</p><p>一般的なチャットインターフェースとは異なり、Gemini CLIはローカル開発環境と統合されます。つまり、プロジェクトのコンテキストを理解し、ファイルを変更し、ビルドやテストを実行し、ワークフローをターミナル内で直接自動化することができます。開発者、サイト信頼性エンジニア（SRE）、コマンドラインのワークフローを離れることなくAI支援のコーディングと自動化を求めるエンジニアにとって役立ちます。</p><p>Gemini CLIは複数のパッケージマネージャーを使ってインストール可能です。最も一般的な方法はnpm経由です。</p>npm install -g @google/gemini-cli<p>その他のインストール方法については、<a href="https://geminicli.com/docs/get-started/installation/">公式のインストールページ</a>を参照してください。</p><p>インストール後、以下のコマンドを実行してCLIを起動します。</p>gemini<p>図1に示すような画面が表示されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4ff43abe550941b4/6a17072ba29299fc2ad00fa4/6dfcec4a77b3dc83bf0d974417bf2e211abb1f4f-876x468.png" alt="Gemini CLIのスクリーンショット。" /><h2>Elasticsearchを構成</h2><p>Elasticsearchインスタンスを実行する必要があります。モデルコンテキストプロトコル（MCP）サーバーを使用するには、Kibana 9.3以降もインストールする必要があります。Elasticsearchクエリ言語 (ES|QL) スキル (<code>esql</code>) を使用するためにKibanaは必要ありません。</p><p><a href="https://www.elastic.co/cloud">Elastic Cloud</a>で無料トライアルを有効化するか、<a href="https://github.com/elastic/start-local"><code>start-local</code></a>スクリプトを使ってローカルにインストールできます。</p>curl -fsSL https://elastic.co/start-local | sh<p>これにより、ElasticsearchとKibanaがコンピュータにインストールされ、Gemini CLIの設定に使用するAPIキーが生成されます。</p><p>APIキーは前のコマンドの出力として表示され、 <strong><code>elastic-start-local</code></strong>フォルダ内の<strong>.env</strong>ファイルに保存されます。</p><p>オンプレミスのElasticsearchを使用している場合（例えば、<code>start-local</code>）、MCPでElastic Agent Builderを使用するには、大規模言語モデル（LLM）を接続する必要があります。さまざまなオプションを理解するには、<a href="https://www.elastic.co/docs/explore-analyze/ai-features/llm-guides/llm-connectors">このドキュメントページ</a>をご覧ください。</p><p>Elastic Cloud（またはサーバーレス）を使用している場合は、LLM接続が事前構築されています。</p><h2>Elasticsearch拡張機能をインストールしてください</h2><p>次のコマンドを使用して、Gemini CLI用のElasticsearch拡張機能をインストールできます。</p>gemini extensions install https://github.com/elastic/gemini-cli-elasticsearch<p>Geminiを開き、以下のコマンドを実行することで、拡張機能が正常にインストールされたことを確認できます。</p>/extensions list<p>Elasticsearch拡張機能が利用可能になっているはずです。</p><p>MCP統合を使用するには、Elasticsearch 9.3以降のバージョンがインストールされている必要があります。<a href="https://www.elastic.co/kibana">Kibana</a>からMCPサーバーのURLを取得する必要があります。</p><ul><li><p>MCPサーバーのURLは、[エージェント] &gt; [すべてのツールを表示] &gt; [MCPの管理] &gt; [MCPサーバーのURLをコピー] から取得できます。</p></li><li><p>URLは次のようになります：https://your-kibana-instance/api/agent_builder/mcp</p></li></ul><p>ElasticsearchエンドポイントのURLが必要です。これは通常、Kibana Elasticsearchページの最上部に表示されます。Elasticsearchを<code>start-local</code>で実行している場合、 <code>start-local</code> .envファイルの<code>ES_LOCAL_URL</code>キーにエンドポイントが既に存在します。</p><p>APIキーも必要です。Elasticsearchを<code>start-local</code>で実行している場合、 <code>start-local</code> .envファイルには既に<code>ES_LOCAL_API_KEY</code>が含まれています。それ以外の場合は、<a href="https://www.elastic.co/docs/deploy-manage/api-keys/elasticsearch-api-keys">こちらに</a>記載されているように、Kibanaインターフェースを使用してAPIキーを作成できます。</p><ul><li><p>Kibanaでは、[スタック管理] &gt; [セキュリティ] &gt; [APIキー] &gt; [APIキーの作成] の順に操作します。</p></li><li><p>API キーには読み取り権限のみを設定し、<a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/permissions#grant-access-with-roles">ここに</a>記載されているように<code>feature_agentBuilder.read</code>権限を有効にすることをお勧めします。</p></li><li><p>エンコードされたAPIキーの値をコピーしてください。</p></li></ul><p>シェルで必要な環境変数を設定してください。</p>export ELASTIC_URL="your-elasticsearch-url"
export ELASTIC_MCP_URL="your-elasticsearch-mcp-url"
export ELASTIC_API_KEY="your-encoded-api-key"<h2>サンプルデータセットをインストールする</h2><p>Kibanaから入手可能な<strong>eCommerce orders</strong>データをインストールできます。このデータベースには、eコマースWebサイトからの4,675件の注文に関する情報を含む<strong><code>kibana_sample_data_ecommerce</code></strong>という単一のインデックスが含まれています。各注文について、次の情報があります。</p><ul><li><p>顧客情報（名前、ID、生年月日、メールなど）。</p></li><li><p>注文日。</p></li><li><p>注文ID。</p></li><li><p>商品（価格、数量、ID、カテゴリー、割引、その他の詳細を含む全商品のリスト）</p></li><li><p>SKU。</p></li><li><p>合計金額（税抜、税込）。</p></li><li><p>合計数量。</p></li><li><p>地理情報（都市、国、大陸、場所、地域）。</p></li></ul><p>サンプルデータをインストールするには、Kibanaの<strong>統合</strong>ページを開き（検索トップバーで「Integration」を検索）、<strong>Sample Data</strong>をインストールしてください。詳細については、<a href="https://www.elastic.co/docs/explore-analyze/#gs-get-data-into-kibana">こちらの</a>ドキュメントを参照してください。</p><p>この記事の目的は、Gemini CLIをElasticsearchに接続し、<strong><code>kibana_sample_data_ecommerce</code></strong>インデックスとやり取りするのがいかに簡単かを示すことです。</p><h2>Elasticsearch MCPの使用方法</h2><p>Geminiで以下のコマンドを使用して接続状況を確認できます。</p>/mcp list<p>図2に示すように、 <strong><code>elastic-agent-builder</code></strong>が有効になっているはずです。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt52b85e7255360f3b/6a17072da929cf33d3ae08f5/1508423bc1d1bc3c04a1cb01e2d59495a3516ed1-1465x844.png" alt="ツールのリストを備えた「elastic-agent-builder」MCPサーバー。" /><p>Elasticsearchはデフォルトのツールセットを提供しています。詳細は<a href="https://www.elastic.co/docs/explore-analyze/ai-features/agent-builder/tools/builtin-tools-reference">こちらを</a>ご覧ください。</p><p>これらのツールを使用して、Elasticsearchと対話し、次のような質問をすることができます。</p><ul><li><p><code>Give me the list of all the indexes available in Elasticsearch.</code></p></li><li><p><code>How many customers are based in the USA in the kibana_sample_data_ecommerce index of Elasticsearch?</code></p></li></ul><p>質問に応じて、Geminiは利用可能なツールの一つ以上を使って回答を試みます。</p><h2>/elasticコマンド</h2><p>Gemini CLIのElasticsearch拡張機能では、さらに<strong><code>/elastic</code></strong>コマンドを追加しました。</p><p><strong><code>/help</code></strong>コマンドを実行すると、利用可能なすべての<code>/elastic</code>オプション（図3）が表示されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt741c7451ecab10d2/6a17072ea6c2b9ccd6e79643/5b2a0727ce7a04354878dd048253d3f4d062324b-1983x230.png" alt="利用可能な `/elastic` コマンド。" /><p>これらのコマンドは、<code>elastic-agent-builder</code> MCPサーバーの特定のツールを直接実行したい場合に便利です。例えば、以下のコマンドを使用すると、 <code>kibana_sample_data_ecommerce</code>のマッピングを取得できます。</p>/elastic:get-mapping kibana_sample_data_ecommerce<p>これらのコマンドは、どのツールを呼び出すかをGeminiモデルに頼るのではなく、基本的に特定のツールを実行するためのショートカットです。</p><h2>Elasticsearchスキルの使用方法</h2><p>この拡張機能には、Elasticsearchで利用可能な<a href="https://www.elastic.co/docs/explore-analyze/discover/try-esql">Elasticsearchクエリ言語</a>である<a href="https://github.com/elastic/gemini-cli-elasticsearch/tree/main/skills/esql">ES|QL用のエージェントスキル</a>も付属しています。<a href="https://agentskills.io/home">エージェントスキル</a> は、Gemini CLIのようなAIコーディングエージェントに特定のタスクに合わせたカスタム指示を提供するオープンフォーマットです。<em>段階的開示</em>と呼ばれる概念を採用しており、最初のシステムプロンプトにスキルの簡単な説明のみを追加します。エージェントにElasticsearchへのクエリなどのタスクを実行するように依頼すると、リクエストが関連するスキルと照合され、詳細な指示が動的に読み込まれます。これは、トークン予算を効率的に管理すると同時に、AIが必要とする正確なコンテキストを提供する方法です。</p><p><strong><code>esql</code></strong><strong>スキル</strong>は、Gemini CLIがES|QLクエリを直接クラスターに対して書き込み、実行するように設計されています。ES|QLは強力なパイプクエリ言語で、データ調査、ログ分析、アグリゲーションを非常に直感的に行うことができます。このスキルを有効にすると、ES|QLの構文を調べる必要はなくなり、Gemini CLIにデータについて自然言語で質問するだけであとはエージェントが処理します。</p><p>実行は、ターミナルで実行されるシンプルな<a href="https://curl.se/">curl</a>コマンドを使用して行われます。これは、Elasticsearchが豊富なREST APIを提供し、システムをあらゆるアーキテクチャに容易に統合できるためです。</p><p><strong><code>esql</code></strong><strong>スキルが提供するもの：</strong></p><ul><li><p><strong>インデックスとスキーマの検出：</strong>エージェントは、スキルに搭載されたツールを使用して、利用可能なインデックスを一覧表示し、フィールドマッピングを取得できます。例えば、eCommerce データセットのクエリを書く前に、エージェントは <strong><code>kibana_sample_data_ecommerce</code></strong> でスキーマチェックを実行して、<strong><code>taxful_total_price</code></strong> や <strong><code>category</code></strong> のような利用可能なフィールドを理解することができます。</p></li><li><p><strong>シームレスな自然言語翻訳：</strong>スキルはエージェントに単なるリファレンスマニュアルにとどまらず、ユーザーの意図を解釈するための具体的なガイドを提供します。「サービス別にグループ化された平均応答時間を表示して」といった自然言語によるリクエストを入力すると、エージェントはスキルのバンドルされたパターンマッチングを使用して、入力された言葉を即座に正しいES|QLアグリゲーション、フィルタ、コマンドに変換します。</p></li><li><p><strong>自動修正：</strong> クエリが失敗した場合（例：タイプミスマッチや構文エラーなど）、スキルは生成されたクエリとElasticsearchのエラーを正確に返します。これにより、エージェントは即座にクエリを修正して再試行でき、介入する必要がありません。</p></li></ul><p><code>esql</code>スキルは<code>elastic-agent-builder</code> MCPサーバーのツールとしても利用できるため、このサーバーを一時的に無効にする必要があります。以下のコマンドを使用して無効にすることができます。</p>/mcp disable elastic-agent-builder<p>そうすれば、Gemini CLIに次のようなプロンプトを入力するだけで済みます。</p>Find the top 5 product categories by total sales revenue in the kibana_sample_data_ecommerce index<p>エージェントは以下を実行します：</p><ul><li><p><code>esql</code> スキルの必要性を認識します。</p></li><li><p><strong><code>kibana_sample_data_ecommerce</code></strong>のスキーマを確認してください。</p></li><li><p><code>FROM kibana_sample_data_ecommerce | STATS total_revenue = SUM(taxful_total_price) BY category.keyword | SORT total_revenue DESC | LIMIT 5</code> のようなES|QLクエリを構築します。</p></li><li><p>Elasticsearch APIに対してクエリを実行します。</p></li><li><p>最終的な答えを端末に直接表示します。</p></li></ul><p>ここでは、前回の質問に対するGeminiからの回答例を報告します。</p>───────────────────────────────────────────────────────────
&gt; Find the top 5 product categories by total sales revenue in the kibana_sample_data_ecommerce index   ───────────────────────────────────────────────────────────
✓  Activate Skill "esql": Interact with Elasticsearch using ES|QL and curl. Use when querying, managing indices,  …
Skill esql activated. Resources loaded from /home/user/.gemini/extensions/elasticsearch/skills/esql: 
Showing up to 200 items (files + folders).                                                                     /home/user/.gemini/extensions/elasticsearch/skills/esql/                                                            ├───SKILL.md 
└───references/
├───esql-reference.md 
├───generation-tips.md 
└───query-patterns.md

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

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

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

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

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

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

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

 ✓  Shell 

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

✦ I've formatted and presented the answer. I'm finished.
 ───────────────────────────────────────────────────────────<p>Geminiモデルが最終的な応答を生成する際にどのような手順を踏むかは非常に興味深い点です。ここでは、モデルの推論プロセスにおけるスキルの影響が明確に見て取れます。モデルがスキルを使用する必要がある、またはシェルコマンドを実行する必要があると初めて認識したとき、ヒューマン・イン・ザ・ループ方式を使用して許可を要求します。</p><p>スキーマの発見、クエリの生成、実行といった面倒な作業を<code>esql</code>スキルが処理することで、回答を得るための仕組みではなく、回答そのものに集中できるようになります。必要なデータが、適切な形式でターミナルに直接表示されます。構文を記述したり、別のアプリケーションに切り替えたりする必要は一切ありません。</p><h2>まとめ</h2><p>この記事では、最近リリースしたGemini CLI用のElasticsearch拡張機能を紹介しました。この拡張機能を使用すると、GeminiおよびElastic Agent Builderが提供するElasticsearch MCPサーバー（バージョン 9.3.0 以降で利用可能）と<code>/elastic</code>コマンドを使用してElasticsearchインスタンスとやり取りできます。</p><p>さらに、この拡張機能には、ユーザーの自然言語からのリクエストをES|QLに変換する <code>esql</code>スキルも含まれています。このスキルは、MCPサーバーが使用できない場合に特に役立ちます。なぜなら、基本的な通信はターミナルで実行されるシンプルなcurlコマンドによって行われるためです。Elasticsearchは、あらゆるプロジェクトに簡単に統合できる豊富なREST APIセットを提供します。これは特にエージェント型AIアプリケーションの開発時に有用です。</p><p>Gemini CLI拡張機能の詳細については<a href="https://github.com/elastic/gemini-cli-elasticsearch">こちら</a>のプロジェクトリポジトリをご覧ください。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/gemini-cli-extension-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/gemini-cli-extension-elasticsearch</guid>
    <category><![CDATA[統合]]></category>
    <category><![CDATA[エージェント型AI]]></category>
    <dc:creator><![CDATA[Walter Rafelsberger,Enrico Zimuel]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4ff43abe550941b4/6a17072ba29299fc2ad00fa4/6dfcec4a77b3dc83bf0d974417bf2e211abb1f4f-876x468.png" length="0" type="image/png"/>
    <pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Jinaモデル、その機能とElasticsearchでの使用方法の紹介]]></title>
    <description><![CDATA[Jinaのマルチモーダル埋め込み、リランカーv3、セマンティック埋め込みモデル、さらにそれらをElasticsearchでネイティブに使用する方法を探ります。]]></description>
    <content:encoded><![CDATA[<p>Jina by Elasticは、アプリケーションとビジネスプロセスの自動化のための検索基盤モデルを提供します。これらのモデルは、Elasticsearchアプリケーションや革新的なAIプロジェクトにAIを導入するためのコア機能を提供します。</p><p>Jinaモデルは、情報処理、整理、検索をサポートするように設計された大きく3つのカテゴリーに分類されます。</p><ul><li><p>セマンティック埋め込みモデル</p></li><li><p>リランキングモデル</p></li><li><p>小規模な生成言語モデル</p></li></ul><h2>セマンティック埋め込みモデル</h2><p>セマンティック埋め込みの背後にある考え方は、AIモデルがインプットの意味的側面を高次元空間の幾何学の観点から表現することを学習できるというものです。</p><p>セマンティック埋め込みは、高次元空間内の点（技術的には<em>ベクトル</em>）と考えることができます。埋め込みモデルは、ニューラルネットワークの一種で、デジタルデータ（テキストや画像など、あらゆるものが入力となりえますが、最も一般的なのはテキストや画像）を入力として受け取り、対応する高次元点の位置を一連の数値座標として出力します。モデルが適切に機能している場合、2つのセマンティック埋め込み間の距離は、対応するデジタルオブジェクトがどの程度同じ意味を持つかに比例します。</p><p>これが検索アプリケーションにとっていかに重要であるかを理解するには、「dog」という単語の埋め込みと「cat」という単語の埋め込みを空間上の点として想像してみましょう。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbad74e5d8292a60e/6a17db73abe0f2114edfe8d2/802cf9bbcb82180d3fc91009f9f62027eee8f031-615x615.png" alt="" /><p>優れた埋め込みモデルは、「feline」という単語に対して「dog」よりも「cat」にずっと近い埋め込みを生成し、「canine」は「cat」よりも「dog」にずっと近い埋め込みを生成するはずです。なぜなら、これらの単語はほぼ同じ意味だからです。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb2b25691801a881/6a17db747b54f946d28b37a5/bce49daf9a31b8fb7ce1c6ef7ae4e8117a4e8b33-615x615.png" alt="" /><p>モデルが多言語対応であれば、「cat」と「dog」の翻訳でも同じ結果が期待できます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt976ba40be7776449/6a17db75be6086c2bd0045f2/ce4d030385324526cbd7539140e0e634d939371c-615x615.png" alt="" /><p>埋め込みモデルは、物事間の意味の類似性や不一致を埋め込み間の空間的関係に翻訳します。上の図は2次元のみであるため、画面上で確認できますが、埋め込みモデルでは数十から数千の次元のベクトルが生成されます。これにより、数千語以上を含む文書に対して、何百または何千もの次元を持つ空間上の点を割り当てることで、全体のテキストの意味の微妙なニュアンスをエンコードすることが可能になります。</p><h2>マルチモーダル埋め込み</h2><p>マルチモーダルモデルは、セマンティック埋め込みの概念をテキスト以外のもの、特に画像にも拡張します。画像の埋め込みは、その画像の忠実な記述の埋め込みに近いものとなることが期待されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt66dc8895485734ec/6a17db77b1e11318d279f155/1ac6aef5b1423e5fe4853e8a547a74e66b0885c2-615x615.png" alt="" /><p>セマンティック埋め込みには多くの用途があります。とりわけ、効率的な分類器の構築、データのクラスタリング、データの重複排除やデータの多様性の調査などのさまざまなタスクの実行に使用できます。いずれも、手作業では管理できないほど大量のデータを扱うビッグデータアプリケーションにとって重要です。</p><p>埋め込みの最大の直接的な利用は情報検索です。Elasticsearchでは、埋め込みを含む検索オブジェクトをキーとして格納できます。クエリは埋め込みベクトルに変換され、検索によって埋め込みに最も近いキーを持つ格納オブジェクトが返されます。</p><p>従来の<em>ベクトルベースの検索</em>（<em>低密度ベクトル検索</em>とも呼称）が、ドキュメントやクエリの単語やメタデータに基づくベクトルを使用するのに対し、<em>埋め込みベースの検索</em>（<em>高密度ベクトル検索</em>とも呼称）は、単語ではなくAIによって評価された意味を使用します。これにより、一般に従来の検索方法よりもはるかに柔軟かつ正確になります。</p><h2>マトリョーシカ表現学習</h2><p>埋め込みの次元数や数値の精度はパフォーマンスに大きな影響を与えます。空間が非常に高次元で数値が非常に高精度な場合、非常に詳細で複雑な情報を表すことができますが、トレーニングと実行に費用がかかる、より大規模なAIモデルが必要となります。生成されるベクトルはより多くのストレージ容量を必要とし、距離を計算するのにより多くの計算サイクルが必要です。セマンティック埋め込みモデルを使用するには、精度とリソース消費の間で重要なトレードオフを行う必要があります。</p><p>ユーザーの柔軟性を最大化するために、Jinaモデルは<a href="https://arxiv.org/abs/2205.13147">マトリョーシカ表現学習</a>と呼ばれる技術で訓練されています。これにより、モデルは最も重要な意味的区別を埋め込みベクトルの最初の次元に前もってロードするため、より高い次元を切り捨てても良好なパフォーマンスを得ることができます。</p><p>実際には、これはJinaモデルのユーザーが埋め込みの次元数を選択できることを意味します。次元を少なく選択すると精度は低下しますが、パフォーマンスの低下は軽微です。ほとんどのタスクで、Jinaモデルのパフォーマンス指標は、埋め込みサイズを50％縮小するたびに1〜2％低下し、サイズが約95％小さくなります。</p><h2>非対称検索</h2><p>意味的類似性は通常、対称的に測定されます。「cat」と「dog」を比較したときに得られる値は、「dog」と「cat」を比較したときに得られる値と同じです。しかし、情報検索に埋め込みを使用する場合、対称性を破り、検索オブジェクトをエンコードする方法とは異なる方法でクエリをエンコードすると、埋め込みがより効果的に機能します。</p><p>これは、埋め込みモデルをトレーニングする方法によるものです。トレーニングデータには、単語のような同じ要素が多くの異なるコンテキストでインスタンスとして含まれており、モデルは要素間のコンテキスト上の類似点と相違点を比較することで意味論を学習します。</p><p>例えば、「animal」という単語は、「cat」や「dog」と同じ文脈にはあまり出てこないので、「animal」の埋め込みは「cat」や「dog」に特に近いわけではない可能性があります。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf219074e18a6290a/6a17db78be6086cf060045f6/9a33163405af6c71ee7f4ba8ebc86af39e295a69-615x615.png" alt="" /><p>これにより、「animal」のクエリで猫や犬に関するドキュメントが検索される可能性が低くなります。これは目標とは逆の結果となります。そのため、代わりに、クエリの場合と検索のターゲットの場合で「animal」を異なる方法でエンコードします。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt33438b4964001467/6a17db79b1e113101c79f159/363992d4f0affba7937c0c8a9f82c9a531fcd3ba-615x615.png" alt="" /><p><em>非対称検索</em>とは、クエリに異なるモデルを使用したり、埋め込みモデルを特別に訓練して、検索のために格納する際に一方向にエンコードし、クエリを別の方向にエンコードすることを意味します。</p><h2>マルチベクトル埋め込み</h2><p>単一の埋め込みは、インデックス付きデータベースの基本的なフレームワークに適合するため、情報検索に適しています。検索キーとして単一の埋め込みベクトルを使用して、検索用のオブジェクトを格納します。ユーザーがドキュメントストアをクエリする際、そのクエリは埋め込みベクトルに変換され、そのキーが（高次元の埋め込み空間において）クエリ埋め込みに最も近いドキュメントが一致候補として取得されます。</p><p>マルチベクトル埋め込みの動作は少し異なります。クエリと格納されたオブジェクト全体を示す固定長のベクトルを生成する代わりに、それらの小さな部分を表す埋め込みのシーケンスを生成します。これらの部分は通常、テキストの場合はトークンまたは単語、視覚データの場合は画像タイルです。これらの埋め込みは、その文脈における部分の意味を反映しています。</p><p>例えば、次の文を考えてみましょう。</p><ul><li><p>She had a heart of gold（彼女は心優しい人でした）.</p></li><li><p>She had a change of heart（彼女は心変わりしたのです）.</p></li><li><p>彼女は心臓発作を起こしました。</p></li></ul><p>表面的には非常によく似ているように見えますが、マルチベクトルモデルでは「heart」の各インスタンスに対して非常に異なる埋め込みが生成され、文全体の文脈の中でそれぞれが別の意味を持つことが示されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5c81f089771e6029/6a17db7b7f6f157601c099ec/a33e60c8d8ee3d312bca8375ca2a8b0a0cd40ba9-615x615.png" alt="" /><p>2つのオブジェクトのマルチベクトル埋め込みを比較する場合、多くの場合、面取り距離の測定が必要になります。つまり、1 つのマルチベクトル埋め込みの各部分を別のマルチベクトル埋め込みの各部分と比較し、それらの間の最小距離を合計します。以下に説明するJinaリランカーを含む他のシステムでは、類似性を評価するために特別にトレーニングされたAIモデルにそれらを入力します。マルチベクトル埋め込みには単一ベクトル埋め込みよりもはるかに詳細な情報が含まれているため、通常、両方のアプローチは単一ベクトル埋め込みを単純に比較するよりも精度が高くなります。</p><p>しかし、マルチベクトル埋め込みはインデキシングにはあまり適していません。次のセクションの<code>jina-colbert-v2</code>モデルで説明するように、これらはタスクのリランキングによく使用されます。</p><h2>Jina埋め込みモデル</h2><h3>Jina埋め込みv4</h3><p><a href="https://jina.ai/news/jina-embeddings-v4-universal-embeddings-for-multimodal-multilingual-retrieval/"><strong>jina-embeddings-v4</strong></a>は、広く使用されているさまざまな言語の画像とテキストをサポートする、38億（3.8x10⁹）パラメーターの多言語およびマルチモーダル埋め込みモデルです。視覚的知識と言語的知識を活用する新しいアーキテクチャを使用して両方のタスクのパフォーマンスを向上させ、画像検索、特に<a href="https://huggingface.co/tasks/visual-document-retrieval">視覚的ドキュメント検索</a>で優れた性能を発揮します。これは、チャート、スライド、マップ、スクリーンショット、ページスキャン、ダイアグラムなどの画像を処理することを意味します。これらは一般的な種類の画像で、しばしば重要な埋め込まれたテキストが含まれており、実世界のシーンの画像で訓練されたコンピュータービジョンモデルの範囲外にあります。</p><p>コンパクトな<a href="https://huggingface.co/docs/peft/en/package_reference/lora">Low-Rank Adaptation（LoRA）アダプター</a>を使って、このモデルを複数の異なるタスクに最適化しました。これにより、メモリや処理の追加コストを最小限に抑えながら、いずれのタスクでもパフォーマンスを犠牲にすることなく、単一のモデルを複数のタスクに特化させることができます。</p><p>主な機能には以下のようなものがあります。</p><ul><li><p>ビジュアルドキュメント検索における最先端のパフォーマンス、および大規模モデルをはるかに凌駕する多言語テキストと通常の画像のパフォーマンス。</p></li><li><p>大きなインプットコンテキストサイズのサポート：32,768トークンは約80ページのダブルスペースの英語テキストに相当し、20メガピクセルは4,500 x 4,500ピクセルの画像に相当します。</p></li><li><p>最大2048次元から128次元まで、ユーザーが選択した埋め込みサイズ。経験的に、そのしきい線を下回るとパフォーマンスが劇的に低下することがわかりました。</p></li><li><p>単一埋め込みとマルチベクトル埋め込みの両方をサポートします。テキストの場合、マルチベクトル出力は、インプットトークンごとに1つの128次元埋め込みで構成されます。画像の場合、28x28ピクセルタイルごとに1つの128次元埋め込みを生成します。</p></li><li><p>目的のために特別に訓練された2つのLoRAアダプターによる非対称検索最適化。</p></li><li><p>意味的類似度計算に最適化されたLoRAアダプター。</p></li><li><p>プログラミング言語とITフレームワークへの特別なサポート。LoRAアダプターを介してのサポートも提供します。</p></li></ul><p>私たちは、幅広い一般的な検索、自然言語理解、AI分析タスクのための汎用的な多目的ツールとして<code>jina-embeddings-v4</code>を開発しました。機能を考えると比較的小規模なモデルですが、導入には依然としてかなりのリソースが必要であり、クラウドAPI経由または高ボリューム環境での使用に最適です。</p><h3>Jina embeddings v3</h3><p><a href="https://jina.ai/news/jina-embeddings-v3-a-frontier-multilingual-embedding-model/"><strong>jina-embeddings-v3</strong></a>は、6億未満のパラメーターを持つ、コンパクトで高性能な多言語のテキストのみの埋め込みモデルです。最大8192トークンのテキストインプットをサポートし、デフォルトの1024次元から64次元まで、ユーザーが選択したサイズの単一ベクトル埋め込みを出力します。</p><p>私たちは、情報検索や意味的類似性だけでなく、感情分析やコンテンツモデレーションなどの分類タスク、ニュースの集約や推奨などのクラスタリングタスクなど、さまざまなテキストタスク向けに<code>jina-embeddings-v3</code>をトレーニングしてきました。<code>jina-embeddings-v4</code>と同様に、このモデルは次の使用カテゴリーに特化したLoRAアダプターを提供します。</p><ul><li><p>非対称検索</p></li><li><p>意味的類似性</p></li><li><p>分類</p></li><li><p>クラスタリング</p></li></ul><p><code>jina-embeddings-v3</code> は <code>jina-embeddings-v4</code>よりもはるかに小さいモデルであり、インプットコンテキストのサイズが大幅に削減されていますが、操作にかかるコストは少なくなります。それにもかかわらず、テキストに関しては非常に競争力のあるパフォーマンスを有し、多くのユースケースにとってより良い選択肢です。</p><h3>Jinaコード埋め込み</h3><p>Jinaの専門的なコード埋め込みモデルである<a href="https://jina.ai/models/jina-code-embeddings-1.5b"><strong>jina-code-embeddings（0.5bおよび1.5b）</strong></a>は、15プログラミング方式とフレームワーク、さらにコンピューティングや情報技術に関連する英語のテキストをサポートしています。これらは、それぞれ5億 （0.5x10⁹）と15億（1.5x10⁹）のパラメーターを持つコンパクトなモデルです。どちらのモデルも、最大32,768トークンのインプットコンテキストサイズをサポートしており、ユーザーは出力の埋め込みサイズを選択（小さいモデルでは896から64次元、大きいモデルでは1536から128次元）できます。</p><p>これらのモデルは、LoRAアダプターではなく<a href="https://arxiv.org/abs/2101.00190">プレフィックスチューニング</a>を使用して、5つのタスク固有の特殊化のための非対称検索をサポートしています。</p><ul><li><p><strong>コードからコードへ。</strong>さまざまなプログラミング言語で同様のコードを取得できます。コードの調整、コードの重複排除、移植とリファクタリングのサポートに使用されます。</p></li><li><p><strong>自然言語からコードへ。</strong>自然言語クエリ、コメント、説明、ドキュメントに合わせたコードを取得します。</p></li><li><p><strong>コードから自然言語へ。</strong>コードをドキュメントまたはその他の自然言語テキストと一致させます。</p></li><li><p><strong>コード間の補完。</strong>既存のコードを完成させたり強化したりするために、関連するコードを提案します。</p></li><li><p><strong>技術的な内容のQ＆A。</strong>情報技術に関する質問に対する自然言語による回答を特定します。テクニカルサポートのユースケースに最適です。</p></li></ul><p>これらのモデルは、比較的小さい計算コストで、コンピューターのドキュメント作成やプログラミング資料に関連するタスクに優れたパフォーマンスを提供します。開発環境やコードアシスタントに統合するのに適しています。</p><h3>Jina ColBERT v2</h3><p><a href="https://jina.ai/models/jina-colbert-v2"><strong>jina-colbert-v2</strong></a>は、5億6000万のパラメーターを持つマルチベクトルテキスト埋め込みモデルです。多言語対応で、89言語の素材を使用してトレーニングされており、可変の埋め込みサイズと非対称検索をサポートしています。</p><p>前述のように、マルチベクトル埋め込みはインデックス作成にはあまり適していませんが、他の検索戦略の結果の精度を高めるのに非常に役立ちます。<code>jina-colbert-v2</code>を使用すると<strong>、</strong>マルチベクトル埋め込みを事前に計算し、それを使用してクエリ時に検索候補をリランキングすることができます。このアプローチは、次のセクションのリランキングモデルの1つを使用するほど正確ではありませんが、クエリや候補の一致ごとにAIモデル全体を呼び出すのではなく、格納されているマルチベクター埋め込みを比較するだけなので、はるかに効率的です。これは、リランキングモデルを使用する際の遅延や計算オーバーヘッドが大きすぎる、または比較する候補の数が多すぎるユースケースに最適です。</p><p>このモデルは、インプットトークンごとに埋め込みのシーケンスを出力し、ユーザーは128次元、96次元、または64次元の埋め込みのトークンを選択できます。候補テキストの一致は8,192トークンに制限されます。クエリは非対称にエンコードされるため、ユーザーはテキストがクエリか候補一致かを指定する必要があり、クエリは32トークンに制限する必要があります。</p><h3>Jina CLIP v2</h3><p><a href="https://jina.ai/news/jina-clip-v2-multilingual-multimodal-embeddings-for-text-and-images/"><strong>jina-clip-v2</strong></a>は、9億パラメーターのマルチモーダル埋め込みモデルであり、テキストが画像のコンテンツを説明する場合に、テキストと画像が近い埋め込みを生成するようにトレーニングされています。その主な用途は、テクスチャクエリに基づいて画像を取得することですが、テキストからテキストへの検索とテキストから画像への検索に別々のモデルを必要としないため、高性能のテキストのみのモデルでもあり、ユーザーのコスト削減に役立ちます。</p><p>このモデルは8,192トークンのテキストインプットコンテキストをサポートし、画像は埋め込みを生成する前に512x512ピクセルに拡大されます。</p><p>対照言語画像事前トレーニング（CLIP）アーキテクチャは、トレーニングと操作が簡単で、非常にコンパクトなモデルを作成できますが、基本的な制限がいくつかあります。あるメディアの知識を別のメディアでのパフォーマンスの向上に活用することはできません。あるメディアを利用して別のメディアのパフォーマンスを向上させることはできません。そのため、「dog」と「cat」という単語の意味はどちらも「car」よりも近いことはわかっていても、犬の写真と猫の写真はどちらも車の写真よりも関連性が高いことは必ずしもわかっていません。</p><p>また、これらは<em>モダリティギャップ</em>と呼ばれる問題も抱えています。これはつまり、犬に関するテキストの埋め込みは、犬の画像の埋め込みよりも、猫に関するテキストの埋め込みに近い可能性が高いということです。この制限のため、CLIPはテキストから画像への検索モデルとして、またはテキストのみのモデルとして使用し、1つのクエリ内でこれら2つを混在させないことをお勧めします。</p><h2>リランキングモデル</h2><p>リランキングモデルは、1つまたは複数の候補一致と、クエリをモデルへのインプットとして取り、それらを直接比較して、はるかに高い精度の一致を生成します。</p><p>原理的には、各クエリを保存されている各ドキュメントと比較することで、情報検索にリランキングを直接使用できますが、これは計算コストが非常に高く、最小のコレクション以外では実用的ではありません。そのため、リランカーは、埋め込みベースの検索やその他の検索アルゴリズムなど、他の手段によって見つかった候補一致の比較的短いリストを評価するために使用される傾向があります。リランキングモデルは、検索を実行するとクエリが異なるデータセットを持つ個別の検索システムに送信され、それぞれが異なる結果を返す可能性があるハイブリッド検索スキームやフェデレーション検索スキームに最適です。多様な結果を1つの高品質な結果に統合する場合に非常に効果的です。</p><p>埋め込みベースの検索は、保存されているすべてのデータの再インデックスや、結果に対するユーザーの期待の変更など、大きな負担を伴う可能性があります。既存の検索スキームにリランカーを追加することで、検索ソリューション全体を再構築することなく、AIの利点の多くを追加することができます。</p><h2>Jinaリランカーモデル</h2><h3>Jinaリランカーm0</h3><p><a href="https://jina.ai/models/jina-reranker-m0/"><strong>jina-reranker-m0</strong></a>は、24億（2.4x10⁹）パラメーターのマルチモーダルリランカーで、テキストクエリとテキストや画像からなる候補一致をサポートします。これはビジュアルドキュメント検索の主要モデルであり、PDF、テキストのスキャン、スクリーンショット、テキストなど半構造化情報を含むコンピュータ生成または修正された画像、加えてテキストドキュメントと画像からなる混合データの格納に理想的なソリューションです。</p><p>このモデルは、単一のクエリと候補一致を受け取り、スコアを返します。同じクエリを異なる候補で使用すると、スコアは比較可能となり、それらのランク付けに使用できます。クエリテキストや候補テキストや画像を含む最大10,240トークンのインプットサイズをサポートします。画像をカバーするために必要な28x28ピクセルのタイルはすべて、入力サイズを計算するためのトークンとしてカウントされます。</p><h3>Jinaリランカーv3</h3><p><a href="https://jina.ai/models/jina-reranker-v3/"><strong>jina-reranker-v3</strong></a>は、同等のサイズのモデルに対して最先端のパフォーマンスを備えた6億パラメーターのテキストリランカーです。<code>jina-reranker-m0</code>とは異なり、1つのクエリと最大64件の一致候補のリストを受け取り、ランキング順を返します。クエリとすべてのテキスト候補を含む131,000トークンの入力コンテキストがあります。</p><h3>Jinaリランカーv2</h3><p><a href="https://jina.ai/models/jina-reranker-v2"><strong>jina-reranker-v2-base-multilingual</strong></a>は非常にコンパクトで汎用的なリランカーで、関数呼び出しやSQLクエリをサポートする追加の機能を備えています。3億弱のパラメーターで、高速、効率的、正確な多言語テキストリランキングを提供し、テキストクエリにマッチするSQLテーブルと外部関数を選択するための追加サポートもあり、エージェント的なユースケースに適しています。</p><h2>小規模な生成言語モデル</h2><p>生成言語モデルは、OpenAIのChatGPT、Google Gemini、AnthropicのClaudeのように、テキストまたはマルチメディアのインプットを受け取り、テキスト出力で応答するモデルです。<em>大規模</em>言語モデル（LLM）と<em>小規模</em>言語モデル（SLM）を明確に区別する境界はありませんが、最先端のLLMを開発、運用、使用する際の実用的な問題はよく知られています。最もよく知られているものは一般公開されていないため、そのサイズを推定することしかできませんが、ChatGPT、Gemini、Claudeは1～3兆（1～3x10¹²）のパラメーター範囲にあると予想されます。</p><p>これらのモデルを実行することは、たとえ公開されたものであっても、従来のハードウェアの範囲をはるかに超えており、広大な並列アレイに配置された最先端のチップを必要とします。有料のAPIを使ってLLMにアクセスすることもできますが、これには大きなコストがかかり、レイテンシーも大きく、データ保護、デジタル主権、クラウドの本国送還などの要求と整合させるのは困難です。さらに、その規模のモデルのトレーニングとカスタマイズに関連するコストはかなりの額になる可能性があります。</p><p>その結果、最大規模のLLMのすべての機能は備えていないものの、特定の種類のタスクを低コストで同様に実行できる小規模モデルの開発に多大な研究が行われてきました。一般的に、企業は特定の問題に対処するためにソフトウェアをデプロイしますが、AIソフトウェアも同様で、LLMよりもSLMベースのソリューションの方が望ましい場合が多いのです。これらは通常、一般的なハードウェア上で実行でき、実行速度が速く、消費電力が少なく、カスタマイズがはるかに簡単です。</p><p>JinaのSLMサービスは、AIを実用的な検索ソリューションに最も効果的に組み込む方法に重点を置いて拡大しています。</p><h2>Jina SLM</h2><h3>ReaderLM v2</h3><p><a href="https://jina.ai/models/ReaderLM-v2"><strong>ReaderLM-v2</strong></a>は、ユーザーが提供したJSONスキーマや自然言語命令に基づいて、HTMLをMarkdownまたはJSONに変換する生成言語モデルです。</p><p>データの前処理と正規化はデジタルデータの優れた検索ソリューションを開発する上で不可欠な部分ですが、現実世界のデータ、特にウェブから得られる情報は混沌としていることが多く、単純な変換戦略では非常に脆弱になることがよくあります。代わりに、<code>ReaderLM-v2</code> はウェブページのDOMツリーダンプの混沌を理解し、有用な要素を堅牢に識別できるインテリジェントなAIモデルソリューションを提供します。</p><p>15億（1.5x10⁹）パラメーターを持つこのシステムは最先端のLLMよりも3桁コンパクトですが、この1つの狭義のタスクにおいては最先端のLLMと同等のパフォーマンスを発揮します。</p><h3>Jina VLM</h3><p><a href="https://jina.ai/models/jina-vlm"><strong>JINA-VLM</strong></a>は、画像に関する自然言語の質問に答えるために訓練された24億（2.4×10⁹）パラメーターの生成言語モデルです。視覚的ドキュメント分析、つまりスキャン、スクリーンショット、スライド、図表、類似の非自然画像データに関する質問に回答する機能を非常に強力にサポートしています。</p><p>例：</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt124b9932e01dcd40/6a17db7d4202291eca29f4bc/adfa1420d079ca4fd5582eef4349b1265b378e76-950x500.png" alt="" /><p>画像内のテキストの読み取りにも非常に優れています。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1a862a9c9a0e42ce/6a17db7fb1e1133a2979f15d/ea3956e7ad86f8e171841cab2c28c8b3498da1d4-1002x500.png" alt="" /><p>しかし、<code>jina-vlm</code>の真に優れた点は、情報収集や人工画像の内容を理解することです。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt761cf621ea32e4ae/6a17db8163baff7730741b26/f68606f9d2d99e2cd616d4ff81db3574dc4e26a5-1020x700.png" alt="" /><p>または：</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4df4d31e574df7e3/6a17db82e3179134e02d56e9/297e85e7e78f296388a02301e1e08fed70827423-1000x500.png" alt="" /><p><code>jina-vlm</code> 自動キャプション生成、製品の説明、画像の代替テキスト、視覚障害者向けのアクセシビリティ用途に最適です。また、検索拡張生成（RAG）システムが視覚情報を使用したり、AIエージェントが人間の助けを借りずに画像を処理したりする可能性も生まれます。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/jina-models-elasticsearch-guide</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/jina-models-elasticsearch-guide</guid>
    <category><![CDATA[統合]]></category>
    <category><![CDATA[Jina AI]]></category>
    <dc:creator><![CDATA[Scott Martens]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta03919124faf767a/6a17db84ec0f89b8fe5a64d8/407b4c862b51ebdfc7f26db4e25950a65caf1673-656x442.png" length="0" type="image/png"/>
    <pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[MastraとElasticsearchを使用してセマンティックリコールを備えた知識エージェントを構築する]]></title>
    <description><![CDATA[メモリと情報検索用のベクトル ストアとして Mastra と Elasticsearch を使用して、セマンティック リコールを備えたナレッジ エージェントを構築する方法を学びます。]]></description>
    <content:encoded><![CDATA[<p><a href="https://www.elastic.co/search-labs/blog/context-engineering-overview">コンテキスト エンジニアリングは</a>、信頼性の高い AI エージェントとアーキテクチャの構築においてますます重要になっています。モデルがどんどん良くなるにつれて、その有効性と信頼性はトレーニングされたデータに依存するのではなく、適切なコンテキストにどれだけ適切に基づいているかに依存するようになります。最も関連性の高い情報を適切なタイミングで取得して適用できるエージェントは、正確で信頼できる出力を生成する可能性がはるかに高くなります。</p><p>このブログでは、 <a href="https://mastra.ai/">Mastra</a>を使用して、Elasticsearch をメモリおよび検索バックエンドとして使用し、ユーザーの発言を記憶し、後で関連情報を思い出すことができるナレッジ エージェントを構築します。これと同じ概念を実際のユースケースに簡単に拡張できます。サポート エージェントが過去の会話や解決策を記憶し、特定のユーザーへの応答をカスタマイズしたり、以前のコンテキストに基づいてより迅速に解決策を提示したりできると考えてください。</p><p>ここから手順に従って、ステップごとに構築する方法を確認してください。迷ってしまったり、完成した例を実行したいだけの場合は、<a href="https://github.com/jdarmada/getting-started-mastra-elastic/tree/main">ここにある</a>リポジトリを確認してください。</p><h2>マストラとは何ですか？</h2><p>Mastra は、推論、メモリ、ツールの交換可能なパーツを備えた AI エージェントを構築するためのオープンソースの TypeScript フレームワークです。<a href="https://mastra.ai/docs/memory/semantic-recall">セマンティック リコール</a>機能により、エージェントはメッセージをベクター データベースに埋め込みとして保存することで、過去のやり取りを記憶して取り出すことができます。これにより、エージェントは長期的な会話のコンテキストと継続性を維持できます。Elasticsearch は効率的な高密度ベクトル検索をサポートしているため、この機能を有効にするのに最適なベクトル ストアです。セマンティックリコールがトリガーされると、エージェントは関連する過去のメッセージをモデルのコンテキストウィンドウに引き出し、モデルが取得したコンテキストを推論と応答の基礎として使用できるようにします。</p><h2>始めるために必要なもの</h2><ul><li><p>ノード v18+</p></li><li><p>Elasticsearch（バージョン8.15以降）</p></li><li><p>Elasticsearch APIキー</p></li><li><p><a href="https://help.openai.com/en/articles/4936850-where-do-i-find-my-openai-api-key">OpenAI APIキー</a></p></li></ul><p>注: デモでは OpenAI プロバイダーを使用するため、これが必要になりますが、Mastra は他の AI SDK とコミュニティ モデル プロバイダーをサポートしているため、設定に応じて簡単に交換できます。</p><h2>Mastraプロジェクトの構築</h2><p>プロジェクトの足場を提供するために、Mastra の組み込み CLI を使用します。次のコマンドを実行します。</p>npm create mastra@latest<p>次のような一連のプロンプトが表示されます。</p><p>1. プロジェクトに名前を付けます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt87f941f654d03827/6a16f7af67045b214d45bfa1/2b9fe559e0276140dd539e24f916a73c60870405-620x84.png" alt="Mastraアプリでプロンプトに名前を付ける" /><p>2. このデフォルト設定を維持することもできますし、空白のままにしておくこともできます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7dbb3d4f27435cac/6a16f7b0cdacbf29497d27de/e04729eb03bce8499e973e18c28642402340d0e5-852x68.png" alt="プロンプトファイルを保存する場所をmastraに伝える" /><p>3. このプロジェクトでは、OpenAI が提供するモデルを使用します。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1f654f6cb9397e94/6a16f7b2964cea899a08b942/a86596a469a71bdf8bd99cbaf528d0f0cf7272c0-436x222.png" alt="MastraでOpenAIが提供するモデルを選択する" /><p>4. すべての環境変数を、後のステップで設定する `.env` ファイルに保存するため、「今はスキップ」オプションを選択します。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltff106117521a3519/6a16f7b3c1e8a5031af880d8/02b19ccc34af0bdacf52fd94b519d036540ca2e6-426x114.png" alt="OpenAIキーについては今はスキップを選択" /><p>5. このオプションをスキップすることもできます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcda7d9c51c3878d7/6a16f7b450916809dbe1b892/b3fe63d19d270bc2e0de1dd92033bf8b26750819-990x208.png" alt="" /><p>初期化が完了したら、次のステップに進むことができます。</p><h3>依存関係のインストール</h3><p>次に、いくつかの依存関係をインストールする必要があります。</p>npm install ai @ai-sdk/openai @elastic/elasticsearch dotenv<ul><li><p><code>ai</code> - JavaScript/TypeScript で AI モデル、プロンプト、ワークフローを管理するためのツールを提供するコア AI SDK パッケージ。Mastra は Vercel の<a href="https://ai-sdk.dev/">AI SDK</a>上に構築されているため、エージェントとのモデルのインタラクションを有効にするにはこの依存関係が必要です。</p></li><li><p><code>@ai-sdk/openai</code> - AI SDK を OpenAI モデル (GPT-4、GPT-4o など) に接続し、OpenAI API キーを使用した API 呼び出しを可能にするプラグイン。</p></li><li><p><code>@elastic/elasticsearch</code> - <a href="https://www.elastic.co/docs/reference/elasticsearch/clients/javascript">Node.js 用の公式 Elasticsearch クライアント</a>、インデックス作成、検索、ベクター操作のために Elastic Cloud またはローカル クラスターに接続するために使用されます。</p></li><li><p><code>dotenv</code> - .envから環境変数を読み込みますファイルをprocess.envにコピーし、API キーや Elasticsearch エンドポイントなどの資格情報を安全に挿入できるようになります。</p></li></ul><h3>環境変数の設定</h3><p>プロジェクトのルート ディレクトリに<code>.env</code>ファイルが存在しない場合は作成します。あるいは、<a href="https://github.com/jdarmada/getting-started-mastra-elastic/blob/main/.env.example">リポジトリ</a>に提供されている例<code>.env</code>をコピーして名前を変更することもできます。このファイルでは、次の変数を追加できます。</p>ELASTICSEARCH_ENDPOINT="your-endpoint-here"
ELASTICSEARCH_API_KEY="your-key-here"
OPENAI_API_KEY="your-key-here"<p>これで基本的な設定は完了です。ここから、エージェントの構築とオーケストレーションを開始できます。さらに一歩進んで、Elasticsearch をストアおよびベクター検索レイヤーとして追加します。</p><h2>ベクターストアとしてElasticsearchを追加する</h2><p><code>stores</code>という新しいフォルダーを作成し、その中にこの<a href="https://github.com/jdarmada/getting-started-mastra-elastic/blob/main/src/mastra/stores/elastic-store.ts">ファイル</a>を追加します。Mastra と Elastic が公式の Elasticsearch ベクター ストア統合を出荷する前に、 <a href="https://github.com/abhiaiyer91">Abhi Aiyer</a> (Mastra CTO) が<code>ElasticVector</code>と呼ばれるこの初期のプロトタイプ クラスを共有しました。簡単に言えば、Mastra のメモリ抽象化を Elasticsearch の高密度ベクトル機能に接続することで、開発者はエージェントのベクトル データベースとして Elasticsearch を導入できるようになります。</p><p>統合の重要な部分を詳しく見てみましょう。</p><h3>Elasticsearchクライアントの取り込み</h3><p>このセクションでは、 <code>ElasticVector</code>クラスを定義し、標準デプロイメントとサーバーレスデプロイメントの両方をサポートする Elasticsearch クライアント接続を設定します。</p>export interface ElasticVectorConfig extends ClientOptions {
    /**
     * Explicitly specify if connecting to Elasticsearch Serverless.
     * If not provided, will be auto-detected on first use.
     */
    isServerless?: boolean;
    
    /**
     * Maximum documents to count accurately when describing indices.
     * Higher values provide accurate counts but may impact performance on large indices.
     * 
     * @default 10000
     */
    maxCountAccuracy?: number;
}

export class ElasticVector extends MastraVector {
    private client: Client;
    private isServerless: boolean | undefined;
    private deploymentChecked: boolean = false;
    private readonly maxCountAccuracy: number;

    constructor(config: ElasticVectorConfig) {
        super();
        this.client = new Client(config);
        this.isServerless = config.isServerless;
        this.maxCountAccuracy = config.maxCountAccuracy ?? 10000;
    }
}<ul><li><p><code>ElasticVectorConfig extends ClientOptions</code>: これにより、すべての Elasticsearch クライアント オプション ( <code>node</code> 、 <code>auth</code> 、 <code>requestTimeout</code>など) を継承し、カスタム プロパティを追加する新しい構成インターフェースが作成されます。つまり、ユーザーは、サーバーレス固有のオプションとともに、有効な Elasticsearch 構成を渡すことができるということです。</p></li><li><p><code>extends MastraVector</code>: これにより、 <code>ElasticVector</code> 、すべてのベクター ストア統合が準拠する共通インターフェースである Mastra の基本<code>MastraVector</code>クラスから継承できるようになります。これにより、エージェントの観点から見ると、Elasticsearch は他の Mastra ベクター バックエンドと同じように動作するようになります。</p></li><li><p><code>private client: Client</code>: これは、Elasticsearch JavaScript クライアントのインスタンスを保持するプライベート プロパティです。これにより、クラスはクラスターと直接通信できるようになります。</p></li><li><p><code>isServerless</code> および<code>deploymentChecked</code> : これらのプロパティは連携して、サーバーレスまたは標準の Elasticsearch デプロイメントに接続されているかどうかを検出し、キャッシュします。この検出は最初の使用時に自動的に行われますが、明示的に構成することもできます。</p></li><li><p><code>constructor(config: ClientOptions)</code>: このコンストラクターは、構成オブジェクト (Elasticsearch の資格情報とオプションのサーバーレス設定を含む) を受け取り、それを使用して<code>this.client = new Client(config)</code>行でクライアントを初期化します。</p></li><li><p><code>super()</code>: これは Mastra の基本コンストラクターを呼び出すため、ログ記録、検証ヘルパー、およびその他の内部フックを継承します。</p></li></ul><p>この時点で、Mastraは新しいベクターストアがあることを知っています。 <code>ElasticVector</code></p><h3>展開タイプの検出</h3><p>インデックスを作成する前に、アダプターは標準の Elasticsearch を使用しているか Elasticsearch Serverless を使用しているかを自動的に検出します。サーバーレス デプロイメントでは手動でのシャード構成が許可されないため、これは重要です。</p>private async detectServerless(): Promise&lt;boolean&gt; {
    // Return cached result if already detected
    if (this.deploymentChecked) {
        return this.isServerless ?? false;
    }

    // Use explicit configuration if provided
    if (this.isServerless !== undefined) {
        this.deploymentChecked = true;
        this.logger?.info(
            `Using explicit deployment type: ${this.isServerless ? 'Serverless' : 'Standard'}`
        );
        return this.isServerless;
    }

    try {
        const info = await this.client.info();
        
        // Primary detection: build flavor (most reliable)
        const isBuildFlavorServerless = info.version?.build_flavor === 'serverless';
        
        // Secondary detection: tagline (fallback)
        const isTaglineServerless = info.tagline?.toLowerCase().includes('serverless') ?? false;
        
        this.isServerless = isBuildFlavorServerless || isTaglineServerless;
        this.deploymentChecked = true;
        
        this.logger?.info(
            `Auto-detected ${this.isServerless ? 'Serverless' : 'Standard'} Elasticsearch deployment`,
            { 
                buildFlavor: info.version?.build_flavor, 
                version: info.version?.number,
                detectionMethod: isBuildFlavorServerless ? 'build_flavor' : 'tagline'
            }
        );
        
        return this.isServerless;
    } catch (error) {
        this.logger?.warn(
            'Could not auto-detect deployment type, assuming Standard Elasticsearch. ' +
            'Set isServerless: true explicitly in config if using Serverless.',
            { error: error instanceof Error ? error.message : String(error) }
        );
        this.isServerless = false;
        this.deploymentChecked = true;
        return false;
    }
}<p>何が起こっていますか：</p><ul><li><p>まず、構成で明示的に<code>isServerless</code>が設定されているかどうかを確認します (自動検出をスキップします)</p></li><li><p>Elasticsearch の<code>info()</code> API を呼び出してクラスター情報を取得します</p></li><li><p><code>build_flavor field</code>をチェックします (サーバーレス デプロイメントは<code>serverless</code>を返します)</p></li><li><p>ビルドフレーバーが利用できない場合はタグラインをチェックする</p></li><li><p>結果をキャッシュして、API 呼び出しの繰り返しを回避します。</p></li><li><p>検出に失敗した場合は標準展開をデフォルトとする</p></li></ul><p> 使用例:</p>// Option 1: Auto-detect (recommended)
const vector = new ElasticVector({
    node: 'https://your-cluster.es.cloud',
    auth: { apiKey: 'your-api-key' }
});
// Detection happens automatically on first index operation

// Option 2: Explicit configuration (faster startup)
const vector = new ElasticVector({
    node: 'https://your-serverless.es.cloud',
    auth: { apiKey: 'your-api-key' },
    isServerless: true  // Skips auto-detection
});<h3>Elasticsearchに「メモリ」ストアを作成する</h3><p>以下の関数は、埋め込みを保存するための Elasticsearch インデックスを設定します。インデックスがすでに存在するかどうかを確認します。そうでない場合は、埋め込みとカスタム類似度メトリックを格納するための<code>dense_vector</code>フィールドを含む以下のマッピングを使用して作成します。</p><p>注意すべき点:</p><ul><li><p><code>dimension</code>パラメータは各埋め込みベクトルの長さであり、使用している埋め込みモデルによって異なります。私たちの場合、サイズ<code>1536</code>のベクトルを出力する OpenAI の<code>text-embedding-3-small</code>モデルを使用して埋め込みを生成します。これをデフォルト値として使用します。</p></li><li><p>以下のマッピングで使用される<code>similarity</code>変数は、ヘルパー関数 c <code>onst similarity = this.mapMetricToSimilarity(metric)</code>から定義されます。この関数は、 <code>metric</code>パラメータの値を受け取り、選択された距離メトリックの Elasticsearch 互換キーワードに変換します。</p><ul><li><p>たとえば、Mastra では、ベクトルの類似性を表すために<code>cosine</code> 、 <code>euclidean</code> 、 <code>dotproduct</code>などの一般的な用語を使用します。メトリック<code>euclidean</code> Elasticsearch マッピングに直接渡すと、Elasticsearch はキーワード<code>l2_norm</code>がユークリッド距離を表すと想定するため、エラーが発生します。</p></li></ul></li><li><p>サーバーレス互換性: サーバーレスデプロイメントのシャードとレプリカの設定は Elasticsearch Serverless によって自動的に管理されるため、コードでは自動的に省略されます。</p></li></ul>async createIndex(params: CreateIndexParams): Promise&lt;void&gt; {
    const { indexName, dimension = 1536, metric = 'cosine' } = params;

    try {
        const exists = await this.client.indices.exists({ index: indexName });

        if (exists) {
            try {
                await this.validateExistingIndex(indexName, dimension, metric);
                this.logger?.info(`Index "${indexName}" already exists and is valid`);
                return;
            } catch (validationError) {
                throw new Error(
                    `Index "${indexName}" exists but does not match the required configuration: ${
                        validationError instanceof Error ? validationError.message : String(validationError)
                    }`
                );
            }
        }

        const isServerless = await this.detectServerless();
        const similarity = this.mapMetricToSimilarity(metric);

        const indexConfig: any = {
            index: indexName,
            mappings: {
                properties: {
                    vector: {
                        type: 'dense_vector',
                        dims: dimension,
                        index: true,
                        similarity: similarity,
                    },
                    metadata: {
                        type: 'object',
                        enabled: true,
                        dynamic: true, // Allows flexible metadata structures
                    },
                },
            },
        };

        // Only configure shards/replicas for non-serverless deployments
        // Serverless manages infrastructure automatically
        if (!isServerless) {
            indexConfig.settings = {
                number_of_shards: 1,
                number_of_replicas: 0, // Increase for production HA deployments
            };
        }

        await this.client.indices.create(indexConfig);

        this.logger?.info(
            `Created ${isServerless ? 'Serverless' : 'Standard'} Elasticsearch index "${indexName}"`,
            { dimension, metric, similarity }
        );
    } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        this.logger?.error(`Failed to create index "${indexName}": ${errorMessage}`);
        throw new Error(`Failed to create index "${indexName}": ${errorMessage}`);
    }
}<h3>やりとりの後に新しい記憶やメモを保存する</h3><p>この関数は、各インタラクションの後に生成された新しい埋め込みをメタデータとともに取得し、Elastic の<code>bulk</code> API を使用してそれらをインデックスに挿入または更新します。<code>bulk</code> API は複数の書き込み操作を 1 つのリクエストにグループ化します。このインデックス作成パフォーマンスの向上により、エージェントのメモリが増加し続けても更新の効率が維持されます。</p>async upsert(params: UpsertVectorParams): Promise&lt;string[]&gt; {
    const { indexName, vectors, metadata = [], ids } = params;

    try {
        // Generate unique IDs if not provided
        const vectorIds = ids || vectors.map((_, i) =&gt; 
            `vec_${Date.now()}_${i}_${Math.random().toString(36).substr(2, 9)}`
        );

        const operations = vectors.flatMap((vec, index) =&gt; [
            { index: { _index: indexName, _id: vectorIds[index] } },
            {
                vector: vec,
                metadata: metadata[index] || {},
            },
        ]);

        const response = await this.client.bulk({
            refresh: true,
            operations,
        });

        if (response.errors) {
            const erroredItems = response.items.filter((item: any) =&gt; item.index?.error);
            const erroredIds = erroredItems.map((item: any) =&gt; item.index?._id);
            const errorDetails = erroredItems.slice(0, 3).map((item: any) =&gt; ({
                id: item.index?._id,
                error: item.index?.error?.reason || item.index?.error,
                type: item.index?.error?.type
            }));
            
            const errorMessage = `Failed to upsert ${erroredIds.length}/${vectors.length} vectors`;
            console.error(`${errorMessage}. Sample errors:`, JSON.stringify(errorDetails, null, 2));
            this.logger?.error(errorMessage, { 
                failedCount: erroredIds.length, 
                totalCount: vectors.length,
                sampleErrors: errorDetails 
            });
            
            // Still return successfully inserted IDs
            const successfulIds = vectorIds.filter((id, idx) =&gt; 
                !erroredIds.includes(id)
            );
            
            if (successfulIds.length === 0) {
                throw new Error(`${errorMessage}. All operations failed. See logs for details.`);
            }
            
            return successfulIds;
        }

        this.logger?.info(`Successfully upserted ${vectors.length} vectors to "${indexName}"`);
        return vectorIds;
    } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        this.logger?.error(`Failed to upsert vectors to "${indexName}": ${errorMessage}`);
        throw new Error(`Failed to upsert vectors to "${indexName}": ${errorMessage}`);
    }
}<h3>意味的想起のための類似ベクトルのクエリ</h3><p>この機能は、セマンティック リコール機能の中核です。エージェントはベクトル検索を使用して、インデックス内に保存されている類似の埋め込みを見つけます。</p>async query(params: QueryVectorParams&lt;any&gt;): Promise&lt;QueryResult[]&gt; {
    const { indexName, queryVector, topK = 10, filter, includeVector = false } = params;

    try {
        const knnQuery: any = {
            field: 'vector',
            query_vector: queryVector,
            k: topK,
            num_candidates: Math.max(topK * 10, 100), // Search more candidates for better recall
        };

        // Apply metadata filters if provided
        if (filter) {
            knnQuery.filter = this.buildElasticFilter(filter);
        }

        const sourceFields = ['metadata'];
        if (includeVector) {
            sourceFields.push('vector');
        }

        const response = await this.client.search({
            index: indexName,
            knn: knnQuery,
            size: topK,
            _source: sourceFields,
        });

        const results = response.hits.hits.map((hit: any) =&gt; ({
            id: hit._id,
            score: hit._score || 0,
            metadata: hit._source?.metadata || {},
            vector: includeVector ? hit._source?.vector : undefined,
        }));

        this.logger?.debug(`Query returned ${results.length} results from "${indexName}"`);
        return results;
    } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        this.logger?.error(`Failed to query vectors from "${indexName}": ${errorMessage}`);
        throw new Error(`Failed to query vectors from "${indexName}": ${errorMessage}`);
    }
}<p>内部構造:</p><ul><li><p>Elasticsearch の<code>knn</code> API を使用して<a href="https://www.elastic.co/docs/solutions/search/vector/knn">kNN</a> (k 近傍法) クエリを実行します。</p></li><li><p>入力クエリ ベクトルに類似する上位 K 個のベクトルを取得します。</p></li><li><p>オプションでメタデータ フィルターを適用して結果を絞り込む (例: 特定のカテゴリまたは時間範囲内のみを検索する)</p></li><li><p>ドキュメント ID、類似度スコア、保存されたメタデータを含む構造化された結果を返します。</p></li></ul><h2>知識エージェントの作成</h2><p><code>ElasticVector</code>統合を通じて Mastra と Elasticsearch の接続を確認したので、次は Knowledge Agent 自体を作成しましょう。</p><p>フォルダー<code>agents</code>内に、 <code>knowledge-agent.ts</code>というファイルを作成します。まず、環境変数を接続し、Elasticsearch クライアントを初期化します。</p>import { Agent } from '@mastra/core/agent';
import { Memory } from '@mastra/memory';
import { openai } from '@ai-sdk/openai';
import { Client } from '@elastic/elasticsearch';
import { ElasticVector } from '../stores/elastic-store';
import dotenv from "dotenv";

dotenv.config();

const ELASTICSEARCH_ENDPOINT = process.env.ELASTICSEARCH_ENDPOINT;
const ELASTICSEARCH_API_KEY = process.env.ELASTICSEARCH_API_KEY;

//Error check for undefined credentials
if (!ELASTICSEARCH_ENDPOINT || !ELASTICSEARCH_API_KEY) {
  throw new Error('Missing Elasticsearch credentials');
}

//Check to see if a connection can be established
const testClient = new Client({
  node: ELASTICSEARCH_ENDPOINT,
  auth: { 
    apiKey: ELASTICSEARCH_API_KEY 
  },
});

try {
  await testClient.ping();
  console.log('Connected to Elasticsearch successfully');
} catch (error: unknown) {
  if (error instanceof Error) {
    console.error('Failed to connect to Elasticsearch:', error.message);
  } else {
    console.error('Failed to connect to Elasticsearch:', error);
  }
  process.exit(1);
}
//Initialize the Elasticsearch vector store
const vectorStore = new ElasticVector({
  node: ELASTICSEARCH_ENDPOINT,
  auth: {
    apiKey: ELASTICSEARCH_API_KEY,
  },
//Optional: Explicitly set to true if using Elasticsearch Serverless to skip auto-detection and improve startup time
//isServerless: true,
});<p>ここでは、次の操作を行います。</p><ul><li><p><code>dotenv</code>を使用して、 <code>.env</code>ファイルから変数を読み込みます。</p></li><li><p>Elasticsearch の資格情報が正しく挿入されているかどうかを確認し、クライアントへの接続を正常に確立できるかどうかを確認します。</p></li><li><p>Elasticsearch エンドポイントと API キーを<code>ElasticVector</code>コンストラクターに渡して、先ほど定義したベクター ストアのインスタンスを作成します。</p></li><li><p>Elasticsearch Serverless を使用している場合は、オプションで<code>isServerless: true</code>を指定します。これにより、自動検出手順がスキップされ、起動時間が短縮されます。省略した場合、アダプタは最初の使用時にデプロイメント タイプを自動的に検出します。</p></li></ul><p>次に、Mastra の<code>Agent</code>クラスを使用してエージェントを定義します。</p>export const knowledgeAgent = new Agent({
    name: 'KnowledgeAgent',
    instructions: 'You are a helpful knowledge assistant.',
    model: openai('gpt-4o'),
    memory: new Memory({

        vector: vectorStore,

        //embedder used to create embeddings for each message
        embedder: 'openai/text-embedding-3-small',

        //set semantic recall options
        options: {
            semanticRecall: {
                topK: 3, // retrieve 3 similar messages
                messageRange: 2, // include 2 messages before/after each match
                scope: 'resource',
            },
        },
    }),
});<p>定義できるフィールドは次のとおりです。</p><ul><li><p><code>name</code> そして<code>instructions</code> : アイデンティティと主な機能を与えます。</p></li><li><p><code>model</code>: <code>@ai-sdk/openai</code>パッケージを通じて OpenAI の<code>gpt-4o</code>を使用しています。</p></li><li><p><code>memory</code>:</p><ul><li><p><code>vector</code>: Elasticsearch ストアを指すので、埋め込みはそこから保存され、取得されます。</p></li><li><p><code>embedder</code>: 埋め込みを生成するためにどのモデルを使用するか</p></li><li><p><code>semanticRecall</code> オプションによってリコールの動作が決まります。</p><ul><li><p><code>topK</code>: 意味的に類似したメッセージを取得する数。</p></li><li><p><code>messageRange</code>: 各マッチにどの程度の会話を含めるか。</p></li><li><p><code>scope</code>: メモリの境界を定義します。</p></li></ul></li></ul></li></ul><p>もうすぐ終わりです。新しく作成したエージェントを Mastra 構成に追加するだけです。<a href="http://index.ts/"><code>index.ts</code></a>というファイルで、ナレッジ エージェントをインポートし、 <code>agents</code>フィールドに挿入します。</p>export const mastra = new Mastra({
  agents: { knowledgeAgent },
  storage: new LibSQLStore({
    // stores observability, scores, ... into memory storage, if it needs to persist, change to file:../mastra.db
    url: ":memory:",
  }),
  logger: new PinoLogger({
    name: 'Mastra',
    level: 'info',
  }),
  telemetry: {
    // Telemetry is deprecated and will be removed in the Nov 4th release
    enabled: false, 
  },
  observability: {
    // Enables DefaultExporter and CloudExporter for AI tracing
    default: { enabled: true }, 
  },
});<p>その他のフィールドには以下が含まれます。</p><ul><li><p><code>storage</code>: これは、実行履歴、観測性メトリック、スコア、キャッシュのための Mastra の内部データ ストアです。Mastra ストレージの詳細については、<a href="https://mastra.ai/docs/server-db/storage">こちらを</a>ご覧ください。</p></li><li><p><code>logger</code>: Mastra は、軽量の構造化 JSON ロガーである<a href="https://github.com/pinojs/pino">Pino</a>を使用します。エージェントの開始と停止、ツールの呼び出しと結果、エラー、LLM 応答時間などのイベントをキャプチャします。</p></li><li><p><code>observability</code>: エージェントの AI トレースおよび実行の可視性を制御します。追跡対象:</p><ul><li><p>各推論ステップの開始/終了。</p></li><li><p>使用されたモデルまたはツール。</p></li><li><p>入力と出力。</p></li><li><p>スコアと評価</p></li></ul></li></ul><h3>Mastra Studioでエージェントをテストする</h3><p>おめでとうございます！ここまで到達したら、このエージェントを実行し、そのセマンティックリコール能力をテストする準備が整いました。幸いなことに、Mastra には組み込みのチャット UI が用意されているため、独自に構築する必要はありません。</p><p>Mastra 開発サーバーを起動するには、ターミナルを開いて次のコマンドを実行します。</p>npm run dev<p>サーバーの初期バンドルと起動が完了すると、Playground のアドレスが提供されるはずです。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5f857fddc74ffc9/6a16f7b6a6c2b995d5e794c0/8b045f70008d26aec4d2e6b59d61085555b9c5b2-686x116.png" alt="プレイグラウンドのサーバーアドレス" /><p>このアドレスをブラウザに貼り付けると、Mastra Studio が表示されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7fdda6ce46ce068/6a16f7b7b0367d4f7672bacf/69bc80fe8486edd9e0cf91d87b39f465aeb23111-1600x438.png" alt="プレイグラウンドのアドレスを貼り付けてMastra Studioにアクセスする" /><p><code>knowledgeAgent</code>のオプションを選択してチャットを開始してください。</p><p>すべてが正しく接続されているかどうかを確認するための簡単なテストでは、次のような情報を入力します。「チームは、主にエンタープライズ契約の更新により、10 月の売上実績が 12% 増加したと発表しました。次のステップは、中規模市場の顧客へのリーチを拡大することです。」次に、新しいチャットを開始して、「次に重点を置く必要があると言った顧客セグメントはどれですか?」などの質問をします。ナレッジエージェントは、最初のチャットで提供した情報を思い出せるはずです。次のような応答が表示されます。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfec3266e81a7213b/6a16f7b92b835f6f70f4afe2/da8ebddad89874023ed440a8f1ad2cb04ed043f4-1070x288.png" alt="Mastra Studioでナレッジエージェントとチャット - エージェントは情報を思い出すことができます" /><p>このような応答が表示された場合、エージェントが以前のメッセージを Elasticsearch に埋め込みとして正常に保存し、後でベクトル検索を使用して取得したことを意味します。</p><h3>エージェントの長期記憶ストアの検査</h3><p>Mastra Studio のエージェント構成の<code>memory</code>タブに移動します。これにより、エージェントが時間の経過とともに何を学習したかを確認できます。Elasticsearch に埋め込まれて保存されるすべてのメッセージ、応答、およびやり取りは、この長期メモリの一部になります。過去のやり取りを意味的に検索して、エージェントが以前に学習した思い出の情報やコンテキストをすぐに見つけることができます。これは本質的には、エージェントがセマンティックリコール中に使用するメカニズムと同じものですが、ここではそれを直接検査できます。以下の例では、「sales」という用語を検索し、sales に関連する内容を含むすべてのインタラクションを取得しています。</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte428134d7bf2a43a/6a16f7bbb0367d185872bad3/3decaa0c332d288c5ae0b11c25f592c7d50c2f0f-1104x1320.png" alt="知識エージェントの長期記憶ストアを検査する方法" /><h2>まとめ</h2><p>Mastra と Elasticsearch を接続することで、コンテキスト エンジニアリングの重要なレイヤーであるメモリをエージェントに付与できます。セマンティックリコールを使用すると、エージェントは時間の経過とともにコンテキストを構築し、学習した内容に基づいて応答することができます。つまり、より正確で信頼性が高く、自然なやりとりが可能になります。</p><p>この早期の統合は単なる出発点にすぎません。ここで同じパターンを使用すると、過去のチケットを記憶しているサポートエージェント、関連ドキュメントを取得する内部ボット、会話の途中で顧客の詳細を思い出すことができる AI アシスタントなどが可能になります。当社は公式の Mastra 統合にも取り組んでおり、近い将来この組み合わせがさらにシームレスになる予定です。</p><p>次に何を構築するのか楽しみにしています。ぜひ試してみて、 <a href="https://mastra.ai/">Mastra</a>とそのメモリ機能を調べ、発見したことをコミュニティと自由に共有してください。</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/knowledge-agent-semantic-recall-mastra-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/knowledge-agent-semantic-recall-mastra-elasticsearch</guid>
    <category><![CDATA[エージェント型AI]]></category>
    <category><![CDATA[開発者エクスペリエンス]]></category>
    <category><![CDATA[統合]]></category>
    <dc:creator><![CDATA[JD Armada]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt09afdbff05603865/6a16f7bd839dfabbf2dcfcb5/b8d51c2726d5573385c9246a7821d12ade4f1b0e-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 06 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>