業務用スクリプトの依頼文に入力・出力・エラー処理のルールを入れる
「これを自動化して」を、実行可能な task description に変えます。sensitive data を含まない合成 sample と、手作業で確認した expected result を添えて、team ごとの work logs を集計する script request を完成させます。
求める正確な出力構造の例を AI にいくつか示し、返された JSON を使用前に検証します。小さな合成チケットデータセットを使い、書式例と自動チェックを組み合わせる方法を示します。
この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 English
対象読者繰り返し発生する業務項目を AI で変換し、自由記述ではなく予測可能な機械可読出力を必要とする人向けのガイドです。
短いサポートチケットを構造化レコードへ変換したいとします。各結果には ticket_id, priority, owner_team, action の4つのキーだけを含める必要があります。priority は LOW, MEDIUM, HIGH のいずれかです。owner_team は IT, FACILITIES, FINANCE のいずれかです。4つの値はすべて空でない文字列でなければなりません。
重要なのは、AI の回答とは独立して形式を定義することです。AI が生成するのは候補レコードです。その候補が必要な構造を満たしているかどうかは、スクリプトが判断します。
以下のチケットは合成データであり、この記事のために作成したものです。意図した構造化結果を手作業で判断できるよう、あえて単純な内容にしています。
| ticket_id | 合成チケット本文 | 想定分類 |
|---|---|---|
| T101 | 今日の支払い処理前に給与計算スプレッドシートを開けない。 | HIGH · FINANCE |
| T102 | 会議室 B の照明がちらついているが、部屋はまだ使用できる。 | LOW · FACILITIES |
| T103 | 新入社員のノート PC が社内 Wi-Fi に接続できない。 | MEDIUM · IT |
このチュートリアルでは、想定される action もあらかじめ固定されています。T101 は Check payroll workbook access、T102 は Inspect meeting room B light、T103 は Troubleshoot laptop Wi-Fi connection とします。これらの想定値は合成演習の一部であり、実際のサポート業務に対する一般的なルールではありません。
Few-shot プロンプトでは、新しい入力の前に1つ以上の完成例を提示します。以下のデモでは、分類方法と正確な JSON 形状の両方を示します。確認対象となる3件とは異なる合成チケットを使用します。
Convert each ticket into a JSON object.
Rules:
- Return one JSON array only.
- Do not add explanations or Markdown.
- Use exactly these keys in every object: ticket_id, priority, owner_team, action.
- priority must be LOW, MEDIUM, or HIGH.
- owner_team must be IT, FACILITIES, or FINANCE.
Example 1 input:
Ticket ID: E001
Text: Printer on floor 2 is out of paper.
Example 1 output:
{"ticket_id":"E001","priority":"LOW","owner_team":"IT","action":"Refill or check floor 2 printer"}
Example 2 input:
Ticket ID: E002
Text: Expense approval file is unavailable before today's reimbursement deadline.
Example 2 output:
{"ticket_id":"E002","priority":"HIGH","owner_team":"FINANCE","action":"Check expense approval file access"}
Now process these tickets:
T101: Payroll spreadsheet cannot be opened before today's payment run.
T102: Meeting room B light is flickering but the room is still usable.
T103: New employee laptop cannot connect to the office Wi-Fi.
例ではフィールド名だけでなく、大文字のカテゴリ値、短い action 句、引用符付き JSON 文字列、周囲に説明文を付けないことも示しています。これにより、回答の提示方法に関する曖昧さを減らせます。
この合成演習では、想定回答は以下の JSON 配列です。チェッカーを実行する前に、実際の AI 回答を ai_output.json として保存してください。形式が壊れた回答を先に黙って修正しないでください。チェッカーの目的は、元の回答が仕様に従っていたかを明らかにすることです。
[
{
"ticket_id": "T101",
"priority": "HIGH",
"owner_team": "FINANCE",
"action": "Check payroll workbook access"
},
{
"ticket_id": "T102",
"priority": "LOW",
"owner_team": "FACILITIES",
"action": "Inspect meeting room B light"
},
{
"ticket_id": "T103",
"priority": "MEDIUM",
"owner_team": "IT",
"action": "Troubleshoot laptop Wi-Fi connection"
}
]
オブジェクトは正確に3件、フィールド値は合計12個あるはずです。許可された3つの priority がそれぞれ1回ずつ、3つの owner team もそれぞれ1回ずつ出現します。
次のスクリプトを check_ai_output.py として保存してください。JSON 構文、配列長、正確なキー、データ型、許可されたカテゴリ値、ticket ID、合成演習で想定した分類を検証します。AI の回答を解析した後にだけ確認用 CSV を書き出します。
import csv
import json
from pathlib import Path
SOURCE = Path("ai_output.json")
OUTPUT_DIR = Path("outputs") / "few_shot_check_result"
REPORT = OUTPUT_DIR / "format_check.csv"
EXPECTED = {
"T101": ("HIGH", "FINANCE", "Check payroll workbook access"),
"T102": ("LOW", "FACILITIES", "Inspect meeting room B light"),
"T103": ("MEDIUM", "IT", "Troubleshoot laptop Wi-Fi connection"),
}
REQUIRED_KEYS = {"ticket_id", "priority", "owner_team", "action"}
PRIORITIES = {"LOW", "MEDIUM", "HIGH"}
TEAMS = {"IT", "FACILITIES", "FINANCE"}
def main() -> None:
if not SOURCE.is_file():
raise FileNotFoundError(f"AI output not found: {SOURCE}")
if OUTPUT_DIR.exists():
raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")
with SOURCE.open("r", encoding="utf-8") as stream:
data = json.load(stream)
if not isinstance(data, list):
raise ValueError("Top-level JSON value must be an array.")
if len(data) != len(EXPECTED):
raise ValueError(f"Expected {len(EXPECTED)} objects, got {len(data)}.")
rows = []
seen = set()
for index, item in enumerate(data, start=1):
errors = []
if not isinstance(item, dict):
raise ValueError(f"Item {index} is not a JSON object.")
if set(item) != REQUIRED_KEYS:
errors.append("keys")
for key in REQUIRED_KEYS:
if key not in item or not isinstance(item.get(key), str) or not item.get(key).strip():
errors.append(f"invalid_{key}")
ticket_id = item.get("ticket_id", "")
if ticket_id in seen:
errors.append("duplicate_ticket_id")
seen.add(ticket_id)
if item.get("priority") not in PRIORITIES:
errors.append("priority")
if item.get("owner_team") not in TEAMS:
errors.append("owner_team")
expected = EXPECTED.get(ticket_id)
if expected is None:
errors.append("unexpected_ticket_id")
else:
actual = (
item.get("priority"),
item.get("owner_team"),
item.get("action"),
)
if actual != expected:
errors.append("content_mismatch")
rows.append({
"item": index,
"ticket_id": ticket_id,
"status": "PASS" if not errors else "FAIL",
"errors": ";".join(errors),
})
missing_ids = set(EXPECTED) - seen
if missing_ids:
raise ValueError(f"Missing ticket IDs: {sorted(missing_ids)}")
OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
OUTPUT_DIR.mkdir()
with REPORT.open("x", encoding="utf-8", newline="") as stream:
writer = csv.DictWriter(
stream,
fieldnames=["item", "ticket_id", "status", "errors"],
)
writer.writeheader()
writer.writerows(rows)
failures = sum(row["status"] == "FAIL" for row in rows)
print(f"Objects checked: {len(rows)}.")
print(f"Passed: {len(rows) - failures}; failed: {failures}.")
print(f"Report: {REPORT.as_posix()}")
if failures:
raise RuntimeError("AI output failed one or more checks.")
if __name__ == "__main__":
main()
ai_output.json が合成の想定出力と完全に一致する場合、3件すべてのオブジェクトが合格するはずです。以下の想定コンソールテキストは手作業で導出したもので、実行ログではありません。
Objects checked: 3.
Passed: 3; failed: 0.
Report: outputs/few_shot_check_result/format_check.csv| 問題 | チェッカーが示すべき内容 |
|---|---|
| AI が JSON の前に説明文を追加する | ファイルが単一の有効な JSON 値ではないため json.load が失敗します。 |
| 1つのオブジェクトで priority の代わりに urgency を使う | 正確なキーのチェックが失敗します。 |
| priority が urgent になっている | 許可値チェックが失敗します。 |
| T103 が2回出現する | 重複 ticket ID のチェックが失敗し、別の想定 ID が欠落している可能性があります。 |
| JSON 構造は有効だが分類が間違っている | この合成演習では content_mismatch が記録されます。 |
Few-shot プロンプトは指示を改善しますが、決定論的な出力を保証するものではありません。AI システム、設定、文脈、後続プロンプトが変われば回答も変わる可能性があります。複数回成功した後でもバリデーターは残してください。
この例では、意図的に小さなスキーマを手書きの Python チェックで検証しています。より大規模な本番スキーマでは、正式なスキーマシステムと別の意味検証が役立つ場合があります。また、有効な JSON はあくまで形式上の結果です。基礎となる分類が事実上または運用上間違っている可能性は残ります。
2026-09-20 · 手作業で確認した例 · 対象: Python 3.12 · 標準ライブラリ: csv, json, pathlib · 未実行
説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。