メインコンテンツへ移動

検索とインデックス作成

追加バージョン: @mastra/core@1.1.0

検索を使用すると、Agent はインデックス化された Workspace ファイルから関連するコンテンツを見つけられます。Agent が質問に回答したり情報を探したりする必要がある場合、すべてのファイルを読み込む代わりに、インデックス化されたコンテンツを検索できます。

仕組み
仕組みへの直接リンク

Workspace の検索には、インデックス作成とクエリの2つのフェーズがあります。

インデックス作成
インデックス作成への直接リンク

コンテンツを検索するには、事前にインデックスを作成する必要があります。ドキュメントのインデックスを作成すると、次の処理が行われます。

  • コンテンツがトークン化されます(検索可能な語に分割されます)
  • BM25 の場合: 単語の出現頻度とドキュメントの統計情報が計算されます
  • ベクトルの場合: embedder 関数を使用してコンテンツが埋め込みに変換され、ベクトルストアに保存されます

インデックス化された各ドキュメントには、次の情報が含まれます。

  • id - 一意の識別子(通常はファイルパス)
  • content - テキストコンテンツ
  • metadata - ドキュメントとともに保存される任意のキーと値のデータ

クエリ
クエリへの直接リンク

検索時には、次の処理が行われます。

  1. インデックス作成時と同じトークン化または埋め込みを使用して、クエリが処理されます
  2. クエリとの関連性に基づいてドキュメントにスコアが付けられます
  3. 結果がスコア順に並べられ、一致したコンテンツとともに返されます

Workspace は、BM25 キーワード検索、ベクトルセマンティック検索、およびその両方を組み合わせたハイブリッド検索という3つの検索モードをサポートします。

BM25 は、単語の出現頻度とドキュメントの長さに基づいてドキュメントをスコアリングします。完全一致や特定の専門用語の検索に適しています。

src/mastra/workspaces.ts
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'

const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
})

BM25 のパラメーターをカスタマイズする場合(k1 は単語頻度の飽和度、b はドキュメント長の正規化を表します)は、次のように設定します。

src/mastra/workspaces.ts
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: {
k1: 1.5,
b: 0.75,
},
})

ベクトル検索では、埋め込みを使用して意味的に類似するコンテンツを検索します。ベクトルストアと embedder 関数が必要です。

src/mastra/workspaces.ts
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'
import { PineconeVector } from '@mastra/pinecone'
import { embed } from 'ai'
import { openai } from '@ai-sdk/openai'

const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
vectorStore: new PineconeVector({
apiKey: process.env.PINECONE_API_KEY,
index: 'workspace-index',
}),
embedder: async (text: string) => {
const { embedding } = await embed({
model: openai.embedding('text-embedding-3-small'),
value: text,
})
return embedding
},
})

バッチ埋め込み
バッチ埋め込みへの直接リンク

上記の embedder は、一度に1つのテキストを受け取ります。数百のファイルを含む Workspace のインデックスを作成すると Provider が数百回呼び出されるため、時間とコストがかかります。

Provider がバッチ処理をサポートしている場合(OpenAI の embedMany など)は、テキストの配列を受け取り、1回の呼び出しで複数の埋め込みを返す embedder を渡します。この機能を有効にするには、関数に batch: true プロパティを設定します。Mastra は実行時にこのプロパティを確認し、バッチ処理に切り替えます。

次の例では、単一テキスト用の embedder をバッチ対応のものに置き換えています。embedder 関数は配列を受け取り、同じ順序で埋め込みの配列を返します。また、次の2つの追加プロパティを持ちます。

  • batch: true: 関数がバッチ対応であることを示します。このプロパティがない場合、Mastra は一度に1つのテキストを渡して関数を呼び出します。
  • maxBatchSize: Provider が1回の呼び出しで受け付ける最大の配列サイズです。Mastra は、それより大きなリクエストをこのサイズのチャンクに分割して並列送信します。Provider のドキュメントに記載された上限(OpenAI は 2048、Cohere は 96、Voyage は 128 など)を設定してください。保留中のすべてのテキストを1つのリクエストで送信する場合は省略します。
src/mastra/workspaces.ts
import { Workspace, LocalFilesystem } from '@mastra/core/workspace'
import { PineconeVector } from '@mastra/pinecone'
import { embedMany } from 'ai'
import { openai } from '@ai-sdk/openai'

const model = openai.embedding('text-embedding-3-small')

const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
vectorStore: new PineconeVector({
apiKey: process.env.PINECONE_API_KEY,
index: 'workspace-index',
}),
embedder: Object.assign(
async (texts: string[]) => {
const { embeddings } = await embedMany({ model, values: texts })
return embeddings
},
{ batch: true as const, maxBatchSize: 2048 },
),
})

Object.assign は、embedder 関数に batch プロパティと maxBatchSize プロパティを追加します。Mastra はこれらをメタデータとして読み取り、Provider に渡すことはありません。

単一テキスト用の embedder も引き続き使用できます。関数シグネチャ (text: string) => Promise<number[]> は変わらないため、既存のコードは変更せずに動作し続けます。

BM25 検索とベクトル検索の両方を設定すると、キーワード一致と意味理解を組み合わせたハイブリッドモードが有効になります。

src/mastra/workspaces.ts
const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
vectorStore: pineconeVector,
embedder: embedderFn,
})

カスタムインデックス名
カスタムインデックス名への直接リンク

デフォルトでは、検索インデックス名は Workspace ID から生成されます。カスタム名を設定するには、searchIndexName を使用します。

const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
searchIndexName: 'my_workspace_vectors',
})

インデックス名は有効な SQL 識別子でなければなりません。先頭は文字またはアンダースコアにし、使用できるのは文字、数字、またはアンダースコアのみで、長さは最大63文字です。

コンテンツのインデックス作成
コンテンツのインデックス作成への直接リンク

手動でのインデックス作成
手動でのインデックス作成への直接リンク

workspace.index() を使用すると、プログラムから検索インデックスにコンテンツを追加できます。ファイルパスがドキュメント ID になります。ドキュメントごとにメタデータを渡すこともできます。

// Basic indexing
await workspace.index('/docs/guide.md', 'Content of the guide...')

// Index with metadata for filtering or context
await workspace.index('/docs/api.md', apiDocContent, {
metadata: {
category: 'api',
version: '2.0',
},
})

手動でのインデックス作成は、次の場合に便利です。

  • ファイル以外のコンテンツ(データベースのレコードや API レスポンスなど)のインデックスを作成する場合
  • インデックスを作成する前にコンテンツを前処理またはチャンク分割する場合
  • ドキュメントにカスタムメタデータを追加する必要がある場合

自動インデックス作成
自動インデックス作成への直接リンク

autoIndexPaths を設定すると、Workspace の初期化時にファイルのインデックスが自動的に作成されます。各エントリには、ディレクトリパス(再帰的にインデックスを作成)または対象を選択するための glob パターンを指定できます。

const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
autoIndexPaths: ['docs', 'support/faq'],
})

await workspace.init()

init() が呼び出されると、一致するすべてのファイルが読み込まれ、検索用のインデックスが作成されます。ファイルパスがドキュメント ID になります。

glob パターンを使用すると、特定のファイル形式を対象にインデックスを作成できます。

const workspace = new Workspace({
filesystem: new LocalFilesystem({ basePath: './workspace' }),
bm25: true,
autoIndexPaths: ['docs/**/*.md', 'support/**/*.txt'],
})

検索
検索への直接リンク

workspace.search() を使用して関連するコンテンツを検索します。結果は関連性スコアの順に並べられます。

const results = await workspace.search('password reset')

for (const result of results) {
console.log(`${result.id}: ${result.score}`)
console.log(result.content)
}

検索オプション
検索オプションへの直接リンク

オプションを使用して検索動作をカスタマイズできます。

const results = await workspace.search('authentication flow', {
topK: 10,
mode: 'hybrid',
minScore: 0.5,
vectorWeight: 0.5,
})
オプション説明
topK返す結果の最大数。デフォルト: 5
mode検索モード: 'bm25''vector'、または 'hybrid'。デフォルトでは、設定に基づいて利用可能な最適なモードが選択されます。
minScoreこのスコアしきい値(0〜1)を下回る結果を除外します。
vectorWeightハイブリッドモードで、BM25 スコアに対してベクトルスコアをどの程度重視するかを指定します。0 = すべて BM25、1 = すべてベクトル、0.5 = 同じ重み。

検索結果
検索結果への直接リンク

各結果には、次の情報が含まれます。

interface SearchResult {
id: string // Document ID (typically file path)
content: string // The matching content
score: number // Relevance score (0-1)
lineRange?: {
// Lines where the match was found
start: number
end: number
}
metadata?: Record<string, unknown> // Metadata stored with the document
scoreDetails?: {
// Score breakdown (hybrid mode only)
vector?: number
bm25?: number
}
}

スコアの見方:

  • スコアの範囲は0〜1で、1は完全一致を表します
  • BM25 スコアは、結果セット内の最も一致度が高い結果を基準に正規化されます
  • ベクトルスコアは、クエリの埋め込みとドキュメントの埋め込み間のコサイン類似度を表します
  • ハイブリッドモードでは、vectorWeight パラメーターを使用してスコアが組み合わされます

各モードを使用する場面
各モードを使用する場面への直接リンク

モード適した用途クエリ例
bm25完全一致、技術的なクエリ、コード"useState フック"、"404 エラー"、"config.yaml"
vector概念的なクエリ、自然言語"ユーザー認証を処理する方法"、"エラー処理のベストプラクティス"
hybrid一般的な検索、種類が不明なクエリAgent のほとんどのユースケース

Agent Tool
Agent Toolへの直接リンク

Workspace に検索を設定すると、Agent はコンテンツの検索とインデックス作成に使用する Tool を受け取ります。詳しくは Workspace クラスのリファレンスを参照してください。