ブログ

MastraとElasticsearchを使用してエージェント型AIアプリケーションを構築する方法

MastraとElasticsearchを使用してエージェント型AIアプリケーションを構築する方法を実例を通じて学びましょう。

この記事では、Mastra TypeScriptフレームワークを使用して、Elasticsearchと連携するエージェント型アプリケーションを構築する方法をご紹介します。

最近、mastra-ai/mastraオープンソースプロジェクトに、ベクトルデータベースとしてのElasticsearchのサポートを追加しました。この新機能により、MastraでElasticsearchをネイティブに使用して埋め込みを保存できます。ベクターに加えて、Elasticsearchはコンテキストエンジニアリングの要件を満たすための高度な機能群を提供します(例:ハイブリッド検索と再ランク付け)。

この記事では、Elasticsearchを使用したRetrieval-Augmented Generation(RAG)アーキテクチャを実装するエージェントの作成について詳しく説明します。エージェント的なアプローチを使用して、Elasticsearchに保存されているSF映画データのコーパスを操作するデモプロジェクトを紹介します。このプロジェクトはelastic/mastra-elasticsearch-exampleで入手できます。

Mastra

Mastraは、エージェント型AIアプリケーションを作成するためのTypeScriptフレームワークです。

Mastraのプロジェクト構造は以下のようになります:

src/
├── mastra/
│   ├── agents/
│   │   └── weather-agent.ts
│   ├── tools/
│   │   └── weather-tool.ts
│   ├── workflows/
│   │   └── weather-workflow.ts
│   ├── scorers/
│   │   └── weather-scorer.ts
│   └── index.ts
├── .env.example
├── package.json
└── tsconfig.json

Mastraでは、エージェントツールワークフロースコアを作成できます。

エージェントは、インプットとしてメッセージを受け取り、アウトプットとして回答を生成するクラスです。エージェントは、ツール、大規模言語モデル(LLM)、およびメモリを使用できます(図1)。

Mastraでエージェントがどのように動作するかを示す図です。

図1:Mastraにおけるエージェントの動作原理を示す図。

エージェントのツールは、「外部の世界」と対話することを可能にします。たとえば、ウェブAPIと通信したり、Elasticsearchにクエリを実行するような内部操作を行ったりします。メモリコンポーネントは、過去の入力と出力を含む会話の履歴を格納するために非常に重要です。この格納されたコンテキストにより、エージェントは過去の対話を活用して、将来の質問に対してより情報に基づいた関連性の高い回答を提供できます。

ワークフローを使用すると、単一のエージェントの推論に頼るのではなく、明確で構造化されたステップを使用して複雑なタスクのシーケンスを定義できます(図2)。タスクをどのように分割し、データをどのように移動させ、何をいつ実行するかを網羅的に制御できます。ワークフローは、デフォルトで組み込みの実行エンジンを使用して実行されますが、ワークフローランナーにデプロイすることもできます。

Mastraのワークフローの例。

図2:Mastraにおけるワークフローの例。

Mastraでは、スコアを定義することもできます。スコアは、モデル評価、ルールベース、統計的な方法を用いてエージェントの出力を評価する自動テストです。スコアラーはスコアを返します。これは、出力が評価基準をどれだけ満たしているかを定量化する数値(通常0から1の間)です。これらのスコアにより、パフォーマンスを客観的に追跡し、さまざまなアプローチを比較し、AIシステムの改善すべき分野を特定することができます。スコアラーは、独自のプロンプトやスコアリング関数でカスタマイズできます。

Elasticsearch

デモプロジェクトを実行するには、Elasticsearchインスタンスを実行する必要があります。Elastic Cloudで無料トライアルを有効化するか、start-localスクリプトを使ってローカルにインストールできます。

curl -fsSL https://elastic.co/start-local | sh

これにより、ElasticsearchとKibanaがコンピュータにインストールされ、Mastraインテグレーションの設定に使用するAPIキーが生成されます。

APIキーは前のコマンドの出力として表示され、elastic-start-localフォルダー内の.envファイルに保存されます。

デモをインストールして設定

デモプロジェクトのソースコードを含む elastic/mastra-elasticsearch-example リポジトリを作成しました。リポジトリに記載されている例は、Elasticsearchからドキュメントを取得するためのRAGアーキテクチャを実装したエージェントをMastraで作成する方法を示しています。

SF映画のデモ用データセットを提供しました。Kaggle上のIMDbデータセットから500本の映画を抽出しました。

最初のステップは、次のコマンドを使用してnpmでプロジェクトの依存関係をインストールします:

npm install

次に、設定内容を格納する.envファイルを構成する必要があります。以下のコマンドを使用して、 .env.exampleファイルの構造をコピーすることで、このファイルを生成できます。

cp .env.example .env

これで、.envを編集できるようになりました。不足している情報を追加します:

OPENAI_API_KEY=
ELASTICSEARCH_URL=
ELASTICSEARCH_API_KEY=
ELASTICSEARCH_INDEX_NAME=scifi-movies

Elasticsearchインデックスの名称は scifi-moviesです。必要であれば、環境変数 ELASTICSEARCH_INDEX_NAMEを使って変更できます。

OpenAIを埋め込みサービスとして使用しました。これは、OPENAI_API_KEY環境変数にOpenAIのAPIキーを提供する必要があることを意味します。

例で使用されている埋め込みモデルは openai/text-embedding-3-small であり、埋め込み次元は1,536です。

最終的な答えを導き出すために、openai/gpt-5-nano モデルを使用してコストを削減しました。

RAGアーキテクチャでは、回答の妥当性を検証するという重労働は検索コンポーネント(この場合は Elasticsearch)が行うため、それほど強力ではない(そして一般的に安価な)最終的なLLMモデルを使用することができます。

小規模なLLMは主に2つのタスクを担当します:

  • クエリの言い換え/埋め込み:ユーザーの自然言語の質問をセマンティック検索用のベクトル埋め込みに変換します。

  • 回答の合成:取得された関連性の高いコンテキストの断片(文書/動画)を取り出し、提示された指示に従って、首尾一貫した最終的な人間が読める回答に合成します。

RAGプロセスは回答に必要とされる正確な事実的文脈を提供するため、最終的なLLMは大規模または高度に複雑である必要はなく、必要な知識をすべて自らのパラメータ内に持つ必要もありません(それは大規模で高価なモデルが優れている領域です)。本質的には、本格的なナレッジベースとしてではなく、Elasticsearchが提供するコンテキストの洗練されたテキストサマライザーおよびフォーマッターとして機能します。これにより、コストやレイテンシーの最適化にgpt-5-nanoのようなモデルを活用できます。

.envファイルの設定後、次のコマンドで映画をElasticsearchに取り込むことができます。

npx tsx src/utility/store.ts

次のような出力が表示されるはずです。

🚀 Starting ingestion of 500 movies from 500_scifi_movies.jsonl...
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 1/500 (0%) | ok:1 | fail:0 | chunks:1 | eta:19m 33s | current:Capricorn One
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 2/500 (0%) | ok:2 | fail:0 | chunks:2 | eta:10m 32s | current:Doghouse
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 3/500 (1%) | ok:3 | fail:0 | chunks:3 | eta:7m 33s | current:Dinocroc
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 4/500 (1%) | ok:4 | fail:0 | chunks:7 | eta:6m 10s | current:Back to the Future           
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 5/500 (1%) | ok:5 | fail:0 | chunks:9 | eta:5m 14s | current:The Projected Man            
Ingesting ░░░░░░░░░░░░░░░░░░░░░░░░ 6/500 (1%) | ok:6 | fail:0 | chunks:11 | eta:4m 41s | current:I, Robot
...
✅ Ingestion complete in 1m 46s. Success: 500, Failed: 0, Chunks: 693.

scifi-moviesインデックスのマッピングには、次のフィールドが含まれています。

  • 埋め込み、1536次元のdense_vector、コサイン類似度。

  • 説明、映画の説明を含むテキスト。

  • 監督、監督の名前を含むテキスト。

  • タイトル、映画のタイトルを含むテキスト。

タイトルとディスクリプションを使用して埋め込みを生成しました。タイトルとディスクリプションは2つの別個のフィールドであるため、両者を連結することで、結果として得られる埋め込みベクトルが、映画の具体的で独自の特徴(タイトル)と豊かな説明的コンテキスト(内容説明)の両方を捉えることができます。これにより、より正確で包括的なセマンティック検索結果が得られます。この結合されたインプットにより、埋め込みモデルは類似度マッチングに向けて、ドキュメントのコンテンツをより適切に単一のベクトル表現として捉えることができます。

デモを実行

次のコマンドでデモを実行できます:

npm run dev

このコマンドを実行するとlocalhost:4111でWebアプリケーションが起動し、Mastra Studioにアクセスできるようになります(図3)。

Elasticsearch Agentの例を使用したMastra Studioのスクリーンショット。

図3:Elasticsearch Agentの例を含むMastra Studioのスクリーンショット。

Mastra Studio はエージェントの構築とテストのためのインタラクティブなUIを提供し、さらにMastraアプリケーションをローカルサービスとして公開するREST APIも備えています。これにより、統合を気にせずにすぐに構築を始められます。

Elasticsearchを使ったセマンティック検索を実行するツールとして、MastraのcreateVectorQueryToolを使ったElasticsearch Agentを提供しました。このエージェントは、RAGアプローチを使用して関連文書(つまり映画)を検索し、ユーザーの質問に答えます。

このエージェントは以下のプロンプトを使用します:

You are a helpful assistant that answers questions based on the provided context.
Follow these steps for each response:

1. First, carefully analyze the retrieved context chunks and identify key information.
2. Break down your thinking process about how the retrieved information relates to the query.
3. Draw conclusions based only on the evidence in the retrieved context.
4. If the retrieved chunks don't contain enough information, explicitly state what's missing.

Format your response as:
THOUGHT PROCESS:
- Step 1: [Initial analysis of retrieved chunks]
- Step 2: [Reasoning based on chunks]

FINAL ANSWER:
[Your concise answer based on the retrieved context]

Important: When asked to answer a question, please base your answer only on the context provided in the tool. 
If the context doesn't contain enough information to fully answer the question, please state that explicitly and stop it.
Do not add more information than what is present in the retrieved chunks.
Remember: Explain how you're using the retrieved information to reach your conclusions.

Mastra Studio > AgentsメニューをクリックしてElasticsearch Agentを選択すると、チャットシステムを使用してエージェントをテストできます。たとえば、SF映画に関する情報を次のような質問で尋ねることができます。

UFOを題材にした映画またはテレビシリーズを5つ見つけてください

エージェントがvectorQueryToolを実行することがわかります。起動したツールをクリックすると、入力と出力を確認できます。実行の最後に、LLMはElasticsearchのscifi-moviesインデックスから得られたコンテキストに基づいて、あなたの質問に回答します(図4)。

 Elasticsearch Agentを使用したLLMからの対応。

図4:Elasticsearch Agentを使用したLLMからの対応。

Mastraは内部で以下の手順を実行します:

  1. ベクトル変換:ユーザーの質問「UFOに関する映画やテレビシリーズを5つ探して」は、OpenAIのopenai/text-embedding-3-smallモデルを使ってベクトル埋め込みに変換されます。

  2. ベクトル検索:この埋め込みはその後、Elasticsearchに対してベクトル検索を用いてクエリを実行するために使用されます。

  3. 結果の取得:Elasticsearchは、クエリに非常に関連性の高い10本の映画(つまり、ユーザーのクエリベクトルに最も近いベクトルを持つ映画)を返します。

  4. 回答生成:取得された映画と元のユーザーの質問は、具体的にはopenai/gpt-5-nano LLM に送信されます。LLMはこの情報を処理し、最終的な回答を生成することで、ユーザーの5つの結果への要望を確実に満たします。

Elasticsearch エージェント

ここではElasticsearch Agentのソースコードを報告しました。

import { Agent } from "@mastra/core/agent";
import { ElasticSearchVector } from '@mastra/elasticsearch';
import { createVectorQueryTool } from '@mastra/rag';
import { ModelRouterEmbeddingModel } from "@mastra/core/llm";
import { Memory } from "@mastra/memory";

const es_url = process.env.ELASTICSEARCH_URL;
const es_apikey = process.env.ELASTICSEARCH_API_KEY;
const es_index_name = process.env.ELASTICSEARCH_INDEX_NAME;
const prompt = 'insert here the previous prompt';

const esVector = new ElasticSearchVector({
  id: 'elasticsearch-vector',
  url: es_url,
  auth: {
    apiKey : es_apikey
  }
});

const vectorQueryTool = createVectorQueryTool({
  vectorStore: esVector,
  indexName: es_index_name,
  model: new ModelRouterEmbeddingModel("openai/text-embedding-3-small")
});

export const elasticsearchAgent = new Agent({
  id: "elasticsearch-agent",
  name: "Elasticsearch Agent",
  instructions: prompt,
  model: 'openai/gpt-5-nano',
  tools: { vectorQueryTool },
  memory: new Memory(),
});

vectorQueryToolは、RAGの例における取得部分を実装するために呼び出されるツールです。MastraにElasticが提供したElasticSearchVector実装を使用しています。

エージェントは、vectorQueryTool、プロンプト、およびメモリを消費するエージェントクラスのオブジェクトです。ご覧のように、Elasticsearchをエージェントに接続するために必要なコードはごくわずかです。

まとめ

この記事では、ElasticsearchとMastraフレームワークを統合し、洗練されたエージェント型AIアプリケーションを構築することのシンプルさとパワーについて実証しました。具体的には、Elasticsearchでインデックス化されたSF映画データのコーパスに対してセマンティック検索を実行できるRAGエージェントの作成について説明しました。

重要なポイントは、ElasticがMastraのオープンソースプロジェクトに直接貢献し、ベクターストアとしてのElasticsearchをネイティブサポートしていることです。この統合により、導入時の障壁が大幅に低下します。これは、 Elasticsearch Agentのソースコードを見れば明らかです。ElasticSearchVectorcreateVectorQueryToolを使用することで、Elasticsearchをエージェントに接続するための総合的なセットアップが、最小限の設定コード行数で済みます。

Elasticsearchは、結果の関連性を高めるためのいくつかの高度な機能を提供しています。例として、ハイブリッド検索は、語彙検索とベクトル検索を組み合わせることで、精度を大幅に向上させます。もう一つの興味深い機能は、ハイブリッド検索の最後に適用できる最新のJinaモデルを使用した再ランク付けです。これらの技術についてさらに詳しく知るには、Elasticsearch Labsの以下の記事を参照してください。

また、提供されている例を参考に、MastraとElasticsearchを使って独自のデータ駆動型エージェントを構築し始めることをお勧めします。Mastraについての詳細は、 こちらのオフィシャルドキュメントをご覧ください。

関連記事

チャットボックスを超えたエージェントビルダー:Augmented Infrastructureの導入

Alexander Wert

Elasticsearchによるエージェントメモリの管理

Someshwaran Mohankumar

Elasticsearch Inference APIとHugging Faceモデルを組み合わせて使用

Jeffrey Rengifo

Elastic Agent Builder と GPT-OSS を使用した HR 向け AI エージェントの構築

Tomás Murúa

TypeScriptを使用したElasticsearch MCPサーバーの作成

Jeffrey Rengifo

最先端の検索体験を構築する準備はできましたか?

十分に高度な検索は 1 人の努力だけでは実現できません。Elasticsearch は、データ サイエンティスト、ML オペレーター、エンジニアなど、あなたと同じように検索に情熱を傾ける多くの人々によって支えられています。ぜひつながり、協力して、希望する結果が得られる魔法の検索エクスペリエンスを構築しましょう。

はじめましょう