Introduction to @mastra/s3vectors

こんにちは、@vvvatanabe です。業務で Mastra を使用してAIエージェントを開発をしながら、Mastra へコントリビュートしています。最近の趣味です。

Mastra は TypeScript 製の AI エージェントフレームワークです。ワークフロー、メモリ、RAG、ツール実行、デプロイを統一 APIで扱えます。ベクターストアは抽象クラス MastraVector に準拠していれば、簡単に差し替えられます。

https://mastra.ai/

RAG を運用するにあたって、スケールしてもコストや運用負荷が跳ね上がらないベクターストアがあるとうれしいです。プレビュー版として公開されている Amazon S3 Vectors は、その要件を満たしうる有力な候補として注目されています。

Amazon S3 Vectors ユーザーガイド

Mastra と S3 Vectors を組み合わせることで、AI エージェントや RAG を手早く構築しつつ、開発・運用コストも抑えやすくなります。そこで今回、Mastra のベクターストアとして使えるよう、抽象クラス MastraVector に準拠した @mastra/s3vectors を実装しました。プルリクエストは Mastra 本体に提出し、先日マージされています。

PR: “feat: add s3vectors vector store adapter” (mastra-ai/mastra #6801)

既に npm へアルファリリース済みです。

@mastra/s3vectors パッケージ(npm)

本記事では、この @mastra/s3vectors の実装で得た知見をもとに、設計上の判断・使い方・注意点を整理してご紹介します。なお、S3 Vectors はプレビュー段階のため、まだ本番導入には至っていませんが、現時点の検証結果を共有します。

※ Amazon S3 Vectors は Preview です。挙動や制限は今後変更される可能性があります(@mastra/s3vectors の README にも記載があります)。本記事の内容は執筆時点の仕様に基づいています。

Quickstart — セットアップと動作コードの例

インストール方法や概要は、まずこちらの公式ドキュメントをご覧ください。

Amazon S3 Vectors ストア

リージョンと認証情報の設定

アプリに組み込むときのリージョンと認証情報は、環境変数で設定できます。

  • AWS_REGION:S3 Vectors を置く AWS リージョン。
  • AWS 認証情報:標準の AWS SDK プロバイダチェーン(AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_PROFILE など)をそのまま使えます。

セマンティックリコール(Agent Memory)

エージェントが過去の会話を意味検索で思い出せるようにする「セマンティックリコール」に、S3 Vectors を使うときの例です。

import { openai } from '@ai-sdk/openai';
import { Agent } from '@mastra/core/agent';
import { Memory } from '@mastra/memory';
import { S3Vectors } from '@mastra/s3vectors';

export const s3vectorsAgent = new Agent({
  name: 's3vectors-agent',
  instructions: `You are a helpful support agent.`,
  model: openai('gpt-4o-mini'),
  // セマンティックリコール(会話メモリ)設定
  memory: new Memory({
    vector: new S3Vectors({
      // メモリ専用のベクトルバケット
      vectorBucketName: 'my-semantic-recall-bucket',
    }),
    embedder: openai.embedding('text-embedding-3-small'),
    options: {
      semanticRecall: {
        // 類似メッセージを3件取得
        topK: 3,
        // 各ヒットの前後2件のメッセージも含める
        messageRange: 2,
        // 同一 resourceId に紐づく全スレッドを横断
        scope: 'resource',
      },
    },
  }),
});

RAG 検索ツール(createVectorQueryTool)

エージェントが必要に応じて ベクター検索ツール を function calling で呼び出し、外部知識(ドキュメント)を取りに行くときの例です。

Agent.stream() / Agent.generate() の実行中に、モデルが自動でツールを選びます。

import { openai } from '@ai-sdk/openai';
import { Agent } from '@mastra/core/agent';
import { S3Vectors } from '@mastra/s3vectors';
import { createVectorQueryTool } from '@mastra/rag';

export const s3vectorsAgentWithRag = new Agent({
  name: 's3vectors-agent',
  instructions: `You are a helpful support agent.`,
  model: openai('gpt-4o-mini'),

  // RAG 検索ツールを登録(S3 Vectors を vectorStore に指定)
  tools: {
    vectorQueryTool: createVectorQueryTool({
      vectorStore: new S3Vectors({
        // RAG 専用のベクトルバケット
        vectorBucketName: 'my-vector-query-bucket',
      }),
      indexName: 'my-vector-query-bucket-index',
      // 検索クエリの埋め込みモデル
      model: openai.embedding('text-embedding-3-small'),
      // LLM が S3 Vectors のサブセットでフィルタを組み立て可能
      enableFilter: true,
    }),
  },
});

実装の全体像 — MastraVector と S3 Vectors のつなぎ込み

アーキテクチャと責務(SDKラッパー/例外統一/フィルタ変換)

今回追加した @mastra/s3vectorsS3Vectors クラスは、AWS SDK v3(@aws-sdk/client-s3vectors)の薄いラッパーとして動作し、Mastra の抽象クラス MastraVector に沿って、インデックス(作成・削除・一覧・属性取得)とベクター(put・query・get・delete)を扱います。

永続接続は不要です。connect は No-op、disconnect は必要に応じてソケット解放のために呼べます。

API 呼び出し時はインデックス名を _ から – に置き換えて小文字化し、外部の例外は MastraError にラップして一貫したエラー情報を返します。

S3VectorsFilterTranslator は、Mastra 側の高レベルフィルタを S3 Vectors 仕様へ変換し、暗黙の AND を明示化しながら型・演算子の妥当性をチェックします。あわせて S3VECTORS_PROMPT を LLM のシステムプロンプトとして使うと、クエリ生成時にサポート外の演算子を避けるよう促せます。

距離メトリックとスコア変換(cosine / euclidean、dotproduct は未対応)

対応する距離メトリックは cosineeuclidean です。呼び出し側で dotproduct を指定した場合は、変換時に無効として即時にエラーを返します。describeIndex().metric の型には dotproduct が含まれますが、S3 側からは返りません(cosine / euclidean のみ)。

この前提のもと、距離は score = 1 / (1 + distance) に単調変換し、Mastra 全体の仕様「スコアが大きいほど類似している」という解釈をそろえています。

インデックス名の正規化と衝突時の扱い(正規化・スキーマ検証)

My_Index のような名前を受け取った場合、実行前に my-index へ正規化してから S3 Vectors の API を呼びます。既に同名のインデックスがある場合はスキーマを照合し、次元数(dimension)が一致していれば作成は no-op として通します。距離メトリックが異なる場合は既存値を維持しつつ警告をログに残し、次元数が一致しない場合はエラーとして明確に失敗させます。

正規化は createIndex に限らず、すべての API 呼び出し前に行います。インデックス名が文字列でない場合は TypeError を投げます。

非フィルタブルメタデータ設計(nonFilterableMetadataKeys)

nonFilterableMetadataKeys をインデックス作成時に指定すると、該当キーは保存しつつフィルタの対象から外せます。長文や大きな本文フィールドを除外しておくと、検索時の評価負荷やコストを抑えやすくなります。なお、この設定は作成後に変更できないため、導入時にあらかじめ決めておくことをおすすめします。

メタデータフィルタのサブセット設計 — 正規化とバリデーション

S3 Vectors が受け付ける演算子に絞り、与えられたフィルタを安全に変換・検証します。変換では暗黙の AND を明示化し、値の型や演算子の位置をチェックします。

対応/未対応演算子の定義

許可する演算子は次のとおりです。

  • 基本比較$eq, $ne を受け付けます。等価比較では文字列・数値・真偽値のみを扱います。
  • 数値比較$gt, $gte, $lt, $lte を受け付けます。値は数値が前提で、Date が来た場合はエポックミリ秒に変換して評価します。
  • 配列比較$in, $nin を受け付けます。空配列は不可で、配列要素はプリミティブ(文字列・数値・真偽値)に限定します。
  • 存在チェック$exists を受け付け、真偽値のみ許可します。
  • 論理演算$and, $or を受け付け、いずれも非空配列で、配列要素はフィールド条件で構成されている必要があります。

一方で、$not, $nor, $regex, $all, $elemMatch, $size, $text などは未対応のためエラーにします。

undefinednull・空オブジェクト {} は 「フィルタなし」として扱います。

暗黙 AND の正規化とトップレベル制約

次のように複数のフィールド条件が並ぶ形は正規化して送信します。

Before: { a: 1, b: 2 } 
After: { $and: [{ a: 1 }, { b: 2 }] } 

この暗黙 AND の正規化は $or の配列要素内部でも適用されます。

Before. { $or: [ {a:1,b:2}, {...} ] }
After: { $or: [ { $and:[{a:1},{b:2}] }, ... ] }

トップレベルでは論理演算子のみを受け付けるため、{ $gt: 1 } のような比較演算子の直置きはエラーとします。

また、$and$or の配列要素にはフィールド条件のみを許可し、直オペレータ要素の { $and: [{ $gt: 1 }] }  は受け付けません。

次の論理演算子をフィールド値の中に入れ子にする形もエラーの扱いです。

例:{ field: { $and: [...] } }

型ガード(等価はプリミティブ限定、Date→epoch ms)

field: ['a','b'] のような配列等価はエラーになります。$in / $nin の利用を想定しています。

等価比較(field: valuefield: { $eq: value })では Date・オブジェクト・配列は受け付けません。Date は、比較や配列演算の文脈でのみエポックミリ秒へ変換して評価します。これにより、クエリ実行時の型揺れを防ぎ、S3 Vectors の仕様に沿った安定した検索を行えます。

読み書きAPIの最適化 — 整合性・クエリ設計・includeVector

upsert/update の要点(次元確認・全置換モデル)

upsert では、はじめにインデックスの次元数(dimension)を取得し、投入する各ベクトルの長さが一致しているかを確認します。メタデータに Date が含まれる場合は、送信前にエポックミリ秒へ変換してから書き込みます。
updateVector は S3 Vectors の「全置換」仕様に合わせ、Get → merge → Put の順で更新して欠損を避けます。update.vectorupdate.metadata のどちらも未指定なら更新内容がないため、No updates provided を返してエラーにします。

クエリ設計(topK / 距離→スコア)

query では、queryVector が空でない float32 配列であること、topK が正の整数であることをチェックします。

返却時は距離を score = 1 / (1 + distance) に単調変換し、「スコアが大きいほど類似」が一貫するようにします。

メタデータフィルタは前章のトランスレータで S3 Vectors のサブセットへ変換し、未対応演算子や不正な形は早めにエラーにします。

注意事項:

  • topK は 30 以下にしてください(S3 Vectors の制限に沿うため)。
  • query の結果にある document フィールドは S3 Vectors では返りません。本文はメタデータの非フィルタブルキーで扱う運用が無難です。

includeVector 時の 2段階取得(帯域の最適化)

デフォルトは includeVector: false です。true のときだけ、ベクトルが欠けている結果の ID に対して 2段目の GetVectors を発行し、不足分だけを補います。
QueryVectors は距離とメタデータ中心の応答なので、常に全候補のベクトル本体を返す方式に比べ、転送量を抑えやすく、帯域コストとレイテンシの両方を改善できます。

includeVector は基本は false のままを推奨します。サーバ側での再ランキング・検証に限って true を使い、クライアントには返さない方針が安全です。

describeIndex.count は O(n)

describeIndex().count は内部で ListVectors をページングして合算するため、計算量は O(n) です。実運用では多用せず、別途カウントを保持したりバッチで定期集計したりして監視してください。最新値が必要な場面に絞って呼び出すことで、負荷とコストの増加を抑えられます。

導入ガイド — エラー対応・チェックリスト

MastraError の扱い

主要な API(createIndex / upsert / query / updateVector / deleteVector / describeIndex / listIndexes)で発生した AWS 由来の例外は、MastraError にラップして返します。domain / category / details をそろえて付与できるため、ログ基盤や APM で原因を追いやすくなります。たとえば、インデックス作成時のサードパーティ障害は STORAGE_S3VECTORS_VECTOR_CREATE_INDEX_FAILED(Third-Party)、無効な引数は STORAGE_S3VECTORS_VECTOR_CREATE_INDEX_INVALID_ARGS(User)として扱います。以降の処理では、このメタ情報を基に、リトライ可否やユーザー通知の方針を判断できます。

導入チェックリスト

導入前に、次を順にチェックしてください。

  • アカウント & 権限
    • リージョン/認証:AWS_REGION と認証(標準プロバイダチェーン)を設定
    • IAM/SCP:s3vectors 名前空間の操作を最小権限で許可
  • インデックス設計(名前・次元・メトリクス)
    • インデックス名:My_Indexmy-index
    • メトリクス:cosineeuclidean のみを使用(dotproduct は無効化)
    • 次元数:インデックス次元 = 埋め込みモデル次元
  • メタデータ & フィルタ設計
    • 非フィルタブルキー:nonFilterableMetadataKeys を導入時に確定(後変更不可)、重い本文は非フィルタブルへ
    • フィルタ変換のサブセット:許可演算子($eq/$ne/$gt/$gte/$lt/$lte/$in/$nin/$exists/$and/$or)のみ
    • LLM ガード:S3VECTORS_PROMPT をシステムプロンプトへ注入
  • クエリ設計
    • topK 制限:topK ≤ 30
    • includeVector:既定は false、再ランク/検証時のみ true 
  • 互換性・プレビュー対策
    • Preview前提の変更に備え、ライブラリ更新を自動テストで継続検証し、互換性が崩れた場合に検知

LLM ガードレール(フィルタ制約用プロンプト)

S3VECTORS_PROMPT をそのままシステムプロンプト等に流し込み、サポート外演算子を使わせない運用ができます。

import { S3VECTORS_PROMPT } from '@mastra/s3vectors';

// 例:LLMに渡す前のテンプレート整形
const systemPrompt = `
You are a helpful assistant.
${S3VECTORS_PROMPT}
`;

まとめ — Mastra × S3 Vectors で“手堅く・軽く”始めるRAG

本記事では、Mastra の MastraVector 抽象クラスに準拠した @mastra/s3vectors を紹介し、S3 Vectors の特性(S3 相当の耐久性/サブ秒検索/JSON フィルタ)を活かして コスト最適な RAG とセマンティックリコールを組み立てる方法、Quickstart のコードから、アダプタの設計(インデックス名の正規化、距離メトリック、フィルタ翻訳、MastraError による例外整理)、クエリ設計(topK とスコア変換)、そして導入時のチェックポイントまでを一通り解説しています。

ぜひ Mastra と @mastra/s3vectors を試してみてください。 既存Mastra製エージェントにも無理なく差し込めるので、プロトタイプから本番寄りの検証までスムーズに進められます。

なお、Amazon S3 Vectors は現在 Preview です。仕様や制限は変わる可能性がありますが、GA に向けた進化に期待しています。本アダプタも随時追従するプルリクエストを送るつもりです。あわせて、コストと運用負荷を抑えた AI エージェント/RAG の実現に向けて、今後もドキュメント整備や機能追加、最適化のコントリビュートを続けたいと思います。

参考文献

 

開発メンバー募集中

より良いチームワークを生み出す

チームの創造力を高めるコラボレーションツール

製品をみる