Azure AI Searchは、保有するベクトルの数ではサイズが決まらない。tierで決まる。vector indexはSKU上でvector search用に予約されたメモリに縛られ、Serverlessモデルではインデックスあたり300 MBのハードリミットがあり、超過するとindexingジョブは即座に失敗する。機能比較ではなくこの一点の性質が、この会社のretrieval層がAzure AI Searchに属するのか専用のベクトルデータベースに属するのかを決める。第6回は繰り返される質問を安くした。本稿は、モデルが一度も見ていない事実を必要とする、はるかにありふれたケースを扱い、第1回のリテールのナレッジ検索がついに形になる。

retrievalはゲートウェイに対してどこに座るか

比較に入る前に片づけておくべき点がある。シリーズの前提を保っているのはこれだからだ。retrievalはゲートウェイのトラフィックではない。アプリケーションはsearch indexを直接クエリし、返ってきたものからプロンプトを組み立て、そのプロンプトを他のあらゆるcompletionと同じようにゲートウェイへ通す。ゲートウェイは、取得したコンテキストが加算するtokenを計測する。これはまさに欲しい可視性だ。retrievalはたいてい、プロンプトサイズが静かに3倍になる場所だからだ。

ゲートウェイに触れる唯一の部分はembeddingだ。クエリとドキュメントのembeddingsの生成はモデル呼び出しなので、他のすべてと同じ扉を通り、同じquotaと同じ帰属が適用される。つまり、第6回がsemantic cachingのために作ったembeddingsデプロイメントは、retrievalが欲しがるデプロイメントと同じである可能性が高く、そのキャパシティはいまや2人の主人に仕えている。

実際に決め手となる制限

機能のチェックリストで見ると、Azure AI Searchと専用のベクトルストアは交換可能に見える。サービス制限はそうは見せない。

  • vector indexのサイズは、データではなくSKUの関数だ。Dedicated課金モデルではtier上でvector search用に予約されたメモリに縛られ、Serverlessではインデックスあたり300 MB、総インデックスストレージのおよそ30パーセントで、劣化ではなくindexingの失敗を招くハードリミットだ。
  • vectorの制限はサービスの作成時期に依存する。より高いvector quotaが適用されるのは、追加キャパシティのあるリージョンで2024年4月以降に作成されたサービスだ。対応リージョンにある古いサービスは、それを得るのに明示的なアップグレードが必要な場合があり、これは設定のトグルではなく移行の問題だ。
  • キャパシティはreplica掛けるpartitionだ。Basicは、2024年4月3日より後に作成されたサービスで3 partitionと3 replica、つまり9 search unitをサポートする。それより古いBasicサービスは1 partitionに制限される。S1からS3はそれぞれ12まで行く。
  • SLAはreplica数だ。クエリワークロードには2以上、クエリとindexingには3以上。partition数はSLAの考慮事項では一切なく、ストレージのためにスケールして可用性も付いてくると思い込んでいた人を驚かせる。
  • インデックス数はtierごとに上限がある。Basicで5または15、S1で50、S2とS3で200。テナントごとに専用インデックスを与えるプラットフォームは、ストレージよりずっと先にこの天井にぶつかる。そしてindex-per-tenantは既定の直感だ。
  • vectorフィールドあたり最大4096 dimensions。全tier共通で、寛大ではあるが、誰かがより大きなembeddingモデルに標準化する前に知っておく価値がある。

まとめて読むと、これらは特定のことを語っている。Azure AI Searchは、ベクトルも扱うsearchサービスとして価格付けされ、スケールされている。ベクトルのコーパスが支配的なコスト要因で、クエリ量とは独立に成長するなら、メモリを保持するためにsearch unitへ支払っていることになる。それが専用のベクトルデータベースが勝つ条件で、アーキテクチャの好みではなく、検算できる定量的な条件だ。

Azure AI Searchが与え、ベクトルストアが与えないもの

対抗する重りは現実のもので、企業のナレッジベースではしばしば決定的だ。

1リクエストでのhybrid search。単一のクエリがsearchパラメーターとvectorQueriesの両方を運び、full-textとvectorのretrievalを並列に走らせ、Reciprocal Rank Fusionで1つのランク付き結果セットへマージする。テキストのランキングはBM25を、vectorのランキングはHNSWまたはexhaustive KNNを使う。これが重要なのは、製品ドキュメントが正確なtokenだらけだからだ。型番、エラーコード、部品番号。lexical searchは確実に見つけ、embeddingsはぼかす。

{
  "search": "device not connecting after the firmware update",
  "vectorQueries": [
    { "kind": "vector", "vector": [ ... ], "k": 50,
      "fields": "contentVector", "exhaustive": false, "oversampling": 10 }
  ],
  "queryType": "semantic",
  "semanticConfiguration": "kb-semantic",
  "top": 10
}

フィルタリング、ファセット、ソート、scoring profileは同じリクエストに適用されるので、ドキュメントレベルの認可(このテナント、この製品ライン、この言語)は別インデックスではなくフィルターで済む。indexer経由のintegrated vectorizationはBlob Storage、Cosmos DB、Azure SQL、OneLakeから取り込み、ingest時にembedする。プラットフォームチームが抱えるはずだったパイプラインが丸ごと消える。そしてこのインデックスは、Microsoft Foundryのagentシナリオでknowledge sourceとしてアタッチできる。

ランキング品質の話の内側には、キャパシティの細部がひとつ隠れている。semantic rankerはキューでスロットリングされる。search unitあたりの最大同時リクエスト数はBasicで2、S1で3、S2以上で4、その背後に有限のキューがある。キューを超えたリクエストは拒否され、リトライしなければならない。上限を上げる手段はsearch unitの追加か、サポートリクエストだ。すべてのクエリでsemantic rankingをオンにするretrieval層は、したがって自らの同時実行の天井をsearch tierの関数にしてしまっており、Basicではその天井は小さい。

判断を、テストとして書き下す

好みではない。3つのチェックを、この順で。

  • コーパスはlexicalとvectorのretrievalを一緒に必要とするか。正確な識別子が重要なら、そして製品ドキュメントでは常に重要だが、1つのサービスで済むhybridとsemantic rankingの価値は大きく、純粋なベクトルストアの上に再実装するならinverted indexも運用することになる。
  • vectorのフットプリントはクエリ量と独立に成長するか。そうなら、それを保持するのに必要なsearch unitをモデル化し、ストレージでサイズされるベクトルデータベースと比較する。これは算数で、答えがひっくり返るのはたいていここだ。
  • 論理的なコーパスはいくつあるか。index-per-tenantはtierごとのインデックス上限にすぐぶつかる。代替はtenant filter付きの1インデックスで、これはクライアントではなくクエリ層で強制しなければならないセキュリティコントロールだ。

このプラットフォームでの答えはAzure AI Searchだ。リテールのナレッジベースは、正確な型番が物を言う数十ギガバイトの製品ドキュメントであり、マネージドサービスを1つ増やす運用コストは、同じAKSクラスター上で自前運用するベクトルストアのコストより低いからだ。数億のベクトルを抱え、lexicalの要件がないagentのメモリストアなら答えは逆になるし、そうでないふりをするならこのシリーズは間違っている。

テナンシー、そしてセキュリティコントロールであるフィルター

tenant filter付きの1インデックスは、インデックス数の上限の下では正しい既定であり、認可の決定をクエリの中に置く。ルールは第6回のvary-byと同じだ。フィルターの値は検証済みtokenから来る。リクエストパラメーターからでは決してない。自分のテナントIDを自分で渡すアプリケーションは、バグ1つで他人のIDを渡す。

retrievalはAPI Managementを通らないので、強制のポイントはアプリケーションかコントロールプレーンであり、ゲートウェイのポリシーではない。これはone-doorモデルの正真正銘の穴で、取り繕うより名指しした方がいい。ゲートウェイはモデルへのアクセスを統治し、searchサービスはドキュメントへのアクセスを統治する。両者は、テナントが誰であるかについて合意しなければならない2つの異なるコントロールプレーンだ。両方を同じEntra IDのclaimから導出することが、両者のずれを防ぐ。

注視すべき失敗モード

  • 劣化ではなくサイズ制限で失敗するindexing。Serverlessでインデックスあたりのvector上限を超えると、操作そのものが失敗する。vector indexのキャパシティは計画の入力であって、バルクロードの最中に発見するものではない。
  • 古いvector quotaのままの古いsearchサービス。2024年4月より前に作成され、いまはより多くを提供するリージョンにあり、誰かがアップグレードするまで静かに制限されている。
  • partitionをスケールして可用性を期待する。partitionはストレージだ。SLAが数えるのはreplicaで、クエリには2、indexingが並走するなら3。
  • 負荷の下でのsemantic rankerのスロットリング。同時実行数はsearch unit単位で、低いtierでは小さい。症状はピーク時に遅くなるクエリではなく、拒否されるクエリだ。
  • tierの天井へ向かうindex-per-tenant。最初の十数テナントでは見事に機能し、そこで止まる。その時点でフィルター付きインデックスへの移行はデータプロジェクトだ。
  • プロンプトサイズを膨張させる取得コンテキスト。ゲートウェイが計測しているので、第5回の数字には、説明のつくコード変更が何もないtoken増として現れる。総支出だけでなく、テナントごとのリクエストあたりtokenにアラートを張ること。

第8回が受け継ぐもの

アプリケーションが直接呼ぶretrieval層、キャッシュと共有されるembeddingsデプロイメント、そして以前よりかなり大きくなったプロンプト。そこから次回の問いが立ち上がる。アプリケーションがretrievalとtool callingと複数のモデルホップを必要とするようになったとき、orchestrationフレームワークはこのゲートウェイの上に属するのか、それともフレームワークはゲートウェイと戦い始めるのか。

次に読む

これを大規模に運用する際のインフラおよびプラットフォーム側の話はercan.cloudのフィールドノートに、ハブはercanermis.comにある。

参考資料