エバリュエーター・オプティマイザーパターン
一方のエージェントが出力を生成し、もう一方が評価してフィードバックを提供し、品質基準が満たされるまで繰り返す反復的改善パターン。
Building Effective Agents より:
「一方の LLM がレスポンスを生成し、もう一方が評価してフィードバックを反復的に提供する。文芸翻訳の洗練や、さらなる調査が必要かどうかの判断を要する複数ラウンド検索タスクに効果的。」
コアコンセプト
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ┌───────────┐ output ┌───────────┐ │
│ │ │─────────────▶│ │ │
│ │ GENERATOR │ │ EVALUATOR │ │
│ │ (エージェント) │◀─────────────│ (エージェント) │ │
│ │ │ feedback │ │ │
│ └───────────┘ └───────────┘ │
│ │ │ │
│ │ (承認された場合) │ │
│ ▼ │ │
│ ┌─────────┐ │ │
│ │ FINAL │◀─────────────────────┘ │
│ │ OUTPUT │ (合格/不合格 + スコア) │
│ └─────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
使用場面
適している場合
| シナリオ | エバリュエーター・オプティマイザーが有効な理由 |
|---|---|
| ドキュメント | 明確さ、完全性を反復的に改善可能 |
| コードリファクタリング | 品質メトリクスが最適化をガイド |
| API 設計 | ユーザビリティと一貫性が洗練可能 |
| UI/UX コピー | トーン、明確さ、エンゲージメントが調整可能 |
| 複雑なアルゴリズム | パフォーマンス/正確性が検証可能 |
適さない場合
| シナリオ | 適さない理由 |
|---|---|
| シンプルな CRUD | オーバーヘッドが正当化されない |
| 時間が重要なタスク | 反復がレイテンシーを追加 |
| 明確な基準がない | 効果的に評価できない |
| 正解/不正解が二値 | 1 パスで十分 |
実装パターン
1. ジェネレーターエージェント
要件に基づいて初期出力を作成。
## ジェネレータータスク
作成: [出力の説明]
要件: [具体的な要件]
形式: [期待される形式]
## 出力形式
明確なセクションで出力を提供:
- メインコンテンツ
- 品質の自己評価
- 不確実な領域
2. エバリュエーターエージェント
基準に対して出力をレビューし、アクション可能なフィードバックを提供。
## エバリュエータータスク
以下の出力をレビュー:
[ジェネレーター出力]
評価基準:
1. 正確性: 要件を満たしているか?
2. 完全性: 全側面がカバーされているか?
3. 明確さ: 理解しやすいか?
4. 品質: ベストプラクティスに従っているか?
## 出力形式
スコア: [0-100]
合格: [true/false](閾値: 80)
強み:
- [うまくいっている点]
問題点:
- [問題 1]: [具体的な問題]
修正: [アクション可能な改善策]
- [問題 2]: [具体的な問題]
修正: [アクション可能な改善策]
判定: [PASS / NEEDS_REVISION]
3. 最適化ループ
# 概念的なフロー
max_iterations = 3
iteration = 0
passed = False
while iteration < max_iterations and not passed:
# 生成
output = generator.create(requirements, feedback)
# 評価
evaluation = evaluator.review(output, criteria)
if evaluation.score >= threshold:
passed = True
else:
feedback = evaluation.issues
iteration += 1
return output, evaluation
サブエージェント設定
ジェネレーターサブエージェント
name: generator
model: sonnet # 複雑なタスクでは inherit
tools: Read, Write, Edit, Glob, Grep
permissionMode: acceptEdits
エバリュエーターサブエージェント
name: evaluator
model: sonnet # 同等以上のモデルを使用
tools: Read, Glob, Grep # 読み取り専用の評価
permissionMode: plan
disallowedTools: Write, Edit, Bash
実践例
例 1: ドキュメント最適化
## 反復 1
### ジェネレーター出力
```typescript
/**
* Creates a user
* @param data - user data
*/
function createUser(data: UserData): User { ... }
エバリュエーターフィードバック
スコア: 65 問題点:
- 不足: パラメータドキュメントが不完全
- 不足: 戻り値の説明
- 不足: エラー条件
- 不足: 使用例
反復 2
ジェネレーター出力(改善版)
/**
* 提供されたデータで新しいユーザーアカウントを作成する。
*
* @param data - ユーザー作成データ
* @param data.email - 有効なメールアドレス(一意である必要あり)
* @param data.password - パスワード(最低8文字、保存前にハッシュ化)
* @param data.name - 表示名(オプション)
*
* @returns 生成された ID を持つ作成済み User オブジェクト
*
* @throws {DuplicateEmailError} メールが既に存在する場合
* @throws {ValidationError} データがバリデーションに失敗した場合
*
* @example
* const user = await createUser({
* email: 'john@example.com',
* password: 'securePass123'
* });
*/
function createUser(data: UserData): Promise<User> { ... }
エバリュエーターフィードバック
スコア: 92 判定: PASS
### 例 2: アルゴリズム最適化
```markdown
## 反復 1
### ジェネレーター出力
function findDuplicates(arr) {
const duplicates = [];
for (let i = 0; i < arr.length; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[i] === arr[j] && !duplicates.includes(arr[i])) {
duplicates.push(arr[i]);
}
}
}
return duplicates;
}
### エバリュエーターフィードバック
スコア: 55
問題点:
- パフォーマンス: O(n²) の時間計算量、includes で O(n)
- 正確性: 動作するが非効率
修正: Set または Map で O(n) の解法にする
### 反復 2
### ジェネレーター出力(改善版)
function findDuplicates(arr) {
const seen = new Set();
const duplicates = new Set();
for (const item of arr) {
if (seen.has(item)) {
duplicates.add(item);
} else {
seen.add(item);
}
}
return [...duplicates];
}
### エバリュエーターフィードバック
スコア: 95
判定: PASS
強み:
- O(n) の時間計算量
- O(n) の空間計算量(この問題では最適)
- クリーンで読みやすい実装
Plan/Review/Implement ワークフローとの統合
/spec-plan(アーキテクチャ設計)と /spec-implement(品質レビュー)での使用:
アーキテクチャ設計の最適化(/spec-plan)
1. code-architect が初期設計を生成
2. エバリュエーターが以下に対してチェック:
- コードベースのパターン
- スケーラビリティ要件
- セキュリティ考慮事項
3. 設計スコアが >= 85 になるまで反復
品質レビューの最適化(/spec-implement)
1. 実装完了
2. qa-engineer がテストカバレッジを評価
3. カバレッジ < 80% の場合、反復:
- ギャップを特定
- テストを追加
- 再評価
停止条件
停止すべき場合
| 条件 | アクション |
|---|---|
| スコア >= 閾値 | 出力を承認 |
| 最大反復回数に到達 | 警告付きでベスト結果を返す |
| エバリュエーターがループに陥る | 人間のレビューを要求して中断 |
| 根本的な欠陥を検出 | ユーザーにエスカレーション |
推奨上限値
| コンテキスト | 最大反復回数 | スコア閾値 |
|---|---|---|
| ドキュメント | 3 | 80 |
| コード品質 | 3 | 85 |
| アルゴリズム | 4 | 90 |
| セキュリティクリティカル | 5 | 95 |
評価メトリクス
Anthropic の "Demystifying evals for AI agents" エンジニアリングブログより:
非決定的評価の主要メトリクス
| メトリクス | 計算式 | 使用場面 |
|---|---|---|
| pass@k | P(k 回の試行で少なくとも 1 回成功) | 「成功できるか?」 |
| pass^k | P(k 回全ての試行が成功) | 「一貫して成功するか?」 |
メトリクスの解釈
pass@k = 1 - (1 - p)^k ここで p = 試行あたりの成功率
p = 0.7 の例:
- pass@1 = 0.70 (1回の試行で70%の成功確率)
- pass@3 = 0.97 (少なくとも1回成功する97%の確率)
- pass^3 = 0.34 (3回全て成功する34%の確率)
pass@k を使用: 能力の評価(エージェントはこのタスクをできるか?) pass^k を使用: 信頼性の評価(エージェントは一貫してこれをできるか?)
3 種類のグレーダー
| グレーダータイプ | 利点 | 欠点 | 最適な用途 |
|---|---|---|---|
| コードベース | 高速、安価、客観的 | 有効なバリエーションに脆弱 | 形式バリデーション、構文チェック |
| モデルベース | 柔軟、スケーラブル | 非決定的、キャリブレーションが必要 | ニュアンスのある品質評価 |
| 人間 | ゴールドスタンダードの品質 | 高コスト、遅い | 最終バリデーション、エッジケース |
グレーダー選択戦略
1. 客観的基準にはコードベースグレーダーから開始
- JSON スキーマバリデーション
- 必須フィールドの存在確認
- 形式準拠
2. 主観的基準にはモデルベースグレーダーを追加
- コード品質評価
- ドキュメントの明確さ
- 設計の適切性
3. 以下には人間のグレーダーを確保:
- モデルベースグレーダーのキャリブレーション
- エッジケースの評価
- 重要な出力の最終承認
評価のベストプラクティス
| プラクティス | 説明 |
|---|---|
| 早期に開始 | 100以上の完璧なタスクではなく、実際の障害から20-50タスクで開始 |
| 結果を評価 | 特定の解法パスではなく結果を評価 |
| クラスの不均衡を避ける | 正例と負例のバランスを取る |
| トランスクリプトを読む | グレーダーが重要なものを測定しているか定期的に検証 |
| 飽和を監視 | 現在のタスクが一貫してパスされたらより難しいタスクを追加 |
アンチパターン
| アンチパターン | 悪い理由 | 代わりに |
|---|---|---|
| 停止条件なし | 無限ループのリスク | 最大反復回数を設定 |
| 同じモデルが自分の出力を評価 | 承認へのバイアス | 別のエージェントを使用 |
| 曖昧な基準 | 収束できない | 具体的なルーブリックを定義 |
| フィードバックを無視 | 改善されない | ジェネレーターは問題に対処必須 |
| 過度な最適化 | 収穫逓減 | 「十分に良い」を受け入れる |
上級: マルチエバリュエーター
複雑な出力には、専門化された複数のエバリュエーターを使用:
ジェネレーター出力
│
├──▶ 正確性エバリュエーター
│
├──▶ スタイルエバリュエーター
│
├──▶ パフォーマンスエバリュエーター
│
└──▶ セキュリティエバリュエーター
合計スコア = 加重平均
フィードバック = 全エバリュエーターから集約
Rules (L1 - Hard)
効果的な最適化ループに不可欠。
- ALWAYS: 開始前に明確な評価基準を定義する(そうでなければ収束できない)
- ALWAYS: 最大反復回数の上限を設定する(無限ループの防止)
- NEVER: ジェネレーターに自分の出力を評価させない(承認へのバイアス)
- NEVER: 後続の反復で評価フィードバックを無視しない
Defaults (L2 - Soft)
品質の高い結果に重要。適切な理由がある場合はオーバーライド可。
- アクション可能なフィードバックを提供する(「改善が必要」だけではなく)
- 反復回数とスコア推移を追跡する
- 最大反復回数に達した場合はベスト結果を返す
- ジェネレーターとエバリュエーターに別のエージェントインスタンスを使用する
Guidelines (L3)
より良い最適化のための推奨事項。
- consider: 複雑な出力には専門化された複数のエバリュエーターの使用を検討
- prefer: 本番品質の出力にはスコア閾値 80 以上を推奨
- consider: 3-4 反復を超えると収穫逓減になることを考慮
