Kubernetes上のマルチテナントRAG:最初に折れるのはどこか
RAGプラットフォームを複数クライアント向けに産業化するとき、問題になるのはLLMではありません。テナント分離、クォータ、テナント別の可観測性です。
Kubernetes上のマルチテナントRAG:最初に折れるのはどこか
ConexiaのためにマルチテナントRAGプラットフォームを構築しました。世間ではRAGについて「LLMを選んでベクトルストアを後ろに付ければいい」というかのように語られています。実際には、シングルクライアントPOCを超えた瞬間から、LLMは最も面白くないコンポーネントになります。最初に折れる3つのポイントと、それを運用可能にするために行ったことを紹介します。
1. 分離は「全層で行う」か「行わない」かのどちらかしかない
開始時の誘惑は、テナントを「論理的な名前空間」で分けることです:キーにプレフィックスを付け、ドキュメントにタグを付けて、それで終わり。最初の漏洩が起きるまでは保ちます。そして最初の漏洩はすぐ来ます。なぜなら分離が壊れうる面が少なくとも6つあるからです:
- ベクトルDB(
whereフィルタが間違っているとテナントAがテナントBのコンテキストを受け取る) - シークレット(LLMキー、スクレイピング認証情報、クライアント別のWebhook)
- クォータ(テナントAがテナントBのLLMプールを枯渇させてはならない)
- 可観測性(ログとメトリクスはテナント別にタグ付けし、クライアント単位でデバッグできるようにする必要がある)
- キャッシュ(スコープが甘いプロンプトキャッシュはテナント間でビジネス情報を漏らす)
- 設定(システムプロンプト、ソース、業務ワークフロー)
私のルール:1テナント = すべての層に伝播する1つの識別子、識別子がない場合はデフォルトで失敗する。サイレントな「デフォルト値」は禁止。テナントIDなしのリクエストは拒否し、雑にテナント0番に割り当てない。
K8sでの具体的な実装:
- 認証ミドルウェアがリクエストコンテキストにテナントIDを注入
- ベクトルDBのラッパーが
tenant_idなしのクエリを拒否 - ネームスペース単位でスコープされたKubernetesシークレット、またはテナント認識パスを持つVaultから同期される
External Secrets - すべてのアプリケーションメトリクスに体系的なPrometheusラベルを付与
# 例:RAGメトリクスに必須のラベル
- name: rag_query_latency_seconds
labels:
- tenant_id
- source_type # web, gmail, messenger
- llm_provider
- cache_hit
「テナントXが今週どのモデルでトークンをいくら消費したか」を5秒で答えられない場合、マルチテナント可観測性はまだ存在していません。
2. 障害の本当の発生源はインジェスチョンパイプライン
LLMはめったに落ちません。一方、スクレイピングとインデキシングのパイプラインは常に落ちます:ソースサイトがHTMLを変更する、ソースAPIがレートリミットを返す、PDFが破損して届く、誰かがログダンプをアップロードしたせいで埋め込みコストが爆発する。
私を救った設計:
- すべてに冪等性:同じドキュメントを2回インデックスしてもエントリは2つにならない。コンテンツのハッシュをキーに使用。
- 隔離キュー:失敗したドキュメントは別キューに送り、メインキューに静かに溜め込まない。
- テナント別の埋め込み予算上限:クライアントが50GBのPDFをアップロードして月間予算を一晩で燃やすことを防ぐ。
- 観測可能なステージに分割されたインデキシングワークフロー(fetch → parse → chunk → embed → upsert)、各ステージにメトリクス。
LLMのベンチマークほど派手ではありませんが、日曜の朝にプラットフォームを生かし続けるのはこちら側です。
3. LLMルーティングはMLではなく運用
誰もが「最適なモデルを選ぶインテリジェントなルーター」を夢見ます。実際には、有用なルーティングは退屈なものです:
- 重要度別のルール(「内部テスト」リクエストはGPT-4には行かせない)
- 可用性によるフォールバック(プライマリプロバイダがタイムアウトしたら切り替え)
- テナント別のサーキットブレーカー:1つの障害クライアントが他を巻き込まないように
- テナント別・日次の予算アラート
各プロンプトに対して動的に最適なモデルを選ぶ「MLルーティング」は研究テーマとしては面白い。しかし本番では、まずルーティングが決定論的で、観測可能で、デバッグ可能であることを目指すべきです。洗練はその後で。
新規プロジェクトで最初にやること
明日からやり直すとしたら:
- テナントIDをすべての場所に、デフォルトで失敗、コードの最初の行から
- テナント別メトリクスを初日から、たとえテナントが1つでも
- 最初のクライアント統合の前にLLMと埋め込みの予算上限を設定
- 何かを最適化する前に、隔離キューと冪等性を持つインジェスチョンパイプラインを構築
- 「本物の」LLMルーティングは最後に、できるだけシンプルに
RAGはAIの問題ではありません。プラットフォームの問題です。そしてプラットフォームは中心(モデル)からではなく、辺縁(分離、クォータ、可観測性)から構築するものです。