マルチテナントLLMアプリ: 共有モデル上で顧客を分離する
1つの共有Bedrockモデルを多くの顧客が使う。モデルはステートレスなので、分離は自分の仕事だ。検索範囲を絞り、クォータを上限で管理し、テナントごとにアイデンティティを運ぶ。

多くの顧客が1つのBedrockモデルを共有するとき、モデルはそもそも分離を提供しないし、するつもりもなかった。モデルはステートレスな関数であり、同じ入力に対しては同じ振る舞いを返すだけで、誰が呼び出したかの記憶を持たない。テナント間のあらゆる境界は、モデルの外側の層で構築する必要があり、モデルに期待するものではない。チームはここを逆に捉え、マネージドサービスが分離を処理してくれると思い込み、あるテナントのデータ、コスト、負荷が別のテナントに漏れ出すアプリを出荷してしまう。共有モデル自体は問題ない。問題は、それ以外のすべてが共有されていることだ。
安心できる点は、モデルがステートレスであることが、マルチテナンシーを扱いやすくもしているということだ。モデルの内部には漏れうるテナントごとの状態が存在しない。そもそも状態自体が存在しないからだ。分離は、すでに構築の仕方を知っている3つの具体的な境界に帰着する。テナントのリクエストがどのデータに到達できるか、共有キャパシティのうちどれだけを消費できるか、そしてどのアイデンティティとして実行されるか、である。
データの分離: モデルではなく検索の範囲を絞る
RAGやエージェントアプリにおける本当の漏洩リスクは、重みではなく、その前に置くコンテキストにある。テナントAの質問がテナントBのドキュメントを検索してしまえば、それは親切な回答の姿をしたデータ漏洩だ。だからテナントの分離は検索層に宿る。
境界をどれだけ厳格にする必要があるかに応じて、実用的な形が2つある。
- テナントごとのナレッジベース。最も硬い境界。各テナントが独自のBedrock Knowledge Baseを持ち、クエリはそのテナントのコーパスからしか検索できない。最も考えやすい構成だが、テナント数が増えるほど管理すべき可動部品も増える。
- 共有ストア、テナントでフィルタ。1つのベクトルストアに、すべてのクエリで必須のテナントIDフィルタをかけ、メタデータによって結果を絞る。運用コストは安いが、そのフィルタは今や重要なセキュリティ要素になる。認証済みのアイデンティティからサーバー側で適用されなければならず、クライアントが設定できる値から適用してはいけない。
避けるべき失敗は、リクエストボディで届いたテナントIDでフィルタしてしまうことだ。クライアントが自分のテナントを名乗れるなら、他人のテナントも名乗れてしまう。テナントは認証済みのプリンシパルから導出し、クライアントが手を出せない場所でスコープを適用する。
うるさい隣人: 共有クォータは共有の障害
Bedrockはアカウントとモデルのレベルで1分あたりのトークン数をスロットリングする。その数値は、そのモデルにアクセスするアカウント内のすべてのテナントで共有される。つまり、1つのテナントが重いバッチジョブを実行すると共有トークン予算を消費し、他のすべてのテナントは自分が発生させていない負荷に対するスロットリングエラーを受け取り始める。モデルは論理的には分離されているが、運用的には結合されている。
ここでの分離とは、共有の上限がそうする前に、テナントごとの計測とキャップをかけることを意味する。
- テナントごとのトークン予算。ウィンドウごとにテナントが消費したトークンを追跡し、自分の割り当てを超えたテナントを拒否またはキューに入れて、そのスパイクが共有プールを食い尽くさないようにする。
- 公平なキューイング。モデルの前段にテナントごとに有界なワーカープールを置くことで、1つのテナントのバーストがそのテナント自身の速度低下にとどまり、全員の障害にはならないようにする。
- 優先度ティア。テナントが異なるサービスレベルに料金を払っているなら、それをアドミッション制御で強制する。無料層のバッチ処理が有料テナントのインタラクティブなトラフィックを飢餓状態にしてはいけない。
アイデンティティ: テナントの境界はツールにまで届くべきだ
分離は検索で止まってはいけない。エージェントがツールを呼び出し、データベースから読み取り、ストレージに書き込む瞬間、テナントの境界はリクエストとともに移動しなければならない。つまり、リクエストはテナントに絞られたアイデンティティのもとで実行され、たとえモデルが誤ったデータを要求するよう仕向けられたとしても、ツールの背後にある認証情報がそれを取得できないようにする。モデル層は何も信用しない。IAM層がすべてを強制する。これはテナントごとに適用された最小権限の原則であり、プロンプトインジェクションの試みがテナント越境の読み取りに変わることを防ぐものだ。
まとめ
共有モデルは、すべてが共有されたアプリを意味しない。モデルはステートレスなので分離を提供せず、自分自身を保護する必要もない。仕事はモデルを取り巻く3つの境界だ。テナントが自分のデータしか見えないよう検索の範囲を絞り、共有トークンクォータで誰かが他を飢餓状態にしないよう容量を計測し上限を設け、プロンプト層が騙されたときの最後の防衛線となるスコープ付き認証情報が届くように、テナントごとのアイデンティティをツールまで運ぶ。この3つを構築すれば1つのモデルが多くの顧客に安全に対応できる。1つでも省けば、モデルは喜んで間違った顧客のデータを間違った顧客に提供してしまうだろう。
次に読むべき記事
- IAM for LLM Apps: Least Privilege When the Caller Is a Model、テナントの境界をツールまで運ぶスコープ付きアイデンティティについての記事。
- Cutting Amazon Bedrock Knowledge Base Costs by ~90% with pgvector、共有検索を手頃にするテナントフィルタ付きベクトルストアについての記事。
同じ問題のプラットフォームとマルチアカウント分離の側面については、クラウド分野のフィールドノートをercan.cloudで、ハブをercanermis.comで公開している。
Ercan の他のサイト
同じ著者、別の領域のサイトが2つ。