システム開発入門の第26週目は、生成AIをアプリに組み込むときの設計を扱いました。
生成AIとは、入力された指示に応じて文章などの結果を返す仕組みです。モデルを呼び出して結果を画面へ出すだけでは、利用者が安心して使える機能にはなりません。入力を検査し、出力を確かめ、処理に失敗した場合の動きを決め、運用状況を追えるようにする必要があります。
今回の授業では、これらを個別の対策ではなく、入力から表示まで続く一つの処理として設計しました。組織での利用範囲や確認責任まで考える場合は、関連記事「生成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で実践する監査ログ設計入門」でも確認できます。
一方で、入力と応答を無条件にそのまま保存すると、マスクする前の情報まで記録に残りかねません。授業では、保存期間、匿名化の方針、ログへアクセスできる人を決める必要性を確認しました。記録する項目と保管範囲は、調査に必要な範囲へ絞ります。
倫理と責任を仕様へ落とし込む
授業後半では、有害な出力が表示された場合や、利用者が出力を使って不利益を受けた場合を題材に、どの段階で誰が確認するかを話し合いました。
出典表示や注意書きは、利用者が判断するための情報になります。ただし、それだけで確認手順の代わりにはなりません。利用目的、表示してよい範囲、人の確認が必要な条件、問題が起きたときの連絡先を仕様として決めます。著作権、プライバシー、偏見への配慮も、実装前の確認項目に含めます。
実装前に確認するチェックリスト
- アプリで生成AIに任せる範囲と、任せない範囲を説明できるか。
- 入力を通過、修正、拒否に分ける条件が決まっているか。
- 出力の形式、禁止語、要確認情報を検査できるか。
- タイムアウト、形式不一致、確認待ちに対応する代替処理があるか。
- 利用者に結果の状態と次の操作を文字で示しているか。
- 監査ログの記録範囲、保存期間、匿名化、アクセス権が決まっているか。
- キャッシュとレート制限の条件が運用ルールに含まれているか。
今回の実践課題
- 入力、検査、モデル呼び出し、出力検証、フォールバック、表示までをフローチャートにする。
- 入力サニタイズのルールを三つ以上挙げ、それぞれが必要な理由を説明する。
- 出力検証の項目を三つ挙げ、検査に失敗した場合の動作を一行ずつ書く。
次回の授業
次回は、今回作成した設計をコードへ移します。学校指定の環境でモデルを呼び出し、前処理、後処理、キャッシュ、フォールバックまでをつないで動作を確かめる予定です。
第26週目の振り返り
生成AIをアプリの機能として扱うには、便利な応答を得る方法だけでなく、入力を受け付ける条件、結果を表示する条件、失敗時の動作、運用中の確認方法まで設計する必要があります。今回の学びは、生成AIを単独の機能ではなく、利用者と運用者を含む仕組みとして捉えることにありました。
この記事に関連する株式会社greedenの取り組み
生成AIをアプリへ組み込むときは、入力、出力、例外処理、運用を一つの流れとして設計する必要があります。株式会社greedenは、生成AIを用いた施策について、相談から業務フロー改善、システム実装、定着まで支援しています。

