🐕

ChromeビルトインAI Gemini Nanoを使ってオフラインの個人情報バリデーション

2024/12/14に公開

作ったもの


個人情報を入力しているため動画にぼかし処理を入れています

実際のデモページ

https://1spdv09llzlygkq2a6qst3dbewlfgf0h.vercel.app/

タイトルの通りですが、Chrome版 Gemini NanoでAIが個人情報のバリデーションを行うフォームを作成しました。

背景

ユーザーがフォームに入力した内容に、個人情報が含まれてしまっていないかをチェックするのは非常に重要です。

例えば、ユーザーの入力を元にLLMが回答を行うようなチャットボットを作る場合、通常ChatGPTであればOpenAI、GeminiであればGoogleなど第3者のサーバーへ個人情報を送信してしまう可能性も出てきてしまいます。

そこで、ユーザーの入力に個人情報が含まれていないことをLLMにチェックさせることはできないかと考えるのですが、LLMを使用するとOpenAIやGoogleに情報を送信してしまうので本末転倒です。そんな矛盾を解決できそうなのが、Chrome版 Gemini Nanoです。

Chrome版 Gemini Nano とは

2024年5月に開催されたGoogle I/O 2024で、ChromeにGemini NanoのAIモデルが直接組み込まれることが発表されました。

この機能によりデベロッパーはクライアントサイドのJavaScriptからローカルのAIモデルにアクセスすることができます。

公式のドキュメントではそのメリットとして以下の点を挙げています。

機密データのローカル処理: クライアントサイド AI はプライバシー保護に役立ちます。たとえば、機密データを扱う場合は、エンドツーエンドの暗号化を使用してユーザーに AI 機能を提供できます。

解決したかった矛盾を解消してくれそうなので、実験的に触ってみることにしました。

Gemini Nanoのセットアップ

Chromeチームが公開しているGoogle Documentの資料に従えば難なくセットアップできました。
注意点として、(ドキュメントに記載はありますが)ブラウザの適当なコンソール上でawait ai.languageModel.create();を一度コールしないとモデルのダウンロードが開始されなかったのが引っかかりポイントかなと思います。
ChromeはCanalyやDevチャンネルのバージョンが推奨されていますが、私の環境ではStable版のChrome v131で動作しました。

プロンプト

正直、ここが一番苦労した部分でした。ポイントをいくつか挙げます。

構造化データ(Json)の出力

Reactのコード上で扱いやすいよう、AIからJson形式の文字列を受け取るように実装しています。

{
  "sensitivity_score": 0.6,  // 機密情報を含んでいると類推される度合いのスコア
  "reason": "理由テキスト" // テキストが機密情報に当たる理由のテキスト
}

OpenAIやGeminiのようなLLMにはStructured OutputsFunction callingの機能によりJson形式の出力を簡単にAIから得るインターフェースが用意されています。
しかし、Gemini Nanoには現状そのようなインターフェースはないため、プロンプトによりJson形式の文字列を出力するようルールを与えています。
ただし、それでもAIがJson形式の文字列で出力しない場合があるため、コード上でも例外処理を記載しています。

Gemini Nanoが英語の出力しかできない

現在Gemini Nanoは英語の出力しかできないよう制限されています。(これは公式のガイドでも説明されています)
そのためデモではバリデーションエラーのメッセージが英語でのみ出力される感じになっています。

また、AIが実際に英語の応答を返さないようなケースで、APIからThe model attempted to output text in an untested languageのエラーメッセージが出力されることを確認しました。

今回のデモでは英語で出力を行うようプロンプトでルールを与えています。
ただし、こちらも入力の言語に引きずられてしまうことがあるため、コード上で例外処理を記載しています。

最終的に完成したプロンプト

ChatGPTの手も借りながら作成したプロンプトは以下のようになりました。

You are an AI tasked with checking whether a user's input contains sensitive information. Output the results in JSON format that can be used programmatically. Ensure the output is in English and does not include code block formatting (e.g., backticks). The JSON structure should follow this format:

{
  "sensitivity_score": 0 to 1,  // Probability that the input contains sensitive information (0 is lowest, 1 is highest)
  "reason": "A concise explanation of why the information is deemed sensitive (null if sensitivity_score is 0)"
}

## Guidelines
1. Analyze the input for sensitive information such as personally identifiable information (PII), credit card numbers, passwords, etc.
2. sensitivity_score should be a number between 0 and 1. A score closer to 1 indicates a higher likelihood that sensitive information is present.

## Mandatory Rules
You must follow these rules strictly:
1. If sensitivity_score is 0, set the reason to null.
2. The reason field must be in English.
3. Do not use code block formatting (e.g., backticks). The JSON output must be presented as plain text.

少数ショットの例(Few-shot examples)も試しましたが、モデルが例に引きずられてよい回答を得られなかったので使用しないことにしました。
また、TemperatureやTop-P、Top-Kのようなパラメーターもレスポンスのランダム性を調整する方法としてあるようでしたが、今回はGemini Nanoの純粋な性能を見たかったので扱わないことにしています。[1]

ソースコード

UIなどのベーシックな部分のコードはv0を使って構築しました。


一回のやりとりでここまでやってくれるv0だいすき

ただし、Prompt APIを呼び出す部分はせっかくなので自分で実装しています。
v0にデモサイトとして公開していますので、興味があればご参照ください。

v0のデモとソースコード

https://v0.dev/chat/FOYrc73RWKN?b=b_DLUEGi8OzkK

デプロイされたデモページ
https://1spdv09llzlygkq2a6qst3dbewlfgf0h.vercel.app/

ほとんどv0任せですが、以下に工夫したポイントを記載しておきます。

Prompt APIの利用

ほぼ公式のガイドに記載されたExampleの通り、なんなく動きました。

APIが使用可能かどうかの取得

const capability = (await ai.languageModel.capabilities()).available;
// "readily" | "after-download" | "no"

セッションの開始とプロンプトの呼び出し

const aiSession = await ai.languageModel.create({
    // You are an AI tasked with checking whether a user's input contains sensitive information… のような指示文
    // Json形式で出力するなどもここでルールを与える
    systemPrompt: SYSTEM_PROMPT
});

// ユーザーの入力したテキストを渡してプロンプトを呼び出す
const result = await aiSession.prompt(text);
// { sensitivity_score: 0.6, reason: "...個人情報にあたる理由のテキスト..." }

AIの判断でユーザーの入力を阻害しない

AIのバリデーションの結果により、結果送信をできないようなUXを避け、警告メッセージを出すにとどめています。

「正解や不正解が明確な使用を避ける」「ユーザーを介さずに処理する使用を避ける」という人間中心の原則を意識しました。[2]

モデルの呼び出しをしすぎない

テキストエリアの入力変更のたびにAIへのプロンプト送信を行うと、前回のプロンプト送信をキャンセルした旨のエラーメッセージ(The request was cancelled)が返されることを確認しました。
どうやらAIの呼び出しを最小限にするようAPI側でコントロールしてくれてはいるものの、キャンセルが繰り返されてしまうのはやや気持ち悪かったため、debounce処理を加えています。[3]

まとめ・感想

精度はいまいち

今回の例ではある程度の個人情報の判別はできていますが、色々例を試しているとうまく判別できないケースがまだまだ多いです。
これはプロンプトの改善(コンテキストや例の提供)に加えて、モデルの性能強化などでも精度を上げていくことは可能だと思います。

20GB相当のモデルのダウンロード

AIのモデルをダウンロードをさせるユーザー体験が今後どう実装されていくかはとても気になるところです。
AIを使用するアプリケーションサイドでユーザーにダウンロードを促すのか、Chromeがインストール時に面倒を見てくれるのか、色々な選択肢があるのかなと思います。

個人的には、ブラウザが位置情報の取得許可を求めるUXに近いイメージでAIの利用許可やダウンロード状況を管理してくれるようになったら扱いやすいな、と思いました。

許可を求めるUIのイメージ

v0が便利すぎる

UIの部分はv0の無料枠で実装、デモページの公開まで行うことができました。
その分の時間をプロンプトの実装やその他の検証に使うことができ、とても快適にデモを実装することができました。
この規模のデモやモックを立ち上げるのには非常に協力なツールだと感じました。

個人情報をチェックするその他の方法

そもそもの話になってしまいますが、AIに個人情報のチェックをさせるというのは、「AIは間違いを犯す可能性がある」という前提がある以上、そこに厳密性を求めることはできません。
入力チェックの厳密さや求められるレスポンスの速さのなどの要件により、取りうる選択肢が他にもあると思います。
例えば、NLP(自然言語処理)によるルールベースのチェック[4]、さらに厳密さを求めるのであれば人間による目視でのフィルタリングが必要でしょう。
要件に応じて正しい技術選定を行いましょう。今回のAIによるチェックは実験的な意味合いが大きいということに注意してください。

脚注
  1. 「プロンプトのアイディアが尽きるまで極力パラメーターの操作は避けた方が良い」とも記載がありました ↩︎

  2. DONTsに記載があります ↩︎

  3. こちらを参考にしました ↩︎

  4. NPLとLLMの違いはこちらが参考になりました ↩︎

Aidemy Tech Blog

Discussion