業務用スクリプトの依頼文に入力・出力・エラー処理のルールを入れる
「これを自動化して」を、実行可能な task description に変えます。sensitive data を含まない合成 sample と、手作業で確認した expected result を添えて、team ごとの work logs を集計する script request を完成させます。
AIチャットアシスタントにテキストを送る前に、明らかな個人情報を削除または置換し、マスキング後の本文と検出レポートの両方を確認して見落としを探します。このチュートリアルでは小さな合成例を使い、元ファイルは変更しません。
この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 English
対象読者氏名、メールアドレス、電話番号を含む可能性がある業務テキストをAIアシスタントに送る前に、実用的な事前確認を行いたい人向けです。
この例はすべて合成データです。氏名、メールアドレス、電話番号、会社情報、メッセージ内容はチュートリアル用に作成した架空のものです。目的は、テキストがローカル環境を離れる前に、明らかな個人情報を除去する練習をすることです。
次のテキストをmessage.txtとして保存します。氏名2件、メールアドレス2件、電話番号2件に加え、単純なマスキング規則では見逃すように意図的に曖昧にした参照1件が含まれています。
Project review notes
Alice Kim asked us to send the revised table to alice.kim@example.com.
If the file is delayed, call Alice at 010-1234-5678.
Bob Lee will review the second draft. His email is bob.lee@example.com and his office number is 02-345-6789.
The final approval should also be checked with A. Kim before Friday.
実際の機密文書を送らなくても、AIアシスタントにマスキング規則の設計方法を聞くことはできます。対象カテゴリを説明し、実際の値ではなく架空の例を使います。
有用な回答では、構造化された識別子と自然言語を区別する必要があります。メールアドレスや電話番号には比較的認識しやすいパターンがあることが多い一方、人名はより難しい対象です。一般語が名前になる場合もあり、イニシャルや複数の文字体系が使われることもあり、同じ人物が複数の表記で登場することもあります。
この合成例では、氏名には小さな承認済みリストを使い、メールアドレスと電話番号には正規表現を使います。これは一般的な個人情報検出器よりも意図的に範囲を狭くしています。
| データ種別 | 規則 | プレースホルダー |
|---|---|---|
| フルネーム | 承認済みの正確な氏名Alice KimとBob Leeだけを置換 | [NAME_1], [NAME_2] |
| メール | ローカル部、@、ドメインを含む一般的なアドレス形式を検出 | [EMAIL_1], [EMAIL_2] |
| 電話番号 | この例に含まれる2種類の電話番号形式を検出 | [PHONE_1], [PHONE_2] |
| その他のテキスト | 手動確認のため変更せず残す | 自動置換なし |
一貫したプレースホルダーを使うと、元の識別子を残さずに繰り返し参照の関係を保てます。下のスクリプトでは、同じ検出値が複数回出現しても同じプレースホルダーを割り当てます。
次のPythonスクリプトはmessage.txtを読み、承認した規則を適用して、新しいoutputsフォルダに結果を書き出します。検出した元の値とプレースホルダーをすべて含むreplacements.csvも作成します。outputsがすでに存在する場合は停止し、message.txtは決して上書きしません。
import csv
import re
import sys
from pathlib import Path
INPUT = Path("message.txt")
OUTPUT_DIR = Path("outputs")
MASKED_FILE = OUTPUT_DIR / "message_masked.txt"
REPORT_FILE = OUTPUT_DIR / "replacements.csv"
KNOWN_NAMES = ["Alice Kim", "Bob Lee"]
EMAIL_RE = re.compile(
r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b"
)
PHONE_RE = re.compile(
r"(?<!\d)(?:010-\d{4}-\d{4}|02-\d{3}-\d{4})(?!\d)"
)
def make_replacer(kind, mapping, rows):
def replace(match):
original = match.group(0)
if original not in mapping:
placeholder = f"[{kind}_{len(mapping) + 1}]"
mapping[original] = placeholder
rows.append(
{
"type": kind,
"original": original,
"replacement": placeholder,
}
)
return mapping[original]
return replace
def mask_known_names(text, mapping, rows):
for name in KNOWN_NAMES:
if name not in text:
continue
if name not in mapping:
placeholder = f"[NAME_{len(mapping) + 1}]"
mapping[name] = placeholder
rows.append(
{
"type": "NAME",
"original": name,
"replacement": placeholder,
}
)
text = text.replace(name, mapping[name])
return text
def main():
if not INPUT.is_file():
sys.exit(f"Input file not found: {INPUT}")
if OUTPUT_DIR.exists():
sys.exit(f"Stop: {OUTPUT_DIR} already exists. Review or rename it first.")
original = INPUT.read_text(encoding="utf-8")
rows = []
name_map = {}
email_map = {}
phone_map = {}
masked = mask_known_names(original, name_map, rows)
masked = EMAIL_RE.sub(make_replacer("EMAIL", email_map, rows), masked)
masked = PHONE_RE.sub(make_replacer("PHONE", phone_map, rows), masked)
OUTPUT_DIR.mkdir()
MASKED_FILE.write_text(masked, encoding="utf-8")
with REPORT_FILE.open("x", encoding="utf-8", newline="") as target:
writer = csv.DictWriter(
target,
fieldnames=["type", "original", "replacement"],
)
writer.writeheader()
writer.writerows(rows)
print(f"Unique names masked: {len(name_map)}")
print(f"Unique emails masked: {len(email_map)}")
print(f"Unique phones masked: {len(phone_map)}")
print(f"Masked copy: {MASKED_FILE}")
print(f"Replacement report: {REPORT_FILE}")
if __name__ == "__main__":
main()
mask_personal_data.pyをmessage.txtと同じフォルダに置き、python mask_personal_data.pyで実行します。この例で期待される結果は、ユニークな氏名2件、メールアドレス2件、電話番号2件がマスキングされることです。
結果を信頼する前に、期待される置換内容を手作業で確認します。このスクリプトでは、ユニークに検出された6件の値が記録されるはずです。
| 種類 | 元の値 | 置換後 |
|---|---|---|
| NAME | Alice Kim | [NAME_1] |
| NAME | Bob Lee | [NAME_2] |
| alice.kim@example.com | [EMAIL_1] | |
| bob.lee@example.com | [EMAIL_2] | |
| PHONE | 010-1234-5678 | [PHONE_1] |
| PHONE | 02-345-6789 | [PHONE_2] |
Alice Kimは元の文章に2回登場しますが、どちらも[NAME_1]に置き換わる必要があります。レポートには出現回数ごとの行ではなく、ユニークに検出された値だけが記録されます。
自動置換は最初の段階にすぎません。どこかに貼り付ける前にoutputs/message_masked.txt全体を読み直してください。この例では、最後の段落にA. Kimが残っています。承認済みリストだけでは、スクリプトはこれがAlice Kimを指している可能性を判断できません。
実際の運用では、文書の性質、適用される規定、AI作業の目的に基づいて何を除去すべきか定義します。可能であれば、大きな文書全体をマスキングして送るより、作業に必要な最小限のテキストだけを提供する方が安全です。
2026-09-21 · hand-checked example · Python 3.12
説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。