1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIエージェントを「確認待ち地獄」に落とさない技術 — Approval Contract / Decision Queue 実践ガイド

1
Posted at

AIエージェントを「確認待ち地獄」に落とさない技術 — Approval Contract / Decision Queue 実践ガイド

AIコーディングエージェントを使っていると、だんだんこういう場面が増えてきます。

「この変更、進めていいですか?」
「このファイルを削除していいですか?」
「本番に近い設定を触ってもいいですか?」
「APIキーを入力してください」

最初は丁寧でいいんです。

でも、毎回これを人間が読んで、毎回その場で判断して、毎回「OKです」と返していると、AIに任せているはずなのに、なぜか人間の方が忙しくなるんですよね。

これ、めっちゃもったいなくないですか。

この記事で言いたいことはシンプルです。

AIエージェントに仕事を任せるなら、プロンプトだけではなく「承認の設計」も先に書いた方がいい。

僕はこれをこの記事では Approval Contract と呼びます。

Approval Contract は、日本語で言えば「承認契約」です。難しく聞こえるかもしれませんが、要するにこういうことです。

  • どんな操作は AI が勝手に進めていいのか
  • どんな操作は人間に確認するべきなのか
  • 確認するとき、何をセットで出すべきなのか
  • 人間が反応しない場合、AI はどう止まるべきなのか
  • 承認した証拠をどこに残すのか

これを事前に決めておく。

AI時代の開発では、コードを書く力よりも、こういう 判断の流れを設計する力 がかなり大事になってくる気がしています。

いま起きている変化: AIは「補完」から「作業者」に寄っている

少しだけ最新状況を整理します。

GitHub Copilot の coding agent は、Issue を割り当てると GitHub Actions 上の環境で作業し、draft Pull Request を作り、session logs で進捗を追える方向に進んでいます。GitHub の説明でも、branch protection はそのまま効き、CI/CD ワークフローを動かす前に人間承認が入る保護コントロールが説明されています。

OpenAI Codex も、単なるコード補完ではなく、Pull Request、リファクタ、migration、ドキュメント作成、複数エージェントでの並列作業、background work のような方向に進んでいます。

さらに MCP、Model Context Protocol ですね。これはざっくり言うと、AI が外部ツールやデータソースへアクセスするための共通規格です。GitHub Copilot の agent mode でも MCP を使うことで、リポジトリ、Issue、PR、外部APIなどにアクセスしやすくなります。

つまり何が起きているか。

AIは、エディタの横にいる補助輪から、開発フローの中で実際に手を動かす作業者になりつつある。

ここまではワクワクする話です。

ただし、作業者が増えると、必ず必要になるものがあります。

それが 権限と承認の設計 です。

人間のチームでも同じですよね。

新しく入ったメンバーに、いきなり本番DBの削除権限を渡すことはありません。まず小さなタスクを任せる。レビューする。権限を分ける。危ない作業はペアで見る。ログを残す。

AIエージェントも同じです。

「AIだから全部任せる」でもなく、「AIだから全部疑う」でもない。

任せていい範囲を設計する。迷ったら確認する道を作る。危ないものは止める。

この当たり前を、Markdown と TypeScript と CI に落とし込むのが今回の記事です。

Approval Contract とは何か

Approval Contract は、AIエージェントと人間の間に置く「判断ルール」です。

プロンプトが「何をしてほしいか」を伝えるものだとしたら、Approval Contract は「どこまで勝手にやってよくて、どこから人間に聞くべきか」を伝えるものです。

たとえば、こんな違いがあります。

悪い例: ふわっと確認する

必要なら確認してください。
危ないことはしないでください。
いい感じに進めてください。

これは、人間同士なら空気で伝わることもあります。

でもAIにとっては曖昧です。

「必要なら」とは、どの条件でしょうか。
「危ないこと」とは、何でしょうか。
「いい感じ」とは、誰にとっていい感じでしょうか。

ここが曖昧だと、AIは2つの方向にブレます。

1つは、慎重になりすぎて何度も確認する方向。
もう1つは、勝手に進めすぎて事故る方向。

どちらも困ります。

良い例: 判断単位を分ける

approval_policy:
  auto_approve:
    - docs_only_change
    - add_unit_tests_without_production_code_change
    - refactor_private_function_with_tests
  require_human_approval:
    - delete_file
    - change_database_schema
    - modify_auth_or_payment_logic
    - add_external_network_access
    - change_ci_cd_or_deployment_config
  always_deny:
    - request_api_key_or_password_in_chat
    - expose_secret_values
    - run_production_destructive_command

これなら、かなり判断しやすくなります。

AIは「この操作は docs_only_change だから進める」「これは database schema 変更だから承認を求める」「これは APIキー要求だから拒否」と判断できます。

人間もレビューしやすいです。

ポイントは、AIに人格的な賢さを期待しすぎないことです。

AIが迷わないように、判断の棚を先に作っておく。

これが Approval Contract の基本です。

Decision Queue: 確認はチャットに流さず、キューに積む

もう1つ大事なのが Decision Queue です。

AIが人間に確認したいことを、チャットの流れにそのまま投げると、すぐ埋もれます。

「これ確認してください」
「こっちも確認してください」
「追加で質問です」

こうなると、人間は何を判断すればいいのか分からなくなります。

だから、確認事項はキューとして扱います。

Decision Queue は、AIが止まっている理由を1件ずつ構造化するための箱です。

id: DQ-2026-001
status: waiting_human
risk: medium
requested_by: coding-agent
summary: ユーザー設定テーブルに timezone カラムを追加してよいか
decision_needed:
  question: DBスキーマ変更を実施してよいですか?
  options:
    - approve
    - reject
    - request_smaller_plan
context:
  related_issue: ISSUE-123
  files:
    - prisma/schema.prisma
    - src/users/userSettings.ts
impact:
  user_visible_change: タイムゾーン別の通知時刻を保存できる
  rollback_plan: migration revert を追加し、リリース前なら安全に戻せる
expires_at: 2026-05-10T18:00:00+09:00
fallback_if_expired: request_smaller_plan

こうしておくと、人間は「何を判断するのか」だけに集中できます。

コード全体を読み込む前に、まず判断の単位が見える。

これが大事なんです。

AI時代のレビューでしんどいのは、AIが書いたコードそのものよりも、そもそも何を判断すればいいのか分からない状態 なんですよね。

Decision Queue は、その迷子感を減らしてくれます。

MCP Elicitation から学べること

MCP の draft specification には Elicitation という考え方があります。

Elicitation は、MCPサーバーがクライアント経由でユーザーに追加情報を求めるための仕組みです。要するに、AIやツールが作業中に「この情報が必要です」と人間に聞くための標準化された流れです。

ここで面白いのは、単に「質問できる」という話ではないことです。

仕様上、クライアントは要求元を明示し、ユーザーが拒否やキャンセルを選べるようにし、送信前に内容を確認・変更できるようにする必要があります。

さらに重要なのが、秘密情報の扱いです。

MCP Elicitation では、form mode でパスワード、APIキー、アクセストークン、決済情報のような秘密情報を要求してはいけないとされています。そういう機密性の高い操作は URL mode のように、適切な外部画面と同意を通すべき、という考え方です。

ここから開発現場が学べることは大きいです。

AIに確認させるなら、確認のUIと境界も設計しないといけない。

ただチャットで「APIキーを教えてください」と言わせてはいけないんです。

これはAIの賢さの問題ではなく、システム設計の問題です。

人間が設計し、AIに任せ、CIで守る範囲

ここで責任分界をはっきりさせます。

人間が設計するもの

  • 何を成功とするか
  • 何を禁止するか
  • どの変更を自動承認するか
  • どの変更を人間承認にするか
  • どのログを残すか
  • どの失敗なら中断するか

AIに任せるもの

  • 影響範囲の洗い出し
  • 変更案の作成
  • テスト追加
  • ドキュメント更新
  • PR本文の下書き
  • Decision Queue の作成

CIやツールで守るもの

  • 禁止ファイル変更の検知
  • secret scanning
  • migration の検知
  • CODEOWNERS によるレビュー要求
  • dangerous command のブロック
  • approval.yml との整合性チェック

人間が全部見る必要はありません。

でも、人間が何も設計しないまま、AIに全部任せるのも危ない。

人間は判断基準を設計する。AIは作業と整理を担当する。CIは約束違反を止める。

この三角形で考えると、AI開発はかなり安定します。

まず作るべき approval.yml

最初から大げさな仕組みを作らなくて大丈夫です。

まずはリポジトリのルートに approval.yml を1枚置くだけでも、かなり変わります。

version: 1
project: sample-web-app
principle: deny_by_default_for_high_risk_changes

risk_levels:
  low:
    description: ユーザー影響が小さく、戻しやすい変更
    examples:
      - README更新
      - テスト追加
      - 内部関数の小さなリファクタ
  medium:
    description: ユーザー影響はあるが、レビューとテストで制御できる変更
    examples:
      - UI文言変更
      - 新しいAPIレスポンス項目の追加
      - 非破壊的なDBカラム追加
  high:
    description: 認証、課金、個人情報、本番運用、破壊的変更に関わる変更
    examples:
      - 認証ロジック変更
      - 決済処理変更
      - DBカラム削除
      - CI/CD設定変更
      - 外部ネットワークアクセス追加

auto_approve:
  - risk: low
    required_checks:
      - unit_tests_pass
      - no_secret_detected
      - no_production_config_change

require_human_approval:
  - risk: medium
    required_packet:
      - summary
      - affected_files
      - test_plan
      - rollback_plan
  - risk: high
    required_packet:
      - summary
      - affected_files
      - risk_reason
      - alternatives
      - test_plan
      - rollback_plan
      - owner_review

always_deny:
  - expose_secret_values
  - ask_user_for_api_key_in_chat
  - run_destructive_command_against_production
  - bypass_branch_protection

これ、ただのYAMLです。

でも、あるだけでAIへの指示が変わります。

「このファイルを読んで、変更前に risk を分類して。medium 以上なら Decision Queue を作って」と言えるからです。

TypeScriptで Approval Contract を検証する

YAMLを書くだけでも効果はありますが、できれば機械的に検証したいです。

たとえば TypeScript と Zod で、Decision Queue の形式をチェックできます。

import { z } from "zod";

const RiskSchema = z.enum(["low", "medium", "high"]);
const DecisionStatusSchema = z.enum([
  "draft",
  "waiting_human",
  "approved",
  "rejected",
  "expired",
]);

const DecisionQueueItemSchema = z.object({
  id: z.string().regex(/^DQ-\d{4}-\d{3}$/),
  status: DecisionStatusSchema,
  risk: RiskSchema,
  summary: z.string().min(10),
  decisionNeeded: z.object({
    question: z.string().min(10),
    options: z.array(z.enum(["approve", "reject", "request_smaller_plan"])).min(2),
  }),
  context: z.object({
    relatedIssue: z.string().optional(),
    files: z.array(z.string()).min(1),
  }),
  impact: z.object({
    userVisibleChange: z.string(),
    rollbackPlan: z.string().min(10),
  }),
  expiresAt: z.string().datetime(),
  fallbackIfExpired: z.enum(["reject", "request_smaller_plan"]),
});

export type DecisionQueueItem = z.infer<typeof DecisionQueueItemSchema>;

export function validateDecisionQueueItem(input: unknown): DecisionQueueItem {
  return DecisionQueueItemSchema.parse(input);
}

これで、AIが作った確認依頼が薄すぎる場合に落とせます。

たとえば rollbackPlan が空ならエラーにする。
affected files がなければエラーにする。
選択肢が approve しかなければエラーにする。

人間に聞く前に、AIの質問品質をチェックするわけです。

これ、地味ですがかなり効きます。

悪い確認依頼って、人間の時間を奪うんですよね。

「どうしますか?」だけ聞かれても困る。

「A案、B案、C案があります。影響はこうです。戻し方はこうです。おすすめはAです。承認しますか?」まで出してほしい。

そこまでを型で強制する。

GitHub Actionsで危険変更を止める

次に CI です。

たとえば、AIエージェントが作ったPRで prisma/schema.prisma.github/workflows が変わっていたら、人間承認ラベルを必須にする、というチェックができます。

name: approval-contract-check

on:
  pull_request:
    types: [opened, synchronize, labeled, unlabeled]

jobs:
  check-approval-contract:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Detect changed files
        id: changed
        run: |
          git diff --name-only origin/${{ github.base_ref }}...HEAD > changed.txt
          cat changed.txt

      - name: Require human approval for high risk files
        run: |
          HIGH_RISK=false

          if grep -E '^(prisma/schema\.prisma|\.github/workflows/|src/auth/|src/payment/)' changed.txt; then
            HIGH_RISK=true
          fi

          if [ "$HIGH_RISK" = "true" ]; then
            echo "High risk files changed. Checking labels..."
            echo '${{ toJson(github.event.pull_request.labels) }}' > labels.json
            if ! grep -q 'human-approved' labels.json; then
              echo "This PR changes high risk files and requires the human-approved label."
              exit 1
            fi
          fi

この例はシンプルですが、考え方としては十分です。

AIが高リスクファイルを触ったら、CIが止める。
人間が確認して human-approved ラベルを付けたら進む。

この流れを作ると、AIに安心して低リスク作業を任せやすくなります。

「全部怖いから任せない」ではなく、怖いところだけ止める

これが現実的です。

プロンプト例1: 作業開始時に Approval Contract を読ませる

あなたはこのリポジトリのAIコーディングエージェントです。

作業前に必ず approval.yml を読み、今回のタスクを low / medium / high に分類してください。

出力してください:
1. タスク概要
2. 想定変更ファイル
3. risk分類
4. 自動実行してよい作業
5. 人間承認が必要な作業
6. もし承認が必要なら Decision Queue item の下書き

禁止事項:
- APIキー、パスワード、アクセストークンをチャットで要求しない
- 本番環境への破壊的操作を実行しない
- approval.yml の always_deny に該当する操作を提案しない

最初にこれを渡すだけで、AIの動き方が変わります。

「とりあえず実装します」ではなく、「まず分類します」になる。

AI開発では、この最初の姿勢がけっこう大事です。

プロンプト例2: 確認依頼を Decision Queue 形式にする

人間の判断が必要な場合、自由文で質問しないでください。
必ず次の形式で Decision Queue item を作ってください。

- id
- risk
- summary
- decision_needed.question
- decision_needed.options
- context.related_issue
- context.files
- impact.user_visible_change
- impact.rollback_plan
- expires_at
- fallback_if_expired

質問は1つの Decision Queue item につき1判断に限定してください。
複数の判断を1つに混ぜないでください。

これも効きます。

AIは、放っておくと複数の質問を1つの文章に混ぜがちです。

「DB変更していいですか?ついでにUIも変えていいですか?あとAPI仕様も変えますか?」みたいな感じです。

人間からすると、答えづらい。

だから 1キュー1判断 にします。

これだけで承認が速くなります。

プロンプト例3: 承認後にやることを固定する

Decision Queue item が approved になった場合のみ、対象作業を進めてください。

承認後に必ず実施してください:
1. 承認IDをコミットメッセージまたはPR本文に記録する
2. 変更ファイル一覧をPR本文に記録する
3. 実行したテストコマンドと結果を記録する
4. rollback_plan が実行可能か再確認する
5. 承認範囲を超える変更が必要になった場合は、作業を止めて新しい Decision Queue item を作る

承認範囲を勝手に拡張しないでください。

承認でよくある事故は、「承認した範囲を超えて、ついでに色々やる」ことです。

人間でもありますよね。

「この文言だけ直して」と言ったのに、ついでにレイアウトまで変わっている。

AIはもっとやりがちです。

だから、承認にはスコープがあります。

承認は白紙委任ではない。指定された範囲の通行証。

この感覚をプロンプトに入れておくと安全です。

プロンプト例4: レビュー時に承認違反を探す

このPRを Approval Contract の観点でレビューしてください。

確認してください:
1. approval.yml に照らして risk 分類は妥当か
2. high risk 変更に human-approved ラベルまたは承認記録があるか
3. Decision Queue item の承認範囲を超えた変更がないか
4. secret、token、password、private key らしき文字列が含まれていないか
5. rollback_plan がPR本文に書かれているか
6. テスト結果が証跡として残っているか

出力形式:
- OK / NG
- NGの場合の理由
- 修正すべきファイル
- 人間が追加判断すべき項目

AIにレビューさせる時も、ただ「レビューして」では弱いです。

何を見てほしいのかを決める。

ここでも人間の仕事は、レビュー観点の設計です。

小さな導入手順

ここまで読むと、ちょっと重く感じるかもしれません。

でも最初の一歩はかなり小さくできます。

Step 1: high risk だけ書く

まずは approval.yml に high risk だけ書きます。

high_risk_files:
  - prisma/schema.prisma
  - .github/workflows/**
  - src/auth/**
  - src/payment/**
  - infra/**

always_deny:
  - ask_for_secret_in_chat
  - run_production_delete
  - bypass_branch_protection

これだけでも十分です。

Step 2: AIに最初に読ませる

次に、AIへの作業依頼の冒頭にこう書きます。

作業前に approval.yml を読んでください。
high risk に該当する場合は、実装前に Decision Queue item を作って止まってください。

Step 3: PRテンプレに承認欄を足す

## Approval

- Risk level: low / medium / high
- Decision Queue ID:
- Human approval required: yes / no
- Human-approved label required: yes / no

## Evidence

- Test command:
- Test result:
- Rollback plan:

この3つだけで、AI開発の安全性はかなり上がります。

完璧な仕組みを作る必要はありません。

まずは、未来の自分がレビューするときに「これ残してくれて助かった」と思える情報を残す。

それでいいと思います。

よくある失敗

失敗1: 何でも人間承認にする

安全に見えます。

でも、全部人間承認にすると、AIを使う意味が薄れます。

READMEの修正、テスト追加、内部関数の小さな整理まで全部止めていたら、人間がボトルネックになります。

大事なのは、全部止めることではありません。

止めるべきところだけ止めること。

失敗2: 承認した証跡を残さない

チャットで「OK」と言っただけだと、後から追えません。

なぜその判断をしたのか。
どの範囲まで許可したのか。
誰が見たのか。

ここが残っていないと、レビュー不能になります。

最低でも PR本文、Issueコメント、ラベル、Decision Queue ファイルのどこかに残したいです。

失敗3: 秘密情報を確認フローに乗せる

これは本当に避けたいです。

APIキー、パスワード、アクセストークン、秘密鍵、決済情報。

こういうものをAIチャットやフォームで直接受け渡しする設計は危ないです。

必要なら、適切な管理画面、シークレットマネージャー、認可されたURL遷移、権限分離を使うべきです。

AIに「キーを貼ってください」と言わせない。

これはチームルールにしていいと思います。

AI時代のエンジニアの役割は、判断の設計に寄っていく

ここまで書いてきたことは、単なる安全対策ではありません。

エンジニアの役割変化の話でもあります。

昔は、実装できる人が強かった。

もちろん今も実装力は大事です。

でもAIがかなりの実装を手伝ってくれるようになると、人間の価値は少しずつ別の場所に移っていきます。

  • 何を作るべきか
  • 何を作らないべきか
  • どこまで任せるか
  • どこで止めるか
  • 何を証拠として残すか
  • どのリスクを許容するか

つまり、判断の設計 です。

AIにコードを書かせる技術だけだと、どこかで詰まります。

AIに安心して任せるための、コンテキスト、制約、承認、証跡、評価。

ここまで含めて設計できる人が、これからの開発現場ではかなり強いと思います。

まとめ

AIエージェントが強くなるほど、「確認してください」は増えます。

でも、その確認を毎回チャットで受けていると、人間が疲れます。

だから、先に設計しておく。

  • Approval Contract で、承認ルールを明文化する
  • Decision Queue で、確認事項を1判断ずつ構造化する
  • MCP Elicitation の考え方から、ユーザー同意・拒否・秘密情報の扱いを学ぶ
  • TypeScript や CI で、確認依頼と危険変更を機械的に検証する
  • 人間は判断基準を設計し、AIは作業と整理を担当し、CIが約束違反を止める

AIを使う開発は、雑にやると怖いです。

でも、ちゃんと設計すると、めちゃくちゃ頼もしい相棒になります。

最初から完璧な承認基盤を作る必要はありません。

まずは approval.yml を1枚置く。
PRテンプレに承認欄を足す。
AIに「作業前にリスク分類して」と頼む。

それだけで、明日のレビューはかなり楽になるはずです。

未来の自分が、たぶんこう言います。

「この承認ルール、先に作っておいてくれて助かったな」と。

そういう小さな設計を、今日のうちに1つだけ置いておく。

AI時代の開発って、案外そこから始まるのかなと思っています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?