はじめに
ここ2ヶ月ほどで、個人開発として 企業向けAIガバナンス基盤「Prism」 を育ててきました。
- v0.x: 「AIとペアプロして、まずは動くものを作る」
- v1.0: ハイブリッドRAG + ストリーミングで、ナレッジプラットフォームらしくする
- v1.1: マルチテナント & RAG完全分離で、SaaSアーキテクチャに近づける
ここまでは「機能を増やす」ことに必死でしたが、だんだんと 「これ、本当に企業で使ったら危ないポイントだらけでは?」 という不安も見えてきました。
そこで v1.2 では、方向性を少し変えて、
- PII(個人情報)を NLPベースで検出・マスキング する
- README に 「PoC & 学習用」であること / 制約 / Known Limitations を明示する
- コードの全体像を理解しやすくするために バックエンド / フロントエンドの解説ドキュメント を用意する
という「セキュリティと学習体験」の2つにフォーカスしてアップデートしました。
この記事では、
- なぜ PII 対応を強化したのか
- どうやって Microsoft Presidio + spaCy で PII Shield を組み込んだか
- README や解説ドキュメントを通して「学習用PoCとしての線引き」をどう言語化したか
をまとめます。
v1.2 の主な変更点
今回のアップデートで追加 / 強化したのは主にこの3つです。
-
🛡️ NLPベースの PII Shield
Microsoft Presidio + spaCy (ja_core_news_lg) を使って、名前・住所・電話番号などを文脈から検出し、LLM 送信前にマスキングします。 -
👥 Multi-User / ロール & テナント文脈の明確化
User,Tenant,TenantMemberモデルで「誰が / どのテナントに所属しているか」を管理し、get_current_contextで毎リクエストごとにuser_id/tenant_id/roleを束ねて取得するようにしました。 -
📘 README & 学習用ドキュメントの整備
README に「Project Status & Known Limitations」セクションを追加し、backend_explanations.md/frontend_explanations.mdで主要ファイルを 初心者でも追えるレベル まで日本語で解説しています。
1. なぜ PII 対応を強化したのか
Prism はもともと「企業向けAIゲートウェイ」というテーマで作っている以上、個人情報や機密情報をどう扱うか は避けて通れません。
v1.0〜v1.1 では、
- シンプルなキーワードチェック
- ルールベースなガバナンス
程度しか入っておらず、
- 「住所っぽい表現」「名前っぽい表現」
- 「メールアドレスだけど少し変形している」
といった 文脈的な PII を検出することはできませんでした。
また、README 上も
- どこまでが安全で
- どこからが危険なのか
- 何を「前提条件」としているのか
が曖昧で、利用者が「これは本番で使えるのか?」と誤解する余地がありました。
そこで v1.2 では、
- 技術的には NLPベースの PII 検出 を入れつつ
- ドキュメントとしては 「STRICT な機密情報はそもそも登録しない前提」 を明確にする
という「多重防御」のスタイルにしています。
2. Microsoft Presidio で PII Shield を実装する
2-1. 全体アーキテクチャ
Prism のチャットフローはざっくり言うと:
-
ユーザーリクエストを受け取る(メッセージ + 添付ファイルのテキスト)
-
ガバナンスカーネルで
- ドメイン判定
- モード判定(FAST / HEAVY / FLASH)
- PII 判定 ← ここに Presidio を組み込み
-
RAG で社内ナレッジを検索
-
LLM(Gemini)に投げてストリーミングで返す
-
すべてをログに記録する
今回の変更で、
- 入力テキスト
- (ゆくゆくは RAG から引いてきたコンテキスト も)
に対して Presidio の AnalyzerEngine をかけ、検出結果に応じて以下のように処理しています。
- LLM に渡すテキスト:
→ 検出箇所を[PII Masked]に置き換え - 監査ログに保存する情報:
→ フルテキストは保存するが、pii_mask_applied: trueと、検出されたカテゴリ一覧だけメタ情報として残す
「LLM に送るのはマスク済み / ログにはフルテキスト」というバランスを取ることで、
- モデルへの情報漏洩リスクは下げつつ
- 内部監査用には「どんな入力が来ていたか」を追える
ようにしています。
2-2. AnalyzerEngine のセットアップ
Presidio では、だいたい次のような流れでセットアップします(擬似コード):
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
analyzer = AnalyzerEngine(
nlp_engine=make_spacy_engine("ja_core_news_lg"),
supported_languages=["ja", "en"]
)
anonymizer = AnonymizerEngine()
-
ja_core_news_lgを使うことで、日本語の 人名・地名・組織名 などをコンテキストから検出できます。 - 英語混じりのテキストも想定し、英語もサポート対象にしています。
検出はこんな感じで行います:
results = analyzer.analyze(
text=message,
language="ja",
entities=["PERSON", "LOCATION", "EMAIL_ADDRESS", "PHONE_NUMBER"]
)
if results:
masked = anonymizer.anonymize(
text=message,
analyzer_results=results,
anonymizers={"DEFAULT": {"type": "replace", "new_value": "[PII Masked]"}}
).text
else:
masked = message
-
entitiesに含める種類は、ビジネス要件に合わせてチューニング可能です。 - 今回は PoC なので、まずは代表的なカテゴリだけに絞っています。
2-3. ガバナンスモードとの連携
Prism にはもともと、
- FAST: 軽い質問 / 公開情報向け
- HEAVY: 契約・人事などの「重いドメイン」
- FLASH: ニュース・速報系
といったモードがあり、ポリシーに応じてモデルや挙動を切り替えています。
ここに PII 検出結果を組み合わせて、
-
PII が検出された場合は 自動的に「HEAVY」寄りの扱い にする
-
特定のエンティティが含まれている場合は、
- 外部Web検索を禁止
- 回答をサマリに限定
といった振る舞いを policies.yaml から調整できるようにしました。
まだルールはシンプルですが、
「モード × PII × ドメイン でガバナンスを制御する」土台はできたかな、という段階です。
3. README と学習用ドキュメントで「線引き」を明文化する
技術的な PII 対応と同じくらい大事だと感じたのが、
このリポジトリは、本番用ではなく PoC & 学習用 です
ということを、README にちゃんと書くことでした。
3-1. Project Status & Known Limitations
README に以下のようなセクションを追加しました:
-
Project Status
「エンタープライズ向けAIゲートウェイのアーキテクチャ検証 & 学習用 PoC」であること -
Known Limitations
- Auth は Mock / OIDC 連携は未実装
- テナント分離は論理分離のみで、本番SaaSレベルの機能は未実装
- PII 検出は補助的なガードレールであり、運用ルール前提であること
- 観測性・評価・SLO は PoC レベルであること
これを書いたことで、自分の中でも
- どこまでできていて
- どこがまだ穴で
- 次に何を強化すべきか
がかなりクリアになりました。
3-2. backend_explanations / frontend_explanations
もうひとつ大きかったのが、コード全体の「解説書」を作ったことです。
-
backend_explanations.md
main.py/auth.py/rag_kernel.pyなど、主要ファイルを対象に、関数単位で「この処理は何をしているか」を日本語でコメントしています。 -
frontend_explanations.md
Angular のapp.component.ts/chat.service.tsなどを同様に解説しています。
これを作る過程で、
- 自分が理解していない部分
- 命名や責務が分かりにくい部分
がどんどん炙り出され、結果的にリファクタリングの TODO リストにもなりました。
4. ふりかえり:AIと一緒に作ったコードを「自分の設計」に戻していく
Prism は、最初から最後まで AIエージェントとのペアプロ で作っています。
- 「フロント経験ほぼゼロ」から Angular の UI を形にし
- FastAPI / RAG / マルチテナント / PII まで、一気に触ることができた
一方で、
- エージェントが書いたコードを見て「正直よく分からない」と感じることも多く
- 自分の中で 「本当に理解している」とは言えないモヤモヤ も残っていました。
v1.2 で、
- PII という「守り」の観点をちゃんと考え
- README や解説ドキュメントを整理しなおしたことで、
「AIに作ってもらったアプリ」から
「AIの力も借りながら、自分の設計として説明できるアプリ」
に、少しずつ近づいてきた感覚があります。
5. これからやりたいこと
今後は、以下のあたりを順番に潰していきたいと思っています。
- SSO + RBAC + マルチテナントの 本番寄り実装(OIDC連携)
- 回答側への PII / 機密ワードフィルタの適用
- シンプルな 評価パイプライン(RAG / LLM の自動テスト)
- Agent Graph + ガバナンスエージェントによるワークフロー化
Prism のソースコードは GitHub に公開しています(PoC & 学習用 / 商用利用時は要連絡):
同じように「AIを使ってアーキテクト寄りのスキルを伸ばしたい」という方の参考になれば嬉しいです。