AI活用

AIエージェントのHuman in the Loop設計|承認・停止・再開を実装する

AIエージェントの誤操作を防ぐHuman in the Loop設計を、リスク分類、承認画面、停止・再開、実行直前の再検証、監査ログまで解説します。

この記事の目次
  1. 結論:承認は「実行の直前」に置く
  2. Human in the Loopが必要な理由
  3. 操作をリスク別に分類する
  4. ルールをコードで判定する例
  5. 承認画面に何を表示するか
  6. 停止・タイムアウト・再開を状態として実装する
  7. 承認後、実行直前に再検証する
  8. 承認ログを監査と改善に使う
  9. HITLだけでは防げないリスク
  10. 導入チェックリスト
  11. よくある質問
  12. すべてのツール呼び出しを承認制にすべきですか?
  13. 承認者は誰にすべきですか?
  14. 承認後に内容を少し修正して実行できますか?
  15. まとめ

AIエージェントのHuman in the Loopは、すべての操作を人が承認する仕組みではありません。誤操作の影響が大きい外部送信、削除、購入、権限変更などを一時停止し、人が対象・差分・影響を確認してから再開できるようにする設計です。

AIエージェントは、文章を返すだけでなく、メール送信、ファイル変更、データベース更新、外部API実行まで行えます。便利になる一方、曖昧な指示、古い画面状態、プロンプトインジェクション、権限の広すぎるツールによって、意図しない操作が実行されるおそれがあります。

この記事では、Human in the Loop(HITL)を実装するために、操作のリスク分類、承認要求、停止・タイムアウト・再開、実行直前の再検証、監査ログを順に整理します。

情報確認日:2026年7月18日(日本時間)

結論:承認は「実行の直前」に置く

安全な承認フローの要点

  • 操作を低・中・高リスクに分類する
  • 承認画面へ対象、差分、権限、取り消し可否を表示する
  • 承認待ちの間は副作用を発生させない
  • 期限切れや対象変更時は古い承認を無効にする
  • 実行直前に対象と権限を再検証する
  • 申請、判断、実行結果を監査ログへ残す

承認はプロンプトの途中ではなく、実際に副作用を起こすツールの直前に置きます。「メールを作ってよい」と「100人へ送ってよい」は別の判断です。下書き作成は自動化し、外部送信だけを人が確認するよう分割すると、速度と安全性を両立できます。

スポンサーリンク

Human in the Loopが必要な理由

AIエージェントの基本構造は、モデルが計画し、ツールを選び、アプリが外部処理を実行する流れです。全体像はAIエージェントとは何か、ツール呼び出しの仕組みはFunction Callingの基本で解説しています。

利用者の依頼
  ↓
モデルが操作を提案
  ↓
アプリがリスクを判定
  ├─ 低リスク → 自動実行
  └─ 要承認   → 停止 → 人が確認
                         ├─ 却下
                         ├─ 修正して再申請
                         └─ 承認 → 再検証 → 実行

NISTのAI RMF関連資料では、人とAIの役割や監督責任を定義し、文書化することが重視されています。OWASPも、LLMへ過剰な機能、権限、自律性を与える「Excessive Agency」をリスクとして挙げています。HITLはその対策の1つですが、最小権限や入力検証の代わりにはなりません。

操作をリスク別に分類する

区分 基本方針
低リスク 公開情報の検索、下書き作成、読み取り専用の集計 自動実行し、必要に応じて結果を記録
中リスク 社内文書の更新、限定相手への送信、可逆な設定変更 条件付き自動化または担当者承認
高リスク 削除、支払い、公開、権限変更、機密情報の外部送信 明示承認、再認証、複数人承認を検討
禁止 法令・規程違反、承認不能な不可逆操作 ツール自体を提供しない

リスクは操作名だけで決まりません。同じメール送信でも、自分宛てのテストと顧客全員への一斉送信では影響が異なります。対象件数、データの機密度、金額、公開範囲、可逆性、本人確認の要否を条件に含めます。

ルールをコードで判定する例

function classifyRisk(action) {
  if (action.type === "delete_database") return "prohibited";

  if (
    action.type === "send_email" &&
    (action.recipientCount > 10 || action.containsSensitiveData)
  ) {
    return "high";
  }

  if (action.type === "update_document") return "medium";
  return "low";
}

モデル自身に最終判定を任せず、アプリ側の決定的なルールで強制します。モデルはリスク判断の補助説明を作れても、承認を迂回する権限は持たせません。

承認画面に何を表示するか

「許可しますか?」だけでは、人は正しく判断できません。承認要求は、実行予定の内容を人が短時間で検証できる情報に変換します。

表示項目 具体例 目的
操作 顧客へメールを送信 何が起きるかを明確にする
対象 送信先20件、顧客グループA 誤った対象を発見する
内容・差分 件名、本文、変更前後 結果を事前確認する
影響 外部送信、取り消し不可 判断の重さを伝える
根拠 利用者の依頼と参照資料 指示との一致を確認する
期限 10分後に失効 古い状態での実行を防ぐ

危険なUI:承認ボタンを常に同じ位置へ置き、要約だけを表示すると、利用者が反射的に押しやすくなります。高リスク操作では対象件数や差分を展開し、必要なら再認証や理由入力を求めます。

停止・タイムアウト・再開を状態として実装する

承認待ちは、単に処理を長時間スリープさせる状態ではありません。申請内容を保存し、ワーカーを解放し、承認イベントを受けて安全に再開できる状態機械として扱います。

draft
  ↓ request_approval
pending_approval
  ├─ reject  → rejected
  ├─ expire  → expired
  └─ approve → approved
                  ↓ revalidate
              executing
                ├─ succeeded
                └─ failed
type ApprovalState =
  | "pending_approval"
  | "approved"
  | "rejected"
  | "expired"
  | "executing"
  | "succeeded"
  | "failed";

type ApprovalRequest = {
  id: string;
  actionType: string;
  targetSnapshotHash: string;
  requestedBy: string;
  expiresAt: string;
  state: ApprovalState;
};

再開処理は何度呼ばれても副作用が重複しないよう、冪等性キーを使います。承認イベントの二重配信やワーカーの再起動が起きても、メールの二重送信や二重決済が発生しない設計が必要です。

承認後、実行直前に再検証する

申請から承認までの間に、文書、価格、送信先、権限が変わる場合があります。承認時のスナップショットと現在値を比較し、変更されていれば再申請します。

async function executeApprovedAction(request) {
  if (new Date(request.expiresAt) <= new Date()) {
    throw new Error("approval_expired");
  }

  const currentTarget = await loadTarget(request.targetId);
  const currentHash = createStableHash(currentTarget);

  if (currentHash !== request.targetSnapshotHash) {
    throw new Error("target_changed_reapproval_required");
  }

  await assertCurrentUserPermission(
    request.approvedBy,
    request.actionType
  );

  return runOnce(request.idempotencyKey, () =>
    performAction(request.action)
  );
}

承認者が実行時にも権限を持っているか、対象が承認時と同じか、期限内か、ポリシーが変更されていないかを確認します。「一度承認されたから永続的に有効」としないことが重要です。

承認ログを監査と改善に使う

{
  "approval_id": "apr_01J...",
  "action_type": "send_email",
  "risk_level": "high",
  "requested_by": "agent-support",
  "requested_for": "user-123",
  "target_count": 20,
  "snapshot_hash": "sha256:...",
  "decision": "approved",
  "decided_by": "manager-456",
  "decision_reason": "送信先と本文を確認",
  "requested_at": "2026-07-18T03:00:00Z",
  "decided_at": "2026-07-18T03:03:10Z",
  "executed_at": "2026-07-18T03:03:12Z",
  "result": "succeeded"
}

ログには判断に必要なメタデータを残しますが、機密本文を無制限に複製しないようにします。却下率、期限切れ率、承認後の失敗率、承認者ごとの偏りを分析すると、ルールが厳しすぎる箇所や、危険な操作が自動化されすぎている箇所を見つけられます。

HITLだけでは防げないリスク

  • 承認画面自体に悪意ある外部文章が混入する
  • 承認者が内容を読まずに許可する
  • ツールへ必要以上の権限が付与されている
  • 承認後に対象や権限が差し替わる
  • 低リスクと分類した操作を大量実行される

そのため、最小権限、入力検証、出力のエスケープ、件数上限、サンドボックス、実行直前の再検証を組み合わせます。外部コンテンツからの指示混入についてはプロンプトインジェクション対策も確認してください。

導入チェックリスト

  • 操作ごとのリスク分類と責任者が決まっている
  • 禁止操作はツールとして公開していない
  • 承認画面に対象、差分、影響、期限が表示される
  • 承認待ちでは副作用が起きない
  • 期限切れと対象変更で再申請になる
  • 実行時に権限を再確認する
  • 冪等性キーで二重実行を防ぐ
  • 緊急停止と手動復旧の手順がある
  • 申請から結果まで監査ログで追跡できる

よくある質問

すべてのツール呼び出しを承認制にすべきですか?

いいえ。低リスクな読み取りまで毎回止めると、承認疲れが起きます。影響、可逆性、対象、機密度に応じて自動実行と承認を分けます。

承認者は誰にすべきですか?

操作対象と責任に応じて決めます。本人の外部送信は本人、一定額以上の購入は管理者、権限変更はシステム管理者など、役割と金額・件数の条件を規程化します。

承認後に内容を少し修正して実行できますか?

承認対象が変わるため、原則として再申請します。誤字修正など許容する変更を設ける場合も、変更可能なフィールドと範囲を明確にし、差分をログへ残します。

まとめ

Human in the Loopは、人がAIの全作業を代行する仕組みではなく、影響の大きい操作へ判断点を置く仕組みです。リスク分類、十分な承認情報、停止・再開の状態管理、実行直前の再検証、監査ログをセットで設計します。

まずは外部送信、削除、公開、支払い、権限変更の5種類を洗い出し、1つの高リスク操作で承認フローを実装してください。運用ログを見ながら、承認が必要な範囲を継続的に調整するのが現実的です。

スポンサーリンク