はじめに
生成AIを業務や学習で利用するときは、どのようなプロンプトを書くかだけでなく、AIへ渡す情報を事前に整理することも重要です。
私は、AIへ相談する際には、目的に不要な情報を含めず、背景や条件も必要な範囲に絞ることを基本としています。
また、ChatGPTのデータコントロールでは、「すべての人のためにモデルを改善する」設定をオフにしています。
ただし、サービス側の設定だけに依存するのではなく、入力前の段階で不要な情報を減らすことも必要です。
そこで、AIへ入力する文章に対して、自分で指定した語句をExcelで管理し、Pythonを使ってローカル環境で置換する方法を作りました。
この記事では、次の流れを紹介します。
- Excelで置換ルールを管理する
- Pythonで指定語句をローカル置換する
- 置換結果を人が確認する
- 確認済みの文章をプロンプトへ使用する
この処理は、完全な匿名化を保証するものではありません。
入力情報を必要最小限にし、人による確認を補助するための予防的な方法として使用します。
目的
今回の目的は、生成AIへ文章を送信する前に、相談内容に不要な語句をローカル環境で置換できるようにすることです。
置換対象をPythonコードへ直接書かず、Excelで管理することで、コードを修正せずにルールを追加、変更、無効化できるようにします。
処理の流れは次のとおりです。
入力する文章を準備する
↓
置換ルールをExcelへ登録する
↓
Pythonをローカル環境で実行する
↓
置換後の文章を人が確認する
↓
不要な背景をさらに削除・一般化する
↓
確認済みの文章をプロンプトへ使用する
重要なのは、置換処理だけで情報管理が完了すると考えないことです。
単純な文字列置換では、表記揺れ、誤置換、文脈からの推測可能性などを完全には処理できません。
そのため、置換後も必ず人が内容を確認します。
やったこと
Excelで置換ルールを管理する
置換対象をPythonコードへ直接書くと、語句を追加するたびにコードを修正する必要があります。
そこで、置換ルールはExcelで管理します。
Excelには、次の列を用意します。
| 列名 | 内容 |
|---|---|
source_text |
置換前の語句 |
replacement_text |
置換後の語句 |
category |
語句の分類 |
enabled |
置換ルールを使用するか |
以下は、処理方法を説明するための架空のサンプルです。
| source_text | replacement_text | category | enabled |
|---|---|---|---|
| サンプル固有語句A | 一般語句A | term | TRUE |
| サンプル固有語句B | 一般語句B | term | TRUE |
| サンプル固有語句C | 一般語句C | term | FALSE |
Excelのシート名は、rulesとします。
enabledをTRUEにした行だけを置換対象にします。
このExcelには置換前の語句が含まれるため、公開リポジトリや一般共有用のフォルダーには保存しません。
アクセスを限定したローカル環境または非公開の保存領域で管理します。
必要なファイルを用意する
次の3つのファイルを、同じフォルダーへ配置します。
masking_rules.xlsx
input_text.txt
mask_text.py
それぞれの役割は次のとおりです。
| ファイル | 役割 |
|---|---|
masking_rules.xlsx |
置換ルールを管理する |
input_text.txt |
AIへ入力する前の文章を保存する |
mask_text.py |
ローカル置換を実行する |
処理後は、同じフォルダーにmasked_text.txtが作成されます。
Pythonで指定語句をローカル置換する
掲載しているコードは、処理の考え方を示すために簡略化したものです。
from pathlib import Path
from typing import Final
import pandas as pd
RULES_PATH: Final[Path] = Path("masking_rules.xlsx")
INPUT_PATH: Final[Path] = Path("input_text.txt")
OUTPUT_PATH: Final[Path] = Path("masked_text.txt")
REQUIRED_COLUMNS: Final[set[str]] = {
"source_text",
"replacement_text",
"enabled",
}
ENABLED_VALUES: Final[set[str]] = {
"true",
"1",
"yes",
"on",
}
def load_replacement_rules(
excel_path: Path,
) -> list[tuple[str, str]]:
if not excel_path.exists():
raise FileNotFoundError(
f"置換ルールファイルが見つかりません: {excel_path}"
)
dataframe = pd.read_excel(
excel_path,
sheet_name="rules",
dtype=str,
).fillna("")
missing_columns = REQUIRED_COLUMNS - set(dataframe.columns)
if missing_columns:
missing = ", ".join(sorted(missing_columns))
raise ValueError(
f"Excelに必要な列がありません: {missing}"
)
rules: list[tuple[str, str]] = []
for row_number, row in dataframe.iterrows():
enabled = row["enabled"].strip().lower()
if enabled not in ENABLED_VALUES:
continue
source_text = row["source_text"].strip()
replacement_text = row["replacement_text"].strip()
if not source_text:
continue
if not replacement_text:
raise ValueError(
f"{row_number + 2}行目のreplacement_textが空です"
)
if source_text == replacement_text:
continue
rules.append(
(
source_text,
replacement_text,
)
)
# 一部が重なる語句は、長い語句から先に置換する
rules.sort(
key=lambda item: len(item[0]),
reverse=True,
)
return rules
def replace_defined_terms(
text: str,
rules: list[tuple[str, str]],
) -> tuple[str, dict[str, int]]:
replaced_text = text
replacement_counts: dict[str, int] = {}
for source_text, replacement_text in rules:
count = replaced_text.count(source_text)
if count == 0:
continue
replaced_text = replaced_text.replace(
source_text,
replacement_text,
)
replacement_counts[replacement_text] = (
replacement_counts.get(replacement_text, 0)
+ count
)
return replaced_text, replacement_counts
def main() -> None:
if not INPUT_PATH.exists():
raise FileNotFoundError(
f"入力ファイルが見つかりません: {INPUT_PATH}"
)
rules = load_replacement_rules(
RULES_PATH,
)
input_text = INPUT_PATH.read_text(
encoding="utf-8",
)
masked_text, replacement_counts = replace_defined_terms(
input_text,
rules,
)
OUTPUT_PATH.write_text(
masked_text,
encoding="utf-8",
)
print(
f"置換後のテキストを保存しました: {OUTPUT_PATH}"
)
if not replacement_counts:
print("置換された語句はありませんでした。")
return
print("置換結果:")
for replacement_text, count in replacement_counts.items():
print(
f"- {replacement_text}: {count}件"
)
if __name__ == "__main__":
main()
このコードは、次の処理を行います。
- Excelから置換ルールを読み込む
-
enabledが有効な行だけを使用する - 長い語句から先に置換する
- 入力テキストをローカル環境で処理する
- 置換後の文章を別ファイルへ保存する
- 置換後の語句と件数を画面に表示する
元のinput_text.txtは上書きせず、置換後の文章をmasked_text.txtへ保存します。
必要なライブラリをインストールする
このコードでは、Excelを読み込むためにpandasとopenpyxlを使用します。
PowerShellまたはターミナルで、次のコマンドを実行します。
python -m pip install pandas openpyxl
インストール後、ファイルを保存したフォルダーで次のコマンドを実行します。
python mask_text.py
正常に処理されると、masked_text.txtが作成されます。
置換結果を確認する
置換が完了しても、そのままAIへ入力することはしません。
masked_text.txtを開き、次の点を確認します。
- 置換したい語句が残っていないか
- 無関係な部分が誤って置換されていないか
- 置換後も文章の意味が通じるか
- 略称や別表記が残っていないか
- 背景から対象を推測できないか
- 相談に不要な情報が残っていないか
必要に応じて、文章をさらに短くしたり、背景を一般化したりします。
実際にAIへ入力するのは、この確認を終えた文章です。
元の文章
↓
Excelのルールでローカル置換
↓
置換後の文章を人が確認
↓
不要な背景を削除・一般化
↓
確認済みの文章をプロンプトへ使用
プロンプトへ入力する
置換済みの文章を使用する場合は、AIへ求める処理も明確にします。
以下の文章は、相談に不要な情報を減らすため、
事前にローカル環境で一部の語句を置換しています。
置換された名称を推測したり、
元の名称を復元しようとしたりしないでください。
文章に含まれる論点だけを使い、
次の観点で整理してください。
1. 問題点
2. 判断に必要な情報
3. 考えられる対応案
4. 追加で人が確認すべき点
不明な情報を推測で補わず、
不足している点は不足していると示してください。
対象の文章:
(置換・確認済みの文章をここに貼り付ける)
このプロンプト自体が、情報管理を保証するものではありません。
重要なのは、AIへ送信する前に、入力内容を必要最小限にしておくことです。
注意点
置換ルールのExcel自体を慎重に管理する
置換ルールのExcelには、置換前と置換後の語句の対応が記録されています。
そのため、置換後の文章よりも、Excelの方が慎重な管理を必要とする場合があります。
次の場所には保存しない方針とします。
- 公開リポジトリ
- 一般共有用のフォルダー
- 公開用の記事データ
- 不特定多数がアクセスできる保存先
Pythonコードと、実際の置換ルールExcelは分けて管理します。
公開するのは処理の考え方を示すコードだけであり、実際の置換ルールは公開しません。
置換は完全な匿名化ではない
語句を置き換えても、次の情報の組み合わせから対象を推測できる可能性があります。
- 特徴的な業務内容
- 時期
- 地域
- 役割
- 条件
- 使用環境
- 特殊な経緯
そのため、外部サービスへ入力する場合は、単語の置換だけでなく、文章全体の一般化や再構成も必要です。
表記揺れは自動では処理できない
同じ対象でも、複数の表記が使われることがあります。
- 正式名称と略称
- 全角と半角
- 大文字と小文字
- スペースの有無
- 日本語名と英語名
- 漢字、ひらがな、カタカナ表記
- 敬称の有無
Excelへ登録されていない表記は、単純な文字列置換では処理されません。
必要に応じて、別表記を複数のルールとして登録します。
短い語句は誤置換しやすい
短い略称や一般的な単語を登録すると、無関係な文章まで置換する可能性があります。
そのため、短すぎる語句の登録はできるだけ避けます。
コードでは長い語句から先に置換していますが、誤置換を完全に防ぐものではありません。
置換順序で結果が変わる場合がある
一部が重なる語句を登録すると、置換順序によって結果が変わることがあります。
例えば、長い語句と、その一部を含む短い語句が登録されている場合、短い語句を先に置換すると、長い語句を正しく処理できない可能性があります。
そのため、コードでは文字数の長い語句から先に処理しています。
元ファイルを上書きしない
元の文章を直接上書きすると、置換ミスがあった場合に確認できなくなります。
そのため、原文と置換後のファイルは分けて保存します。
input_text.txt
masked_text.txt
元ファイルも、アクセスを限定した環境で管理します。
ログへ置換前の語句を出さない
置換対象をログや画面へ表示すると、別の場所に情報が残る可能性があります。
今回のコードでは、置換後の語句と件数だけを表示しています。
次の場所に、置換前の語句を不用意に出力しないよう注意します。
- コンソールログ
- エラーログ
- 処理履歴
- スクリーンショット
- GitHub Issue
- チャット
- メール
自動処理だけで判断しない
Pythonで置換できたことや、AIが問題ないと回答したことだけを、安全性の根拠にはしません。
最終的には、人が文章全体を確認します。
確認する内容には、次のようなものがあります。
- 文脈から対象を推測できないか
- 第三者に不利益を与えないか
- 契約上の制約がないか
- 第三者の権利を侵害しないか
- 入力する必要性があるか
- 一般化後も相談に必要な内容か
置換後でも自由に利用できるとは限らない
語句を置換したからといって、すべての情報を自由に利用できるわけではありません。
次のような内容は、置換後であっても別途確認が必要です。
- 契約上の秘密保持義務
- 個人情報
- 著作権
- 第三者から提供された資料
- 業務上知り得た非公開情報
- 成果物や知的財産の帰属
- 営業秘密
- 各組織の情報セキュリティ規程
固有語句を置換したことと、その情報を利用する権限があることは別の問題です。
ローカル処理でも安全が保証されるわけではない
AIへ送信する前にローカル環境で処理しても、それだけで安全性が保証されるわけではありません。
次の点も確認が必要です。
- PCの利用者とアクセス権
- OSやソフトウェアの更新
- マルウェア対策
- バックアップ
- クラウド同期の設定
- 共有フォルダーの設定
- ファイルの保存期間
- 廃棄時の削除方法
Excelファイルがクラウド同期の対象になっている場合は、共有設定やアクセス範囲も確認します。
外部ライブラリの利用にも注意する
今回のコードでは、Excelを読み込むためにpandasとopenpyxlを使用しています。
利用する際は、次の点を確認します。
- 信頼できる配布元からインストールする
- 不要な外部サービスへファイルをアップロードしない
- コードへ置換対象の語句を直接書かない
- サンプルコードと実際のルールファイルを分ける
- 公開前にコード内のパスやコメントを確認する
実際に得られたこと
Excelで置換ルールを管理することで、Pythonコードを修正せずに、置換対象を追加、変更、無効化できるようになりました。
また、元の文章を上書きせず、置換後の文章を別ファイルとして確認できるようになりました。
今回の処理は、次の流れにまとめられます。
不要な情報を入力しない
↓
必要に応じて指定語句をローカル置換する
↓
置換結果を人が確認する
↓
背景をさらに削除・一般化する
↓
確認済みの文章だけをAIへ入力する
ただし、自動置換だけで確認作業を完了できるわけではありません。
表記揺れ、誤置換、文脈からの推測可能性などについては、人による確認が必要です。
おわりに
生成AIを利用するときは、プロンプトの書き方だけでなく、何を入力するかを事前に整理することも重要です。
今回の方法では、自分で指定した語句をExcelで管理し、Pythonを使ってローカル環境で置換しました。
置換後の文章は必ず人が確認し、必要に応じて背景を削除・一般化したうえでAIへ入力します。
今回の方針は、次の4点にまとめられます。
AIの設定だけに依存しない
入力前に不要な情報を減らす
指定語句はローカル環境で置換する
自動処理後も必ず人が確認する
一方で、置換処理は完全な匿名化を保証するものではありません。
また、置換後であっても、契約上の秘密保持義務、第三者の権利、個人情報、非公開情報などに関係する内容を自由に利用できるとは限りません。
Pythonは情報管理の判断を置き換えるものではなく、入力前の確認作業を補助する手段として利用します。