個人情報マスキング層を自作して生成AIを安全に使う|検出精度88%とClaude API往復を実測

2026.07.08 約 18 分で読めます
個人情報を伏せ字にしてから Claude API に送り、手元の対応表(鍵)で復元する個人情報マスキングの流れを描いたアイキャッチ

「個人情報が入るから、生成AIは使わせられない」。この一言で導入が止まっている会社は多いはずです。私は、送る前に個人情報を伏せ字へ置き換える個人情報マスキング層を Python 標準ライブラリだけで自作しました。その検出精度と、Claude API 往復の品質・コストを実測。検出率は全体 88.0%、往復コストは 10 通で約 9 円でした。取りこぼした 14 件も隠さず、数字ごと全部見せます。

結論:「マスキング層+学習不使用の商用API」の2本柱で前に進める

結論から言うと、生成AIの個人情報リスクは「入れない工夫」と「入っても学習されない契約」の 2 本柱で現実的に抑えられます。前者が今回自作した個人情報マスキング層、後者が Anthropic の商用 API です。実測の要点を先に並べます。

計測項目実測結果
PII 検出精度(20 文書・117 件)再現率 88.0%・適合率 92.8%(F1 90.3%)
プレースホルダーの破損0 件(10 通中 10 通そのまま保持)
復元(アンマスク)成功。実名を見せずに、実名入りの結果を手元で得られた
マスクあり/なしの出力品質対応優先度の判定一致 10/10・情報の欠落なし
コストAPI 20 回で計 $0.055(約 8.8 円・1USD=160 円換算)
平均応答時間約 2.8 秒/件

数字だけ見ると上出来ですが、弱点もはっきり出ました。日本語の人名は約 5 件に 1 件を取りこぼします。この「どこまで信じていいか」の境界線こそ、実測しないと見えない部分でした。順に説明します。

「そのまま入力」の何がまずいのか

先に法とポリシーの土台を 3 分で押さえます。個人情報保護委員会は 2023 年 6 月 2 日、生成AIサービスの利用に関する注意喚起を公表しました。事業者向けの核心はこの一文です。

あらかじめ本人の同意を得ることなく生成AIサービスに個人データを含むプロンプトを入力し、当該個人データが当該プロンプトに対する応答結果の出力以外の目的で取り扱われる場合、当該個人情報取扱事業者は個人情報保護法の規定に違反することとなる可能性がある

個人情報保護委員会「生成AIサービスの利用に関する注意喚起等」(2023年6月2日)

分かれ目は、入力した個人データが「応答を返す」以外の目的——たとえば機械学習——に使われるかどうか。注意喚起は続けて、サービス提供者が個人データを機械学習に利用しないことを十分に確認するよう求めています。裏を返せば、確認できる経路を選び、そもそも個人データを入れない工夫をすれば、議論は前に進みます。

現場の空気も数字に出ています。総務省の令和6年版 情報通信白書によると、生成AIの活用方針を定めている日本企業は 42.7%。米国・ドイツ・中国は約 8 割なので、半分の水準です。約 7 割が「社内情報の漏洩などのセキュリティリスクが拡大すると思う」と回答。一方で約 75% は、業務効率化への効果を期待しています。期待と不安が同居したまま、止まっている構図です。

Claude API はデフォルトで学習に使われない——ただし「商用」に限る

2 本柱の 1 本目から確認します。Anthropic はプライバシーセンターで次のように明言しています。

By default, we will not use your inputs or outputs from our commercial products to train our models.(デフォルトでは、商用製品からの入力・出力をモデルの学習に使用しません)

Anthropic Privacy Center: Is my data used for model training?

見落としやすいのが consumer と commercial の区別です。学習に使われないのは Anthropic API や Claude for Work などの商用製品の話。個人向けの Free / Pro / Max プランは別のポリシーで、設定でオフにしない限り学習に使われます。「Claude だから安全」ではなく、どの製品をどの設定で使うかで決まります。個人アカウントのチャット画面に顧客情報を貼り付けるのは、商用 API の利用とはまったく別の行為です。

では商用 API なら個人データを入れ放題かというと、そうではありません。利用目的の範囲内かどうかの確認や安全管理措置は残ります。そこで 2 本柱のもう 1 本、「そもそも個人情報を送らない」ためのマスキング層を作りました。

作ったもの:ローカルで完結する個人情報マスキング層

個人情報マスキングの仕組みは図の通りです。文書をマスキング層に通して個人情報をプレースホルダーへ置き換え、マスク済みテキストだけを Claude に送ります。結果はプレースホルダー付きで返ってくるので、手元の対応表で元に戻す。個人情報が越えてはいけない境界線を、アーキテクチャで固定する発想です。

個人情報マスキング層のアーキテクチャ図。社内で文書をプレースホルダーに置換し、マスク済みテキストだけをClaude APIへ送り、返ってきた結果を対応表で復元する。対応表はローカルから出さない
個人情報は点線の右(社外)へ出さない。対応表が手元にある限り、外に出た情報から個人は特定できない

検出ルール:構造化PIIは正規表現、人名は文脈+辞書

マスキング層は Python 3.13 の標準ライブラリだけで書きました。pip install が不要だと、社内 PC への配布がぐっと楽になるからです。検出は 2 系統に分けています。

  • 構造化 PII(メール・電話・郵便番号・住所・生年月日・カード番号・マイナンバー)……正規表現。全角・半角の揺れも吸収する
  • 人名……「様」「さん」などの敬称、「担当:」などのラベル、役職語の文脈パターンに、常用姓の辞書(約 130 姓)を組み合わせる

この分野には Microsoft の OSS「Presidio」がありますが、今回は使いませんでした。公式 FAQ にある通り日本語はビルトイン対応外で、新しい言語への適応は自作が前提だからです。英語向けツールを曲げるより、日本語専用に小さく作るほうが早いと判断しました。

設計で効いたのは検出の順番です。カード番号 → マイナンバー → 電話 → 郵便番号の順で先に範囲を確定し、確定済みの範囲に重なる候補は捨てる。こうしないと、16 桁のカード番号の内側を電話番号のパターンが食い荒らします。生年月日は「生年月日」「生まれ」などのラベルが近くにある日付だけをマスクする文脈ゲートにしました。会議の日付まで伏せ字になると、要約のほうが壊れるからです。

可逆マスキング:対応表は社内から出さない

置換は【氏名1】【電話1】のような連番プレースホルダーで行い、元の値との対応を JSON の対応表に保存します。実物はこんな形です。

{
  "【氏名1】": "佐藤健一",
  "【メール1】": "sato.kenichi@midori-shokai.co.jp",
  "【電話1】": "090-1234-5678"
}

同じ人名が何度出ても同じ番号に正規化するので、Claude 側は「誰が誰か」の区別を保ったまま文脈を追えます。復元はこの対応表で逆置換するだけ。顧客リストの名寄せを AI にやらせた記事でも痛感しましたが、日本語の人名は機械処理の鬼門です。その弱点がどの程度残るのか、次で実測します。

マスキングを外部SaaSに任せる構成は本末転倒になりうる

検索すると「AI が個人情報を自動でマスキングします」という Web サービスも複数見つかります。ただ、構成をよく見てください。マスキングのために生の個人情報をそのサービスへ送るなら、データの預け先が生成AIからマスキング業者に変わっただけです。委託先管理の論点はそのまま残ります。今回ローカル完結にこだわったのは、この矛盾を避けるためでした。

実測①:検出精度は全体 88.0%——見逃し 14 件も全部見せる

架空のビジネス文書 20 件(問い合わせメール 10・議事録 5・CRM メモ 5)に、117 個の個人情報を仕込んで検出させました。文書と正解データは同じソースから同時に生成しているので、突合は機械的に行えます。実在の個人情報は一切使っていません。

PII種別ごとの検出精度(再現率・適合率)の横棒グラフ。メール・郵便番号・マイナンバーは100%、人名は再現率78.3%と最も低く、全体では再現率88.0%・適合率92.8%
形の決まった情報はほぼ完封。差が出たのは日本語の人名だった
種別件数再現率適合率見逃し
メール18100%100%0
郵便番号6100%100%0
マイナンバー5100%100%0
電話番号21100%95.5%0
住所785.7%100%1
カード番号580.0%100%1
生年月日977.8%100%2
人名4678.3%83.7%10
全体11788.0%92.8%14

メール・郵便番号・マイナンバーは 100%、電話番号も再現率 100% でした。形の決まった情報は正規表現でほぼ完封できます。問題は人名です。再現率 78.3%、約 5 件に 1 件の取りこぼし。その中身がこちらです。

見逃し 14件の内訳(実物)
├─ 人名 10件
│   ├─ 「鈴木」……… 敬称なしの単独姓 ← 文脈の手がかりゼロ
│   ├─ 「綿引」……… 辞書外の姓 ← 約130姓のリストに無い
│   └─ 「高橋 恵子」… 姓名間のスペース+敬称なし(ほか7件も同型)
├─ 生年月日 2件 …… 名簿にラベル無しで並ぶ日付 ← 文脈ゲートの代償
├─ カード番号 1件 … Amex の15桁(4-6-5 区切り)に正規表現が非対応
└─ 住所 1件 ………「京都市中京区烏丸通御池上ル」← 番地の数字が無い京都表記

誤検出も 8 件ありました。「お客様相談室 様」の「相談室」を人名と誤認する。社名「山田製作所」の一部に反応する。フリーダイヤルを電話番号としてマスクする——といった方向です。こちらは情報が余分に隠れるだけなので、漏えいには直結しません。怖いのは逆方向、つまり見逃しのほうです。

さらに悔しかったのが部分検出の 5 件です。「中川由美子」を「中川由美」までマスクして「子」が残る。「太田 幸子」が全角スペースで割れて「太田」が残る。氏名の断片が未マスクのまま残るこのパターンは、正規表現と辞書の素朴な組み合わせの限界をよく示しています。

実測②:マスク済みの文章で Claude の品質は落ちるのか

次が本命の往復です。タスクは、問い合わせメール 10 通の「3 行要約+対応優先度+次のアクション」への整理。マスクあり(Run A)とマスクなし(Run B)の両方を claude-sonnet-4-6 に投げます(SDK は anthropic 0.116.0)。マスクなしを対照実験にできるのは全部が架空データだからで、本番で Run B はやりません。同じ 1 通がどう流れるか、実物を 4 段で見せます。

① 元のメール(抜粋)
株式会社ミドリ商会の佐藤健一と申します。
登録メールアドレスは sato.kenichi@midori-shokai.co.jp です。
日中は携帯 090-1234-5678 にご連絡ください。

② マスク後(Claude に送るのはこれだけ)
株式会社ミドリ商会の【氏名1】と申します。
登録メールアドレスは 【メール1】 です。
日中は携帯 【電話1】 にご連絡ください。

③ Claude の出力(実名を一度も見ていない)
要約1: 株式会社ミドリ商会【氏名1】よりログイン不可の問い合わせ
優先度: 高
次アクション: ログイン障害の原因確認後【電話1】または【メール1】へ折り返す

④ 対応表で復元(手元で実名に戻す)
次アクション: ログイン障害の原因確認後 090-1234-5678 または
sato.kenichi@midori-shokai.co.jp へ折り返す

社名や製品名はマスクしない設計なので、「どの会社の何の話か」は保たれたままです。Claude は【氏名1】を人名の記号として素直に扱い、10 通すべてでプレースホルダーを壊さずに返しました。出力に生の個人情報が混ざった件数は 0。そもそも渡していないので、混ざりようがありません。

品質差は「敬称の付き方」だけだった

肝心の中身はどうか。対応優先度(高・中・低)の判定は 10 通中 10 通で一致しました。要約の情報量にも欠落は見つからず、唯一の差は、実名を見ている Run B が「佐藤健一氏」のように敬称を補うことがある程度。少なくとも問い合わせのトリアージ用途では、マスキングは品質の足を引っ張りませんでした。請求書を Claude の画像認識で CSV 化した実測でも感じましたが、型の決まった事務処理はこのモデルの得意分野です。

コスト:10 通の往復で約 4.6 円。マスキングの上乗せは約 6%

指標Run A(マスクあり)Run B(マスクなし)
入力トークン計3,8493,034
出力トークン計1,1261,177
コスト$0.02844(約 4.6 円)$0.02676(約 4.3 円)
平均応答時間/件2.78 秒2.82 秒

20 回の呼び出し合計で $0.055、約 8.8 円でした(単価は公式の料金ページにある入力 $3・出力 $15/100 万トークンで算出)。1 通あたり 0.5 円足らず。ただし正直に書くと、マスクありは入力トークンが 26.9% 増えます。【氏名1】のような日本語プレースホルダーは、元の短い姓名よりトークンを消費するからです。それでもコスト差は全体で約 6%、安全料としては誤差の範囲だと思います。

向かない場面と限界——マスキングは「ゼロ化」ではない

ここまでの数字は上々ですが、この構成を銀の弾丸として薦めるつもりはありません。実測で突きつけられた限界を並べます。

  • 見逃した個人情報はそのまま外に出る。今回も「鈴木」「高橋 恵子」などの姓名や京都の住所は、マスクを素通りして Claude に送信されました。マスキングは送信量の最小化であって、ゼロ化ではありません
  • マスキングしても法対応は完結しない。利用目的の範囲内かの確認や安全管理措置は引き続き必要です。また、置換しただけのテキストは個人情報保護法の「匿名加工情報」とは別物です
  • 精度と読みやすさはトレードオフ。生年月日の文脈ゲートを緩めれば取りこぼしは減りますが、会議の日付まで伏せ字になって要約が壊れます。どちらに倒すかは業務ごとの判断です
  • 自動検出に 100% は無い。この分野の代表 OSS である Presidio 自身が、公式 FAQ で「すべての機微情報の発見は保証しない」と明言しています

だから運用は多層になります。①マスキング層で送る量を減らし、②学習不使用が明記された商用 API を選び、③最後に人の目のレビューを挟む。自サイトのセキュリティを多層防御で組んだときと同じで、1 枚の壁にすべてを賭けない設計です。

向かない場面もあります。宛名の差し込みのように個人情報そのものを AI に加工させたいタスクは、マスクすると成立しません。人名の完全な秘匿が契約上求められる案件でも、再現率 78.3% の人名検出を単独で信じるのは危険です。その場合は辞書の拡充と人手チェックの併用が前提になります。

まとめ:数字を持って稟議に行く

  • 個人情報マスキング層は Python 標準ライブラリだけで自作できた。検出精度は全体 88.0%(構造化 PII はほぼ 100%・人名 78.3%)
  • マスクした文章でも Claude の処理品質は落ちず、優先度判定は 10/10 で一致。復元まで含めて往復が成立した
  • コストは 1 通 0.5 円未満。マスキングによる上乗せは約 6% にとどまった
  • ただし見逃しは必ず残る。学習不使用の商用 API と人のレビューを重ねる多層構成が前提

「セキュリティが不安だから全面禁止」のままでは、生成AIへの期待も止まったままです。伏せ字にする、学習されない経路を選ぶ、精度を数字で示す——ここまで揃えると、稟議の議論は前へ進みます。この記事のような「マスキング込みの安全な生成AI導入」は、NEORIVA として法人向けの設計・構築もやっています。ほかの実測記録は業務自動化・API連携のカテゴリにまとめているので、あわせてどうぞ。

こま

こま

元SE × AI開発 × 業務自動化の実践者

SE 4年 + プログラミング歴 8年。業務自動化と AI 組み込み開発を仕事にしながら、現場で使えるものだけを書いています。 最新のAIの現場を発信中!!