生成AI × RAGでなぜ ”権限制御” が必須なのか? ─ ベクトルDBを使ったベストプラクティス入門
RAGを触り始めて次のステップで権限制御について考え始める
はじめに
ChatGPT をはじめとする大規模言語モデル(LLM)は、Retrieval-Augmented Generation(RAG) という検索拡張手法と組み合わせることで、社内ドキュメントやナレッジベースを瞬時に要約し、質問に答える “AI 社内 Google” を実現できます。
しかし RAG には 「誤って機密を吐き出す」 という爆弾が潜んでいます。もしアクセス権のない PDF を AI が読めてしまえば、LLM は善悪の区別なく文章を生成してしまうからです。
本記事では、RAG の導入にあたり必須となる 権限制御(アクセスコントロール) をテーマに、「自分が見えない文書は AI にも見えない」 を技術的にどう実装するかを解説します。
具体的には Pinecone/Weaviate/Qdrant などの ベクトルデータベース を例に、2 つの代表的な実装パターン(インデックス分割方式とメタデータフィルタ方式)と設計の勘所を紹介します。初心者にも分かりやすいように、失敗例やコード断片を交えながら進めていきます。
この記事は誰向け?
- LLM / RAG をプロダクション導入したいエンジニア
- Vector DB を初めて触る or 触り始めたばかり
- 「機密データを AI が勝手にしゃべり出したらどうしよう…」と不安な人
本情報は2025.7月時点の調査結果であり、今後各サービスの仕様変更などにより記事の内容と異なる場合があります。
🎯 ゴール
- 「自分が見えない文書は AI にも見えない」 がなぜ大前提なのか腹落ちする
- Vector DB(Pinecone / Weaviate / Qdrant など)で 権限制御を実装する 2 つの流儀 を理解する
- サンプルコードと設計のコツを持ち帰り、明日から社内 PoC を始められる
0. RAG 超ざっくり復習
RAG(Retrieval-Augmented Generation)は
1️⃣ 検索: Vector DB から関連文書を取得
2️⃣ 生成: 取得した文書を LLM に渡して回答を生成
という 2 段構成です。検索段階で権限外の文書が混入すると、LLM がそれを引用して漏えいする恐れがあります。
1. なぜ「自分が見えない文書は AI にも見えない」が必須?
1-1. 失敗するとこうなる(事例)
| 社員 | 質問 | 権限制御が甘いと… |
|---|---|---|
| 経理部A | 「来期の予算計画を要約して」 | ✅ 正常 |
| 営業部B | 「来期の予算計画を要約して」 | ❌ 極秘予算が漏えい |
| インターンC | 「新製品 X の開発状況は?」 | ❌ 未発表機能を吐露 |
1-2. 実害
- 情報漏えい — NDA や法令違反
- 信頼失墜 — 社員が “AI に聞けば何でも出る” と誤解
- 規制対応 — OWASP Top-10 for LLM Applications LLM-02: Sensitive Information Disclosure が代表的リスク
2. Vector DB で権限を守る 2 大アプローチ
| 方式 | 概要 | メリット | デメリット | 向くケース |
|---|---|---|---|---|
| 🅰️ インデックス分割 | テナント/ユーザ単位でインデックス or Namespace を分ける | • データ混在ゼロ • 小規模なら高速 |
• インデックス数が爆発 | B2B SaaS 等で顧客数が少ない |
| 🅱️ 単一インデックス+メタデータフィルタ | 全データを 1 つに格納し filter で分離 |
• データ重複ゼロ • 大量ユーザにスケール |
• フィルタ負荷が増大 | コンシューマ向け等、ユーザ数が多い |
🅰️ インデックス分割
-
Pinecone: Namespace でのマルチテナンシ実装 に従い、
index.upsert(..., namespace="tenantA")で分離 - Weaviate: Multi-Tenancy Vector Search with millions of tenants で紹介されているとおり、v1.20 からネイティブ multi-tenancy を正式実装し、1 ノードあたり 50000+ tenants に対応。リリース詳細は Weaviate 1.20 Release 参照
🅱️ 単一インデックス+メタデータ
Qdrant の例:
# 登録
qdrant.upsert(
collection_name="docs",
points=[
PointStruct(id=1, vector=v1, payload={"dept": "finance"}),
PointStruct(id=2, vector=v2, payload={"dept": "all"})
]
)
# 検索
hits = qdrant.search(
collection_name="docs",
query_vector=qvec,
query_filter=Filter(
must=[FieldCondition(key="dept", match=MatchValue(value="finance"))]
)
)
- payload 列にインデックスを張ると高速化 → Payload Indexing – Qdrant Docs
- フィルタ付き検索の最適化は A Complete Guide to Filtering in Vector Search が詳しい
3. 設計 Q&A(初心者向け)
| 💬 FAQ | ✅ ベストプラクティス |
|---|---|
| ユーザ単位メタデータは重い? | まずは 部署/ロール単位 に集約し、詳細要件が出たら細分化 |
| “デフォルト拒否” とは? | ゼロトラスト。AI は最初何も見えず、dept=all など許可タグを付けた文書だけ閲覧可 |
| ベンチマーク方法? | 想定最大件数でダミーデータ投入 → 権限付きクエリを QPS テスト → P95 レイテンシ確認 |
| 削除した文書が出てくる… | Namespace 方式なら丸ごと Drop、単一インデックスなら delete(filter=…) + スナップショット除外 |
4. まとめ
- RAG は “検索+生成”。検索時点での権限制御が生命線
- インデックス分割とメタデータフィルタ、状況で使い分け
- 「見えない文書は AI にも見えない」 をコードで保証しよう
参考リンク
-
Pinecone Docs — Implement Multitenancy using Namespaces
https://docs.pinecone.io/guides/index-data/implement-multitenancy -
Weaviate Blog — Multi-Tenancy Vector Search with millions of tenants
https://weaviate.io/blog/multi-tenancy-vector-search -
Qdrant Docs — Payload / Filtering
https://qdrant.tech/documentation/concepts/payload/ -
OWASP Top-10 for LLM Applications — LLM-02 Sensitive Information Disclosure
https://genai.owasp.org/llmrisk/llm022025-sensitive-information-disclosure/ -
Auth0 Blog — Build Trustworthy AI: Access Control for RAG
https://auth0.com/blog/rag-and-access-control-where-do-you-start/
Discussion