サイトアイコン IT & ライフハックブログ|学びと実践のためのアイデア集

【授業レポート】システム開発入門 第26週目 生成AIをアプリに組み込む安全設計

teacher asking a question to the class

Photo by Max Fischer on Pexels.com

システム開発入門の第26週目は、生成AIをアプリに組み込むときの設計を扱いました。

生成AIとは、入力された指示に応じて文章などの結果を返す仕組みです。モデルを呼び出して結果を画面へ出すだけでは、利用者が安心して使える機能にはなりません。入力を検査し、出力を確かめ、処理に失敗した場合の動きを決め、運用状況を追えるようにする必要があります。

今回の授業では、これらを個別の対策ではなく、入力から表示まで続く一つの処理として設計しました。組織での利用範囲や確認責任まで考える場合は、関連記事「生成AI導入で最初に決めるべき運用ルール」も参照できます。

今回扱った設計の全体像

授業で整理した処理は、次の順に進みます。どこか一段だけを強くするのではなく、各段階で起こり得る失敗と次の動作を対応させます。

  1. 利用者の入力を受け付ける。
  2. 個人情報、不適切な語句、長さなどを検査し、必要に応じてマスク、拒否、修正依頼を行う。
  3. 検査を通った入力だけをモデルへ渡す。
  4. 返ってきた内容の形式、禁止語、確認が必要な情報を検査する。
  5. 検査結果に応じて、そのまま表示する、再試行する、確認を求める、代替応答へ切り替える。
  6. 利用者に結果の状態と選べる操作を示す。
  7. 呼び出し状況や失敗を記録し、レート制限とキャッシュを運用する。
生成AI機能を構成する設計要素
段階 設計する内容 失敗時の考え方
入力 マスク、拒否、長さの確認 理由を示して修正を求める
モデル呼び出し タイムアウト、レート制限、キャッシュ 代替処理へ切り替える
出力 形式、禁止語、要確認情報の検査 再試行、保留、代替応答を選ぶ
表示 結果の状態、注意事項、操作 利用者が次の行動を選べるようにする
運用 監査ログ、保存期間、アクセス制御 原因を追跡し、ルールを見直す

田中先生は、生成AIは強力でも単独で正しいとは限らないため、設計段階で「入力の検査」「出力の検証」「失敗時の振る舞い」を決める必要があると説明しました。

入力をモデルへ渡す前の検査

入力サニタイズとは、利用者が入力した内容をモデルへ渡す前に検査し、必要な修正を加える処理です。この授業では、個人情報のマスク、不適切な語句の検出、入力の長さと文字種の確認を対象にしました。

禁止語の一覧だけで入力の安全性が決まるわけではありません。アプリの目的に照らして「受け付ける内容」「拒否する内容」「修正を求める条件」を先に定め、そのルールを処理へ落とし込みます。

検査結果を三つに分ける

検査の結果を「通過」「修正が必要」「受付不可」に分けると、その後の処理が読みやすくなります。単に文字列を加工して先へ進めるのではなく、利用者へ返す説明も同時に決めます。

def prepare_input(text):
    masked = mask_personal_info(text)

    if contains_prohibited(masked):
        return ('reject', '入力内容を修正してください。')

    if is_too_long(masked):
        return ('revise', '要点を短くまとめてください。')

    return ('ok', masked)

出力検証は正しさの保証ではない

出力検証は、モデルが返した内容を表示前に規則と照合する処理です。授業では、指定した形式になっているか、不適切な語句や個人情報を含んでいないか、事実確認が必要な内容がないかを確かめました。

ここで区別したいのは、「形式を満たした」と「内容が正しい」は別の判定だという点です。JSONとして読み取れることを確認しても、書かれた事実まで確認したことにはなりません。確認が必要な情報を検出した場合は、表示を保留するか、確認済みの範囲だけを示します。

モデルが返す確信度らしき値も、そのまま客観的な信頼度として扱いません。画面には「形式確認済み」「要確認」「代替応答」のように、実際に通過した検査と現在の状態を示します。

def validate_output(output):
    if contains_prohibited(output):
        return ('fallback', '代替案を表示します。')

    if not matches_expected_format(output):
        return ('retry', '形式を整えて再試行します。')

    if needs_fact_check(output):
        return ('confirm', '確認が必要な情報を保留します。')

    return ('ok', output)

失敗時のフォールバック設計

フォールバックとは、通常の処理が使えないときに切り替える代替処理です。モデルの呼び出しがタイムアウトした場合は、事前に用意した案内文やローカルデータを返します。出力形式だけが合わない場合は再試行し、内容の確認が必要な場合は人による確認へ回します。

失敗をすべて同じエラーにすると、利用者は待つべきか、入力を直すべきか判断できません。原因ごとに代替処理と表示文を対応させます。外部APIの障害を含む実装例は「FastAPIで実践するフォールバック設計」で詳しく扱っています。

キャッシュとレート制限の役割

キャッシュは、同じ入力に対する結果を一定期間保存し、同じ呼び出しを繰り返さないための仕組みです。応答を速くし、呼び出し回数を抑える用途があります。ただし、入力や応答を保存する以上、監査ログと同じように保存期間とアクセスできる人を決めます。

レート制限は、一定時間内の呼び出し回数を制御する仕組みです。上限に近づいたときの待機案内や代替処理まで決めておくと、呼び出せない状態でも画面の動作が途切れません。

利用者が判断できる画面表示

生成AIを使う画面では、結果だけでなく、その結果がどのような状態にあるかを伝えます。「生成AIによる提案」「確認が必要」「代替応答」といった表示を置き、利用者が結果を確定情報と誤解しないようにします。

授業では、「出典を確認する」「もう一度試す」「人に確認を依頼する」という操作も用意しました。ボタン名は動作が分かる文言にし、状態は色だけに頼らず文字でも示します。注意書きを置くだけで終わらせず、利用者が次の行動を選べる画面にします。

監査ログとデータ保持

監査ログは、呼び出しや処理結果を後から追跡するための記録です。どの処理で失敗したか、フォールバックへ切り替わったかを確認できると、原因の調査とルールの改善に使えます。実装時の考え方は「FastAPIで実践する監査ログ設計入門」でも確認できます。

一方で、入力と応答を無条件にそのまま保存すると、マスクする前の情報まで記録に残りかねません。授業では、保存期間、匿名化の方針、ログへアクセスできる人を決める必要性を確認しました。記録する項目と保管範囲は、調査に必要な範囲へ絞ります。

倫理と責任を仕様へ落とし込む

授業後半では、有害な出力が表示された場合や、利用者が出力を使って不利益を受けた場合を題材に、どの段階で誰が確認するかを話し合いました。

出典表示や注意書きは、利用者が判断するための情報になります。ただし、それだけで確認手順の代わりにはなりません。利用目的、表示してよい範囲、人の確認が必要な条件、問題が起きたときの連絡先を仕様として決めます。著作権、プライバシー、偏見への配慮も、実装前の確認項目に含めます。

実装前に確認するチェックリスト

今回の実践課題

  1. 入力、検査、モデル呼び出し、出力検証、フォールバック、表示までをフローチャートにする。
  2. 入力サニタイズのルールを三つ以上挙げ、それぞれが必要な理由を説明する。
  3. 出力検証の項目を三つ挙げ、検査に失敗した場合の動作を一行ずつ書く。

次回の授業

次回は、今回作成した設計をコードへ移します。学校指定の環境でモデルを呼び出し、前処理、後処理、キャッシュ、フォールバックまでをつないで動作を確かめる予定です。

第26週目の振り返り

生成AIをアプリの機能として扱うには、便利な応答を得る方法だけでなく、入力を受け付ける条件、結果を表示する条件、失敗時の動作、運用中の確認方法まで設計する必要があります。今回の学びは、生成AIを単独の機能ではなく、利用者と運用者を含む仕組みとして捉えることにありました。

この記事に関連する株式会社greedenの取り組み

生成AIをアプリへ組み込むときは、入力、出力、例外処理、運用を一つの流れとして設計する必要があります。株式会社greedenは、生成AIを用いた施策について、相談から業務フロー改善、システム実装、定着まで支援しています。

モバイルバージョンを終了