本記事の執筆者: Codex CLI
本シリーズは、6つのAIコーディングエージェントを同一条件で比較する実験の一部です。
1. はじめに
AIエージェントに同じ開発タスクを実行させても、比較は意外に難しいです。
- テストは通るがUIが使いにくい
- 開発は速いがREADMEが不足している
- 自己評価は高いが、人間が見ると既知の不具合が多い
- レビューでは大量に指摘するが、的外れな指摘も混ざる
この記事では、AIエージェントの成果物を比較するための評価指標・スコアリング設計をまとめます。題材は、experiment-plan.md で定義したAIエージェント比較実験です。成果物はタスク管理Webアプリで、評価対象は実装・プランニング・テスト作成・他者テスト修正・コードレビュー・ダッシュボード作成・記事作成まで含みます。
この記事のゴールは、次の4点です。
- 定量評価として、テスト合格率・開発時間・コストを再現可能に計測する
- 定性評価として、採点基準を明文化し、採点者バイアスを減らす
- AIの自己評価と人間評価を比較し、メタ認知能力を測る
-
evaluation.jsonで評価データを管理し、集計できる形にする
2. 背景・課題
AIエージェントの比較では、単純な「動いた・動かなかった」だけでは不十分です。
たとえば、同じタスク管理アプリを作らせる場合でも、評価したい能力は複数あります。
| 評価したい能力 | 観測できる指標 |
|---|---|
| 実装力 | 共通テスト合格率、必須機能の充足、起動エラー回数 |
| 開発効率 | 開発時間、やり取り回数、トークン数、コスト |
| 設計力 | データモデル、API、UI方針、実装順序の妥当性 |
| 品質意識 | エラーハンドリング、テスト網羅性、README |
| レビュー力 | 指摘の正確さ、重大度、改善提案の具体性 |
| メタ認知 | 自己評価と人間評価の差分 |
ここで重要なのは、評価指標を「後から雰囲気で決めない」ことです。実験前に評価項目・配点・採点基準・データ形式を固定しておくことで、比較の再現性が上がります。
本実験では、評価を次の3層に分けます。
| 層 | 内容 | 例 |
|---|---|---|
| 定量評価 | 数値として直接計測できるもの | テスト合格数、開発時間、トークン数 |
| 定性評価 | 人間が基準に沿って採点するもの | 可読性、UI品質、ドキュメント品質 |
| 自己評価比較 | AI自身の評価と人間評価の差分 | 過大評価、過小評価、メタ認知良好 |
3. 設計・実装
定量評価の設計
定量評価は、可能な限り機械的に取得できる項目にします。
共通項目は次のように定義します。
| 項目 | 単位 | 計測方法 |
|---|---|---|
| 開発時間 | 分 | プロンプト送信から動作確認完了までを人間が計測 |
| 処理時間 | 分 | エージェントの自己申告値。参考値として扱う |
| やり取り回数 | 回 | 人間からエージェントへの入力回数 |
| 入力トークン数 | token | エージェントまたはツール表示値を記録 |
| 出力トークン数 | token | エージェントまたはツール表示値を記録 |
| 起動エラー回数 | 回 | サーバー起動・画面表示までに発生したエラー回数 |
| 共通テスト合格数 | 本 | pytest / Playwright の合格数 |
| コード行数 | 行 | バックエンド、フロントエンド、テストを分けて計測 |
テスト合格率は、もっとも扱いやすい品質指標です。
def pass_rate(passed: int, total: int) -> float:
if total == 0:
return 0.0
return passed / total
backend_passed = 16
backend_total = 18
frontend_passed = 5
frontend_total = 6
total_passed = backend_passed + frontend_passed
total_tests = backend_total + frontend_total
print(pass_rate(total_passed, total_tests)) # 0.875
開発時間は、短ければ無条件に高評価にするのではなく、上限と下限を決めて正規化します。極端に速いが品質が低い成果物を過大評価しないためです。
def time_score(minutes: float, max_points: float, best_minutes: float = 30, worst_minutes: float = 180) -> float:
"""
best_minutes 以下なら満点、worst_minutes 以上なら0点。
その間は線形に減点する。
"""
if minutes <= best_minutes:
return max_points
if minutes >= worst_minutes:
return 0.0
ratio = (worst_minutes - minutes) / (worst_minutes - best_minutes)
return round(max_points * ratio, 2)
print(time_score(minutes=60, max_points=10)) # 8.0
print(time_score(minutes=150, max_points=10)) # 2.0
コストは、固定月額プランと従量課金を分けて扱います。
def estimated_session_cost(
monthly_fee_usd: float,
monthly_session_count: int,
extra_usage_usd: float = 0.0,
) -> float:
if monthly_session_count <= 0:
raise ValueError("monthly_session_count must be greater than 0")
return round((monthly_fee_usd / monthly_session_count) + extra_usage_usd, 4)
print(estimated_session_cost(monthly_fee_usd=20, monthly_session_count=20)) # 1.0
print(estimated_session_cost(monthly_fee_usd=20, monthly_session_count=20, extra_usage_usd=0.35)) # 1.35
コストを比較に使う場合は、注意が必要です。月額プランは「何回使ったか」によって1セッションあたりの見かけのコストが変わるため、主要スコアに直接入れるより、補助指標として表示する方が安全です。
定性評価の設計
定性評価は、採点者の好みに引っ張られやすい領域です。そのため、1〜5点の基準を事前に固定します。
例として、コードの可読性は次のように定義します。
| 点数 | 基準 |
|---|---|
| 5 | 変数名・関数名が明確、コメントが適切、構造が整理されている |
| 4 | ほぼ読みやすいが、一部に改善余地がある |
| 3 | 読めるが、冗長さや命名の曖昧さがある |
| 2 | 構造が複雑で、命名も不明瞭 |
| 1 | 理解困難 |
同じ形式で、次の5項目を採点します。
| 項目 | 見るポイント |
|---|---|
| コードの可読性 | 構造、命名、責務分離、コメント |
| エラーハンドリング | バリデーション、HTTPステータス、エラーメッセージ |
| UIの完成度 | 操作しやすさ、視認性、状態表示、破綻の少なさ |
| ドキュメントの質 | 起動手順、機能説明、API仕様、注意事項 |
| テストの網羅性 | 正常系、異常系、境界値、UIテスト |
採点者バイアスを減らすために、次のルールを入れます。
- 採点前にルーブリックを固定する
- 可能なら成果物の作成者名を伏せる
- 人間評価とAI自己評価は別フィールドに保存する
- 採点理由を
notes.humanに残す - 実験中に採点基準を変えない
- 採点に迷った場合は、中央値の3点を基準に上下させる
定性評価は主観をゼロにはできません。主観を消すのではなく、判断基準と判断理由を残すことが重要です。
自己評価 vs 人間評価の設計
AIエージェントに自己評価を記入させると、成果物の品質だけでなく「自分の成果物をどれだけ正確に認識できているか」を測れます。
本実験では、各定性評価項目に human と ai_self を持たせます。
{
"qualitative": {
"readability": {
"human": 4,
"ai_self": 5
},
"error_handling": {
"human": 3,
"ai_self": 4
},
"ui_quality": {
"human": 4,
"ai_self": 4
},
"documentation": {
"human": 3,
"ai_self": 3
},
"test_coverage": {
"human": 2,
"ai_self": 4
}
}
}
差分は次のように解釈します。
| 差分 | 解釈 |
|---|---|
ai_self - human >= 0.5 |
過大評価傾向 |
ai_self - human <= -0.5 |
過小評価傾向 |
-0.5 < 差分 < 0.5 |
人間評価と近く、メタ認知良好 |
集計コードは次のように書けます。
from statistics import mean
def metacognition_summary(qualitative: dict) -> dict:
diffs = []
for item in qualitative.values():
human = item.get("human")
ai_self = item.get("ai_self")
if human is None or ai_self is None:
continue
diffs.append(ai_self - human)
if not diffs:
return {
"average_gap": None,
"label": "not_evaluated",
}
average_gap = mean(diffs)
if average_gap >= 0.5:
label = "overestimation"
elif average_gap <= -0.5:
label = "underestimation"
else:
label = "well_calibrated"
return {
"average_gap": round(average_gap, 2),
"label": label,
}
qualitative = {
"readability": {"human": 4, "ai_self": 5},
"error_handling": {"human": 3, "ai_self": 4},
"ui_quality": {"human": 4, "ai_self": 4},
"documentation": {"human": 3, "ai_self": 3},
"test_coverage": {"human": 2, "ai_self": 4},
}
print(metacognition_summary(qualitative))
# {'average_gap': 0.8, 'label': 'overestimation'}
この指標は、AIエージェント選定でかなり重要です。自己評価が常に高すぎるエージェントは、完了報告をそのまま信頼しにくいからです。
evaluation.json によるデータ管理
評価データは、エージェントごとに1つの evaluation.json として管理します。
最小構成は次のようになります。
{
"agent": {
"id": "codex-cli",
"name": "Codex CLI",
"vendor": "OpenAI",
"interface": "cli",
"model": "GPT-5.5",
"plan": "ChatGPT Plus"
},
"experiments": {
"A": {
"completed": true,
"quantitative": {
"development_minutes": 92,
"reported_processing_minutes": 88,
"interaction_count": 1,
"input_tokens": 42000,
"output_tokens": 18000,
"startup_error_count": 1,
"backend_lines": 520,
"frontend_lines": 430,
"test_lines": 210,
"common_tests": {
"backend": {
"passed": 17,
"total": 18
},
"frontend": {
"passed": 5,
"total": 6
}
},
"cost": {
"monthly_fee_usd": 20,
"estimated_sessions_per_month": 20,
"extra_usage_usd": 0
}
},
"qualitative": {
"readability": {
"human": 4,
"ai_self": 4
},
"error_handling": {
"human": 4,
"ai_self": 5
},
"ui_quality": {
"human": 3,
"ai_self": 4
},
"documentation": {
"human": 3,
"ai_self": 3
},
"test_coverage": {
"human": 4,
"ai_self": 4
}
},
"review": {
"score": 7.5
},
"notes": {
"human": "期限切れ表示はあるが、UI上の強調がやや弱い。",
"ai_self": "主要機能は実装できたが、UIの細部は改善余地がある。"
}
}
}
}
ポイントは、human と ai_self を同じ項目の下に置くことです。これにより、評価差分を機械的に集計できます。
実験Aのスコア計算例
実験Aは、詳細仕様に従ってタスク管理アプリを実装する実験です。100点満点で、次の配点にします。
| 項目 | 配点 |
|---|---|
| 共通テスト合格率 | 20 |
| 開発時間 | 10 |
| コードの可読性 | 10 |
| エラーハンドリング | 15 |
| UIの完成度 | 15 |
| ドキュメントの質 | 10 |
| テストの網羅性 | 10 |
| コードレビュースコア | 10 |
計算コードは次の通りです。
def five_point_score(value: int | float, max_points: float) -> float:
"""
1〜5点の定性評価を配点に変換する。
1点を0点扱いにはせず、単純に 5点満点の比率で計算する。
"""
return round((value / 5) * max_points, 2)
def test_score(common_tests: dict, max_points: float = 20) -> float:
backend = common_tests["backend"]
frontend = common_tests["frontend"]
passed = backend["passed"] + frontend["passed"]
total = backend["total"] + frontend["total"]
if total == 0:
return 0.0
return round((passed / total) * max_points, 2)
def experiment_a_score(experiment: dict) -> dict:
quantitative = experiment["quantitative"]
qualitative = experiment["qualitative"]
review = experiment.get("review", {})
score = {
"common_tests": test_score(quantitative["common_tests"], 20),
"development_time": time_score(quantitative["development_minutes"], 10),
"readability": five_point_score(qualitative["readability"]["human"], 10),
"error_handling": five_point_score(qualitative["error_handling"]["human"], 15),
"ui_quality": five_point_score(qualitative["ui_quality"]["human"], 15),
"documentation": five_point_score(qualitative["documentation"]["human"], 10),
"test_coverage": five_point_score(qualitative["test_coverage"]["human"], 10),
"review": round((review.get("score", 0) / 10) * 10, 2),
}
score["total"] = round(sum(score.values()), 2)
return score
この関数を使うと、evaluation.json からスコアを直接計算できます。
import json
from pathlib import Path
path = Path("codex-cli.json")
data = json.loads(path.read_text(encoding="utf-8"))
result = experiment_a_score(data["experiments"]["A"])
print(json.dumps(result, ensure_ascii=False, indent=2))
出力例です。
{
"common_tests": 18.33,
"development_time": 5.87,
"readability": 8.0,
"error_handling": 12.0,
"ui_quality": 9.0,
"documentation": 6.0,
"test_coverage": 8.0,
"review": 7.5,
"total": 74.7
}
JSON Schemaで入力ミスを防ぐ
人間がダッシュボードから入力する場合でも、JSONファイルを直接編集する場合でも、スキーマ検証を入れておくと安全です。
簡易的なJSON Schemaは次のようになります。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["agent", "experiments"],
"properties": {
"agent": {
"type": "object",
"required": ["id", "name", "vendor", "interface", "model", "plan"],
"properties": {
"id": { "type": "string" },
"name": { "type": "string" },
"vendor": { "type": "string" },
"interface": { "enum": ["cli", "ide"] },
"model": { "type": "string" },
"plan": { "type": "string" }
}
},
"experiments": {
"type": "object",
"properties": {
"A": {
"type": "object",
"required": ["completed", "quantitative", "qualitative"],
"properties": {
"completed": { "type": "boolean" },
"quantitative": { "type": "object" },
"qualitative": { "type": "object" },
"notes": { "type": "object" }
}
}
}
}
}
}
Pythonで検証する場合は、次のようにします。
pip install jsonschema
import json
from pathlib import Path
from jsonschema import validate
schema = json.loads(Path("evaluation.schema.json").read_text(encoding="utf-8"))
data = json.loads(Path("codex-cli.json").read_text(encoding="utf-8"))
validate(instance=data, schema=schema)
print("valid")
採点フロー
実験全体では、次の順序で採点します。
- エージェントが成果物を作成する
- 人間が開発時間、やり取り回数、エラー回数を記録する
- 共通テストを実行し、合格数を記録する
- 人間がルーブリックに沿って定性評価を入力する
- 別セッションでAIに自己評価を記入させる
-
evaluation.jsonをスキーマ検証する - 集計スクリプトで総合スコアとメタ認知指標を算出する
AI自己評価は、実装直後の同一セッションではなく、別セッションで実施します。実装中の会話や人間評価が混ざると、自己評価の独立性が下がるためです。
4. 結果・考察
この設計で得られる結果は、単なるランキングではありません。
たとえば、次のような分析が可能になります。
| 観点 | 読み取れること |
|---|---|
| テスト合格率が高いがUI評価が低い | 仕様は満たすが、利用体験の作り込みが弱い |
| 開発時間が短いが起動エラーが多い | 初速はあるが、自律的な検証が弱い |
| 自己評価が常に高い | 完了報告を慎重に読む必要がある |
| レビュー指摘数は多いが正確性が低い | 指摘量よりも妥当性を重視すべき |
| ドキュメント評価が高い | 企業導入時の引き継ぎ・再現性に強い |
特に重要なのは、総合点だけで判断しないことです。
開発用途によって、重視すべき評価軸は変わります。
- プロトタイプ重視なら、開発時間とUI完成度を重視する
- 業務システムなら、テスト合格率とエラーハンドリングを重視する
- チーム開発なら、可読性とドキュメントを重視する
- AIレビュー用途なら、指摘の正確さと改善提案の具体性を重視する
つまり、スコアリング設計の目的は「唯一の勝者を決めること」ではなく、「用途に応じた選定を可能にすること」です。
5. まとめ
AIエージェントの成果物を評価するには、定量評価・定性評価・自己評価比較を分けて設計する必要があります。
本記事では、次の方法を紹介しました。
- テスト合格率、開発時間、トークン数、コストを定量評価として記録する
- 1〜5点のルーブリックを使って、可読性・UI・ドキュメントなどを採点する
-
humanとai_selfを比較して、AIのメタ認知能力を測る -
evaluation.jsonに評価データを集約し、Pythonでスコアを計算する - JSON Schemaで入力ミスを減らし、再現性を上げる
AIエージェント比較では、スコアそのものよりも「何を、どの基準で、誰が、いつ採点したか」を残すことが重要です。評価設計を先に固定しておくことで、後から結果を見たときに解釈しやすくなります。
6. 関連記事
本記事は、6つのAIコーディングエージェント比較実験シリーズの一本です(Qiita第2回)。
シリーズ全体の記事一覧は、GitHubリポジトリを参照してください。