← Claudeエージェント実装:深掘り編
LESSON 05 / 06

ヒューマン・イン・ザ・ループの実装

所要時間 13分 上級レベル

「全自動」のエージェントは危険です。「人間が関与すべきポイント」 を適切に設計することが、本番運用の鍵となります。

人間介入が必要な3つの場面

場面 承認の重さ
1. 不可逆アクション 支払い、削除、メール送信 必須・即時
2. 高リスクアクション 外部API呼び出し、機密データ取得 条件付き
3. 確信度が低い判断 曖昧な分類、複数選択肢 推奨

承認フローの実装パターン

パターン1: ブロッキング承認

async def execute_with_approval(action, action_meta):
    # 承認リクエスト送信
    approval_id = send_approval_request(
        action=action,
        action_meta=action_meta,
        approver=action_meta.required_approver,
    )

    # 承認待ち(タイムアウトあり)
    try:
        approval = await wait_for_approval(approval_id, timeout=3600)
    except TimeoutError:
        return ActionResult(
            status="timeout",
            message="承認がタイムアウトしました"
        )

    if not approval.approved:
        return ActionResult(
            status="rejected",
            message=f"承認者により拒否:{approval.reason}"
        )

    # 承認後、実行
    return execute(action)

パターン2: 非同期承認

承認待ちの間、エージェントは 他のタスク を進められる。

async def queue_action_for_approval(action):
    pending_id = await pending_queue.add(action)

    # メイン処理は続行
    return ActionResult(
        status="pending_approval",
        pending_id=pending_id,
        message=f"承認待ちです。完了後に通知されます。"
    )

# 承認後に呼び出されるコールバック
async def on_approval_received(pending_id, approval):
    if approval.approved:
        action = await pending_queue.get(pending_id)
        result = await execute(action)
        await notify_agent(action.session_id, result)

パターン3: 推奨提示モード(Co-pilot 型)

エージェントは 提案するだけ。実行は人間が決定。

def suggest_action(situation):
    # エージェントは推奨アクションを提示
    suggestion = call_claude(
        system="状況を分析し、推奨アクションを3つ提示してください。",
        user=situation,
    )

    return {
        "options": suggestion.options,
        "reasoning": suggestion.reasoning,
        "execute_endpoint": "/api/execute",
    }

# UIで人間が選択 → 実行

承認UIの設計

# 承認画面に表示すべき情報

【アクション】
- ツール名: send_email
- 引数:
  - to: customer@example.com
  - subject: ご注文ありがとうございます
  - body: ...

【コンテキスト】
- セッションID: xxx
- ユーザー要望: 「注文確認メールを送って」
- 直前の会話: ...

【リスク評価】
- レベル: 中(メール送信は取り消し不可)
- 影響範囲: 1顧客
- データ流出リスク: 低

【承認/拒否】
[承認] [修正して承認] [拒否] [理由を入力]

タイムアウトの設計

シーン タイムアウト タイムアウト時の動作
緊急の対応 10〜30分 エスカレーション
通常業務 2〜4時間 営業時間内に再通知
大型決定 1〜3日 関連者全員に通知
定型処理 10〜30秒 自動拒否+エラー

承認の自動化レベル

すべての承認を人間がやるのは現実的ではない。段階的な自動化

# 自動化レベルの判定基準

def determine_auto_approval(action):
    if action.amount_jpy < 1000:
        return "auto"  # 1000円以下は自動承認
    if action.category in ["read_only", "search"]:
        return "auto"  # 読み取り専用は自動
    if action.is_repeat_of_approved_action():
        return "auto"  # 同種の承認済みアクションの繰り返し
    if action.amount_jpy < 50000:
        return "manager_approval"  # 5万円以下はマネージャ承認
    return "executive_approval"  # それ以上は経営層承認

監査ログの記録

# 全ての承認イベントを記録

CREATE TABLE approval_log (
    id UUID PRIMARY KEY,
    timestamp TIMESTAMP,
    session_id TEXT,
    action_type TEXT,
    action_args JSONB,
    risk_level TEXT,
    requested_approver TEXT,
    actual_approver TEXT,
    status TEXT,  -- approved/rejected/timeout/auto
    reason TEXT,
    response_time_ms INTEGER
);

# 監査クエリ例
- 月次の自動承認/手動承認の比率
- 承認者ごとの平均応答時間
- 拒否されたアクションのパターン
- タイムアウトの頻度

失敗パターン

失敗 対処
承認疲れ(毎回スキップされる) 自動化レベルを上げる、承認頻度を見直す
承認者が不在で停滞 代理承認者・エスカレーション
承認画面の情報が薄く判断できない UIの改善、コンテキスト提示
承認後の実行で失敗 承認時に「実行可能か」事前チェック

このレッスンのまとめ

「不可逆アクション」「高リスクアクション」「確信度の低い判断」では人間介入が必須。承認パターン(ブロッキング/非同期/推奨提示)を使い分け、タイムアウト・自動化レベル・監査ログを実装します。次のレッスンでは、評価・トレース・デバッグを学びます。

よくある質問

この記事に関連する質問と答えをまとめました。

Q.人間介入をどこに入れるべき?
A.
①不可逆アクション(支払い・削除・送信)、②高リスクアクション、③確信度の低い判断の3場面です。すべて自動化すると必ず事故が起きます。
Q.承認のタイムアウトはどれくらい?
A.
緊急対応は10〜30分、通常業務は2〜4時間、大型決定は1〜3日が目安です。タイムアウト時のフォールバック動作も設計しておくのが安全な運用です。