業務用スクリプトの依頼文に入力・出力・エラー処理のルールを入れる
「これを自動化して」を、実行可能な task description に変えます。sensitive data を含まない合成 sample と、手作業で確認した expected result を添えて、team ごとの work logs を集計する script request を完成させます。
AIは問い合わせチケットを素早く分類できますが、実際に使う前に人手でラベル付けした小さな基準データと比較して精度を測る必要があります。このガイドでは、小さな合成例を使い、AI予測と正解ラベルを比較してPythonで正解率と混同行列を確認します。
この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 English
対象読者AIチャットアシスタントで問い合わせチケットなどの短い文章を分類し、その精度を簡単に測定したい人向けです。
AIチャットアシスタントは、問い合わせチケット、メール、コメント、短いメモにカテゴリを付けられます。しかし、数件の予測がもっともらしく見えても、全体の分類精度は分かりません。重要なのは個々の予測が自然に見えるかではなく、あらかじめ人がラベル付けした基準データとAIの予測がどの程度一致するかです。
小さな人手ラベル付きテストセットを用意すると、固定された正解表として使えます。各AI予測をその正解と比較し、正解率を計算し、さらに混同行列を使ってどのクラス同士が混同されているか確認できます。正解率は全体を1つの数字で示し、混同行列は誤りのパターンを示します。
以下の8件の問い合わせチケットは、このチュートリアル用に作成した合成例です。ラベルは billing、login、bug の3種類を使います。billing は支払い、請求、カード関連、login は認証やアカウントアクセス、bug はソフトウェアの動作不良を表します。hand_label 列は、AIに分類させる前に人が付けた基準ラベルです。
| id | ticket | hand_label |
|---|---|---|
| T1 | I was charged twice for the same order. | billing |
| T2 | My password reset link says it has expired. | login |
| T3 | The app closes whenever I open the reports page. | bug |
| T4 | Where can I download last month's invoice? | billing |
| T5 | I cannot sign in after changing my email address. | login |
| T6 | The export button does nothing when I click it. | bug |
| T7 | My card was declined but the bank says it is fine. | billing |
| T8 | The dashboard shows a blank screen after login. | bug |
データセットが小さいため、期待されるラベルをすべて手作業で確認できます。そのため、より大きなラベル付きデータへ同じ評価方法を適用する前に、評価手順自体を確認するのに適しています。
分類プロンプトは、許可するラベルと出力形式を固定すると評価しやすくなります。説明が別途必要でなければ、自由記述を求めない方が比較しやすくなります。
AIが次のような合成予測を返したとします。8件中6件が正解です。T7は基準ラベルが billing ですがAIは login と予測し、T8は基準ラベルが bug ですがAIは login と予測しています。
| id | hand_label | ai_label | correct |
|---|---|---|---|
| T1 | billing | billing | yes |
| T2 | login | login | yes |
| T3 | bug | bug | yes |
| T4 | billing | billing | yes |
| T5 | login | login | yes |
| T6 | bug | bug | yes |
| T7 | billing | login | no |
| T8 | bug | login | no |
したがって、全体の正解率は8件中6件です。手計算では 6 ÷ 8 = 0.75 なので、正解率は75%です。
混同行列は、基準ラベルと予測ラベルの組み合わせごとの件数を数える表です。この例では行を hand_label、列をAIの予測ラベルとします。対角線上の値は正解、対角線外は誤分類です。
| hand \ predicted | billing | login | bug |
|---|---|---|---|
| billing | 2 | 1 | 0 |
| login | 0 | 2 | 0 |
| bug | 0 | 1 | 2 |
この行列を見ると、2つの誤りの内容がすぐ分かります。billing のチケット1件が login に分類され、bug のチケット1件も login に分類されています。この小さな例では、基準ラベルが login のチケットを billing や bug と誤分類したケースはありません。ただし、これは login が一般的に最も分類しやすいことを意味するのではなく、この8件の合成例についての結果にすぎません。
比較データを id、hand_label、ai_label 列を持つ ticket_labels.csv に保存します。以下のスクリプトはラベルを検証し、正解数を数え、混同行列を作り、結果を outputs/classification_report.txt に保存します。Python 3.12の標準ライブラリだけを使い、入力ファイルは変更せず、出力ファイルがすでに存在する場合は停止します。
import csv
from collections import Counter
from pathlib import Path
INPUT_FILE = Path("ticket_labels.csv")
OUTPUT_DIR = Path("outputs")
OUTPUT_FILE = OUTPUT_DIR / "classification_report.txt"
LABELS = ["billing", "login", "bug"]
def main():
if not INPUT_FILE.is_file():
raise SystemExit(f"Input file not found: {INPUT_FILE}")
if OUTPUT_FILE.exists():
raise SystemExit(f"Output already exists: {OUTPUT_FILE}")
rows = []
with INPUT_FILE.open("r", encoding="utf-8", newline="") as file:
reader = csv.DictReader(file)
required = {"id", "hand_label", "ai_label"}
if reader.fieldnames is None or not required.issubset(reader.fieldnames):
raise SystemExit("ticket_labels.csv is missing required columns.")
for row_number, row in enumerate(reader, start=2):
hand = row["hand_label"].strip()
predicted = row["ai_label"].strip()
if hand not in LABELS:
raise SystemExit(f"Invalid hand_label on row {row_number}: {hand}")
if predicted not in LABELS:
raise SystemExit(f"Invalid ai_label on row {row_number}: {predicted}")
rows.append((row["id"].strip(), hand, predicted))
if not rows:
raise SystemExit("No labeled rows found.")
correct = sum(1 for _, hand, predicted in rows if hand == predicted)
accuracy = correct / len(rows)
counts = Counter((hand, predicted) for _, hand, predicted in rows)
report = []
report.append(f"tickets={len(rows)}")
report.append(f"correct={correct}")
report.append(f"accuracy={accuracy:.3f}")
report.append("")
report.append("confusion_matrix")
report.append("hand\\predicted\t" + "\t".join(LABELS))
for hand in LABELS:
values = [str(counts[(hand, predicted)]) for predicted in LABELS]
report.append(hand + "\t" + "\t".join(values))
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
OUTPUT_FILE.write_text("\n".join(report) + "\n", encoding="utf-8")
print(f"Wrote: {OUTPUT_FILE}")
if __name__ == "__main__":
main()
75%という数値だけを見るより、2件の誤分類を直接確認する方が重要です。T7には card という語があるため、定義が弱いプロンプトでは別の問題と混同される可能性がありますが、この基準体系では billing です。T8には after login という表現がありますが、実際に報告されている問題はダッシュボードが空白になることであり、基準体系では bug としています。こうした例は、単独のキーワードではなく問題の本質に基づいてラベルを定義する必要があることを示します。
混同行列はテストしたサンプルについての記述的な結果であり、将来の性能を証明するものではありません。小さく均衡した例は評価方法を学ぶには有用ですが、実際の評価では現実の表現、曖昧なケース、クラス頻度を反映できる十分な量の人手ラベルデータが必要です。
2026-09-21 · hand-checked example · Python 3.12
説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。