1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

〖個人開発〗NLPベースのPII検出と「学習用PoCとしての線引き」をPrismに組み込んだ話 (v1.2: PII Shield & Learning Docs 編)

1
Posted at

はじめに

ここ2ヶ月ほどで、個人開発として 企業向けAIガバナンス基盤「Prism」 を育ててきました。

  • v0.x: 「AIとペアプロして、まずは動くものを作る」
  • v1.0: ハイブリッドRAG + ストリーミングで、ナレッジプラットフォームらしくする
  • v1.1: マルチテナント & RAG完全分離で、SaaSアーキテクチャに近づける

ここまでは「機能を増やす」ことに必死でしたが、だんだんと 「これ、本当に企業で使ったら危ないポイントだらけでは?」 という不安も見えてきました。

そこで v1.2 では、方向性を少し変えて、

  • PII(個人情報)を NLPベースで検出・マスキング する
  • README に 「PoC & 学習用」であること / 制約 / Known Limitations を明示する
  • コードの全体像を理解しやすくするために バックエンド / フロントエンドの解説ドキュメント を用意する

という「セキュリティと学習体験」の2つにフォーカスしてアップデートしました。

この記事では、

  1. なぜ PII 対応を強化したのか
  2. どうやって Microsoft Presidio + spaCy で PII Shield を組み込んだか
  3. README や解説ドキュメントを通して「学習用PoCとしての線引き」をどう言語化したか

をまとめます。


v1.2 の主な変更点

今回のアップデートで追加 / 強化したのは主にこの3つです。

  1. 🛡️ NLPベースの PII Shield
    Microsoft Presidio + spaCy (ja_core_news_lg) を使って、名前・住所・電話番号などを文脈から検出し、LLM 送信前にマスキングします。

  2. 👥 Multi-User / ロール & テナント文脈の明確化
    User, Tenant, TenantMember モデルで「誰が / どのテナントに所属しているか」を管理し、get_current_context で毎リクエストごとに user_id / tenant_id / role を束ねて取得するようにしました。

  3. 📘 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 のチャットフローはざっくり言うと:

  1. ユーザーリクエストを受け取る(メッセージ + 添付ファイルのテキスト)

  2. ガバナンスカーネルで

    • ドメイン判定
    • モード判定(FAST / HEAVY / FLASH)
    • PII 判定 ← ここに Presidio を組み込み
  3. RAG で社内ナレッジを検索

  4. LLM(Gemini)に投げてストリーミングで返す

  5. すべてをログに記録する

今回の変更で、

  • 入力テキスト
  • (ゆくゆくは 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を使ってアーキテクト寄りのスキルを伸ばしたい」という方の参考になれば嬉しいです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?