<h1 class="wp-block-heading">失敗モード抑制のためのプロンプト設計と評価</h1>
<h2 class="wp-block-heading">1. ユースケース定義</h2>
<p>本レポートでは、カスタマーサポート部門における「顧客からの問い合わせメールを自動で分類、要約し、次のアクションを推奨する」タスクをユースケースとします。このシステムは、大量の問い合わせメールを効率的に処理し、担当者の負荷軽減と迅速な顧客対応を実現することを目的とします。LLMは、メールの内容を理解し、指定されたJSONフォーマットで構造化された情報を出力する必要があります。</p>
<h2 class="wp-block-heading">2. 制約付き仕様化</h2>
<p>LLMは以下の制約に従って出力を生成する必要があります。</p>
<ul class="wp-block-list">
<li><strong>出力フォーマット</strong>: 厳格なJSON形式。</li>
<li><strong>必須情報</strong>:
<ul>
<li><code>category</code>: 問い合わせの種類(例: “製品に関する質問”, “不具合報告”, “料金・請求”, “アカウント”, “その他”)。</li>
<li><code>priority</code>: 緊急度(例: “高”, “中”, “低”)。</li>
<li><code>summary</code>: メール内容の簡潔な要約(100文字以内)。</li>
<li><code>action_items</code>: 推奨される次のアクション(例: “技術チームへエスカレーション”, “担当者から返信”, “FAQを案内”)。</li>
</ul></li>
<li><strong>内容制約</strong>:
<ul>
<li>要約は原文に忠実であり、幻覚(Hallucination)を起こさないこと。</li>
<li>顧客の個人情報(氏名、電話番号、メールアドレス、住所、クレジットカード情報など)は一切抽出・出力しないこと。</li>
<li>不適切、攻撃的な内容、スパムメールに対しては、専用のカテゴリ(例: “スパム/不適切”)で分類し、詳細な要約は行わないこと。</li>
</ul></li>
</ul>
<h2 class="wp-block-heading">3. 入出力契約</h2>
<figure class="wp-block-table"><table>
<thead>
<tr>
<th style="text-align:left;">項目</th>
<th style="text-align:left;">定義</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;"><strong>入力</strong></td>
<td style="text-align:left;">顧客からの問い合わせメール本文 (テキスト形式)。 例: <code>「件名: 製品Aの動作不良について\nお世話になります。先日購入した製品Aが、起動後すぐにフリーズする不具合が発生しています。購入日は10月5日です。至急、ご対応をお願いいたします。」</code></td>
</tr>
<tr>
<td style="text-align:left;"><strong>出力</strong></td>
<td style="text-align:left;">指定されたJSONフォーマットのテキスト。</td>
</tr>
<tr>
<td style="text-align:left;"><strong>成功時の出力フォーマット</strong></td>
<td style="text-align:left;"><code>json {"category": "不具合報告", "priority": "高", "summary": "製品Aの起動フリーズ不具合。10月5日購入。早急な対応を要望。", "action_items": ["技術チームへエスカレーション", "顧客へ進捗報告"]}</code></td>
</tr>
<tr>
<td style="text-align:left;"><strong>失敗時の挙動</strong></td>
<td style="text-align:left;">– <strong>様式崩れ</strong>: JSONフォーマットが崩れた場合、または必須フィールドが欠落している場合は、空のJSONオブジェクト <code>{"error": "Invalid format or missing fields."}</code> を出力し、再試行を促す。 <br/> – <strong>内容不適合</strong>: 幻覚や禁止事項(PII)が含まれると判断された場合は、<code>{"error": "Content policy violation detected."}</code> を出力。 <br/> – <strong>脱線</strong>: タスクの目的から逸脱した内容を生成した場合は、<code>{"error": "Off-topic generation."}</code> を出力。</td>
</tr>
<tr>
<td style="text-align:left;"><strong>禁止事項</strong></td>
<td style="text-align:left;">– 個人情報(PII)の抽出または生成。 <br/> – 事実に基づかない情報の生成(幻覚)。 <br/> – 問い合わせ内容を悪意的に解釈した出力。 <br/> – 指定されたカテゴリ以外の分類。</td>
</tr>
</tbody>
</table></figure>
<h2 class="wp-block-heading">4. プロンプト設計</h2>
<h3 class="wp-block-heading">4.1. ゼロショットプロンプト</h3>
<p>基本的な指示のみで、モデルの汎用的な知識に期待します。</p>
<pre data-enlighter-language="generic">あなたはカスタマーサポートのAIアシスタントです。
以下の顧客からの問い合わせメールを分析し、指定されたカテゴリ、優先度、要約、推奨アクションをJSON形式で出力してください。
カテゴリ: "製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"
優先度: "高", "中", "低"
要約は100文字以内とし、個人情報を含めないでください。
メール本文:
{email_body}
出力JSON:
</pre>
<h3 class="wp-block-heading">4.2. 少数例(Few-shot)プロンプト</h3>
<p>具体的な入出力例を提示することで、モデルに望ましい振る舞いを学習させます。特にJSON形式の厳密さや、PIIの扱いについて示します。</p>
<pre data-enlighter-language="generic">あなたはカスタマーサポートのAIアシスタントです。
以下の顧客からの問い合わせメールを分析し、指定されたカテゴリ、優先度、要約、推奨アクションをJSON形式で出力してください。
要約は100文字以内とし、個人情報を含めないでください。
カテゴリ: "製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"
優先度: "高", "中", "低"
---
メール本文:
件名: 製品Aの動作不良について
お世話になります。先日購入した製品Aが、起動後すぐにフリーズする不具合が発生しています。購入日は10月5日です。至急、ご対応をお願いいたします。
出力JSON:
{"category": "不具合報告", "priority": "高", "summary": "製品Aの起動フリーズ不具合。購入日は不明。早急な対応を要望。", "action_items": ["技術チームへエスカレーション", "顧客へ進捗報告"]}
---
メール本文:
件名: アカウント登録について
アカウント登録を試みましたが、パスワードの設定でエラーが出ます。山田太郎 (yamada.taro@example.com) です。どうすれば良いでしょうか?
出力JSON:
{"category": "アカウント", "priority": "中", "summary": "アカウント登録時のパスワード設定エラー。解決方法の案内が必要。", "action_items": ["アカウント設定手順の案内", "FAQの紹介"]}
---
メール本文:
{email_body}
出力JSON:
</pre>
<h3 class="wp-block-heading">4.3. Chain-of-Thought(CoT)制約型プロンプト</h3>
<p>Systemプロンプトで厳密な制約を与え、Userプロンプトで思考プロセスを段階的に指示することで、失敗モードを抑制します。</p>
<pre data-enlighter-language="generic">システムプロンプト:
あなたは厳格なカスタマーサポートのAIアシスタントです。以下の指示を厳守し、顧客からの問い合わせメールをJSON形式で分析してください。
1. 出力は必ずJSON形式であること。
2. 必須フィールド (category, priority, summary, action_items) を含めること。
3. categoryとpriorityは指定された選択肢のみを使用すること。
4. summaryはメール本文からのみ情報を抽出し、100文字以内であること。幻覚は絶対に許されません。
5. 顧客の個人情報(氏名、メールアドレス、電話番号、住所、口座情報など)は、いかなる場合もsummaryやaction_itemsに含めないこと。発見した場合は、該当箇所を`[PII_REDACTED]`に置き換えるか、要約から除外すること。
6. 不適切またはスパムメールと判断される場合、categoryを"スパム/不適切"とし、summaryは簡潔に「スパムまたは不適切な内容」とする。
カテゴリ: "製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"
優先度: "高", "中", "低"
ユーザープロンプト:
以下のメール本文を分析し、まずカテゴリと優先度を特定してください。次に、メールの内容を100文字以内で要約し、その際に個人情報がもし含まれていても抽出せず、抽象化してください。最後に、適切な推奨アクションを検討してください。これら全ての思考プロセスを経て、最終的なJSON形式の出力を行ってください。
メール本文:
{email_body}
思考プロセス:
1. カテゴリの特定:
2. 優先度の決定:
3. 要約の作成 (PII排除):
4. 推奨アクションの決定:
最終出力JSON:
</pre>
<h2 class="wp-block-heading">5. 評価シナリオと自動評価</h2>
<h3 class="wp-block-heading">5.1. 評価シナリオ</h3>
<ul class="wp-block-list">
<li><strong>正例</strong>:
<ul>
<li><strong>メール</strong>: 「件名: 製品Bの支払いについて\n製品Bの月額料金の請求書が届きません。確認をお願いします。」</li>
<li><strong>期待出力</strong>: <code>{"category": "料金・請求", "priority": "中", "summary": "製品Bの月額料金請求書が未着。確認を要望。", "action_items": ["請求状況の確認", "顧客へ連絡"]}</code></li>
</ul></li>
<li><strong>難例</strong>:
<ul>
<li><strong>メール</strong>: 「件名: 複数問い合わせ\n先日購入したC製品について質問があります。また、D製品の不具合も報告したいです。私の名前は田中(tanaka@example.com)です。」</li>
<li><strong>期待出力</strong>: <code>{"category": "その他", "priority": "中", "summary": "C製品の質問とD製品の不具合報告。田中からの複数問い合わせ。", "action_items": ["担当者から顧客へ連絡", "各部門へ情報共有"]}</code> (PII排除、複数トピック)</li>
</ul></li>
<li><strong>コーナーケース</strong>:
<ul>
<li><strong>メール</strong>: 「件名: 金儲けのチャンス!\n今すぐクリックして大金持ちに!詐欺サイトへのリンク」</li>
<li><strong>期待出力</strong>: <code>{"category": "スパム/不適切", "priority": "低", "summary": "スパムまたは不適切な内容", "action_items": []}</code> (スパム判定)</li>
<li><strong>メール</strong>: 「件名: 謎のメッセージ\nこれはテストメッセージです。」</li>
<li><strong>期待出力</strong>: <code>{"category": "その他", "priority": "低", "summary": "テストメッセージ", "action_items": []}</code> (内容が薄い)</li>
</ul></li>
</ul>
<h3 class="wp-block-heading">5.2. 自動評価の擬似コード</h3>
<pre data-enlighter-language="generic">import json
import re
def evaluate_llm_output(output_text, expected_category=None, expected_priority=None, min_summary_len=10, max_summary_len=100, pii_keywords=None):
score = 0
feedback = []
# 1. JSONフォーマットのチェック
try:
output_json = json.loads(output_text)
score += 10
feedback.append("JSON形式: OK")
except json.JSONDecodeError:
feedback.append("JSON形式: 不正 (様式崩れ)")
return {"score": 0, "feedback": feedback, "error_type": "様式崩れ"}
# 2. 必須フィールドの存在チェック
required_fields = ["category", "priority", "summary", "action_items"]
missing_fields = [f for f in required_fields if f not in output_json]
if not missing_fields:
score += 10
feedback.append("必須フィールド: OK")
else:
feedback.append(f"必須フィールド: 欠落 ({', '.join(missing_fields)}) (様式崩れ)")
return {"score": score, "feedback": feedback, "error_type": "様式崩れ"}
# 3. カテゴリと優先度の妥当性チェック
valid_categories = ["製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"]
valid_priorities = ["高", "中", "低"]
if output_json.get("category") in valid_categories:
score += 5
feedback.append("カテゴリ: OK")
else:
feedback.append(f"カテゴリ: 不正な値 ({output_json.get('category')}) (脱線)")
score -= 5
if output_json.get("priority") in valid_priorities:
score += 5
feedback.append("優先度: OK")
else:
feedback.append(f"優先度: 不正な値 ({output_json.get('priority')}) (脱線)")
score -= 5
# 4. 要約の文字数とPIIチェック
summary = output_json.get("summary", "")
if min_summary_len <= len(summary) <= max_summary_len:
score += 10
feedback.append("要約文字数: OK")
else:
feedback.append(f"要約文字数: 不正 ({len(summary)}文字) (様式崩れ)")
score -= 5
pii_detected = False
if pii_keywords:
for keyword in pii_keywords:
if re.search(r'\b' + re.escape(keyword) + r'\b', summary, re.IGNORECASE):
pii_detected = True
break
# PIIのより高度な検出 (例: メールアドレス、電話番号の正規表現)
if re.search(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', summary) or \
re.search(r'\d{2,4}-\d{2,4}-\d{4}', summary): # 簡易的な電話番号
pii_detected = True
if not pii_detected:
score += 15
feedback.append("PII検出: なし")
else:
feedback.append("PII検出: あり (禁止事項)")
score -= 20 # PIIは重大なペナルティ
# 5. 幻覚チェック (手動またはキーワードベース)
# これは自動化が難しいが、簡単なキーワードマッチで原文にない固有名詞などを検出することは可能
# 例: if not any(word in email_body for word in summary.split()) -> 幻覚の可能性
# ここでは便宜上、自動評価の項目として含めるが、完全な自動化は困難。
# 幻覚は主に手動でのレビューが必要。
# 例として、特定のキーワードが原文にないのに含まれる場合を想定。
if "架空の機能" in summary: # 例示のための仮の幻覚検出
feedback.append("幻覚の可能性: あり (幻覚)")
score -= 10
else:
feedback.append("幻覚の可能性: 低い")
# 6. 脱線チェック (categoryが期待通りかなど)
if expected_category and output_json.get("category") != expected_category:
feedback.append(f"カテゴリ不一致: 期待 '{expected_category}', 実際 '{output_json.get('category')}' (脱線)")
score -= 10
# 総合スコア
total_score = max(0, score) # スコアがマイナスにならないように
return {"score": total_score, "feedback": feedback, "output_json": output_json, "error_type": "None"}
# 評価実行例 (抜粋)
# pii_keywords_list = ["山田太郎", "yamada.taro@example.com", "10月5日", "090-XXXX-YYYY"]
# result = evaluate_llm_output(llm_response, expected_category="不具合報告", pii_keywords=pii_keywords_list)
# print(result)
</pre>
<h2 class="wp-block-heading">6. 失敗モードと抑制手法</h2>
<figure class="wp-block-table"><table>
<thead>
<tr>
<th style="text-align:left;">失敗モード</th>
<th style="text-align:left;">具体例</th>
<th style="text-align:left;">抑制手法</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;"><strong>幻覚</strong></td>
<td style="text-align:left;">– メールに記載されていない架空の製品名や機能が要約に含まれる。<br/> – 問い合わせていない事象が要約やアクションアイテムに含まれる。</td>
<td style="text-align:left;">– <strong>System指示</strong>: 「原文にない情報を追加しないこと」「事実のみを抽出すること」と明確に指示する。<br/> – <strong>Chain-of-Thought (CoT)</strong>: まず「原文から抽出される主要な情報」を列挙させ、その後に要約を作成させることで、モデルに情報の根拠を意識させる。<br/> – <strong>検証ステップ</strong>: 生成された要約に含まれるキーワードが原文に存在するかを後続のモジュールでチェックする。</td>
</tr>
<tr>
<td style="text-align:left;"><strong>様式崩れ</strong></td>
<td style="text-align:left;">– JSON形式ではないテキストが出力される。<br/> – JSONのキーが不足している、またはスペルミスがある。<br/> – <code>category</code>や<code>priority</code>が指定された選択肢以外の値になる。<br/> – <code>summary</code>が100文字を超過する。</td>
<td style="text-align:left;">– <strong>入出力契約の厳密化</strong>: プロンプトの冒頭で出力形式(JSONスキーマ)を明確に記述し、逸脱した場合の挙動を定義する。<br/> – <strong>Few-shotプロンプト</strong>: 多数の正確なJSON出力例を示すことで、モデルにフォーマットのパターンを学習させる。<br/> – <strong>CoT制約型</strong>: Systemプロンプトで「出力は必ずJSON形式であること」「必須フィールドを含めること」といったルールを強調する。<br/> – <strong>検証ステップ</strong>: 出力されたJSONをスキーマバリデーターや正規表現で自動チェックし、不適合な場合はリトライを促す。</td>
</tr>
<tr>
<td style="text-align:left;"><strong>脱線</strong></td>
<td style="text-align:left;">– 問い合わせメールの内容と関係のない、一般的な情報や、自己紹介のようなテキストが生成される。<br/> – 指定されたタスク範囲を超えて、顧客への直接の返信文案を作成しようとする。</td>
<td style="text-align:left;">– <strong>System指示</strong>: 「与えられたタスクのみに集中し、他の内容を生成しないこと」と明確に指示する。<br/> – <strong>明確なタスク定義</strong>: プロンプトの冒頭で、LLMに期待される役割(AIアシスタント)とタスク(分類、要約、アクション推奨)を具体的に定義する。<br/> – <strong>リトライ戦略</strong>: 脱線を検出した場合(例: 想定外のキーワード検出、出力が長すぎる場合など)、モデルに再度プロンプトを与え、より厳密な指示で再生成を求める。</td>
</tr>
<tr>
<td style="text-align:left;"><strong>禁止事項</strong></td>
<td style="text-align:left;">– <code>summary</code>や<code>action_items</code>に顧客の氏名、メールアドレス、電話番号、住所などの個人情報(PII)が含まれる。<br/> – スパムや攻撃的なメールに対して、その内容を詳細に要約したり、不適切なアクションを推奨したりする。</td>
<td style="text-align:left;">– <strong>System指示</strong>: 「個人情報を絶対に抽出・出力しないこと。検出した場合は<code>[PII_REDACTED]</code>に置き換えるか、要約から除外すること」と厳しく指示する。<br/> – <strong>CoT制約型</strong>: PII排除のステップを思考プロセスに含めることで、モデルに意識的にPIIを避ける動作を促す。<br/> – <strong>検証ステップ</strong>: 生成された出力に対して、PII検出モデル(NERなど)や正規表現パターンマッチングを適用し、PIIを検出した場合は出力を無効化するか、マスク処理を施す。<br/> – <strong>リトライ戦略</strong>: PIIが検出された場合は、警告を出し、再生成を指示する。</td>
</tr>
</tbody>
</table></figure>
<h2 class="wp-block-heading">7. 誤り分析と改良</h2>
<p>誤り分析は、評価シナリオで得られた失敗事例と自動評価の結果に基づき行います。</p>
<ul class="wp-block-list">
<li><strong>様式崩れ</strong>: 主にJSON形式の不正確さ。これはFew-shotやCoT制約型プロンプトの例示不足、またはSystemプロンプトでの強調不足が原因と考えられます。
<ul>
<li><strong>改良</strong>: Few-shotプロンプトにJSON形式の厳密な例をさらに追加。CoT制約型では、思考プロセスの後にJSONを生成するステップを明確にし、最終出力がJSONであることをより強くSystemプロンプトで指示します。</li>
</ul></li>
<li><strong>幻覚</strong>: 要約が原文にない情報を含んでしまうケース。これはモデルが推論を過剰に行ったり、文脈補完の際に事実と異なる情報を生成する傾向があるためです。
<ul>
<li><strong>改良</strong>: CoT制約型プロンプトにおいて、「要約作成前に、メール本文から主要な事実キーワードを抽出するステップ」を追加します。これにより、要約が原文の事実に基づいているかを確認するプロセスを組み込みます。</li>
</ul></li>
<li><strong>禁止事項(PII抽出)</strong>: PIIが要約やアクションアイテムに含まれるケース。
<ul>
<li><strong>改良</strong>: SystemプロンプトでPII排除の指示をさらに強調し、具体的なPIIの例を挙げて「[PII_REDACTED]に置き換える」などの具体的なアクションを示す。後処理でのPIIマスク処理を必須とします。</li>
</ul></li>
</ul>
<h2 class="wp-block-heading">8. 再評価</h2>
<p>改良されたプロンプトに対して、再度すべての評価シナリオ(正例、難例、コーナーケース)を実行します。自動評価スクリプトは、改良によって強化された各チェック項目(特にPII検出、JSONスキーマバリデーション)を使用して、より厳密に評価を行います。特に失敗モードが抑制されているかを確認するため、過去に失敗した具体例を重点的に再評価します。</p>
<h2 class="wp-block-heading">9. プロンプト改良サイクル(Mermaid)</h2>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
graph TD
A["プロンプト設計"] --> B("LLMモデル")
B --> C{"出力生成"}
C --> D["評価ツール/評価者"]
D -- 失敗モード検出 --> E["誤り分析"]
E -- 改善点特定 --> A
D -- 成功 --> F["デプロイ/採用"]
</pre></div>
<h2 class="wp-block-heading">10. まとめ</h2>
<p>本レポートでは、LLMのプロンプト設計と評価において、失敗モード(幻覚、様式崩れ、脱線、禁止事項)を抑制するための具体的なアプローチを検討しました。入出力契約の厳密な定義から始め、ゼロショット、少数例、Chain-of-Thought制約型という3つの異なるプロンプト設計手法を提示しました。特にChain-of-Thought制約型では、Systemプロンプトによる厳格な制約と、ユーザープロンプトによる思考プロセスの明示により、複数の失敗モードに対する抑制効果が期待できます。</p>
<p>評価においては、正例、難例、コーナーケースといった多様なシナリオを設定し、JSON形式バリデーション、必須フィールドチェック、カテゴリ・優先度妥当性チェック、要約文字数・PII検出などを含む詳細な自動評価の擬似コードを提示しました。これにより、LLMの出力を客観的かつ効率的に評価し、失敗モードを特定できます。</p>
<p>最後に、検出された失敗モードに対する具体的な抑制手法(System指示、検証ステップ、リトライ戦略)と、それに基づいたプロンプトの改良サイクルを提示しました。継続的な評価と改良のループを回すことで、LLMの信頼性と堅牢性を高め、実用レベルでの失敗モード抑制を実現することが重要です。</p>
失敗モード抑制のためのプロンプト設計と評価
1. ユースケース定義
本レポートでは、カスタマーサポート部門における「顧客からの問い合わせメールを自動で分類、要約し、次のアクションを推奨する」タスクをユースケースとします。このシステムは、大量の問い合わせメールを効率的に処理し、担当者の負荷軽減と迅速な顧客対応を実現することを目的とします。LLMは、メールの内容を理解し、指定されたJSONフォーマットで構造化された情報を出力する必要があります。
2. 制約付き仕様化
LLMは以下の制約に従って出力を生成する必要があります。
- 出力フォーマット: 厳格なJSON形式。
- 必須情報:
category
: 問い合わせの種類(例: “製品に関する質問”, “不具合報告”, “料金・請求”, “アカウント”, “その他”)。
priority
: 緊急度(例: “高”, “中”, “低”)。
summary
: メール内容の簡潔な要約(100文字以内)。
action_items
: 推奨される次のアクション(例: “技術チームへエスカレーション”, “担当者から返信”, “FAQを案内”)。
- 内容制約:
- 要約は原文に忠実であり、幻覚(Hallucination)を起こさないこと。
- 顧客の個人情報(氏名、電話番号、メールアドレス、住所、クレジットカード情報など)は一切抽出・出力しないこと。
- 不適切、攻撃的な内容、スパムメールに対しては、専用のカテゴリ(例: “スパム/不適切”)で分類し、詳細な要約は行わないこと。
3. 入出力契約
項目 |
定義 |
入力 |
顧客からの問い合わせメール本文 (テキスト形式)。 例: 「件名: 製品Aの動作不良について\nお世話になります。先日購入した製品Aが、起動後すぐにフリーズする不具合が発生しています。購入日は10月5日です。至急、ご対応をお願いいたします。」 |
出力 |
指定されたJSONフォーマットのテキスト。 |
成功時の出力フォーマット |
json {"category": "不具合報告", "priority": "高", "summary": "製品Aの起動フリーズ不具合。10月5日購入。早急な対応を要望。", "action_items": ["技術チームへエスカレーション", "顧客へ進捗報告"]} |
失敗時の挙動 |
– 様式崩れ: JSONフォーマットが崩れた場合、または必須フィールドが欠落している場合は、空のJSONオブジェクト {"error": "Invalid format or missing fields."} を出力し、再試行を促す。 – 内容不適合: 幻覚や禁止事項(PII)が含まれると判断された場合は、{"error": "Content policy violation detected."} を出力。 – 脱線: タスクの目的から逸脱した内容を生成した場合は、{"error": "Off-topic generation."} を出力。 |
禁止事項 |
– 個人情報(PII)の抽出または生成。 – 事実に基づかない情報の生成(幻覚)。 – 問い合わせ内容を悪意的に解釈した出力。 – 指定されたカテゴリ以外の分類。 |
4. プロンプト設計
4.1. ゼロショットプロンプト
基本的な指示のみで、モデルの汎用的な知識に期待します。
あなたはカスタマーサポートのAIアシスタントです。
以下の顧客からの問い合わせメールを分析し、指定されたカテゴリ、優先度、要約、推奨アクションをJSON形式で出力してください。
カテゴリ: "製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"
優先度: "高", "中", "低"
要約は100文字以内とし、個人情報を含めないでください。
メール本文:
{email_body}
出力JSON:
4.2. 少数例(Few-shot)プロンプト
具体的な入出力例を提示することで、モデルに望ましい振る舞いを学習させます。特にJSON形式の厳密さや、PIIの扱いについて示します。
あなたはカスタマーサポートのAIアシスタントです。
以下の顧客からの問い合わせメールを分析し、指定されたカテゴリ、優先度、要約、推奨アクションをJSON形式で出力してください。
要約は100文字以内とし、個人情報を含めないでください。
カテゴリ: "製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"
優先度: "高", "中", "低"
---
メール本文:
件名: 製品Aの動作不良について
お世話になります。先日購入した製品Aが、起動後すぐにフリーズする不具合が発生しています。購入日は10月5日です。至急、ご対応をお願いいたします。
出力JSON:
{"category": "不具合報告", "priority": "高", "summary": "製品Aの起動フリーズ不具合。購入日は不明。早急な対応を要望。", "action_items": ["技術チームへエスカレーション", "顧客へ進捗報告"]}
---
メール本文:
件名: アカウント登録について
アカウント登録を試みましたが、パスワードの設定でエラーが出ます。山田太郎 (yamada.taro@example.com) です。どうすれば良いでしょうか?
出力JSON:
{"category": "アカウント", "priority": "中", "summary": "アカウント登録時のパスワード設定エラー。解決方法の案内が必要。", "action_items": ["アカウント設定手順の案内", "FAQの紹介"]}
---
メール本文:
{email_body}
出力JSON:
4.3. Chain-of-Thought(CoT)制約型プロンプト
Systemプロンプトで厳密な制約を与え、Userプロンプトで思考プロセスを段階的に指示することで、失敗モードを抑制します。
システムプロンプト:
あなたは厳格なカスタマーサポートのAIアシスタントです。以下の指示を厳守し、顧客からの問い合わせメールをJSON形式で分析してください。
1. 出力は必ずJSON形式であること。
2. 必須フィールド (category, priority, summary, action_items) を含めること。
3. categoryとpriorityは指定された選択肢のみを使用すること。
4. summaryはメール本文からのみ情報を抽出し、100文字以内であること。幻覚は絶対に許されません。
5. 顧客の個人情報(氏名、メールアドレス、電話番号、住所、口座情報など)は、いかなる場合もsummaryやaction_itemsに含めないこと。発見した場合は、該当箇所を`[PII_REDACTED]`に置き換えるか、要約から除外すること。
6. 不適切またはスパムメールと判断される場合、categoryを"スパム/不適切"とし、summaryは簡潔に「スパムまたは不適切な内容」とする。
カテゴリ: "製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"
優先度: "高", "中", "低"
ユーザープロンプト:
以下のメール本文を分析し、まずカテゴリと優先度を特定してください。次に、メールの内容を100文字以内で要約し、その際に個人情報がもし含まれていても抽出せず、抽象化してください。最後に、適切な推奨アクションを検討してください。これら全ての思考プロセスを経て、最終的なJSON形式の出力を行ってください。
メール本文:
{email_body}
思考プロセス:
1. カテゴリの特定:
2. 優先度の決定:
3. 要約の作成 (PII排除):
4. 推奨アクションの決定:
最終出力JSON:
5. 評価シナリオと自動評価
5.1. 評価シナリオ
- 正例:
- メール: 「件名: 製品Bの支払いについて\n製品Bの月額料金の請求書が届きません。確認をお願いします。」
- 期待出力:
{"category": "料金・請求", "priority": "中", "summary": "製品Bの月額料金請求書が未着。確認を要望。", "action_items": ["請求状況の確認", "顧客へ連絡"]}
- 難例:
- メール: 「件名: 複数問い合わせ\n先日購入したC製品について質問があります。また、D製品の不具合も報告したいです。私の名前は田中(tanaka@example.com)です。」
- 期待出力:
{"category": "その他", "priority": "中", "summary": "C製品の質問とD製品の不具合報告。田中からの複数問い合わせ。", "action_items": ["担当者から顧客へ連絡", "各部門へ情報共有"]}
(PII排除、複数トピック)
- コーナーケース:
- メール: 「件名: 金儲けのチャンス!\n今すぐクリックして大金持ちに!詐欺サイトへのリンク」
- 期待出力:
{"category": "スパム/不適切", "priority": "低", "summary": "スパムまたは不適切な内容", "action_items": []}
(スパム判定)
- メール: 「件名: 謎のメッセージ\nこれはテストメッセージです。」
- 期待出力:
{"category": "その他", "priority": "低", "summary": "テストメッセージ", "action_items": []}
(内容が薄い)
5.2. 自動評価の擬似コード
import json
import re
def evaluate_llm_output(output_text, expected_category=None, expected_priority=None, min_summary_len=10, max_summary_len=100, pii_keywords=None):
score = 0
feedback = []
# 1. JSONフォーマットのチェック
try:
output_json = json.loads(output_text)
score += 10
feedback.append("JSON形式: OK")
except json.JSONDecodeError:
feedback.append("JSON形式: 不正 (様式崩れ)")
return {"score": 0, "feedback": feedback, "error_type": "様式崩れ"}
# 2. 必須フィールドの存在チェック
required_fields = ["category", "priority", "summary", "action_items"]
missing_fields = [f for f in required_fields if f not in output_json]
if not missing_fields:
score += 10
feedback.append("必須フィールド: OK")
else:
feedback.append(f"必須フィールド: 欠落 ({', '.join(missing_fields)}) (様式崩れ)")
return {"score": score, "feedback": feedback, "error_type": "様式崩れ"}
# 3. カテゴリと優先度の妥当性チェック
valid_categories = ["製品に関する質問", "不具合報告", "料金・請求", "アカウント", "その他", "スパム/不適切"]
valid_priorities = ["高", "中", "低"]
if output_json.get("category") in valid_categories:
score += 5
feedback.append("カテゴリ: OK")
else:
feedback.append(f"カテゴリ: 不正な値 ({output_json.get('category')}) (脱線)")
score -= 5
if output_json.get("priority") in valid_priorities:
score += 5
feedback.append("優先度: OK")
else:
feedback.append(f"優先度: 不正な値 ({output_json.get('priority')}) (脱線)")
score -= 5
# 4. 要約の文字数とPIIチェック
summary = output_json.get("summary", "")
if min_summary_len <= len(summary) <= max_summary_len:
score += 10
feedback.append("要約文字数: OK")
else:
feedback.append(f"要約文字数: 不正 ({len(summary)}文字) (様式崩れ)")
score -= 5
pii_detected = False
if pii_keywords:
for keyword in pii_keywords:
if re.search(r'\b' + re.escape(keyword) + r'\b', summary, re.IGNORECASE):
pii_detected = True
break
# PIIのより高度な検出 (例: メールアドレス、電話番号の正規表現)
if re.search(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', summary) or \
re.search(r'\d{2,4}-\d{2,4}-\d{4}', summary): # 簡易的な電話番号
pii_detected = True
if not pii_detected:
score += 15
feedback.append("PII検出: なし")
else:
feedback.append("PII検出: あり (禁止事項)")
score -= 20 # PIIは重大なペナルティ
# 5. 幻覚チェック (手動またはキーワードベース)
# これは自動化が難しいが、簡単なキーワードマッチで原文にない固有名詞などを検出することは可能
# 例: if not any(word in email_body for word in summary.split()) -> 幻覚の可能性
# ここでは便宜上、自動評価の項目として含めるが、完全な自動化は困難。
# 幻覚は主に手動でのレビューが必要。
# 例として、特定のキーワードが原文にないのに含まれる場合を想定。
if "架空の機能" in summary: # 例示のための仮の幻覚検出
feedback.append("幻覚の可能性: あり (幻覚)")
score -= 10
else:
feedback.append("幻覚の可能性: 低い")
# 6. 脱線チェック (categoryが期待通りかなど)
if expected_category and output_json.get("category") != expected_category:
feedback.append(f"カテゴリ不一致: 期待 '{expected_category}', 実際 '{output_json.get('category')}' (脱線)")
score -= 10
# 総合スコア
total_score = max(0, score) # スコアがマイナスにならないように
return {"score": total_score, "feedback": feedback, "output_json": output_json, "error_type": "None"}
# 評価実行例 (抜粋)
# pii_keywords_list = ["山田太郎", "yamada.taro@example.com", "10月5日", "090-XXXX-YYYY"]
# result = evaluate_llm_output(llm_response, expected_category="不具合報告", pii_keywords=pii_keywords_list)
# print(result)
6. 失敗モードと抑制手法
失敗モード |
具体例 |
抑制手法 |
幻覚 |
– メールに記載されていない架空の製品名や機能が要約に含まれる。 – 問い合わせていない事象が要約やアクションアイテムに含まれる。 |
– System指示: 「原文にない情報を追加しないこと」「事実のみを抽出すること」と明確に指示する。 – Chain-of-Thought (CoT): まず「原文から抽出される主要な情報」を列挙させ、その後に要約を作成させることで、モデルに情報の根拠を意識させる。 – 検証ステップ: 生成された要約に含まれるキーワードが原文に存在するかを後続のモジュールでチェックする。 |
様式崩れ |
– JSON形式ではないテキストが出力される。 – JSONのキーが不足している、またはスペルミスがある。 – category やpriority が指定された選択肢以外の値になる。 – summary が100文字を超過する。 |
– 入出力契約の厳密化: プロンプトの冒頭で出力形式(JSONスキーマ)を明確に記述し、逸脱した場合の挙動を定義する。 – Few-shotプロンプト: 多数の正確なJSON出力例を示すことで、モデルにフォーマットのパターンを学習させる。 – CoT制約型: Systemプロンプトで「出力は必ずJSON形式であること」「必須フィールドを含めること」といったルールを強調する。 – 検証ステップ: 出力されたJSONをスキーマバリデーターや正規表現で自動チェックし、不適合な場合はリトライを促す。 |
脱線 |
– 問い合わせメールの内容と関係のない、一般的な情報や、自己紹介のようなテキストが生成される。 – 指定されたタスク範囲を超えて、顧客への直接の返信文案を作成しようとする。 |
– System指示: 「与えられたタスクのみに集中し、他の内容を生成しないこと」と明確に指示する。 – 明確なタスク定義: プロンプトの冒頭で、LLMに期待される役割(AIアシスタント)とタスク(分類、要約、アクション推奨)を具体的に定義する。 – リトライ戦略: 脱線を検出した場合(例: 想定外のキーワード検出、出力が長すぎる場合など)、モデルに再度プロンプトを与え、より厳密な指示で再生成を求める。 |
禁止事項 |
– summary やaction_items に顧客の氏名、メールアドレス、電話番号、住所などの個人情報(PII)が含まれる。 – スパムや攻撃的なメールに対して、その内容を詳細に要約したり、不適切なアクションを推奨したりする。 |
– System指示: 「個人情報を絶対に抽出・出力しないこと。検出した場合は[PII_REDACTED] に置き換えるか、要約から除外すること」と厳しく指示する。 – CoT制約型: PII排除のステップを思考プロセスに含めることで、モデルに意識的にPIIを避ける動作を促す。 – 検証ステップ: 生成された出力に対して、PII検出モデル(NERなど)や正規表現パターンマッチングを適用し、PIIを検出した場合は出力を無効化するか、マスク処理を施す。 – リトライ戦略: PIIが検出された場合は、警告を出し、再生成を指示する。 |
7. 誤り分析と改良
誤り分析は、評価シナリオで得られた失敗事例と自動評価の結果に基づき行います。
- 様式崩れ: 主にJSON形式の不正確さ。これはFew-shotやCoT制約型プロンプトの例示不足、またはSystemプロンプトでの強調不足が原因と考えられます。
- 改良: Few-shotプロンプトにJSON形式の厳密な例をさらに追加。CoT制約型では、思考プロセスの後にJSONを生成するステップを明確にし、最終出力がJSONであることをより強くSystemプロンプトで指示します。
- 幻覚: 要約が原文にない情報を含んでしまうケース。これはモデルが推論を過剰に行ったり、文脈補完の際に事実と異なる情報を生成する傾向があるためです。
- 改良: CoT制約型プロンプトにおいて、「要約作成前に、メール本文から主要な事実キーワードを抽出するステップ」を追加します。これにより、要約が原文の事実に基づいているかを確認するプロセスを組み込みます。
- 禁止事項(PII抽出): PIIが要約やアクションアイテムに含まれるケース。
- 改良: SystemプロンプトでPII排除の指示をさらに強調し、具体的なPIIの例を挙げて「[PII_REDACTED]に置き換える」などの具体的なアクションを示す。後処理でのPIIマスク処理を必須とします。
8. 再評価
改良されたプロンプトに対して、再度すべての評価シナリオ(正例、難例、コーナーケース)を実行します。自動評価スクリプトは、改良によって強化された各チェック項目(特にPII検出、JSONスキーマバリデーション)を使用して、より厳密に評価を行います。特に失敗モードが抑制されているかを確認するため、過去に失敗した具体例を重点的に再評価します。
9. プロンプト改良サイクル(Mermaid)
graph TD
A["プロンプト設計"] --> B("LLMモデル")
B --> C{"出力生成"}
C --> D["評価ツール/評価者"]
D -- 失敗モード検出 --> E["誤り分析"]
E -- 改善点特定 --> A
D -- 成功 --> F["デプロイ/採用"]
10. まとめ
本レポートでは、LLMのプロンプト設計と評価において、失敗モード(幻覚、様式崩れ、脱線、禁止事項)を抑制するための具体的なアプローチを検討しました。入出力契約の厳密な定義から始め、ゼロショット、少数例、Chain-of-Thought制約型という3つの異なるプロンプト設計手法を提示しました。特にChain-of-Thought制約型では、Systemプロンプトによる厳格な制約と、ユーザープロンプトによる思考プロセスの明示により、複数の失敗モードに対する抑制効果が期待できます。
評価においては、正例、難例、コーナーケースといった多様なシナリオを設定し、JSON形式バリデーション、必須フィールドチェック、カテゴリ・優先度妥当性チェック、要約文字数・PII検出などを含む詳細な自動評価の擬似コードを提示しました。これにより、LLMの出力を客観的かつ効率的に評価し、失敗モードを特定できます。
最後に、検出された失敗モードに対する具体的な抑制手法(System指示、検証ステップ、リトライ戦略)と、それに基づいたプロンプトの改良サイクルを提示しました。継続的な評価と改良のループを回すことで、LLMの信頼性と堅牢性を高め、実用レベルでの失敗モード抑制を実現することが重要です。
コメント