チーム向けマルチテナント LLM ゲートウェイアーキテクチャ
チームスコープ、プロジェクトキー、分離クォータ、利用ログ、メディア所有権を備え、資格情報を漏らさないマルチテナント LLM ゲートウェイを設計します。
マルチテナント LLM ゲートウェイとは、複数のチーム、プロジェクト、アプリケーションが一つの OpenAI 互換入口を共有しながら、資格情報、クォータ、利用状況、メディア所有権を分離できるコントロールプレーンです。アーキテクチャ上の課題は「tenant_id カラムを追加する」ことではありません。すべてのリクエストが、誰が呼び出したか、誰が支払うか、どのモデルを使用できるか、後からどの成果物を閲覧できるか、という四つの問いに一貫して答えられるようにすることです。この記事では、チームワークスペース、プロジェクトスコープのキー、レート制限スコープ、画像・動画ジョブのメディア分離など、実装可能なゲートウェイパターンへこれらの問いを対応付けます。
最初の本番成功後にマルチテナントが必要になる理由
初期デプロイは、一つの管理者キーと一つのプロバイダチャネルから始まることがよくあります。次の状況になるまでは、それでも機能します。
- 製品、研究、サポートが同じ支出枠を共有する
- 委託業者が組織の秘密情報を見ずに一時的なモデルアクセスを必要とする
- 財務担当者が先月の請求を発生させたプロジェクトを尋ねる
- 生成動画の URL を別チームからダウンロードできないようにする必要がある
- 一つの高負荷エージェントが全員分のレート制限を使い切る
この段階では、テナント境界をアプリケーションコードだけでなくゲートウェイにも設ける必要があります。アプリケーション側の緩い制限は役立ちますが、漏洩したキーや設定ミスの worker が誤った所有者へ課金することは防げません。テナント分離のない マルチプロバイダ LLM ゲートウェイ は、最終的に障害の影響範囲まで共有するインフラになります。LLM プロキシと AI ゲートウェイ の薄いリバースプロキシと対比すると、プロキシは転送し、マルチテナントゲートウェイは認可と計上を行います。
中核テナンシーモデル:所有者、実行者、スコープ
各リクエストでは、次の三つの ID を分離してください。
- 実行者 — 呼び出しを開始した人またはサービスプリンシパル。
- 課金所有者 — 精算時にクォータが減るウォレット。
- アクセススコープ — キー、モデル、成果物の境界となるチーム / プロジェクト、または個人ワークスペース。
本リポジトリのようなシステムでは、個人トークンは通常ユーザー所有者へ課金され、チームスコープのトークンはチームとプロジェクトの両方に紐付き、チームウォレットを課金先として解決します。チームワークスペースが無効な場合、プロジェクトが非アクティブな場合、実行者にそのプロジェクトで必要な action がない場合、ミドルウェアはチームスコープのトークンを拒否すべきです。この検査はチャネル分配前のホットパスに置きます。
Client / agent
| Bearer sk-...
v
Auth middleware
- resolve token -> user, team_id, project_id, owner_type
- validate membership + project action grants
v
Policy + rate-limit scope
- team:project:user (or personal user scope)
- model allowlists / group grants
v
Relay / task submit
- upstream channel selection
- pre-consume quota against billing owner
v
Usage log + optional media persistence
- store actor, team, project, billing owner
- authorize later content proxy by same scope
実行者と課金所有者を一つのフィールドにまとめると、「誰がチーム予算を使ったか」と「誰が生成ボタンを押したか」を区別できません。スコープがログ上のラベルにすぎなければ、/v1/videos/{id}/content の認可から別テナントへ情報が漏れます。
一致させる必要があるテナンシー面
1. API キーとプロジェクトの紐付け
キーを第一級のテナンシーオブジェクトとして発行します。
- 個人サンドボックス向けの個人キー
team_id+project_idに紐付くチームキー- キーが呼び出せる 安定したゲートウェイ別名を制限する、任意のグループまたはモデル権限
安定した別名(例えば gpt-image-2 や製品向けの video-default)は、チャネル設定で上流モデル ID に対応付けます。クライアントは別名を維持し、運用者は各サービスを書き換えずに上流の生 ID を切り替えられます。クライアント環境へ上流プロバイダの秘密情報を埋め込んではいけません。クライアントはゲートウェイだけに認証し、チャネルがプロバイダ資格情報を保持します。複数チームの製品では、AI API アクセス向け RBAC にも同じ分離原則を適用してください。
2. クォータと事前消費の安全性
課金の安全性はテナンシーの問題です。高コスト処理の前に課金所有者から事前消費し、上流処理の完了後に精算または返金します。画像の n や動画時間などのメディア乗数には検証時に厳格な上限を設け、悪意ある、または不具合のあるクライアントがクォータ計算をオーバーフローさせて負の課金を生み出せないようにしてください。このコードベースでは画像数に上限(MaxImageN = 128)があり、動画時間にも上限(MaxTaskDurationSeconds)があります。チームポリシーがより厳しいプロジェクト予算を追加しても、マルチテナントシステムではこれらのグローバルなガードを維持します。
3. 複合スコープキーによるレート制限
チームトラフィックには team:{id}:project:{id}:user:{id} のようなスコープキーを、個人トラフィックにはユーザー単位のキーを使用します。これにより、一つのプロジェクトのエージェント負荷が別プロジェクトのチャット処理を圧迫することを防げます。制限判定はチャネル選択から分離してください。チームがモデルを使用できても、レート制限は適用されます。
4. 監査面としての利用ログ
精算済みの各呼び出しには、実行者、課金所有者、存在する場合はチーム / プロジェクト、モデル別名、リクエスト ID、メディア乗数(n、秒数、サイズ)を保持します。財務担当者とセキュリティ担当者の両方がこれらのフィールドを必要とします。製品向けの利用状況ビューは認証済みコンソール面です。公開ドキュメントでは、読者を非公開コンソールルートへ繰り返し誘導するのではなく、監査モデルを説明すべきです。
5. メディア所有権は任意のメタデータではない
画像と動画の成果物は HTTP リクエストより長く残ります。オブジェクトキーとタスク ID をテナントリソースとして扱ってください。
| サーフェス | 本リポジトリのスコープ(説明前に要確認) | 所有権ルール |
|---|---|---|
| 画像ワークベンチ UI/API | /api/user/image-workbench と API キー用の派生ルートにおける個人 / セッション / トークンスコープ。オブジェクトキーはユーザー所有 | 現時点でチーム / プロジェクト向け画像ワークベンチルートはない |
| 動画ワークベンチ UI/API | /api/user/video-workbench の個人スコープ および /api/teams/:team_id/video-workbench のチーム / プロジェクトスコープ | チームの実行と資産は、チーム + プロジェクト権限で認可する |
| OpenAI 互換画像入口 | POST /v1/images/generations, POST /v1/images/edits | トークンの課金所有者へ課金する。自ら永続化していないチーム履歴を作り出さない |
| OpenAI 互換動画入口 | POST /v1/videos、取得、content。remix ルートも登録済み | content GET は、タスク作成時と同じ所有者 / スコープを再検査する |
上流プロバイダの URL は頻繁に失効します。オブジェクトを非公開ストレージへ永続化し、認可付きプロキシで再配信するゲートウェイは、リンク切れと意図しない公開露出を減らせます。ワークベンチでオブジェクトストレージが必須の場合、設定不備時にはスコープのない一時 URL を返さず、フェイルクローズしてください。
2 番目のチームを追加する前の分離チェックリスト
スライドではなく、リリースゲートとして使用してください。
| 境界 | 合格基準 |
|---|---|
| 認証 | 削除済みメンバーや無効プロジェクトのチームスコープトークンが失敗する |
| 課金 | チームジョブが個人ウォレットを決して引き落とさず、その逆も起きない |
| モデル | 権限のないプロジェクトは制限付き別名を呼び出せない |
| ログ | チーム横断ログ照会は空または拒否を返し、部分的な行を返さない |
| メディア | 動画 content プロキシは別チームのタスク ID を not found / forbidden として拒否する |
| レート制限 | プロジェクト A の負荷がプロジェクト B の token bucket を消費しない |
| 管理 | スーパー管理者の操作はテナント管理者と分けて監査される |
自動テストでは正常系だけでなく拒否経路も実行してください。マルチテナントの不具合は「soft 404」の判断に潜みます。リソースの存在自体が機密情報なら、外部リソースには 403 より 404 を返す方が適切な場合があります。
チームスコープチャットの参照リクエスト経路
curl https://your-gateway.example.com/v1/chat/completions \
-H "Authorization: Bearer $TEAM_PROJECT_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_STABLE_CHAT_ALIAS",
"messages": [
{"role": "user", "content": "Summarize yesterday deploy risk for project alpha."}
],
"max_tokens": 400
}'
ゲートウェイ内部では、次を行います。
- キーを認証して
team_id/project_idを解決する。 - 実行者がそのプロジェクトのプロジェクトトークンを使用できることを確認する。
- 許可されたグループ / チャネル集合からモデル別名を解決する。
- チームの課金所有者から推定クォータを事前消費する。
- 上流へリレーし、実行者 + 所有者フィールドを持つ消費ログを書く。
- 財務とサポート向けの認証済み利用状況ビューへ同じ ID を公開する。
同じトークン規則と異なるワークベンチスコープを持つメディア
メディアエンドポイントは、課金のために別の認証システムを作るべきではありません。OpenAI 互換入口では、同じトークンとセッション規則を使用します。
# Image generation through OpenAI-compatible ingress (GPT Image returns b64_json)
curl https://your-gateway.example.com/v1/images/generations \
-H "Authorization: Bearer $TEAM_PROJECT_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "Product hero shot on matte black pedestal, studio light",
"size": "1024x1024",
"n": 1,
"output_format": "png"
}'
# Async video job (evaluate Sora 2 only with the official deprecation timeline in mind)
curl https://your-gateway.example.com/v1/videos \
-H "Authorization: Bearer $TEAM_PROJECT_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "YOUR_STABLE_VIDEO_ALIAS",
"prompt": "Slow orbit around a ceramic mug on a wood table",
"seconds": "4",
"size": "1280x720"
}'
ワークベンチ UI のスコープは異なります。
- 画像ワークベンチ は個人向けの運用サーフェスです。プリセット、実行履歴、資産はユーザースコープです。実装していないチーム画像履歴や
/api/teams/:team_id/image-workbenchルートが存在すると説明してはいけません。 - 動画ワークベンチ は個人とチーム / プロジェクトの両スコープに対応します。生成と資産管理の能力をチーム action に対応付け、チームに紐付いたセッションでは実行履歴をプロジェクトスコープに保ってください。
再永続化エンドポイントが資産を別の所有者へ移してはいけません。新規動画開発では、OpenAI Videos API / Sora 2 が 2026-09-24 に終了した後も対応可能なベンダーとゲートウェイアダプターを優先してください(OpenAI の非推奨情報)。まだ Sora トラフィックを扱っている場合は、タスクストレージとクライアントコード経路の移行を今すぐ計画します。
クライアントを書き換えずに拡張できるポリシー層
ポリシーを粗いものから細かいものへ重ねます。
- プラットフォーム既定値 — 画像の最大
n、動画の最大秒数、禁止モデル。 - チームポリシー — 許可グループ、予算アラート、機能フラグ。
- プロジェクト権限 — メディア生成や動画資産管理を行えるメンバー。
- キー制約 — IP 許可リスト、有効期限、モデルの部分集合。
- ランタイム制限 — RPM/TPM と同時タスク上限。
クライアントは /v1/* を呼び続けます。運用者は管理設定とチャネルのモデルマッピングでポリシーを変更します。これが OpenAI 互換 API ゲートウェイ の運用上の価値です。
マルチテナントゲートウェイ固有の失敗モード
- 所有者の暗黙フォールバック: チーム解決に失敗した場合、「親切」のつもりで実行者の個人ウォレットへ課金せず、リクエストを失敗させます。
- 分離ラベルのない共有チャネルアフィニティ: キャッシュキーにテナントスコープを含めなければ、sticky routing の状態が混ざります。
- 画像ワークベンチがチーム対応だと思い込む: ユーザー所有の個人画像資産は、チーム動画プロジェクトとは異なります。
- 法的境界を無視するログ保持: チーム離脱時に選択的削除が必要になる場合があります。保持ジョブには所有者フィルターを設けてください。
- content プロキシの混同: ダッシュボードのセッション認証と API トークン認証の両方で、同じ所有権検査が必要です。
- action 権限のない予算アラート: どのメンバーもキーを作成できるままなら、財務担当者への通知だけでは意味がありません。
OWASP LLM Top 10 のセキュリティ指針が適用されます。過度な代理権、機密情報の漏洩、無制限の消費は、一つのテナントが別のテナントへ影響した時点でテナンシー事故になります。
最小実装手順
- チーム、プロジェクト、メンバー、action 権限をモデル化する。
- トークンと消費ログへ所有者フィールドを追加する。
- 認証ミドルウェアでチームトークン検証を強制する。
- レート制限と利用状況照会をスコープ化する。
- 動画タスク認可と content プロキシを同じスコープ helper へ移し、チーム画像永続化を意図的に追加しない限り画像ワークベンチはユーザー所有のままにする。
- チャット、保存した画像バイト、動画 content のテナント横断拒否に対する e2e テストを追加する。
- その後で初めて、実際の製品トラフィックをチームキーへ移行する。
拒否経路のテストを省略すると、「マルチテナント UI」はあってもマルチテナントの安全性がない製品になります。
関連記事
出典と参考資料
- OWASP Top 10 for LLM Applications
- OpenAI の本番ベストプラクティス
- OpenAI の非推奨情報(Videos API / Sora 2 の 2026-09-24 終了を含む)
- エンタープライズ組織向け Google Cloud マルチテナンシー指針
判断時の確認事項
テナントごとに別データベースが必要ですか?
多くの AI ゲートウェイでは不要です。規律あるクエリフィルターによる行レベル分離が一般的です。個別データベースは規制上の分離や noisy neighbor のストレージ制限には役立ちますが、マイグレーションとチャネル設定が増えます。流行ではなくコンプライアンスに基づいて選択してください。
各マイクロサービスが独自のプロバイダキーを発行すべきですか?
いいえ。サービス ID ごとにゲートウェイキーを発行し、プロバイダキーはチャネルに保持してください。これにより、ローテーション、支出の可視性、フェイルオーバーを維持できます。
個人ワークスペースとチームはどのように共存しますか?
個人所有者タイプを第一級の経路として維持します。ユーザーは個人キーと個人画像ワークベンチで試作し、その後、リクエスト形式を変えずに共有チャット / 動画支出向けのチームプロジェクトキーへ切り替えられます。変わるのは Bearer token とポリシーだけです。
マルチテナントメディアで最大の誤りは何ですか?
上流の結果 URL を永続的な公開リンクとして扱うこと、またはすべてのワークベンチがチームスコープだと思い込むことです。製品で永続性が必要なら保存し、認可付きルートでプロキシし、保存できない場合は失効を文書化し、個人所有かチーム所有かを正確に説明してください。
移行演習
一つの本番アプリケーションを共有管理者キーからチームプロジェクトキーへ移行します。消費ログに正しい課金所有者が表示されること、別チームの動画タスク ID が /v1/videos/{id}/content で拒否されること、追加の共有機能を構築していない限り画像ワークベンチ資産がユーザー所有のままであること、プロジェクトのレート制限が別チームの負荷試験と衝突しなくなったことを確認してください。