0
1

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に実装を任せる前に「評価仕様」を書く技術 — Eval Gate / Acceptance Criteria as Code 実践ガイド

0
Posted at

はじめに

AIコーディングエージェントの進化、かなり速いですよね。

OpenAI Codex はクラウド上のサンドボックスでリポジトリを読み、コードを書き、テストやリンターを実行し、PR相当の変更まで提案できます。GitHub Copilot coding agent も Issue を起点に開発環境を立ち上げ、Draft PR にコミットを積んでいく流れになっています。Claude Code のようなターミナル型エージェントも、プロジェクト内のルールやテストコマンドを読みながら実装を進められます。

つまり、AIに「コードを書いてもらう」こと自体は、もう珍しくなくなってきました。

でも、ここで一つ問題があります。

AIが書いたコードが、本当に仕事として完了しているかを誰が判断するのか。

ここを曖昧にしたままAI開発を進めると、なんとなく動くコードは増えるけど、レビューが重くなります。仕様の認識ズレも増えます。テストは通っているのに、業務的には通っていない、みたいな状態も起きます。

なんかこれって、AIの性能不足というより、人間側が「合格条件」を設計していない問題な気がするんです。

この記事では、AIに実装を任せる前に、人間が 評価仕様 を書くための実践パターンとして、僕なりに Eval Gate / Acceptance Criteria as Code という形で整理してみます。

結論: AI時代の開発は「プロンプト」より「合格条件」が大事

まず結論からです。

AI開発で安定して成果を出すには、プロンプトを上手に書くより先に、次の3つを決めた方がいいです。

  1. 何をもって完了とするか
  2. 何が起きたら失敗とするか
  3. その判断を人間だけでなく、テスト・スクリプト・チェックリストで再現できるか

AIへの指示文はもちろん大事です。

でも、指示文だけだと「いい感じに作って」というお願いに近くなります。AIはその場でかなり賢く補完してくれるので、一見うまくいきます。ただ、補完された前提が人間の期待とズレていた場合、あとからレビューで全部掘り起こすことになります。

そこで、タスク開始前に Acceptance Criteria をコードやMarkdownとして置いておく。

たとえば、こんな感じです。

## Acceptance Criteria

- 未ログインユーザーが `/settings` にアクセスしたら `/login` にリダイレクトされる
- ログイン済みユーザーは自分のプロフィールだけ編集できる
- 他人のプロフィールIDを指定した場合は 403 を返す
- 保存成功時は toast を表示し、フォームの dirty state を解除する
- `npm run test` と `npm run lint` が通る

これだけでもだいぶ違います。

さらに一歩進めて、この条件をテストや小さな検証スクリプトに落とします。これがこの記事でいう Acceptance Criteria as Code です。

なぜ今「評価仕様」が重要なのか

AIエージェントは、昔の補完ツールとは違います。

補完ツールは、基本的に人間がキーボードを握っていました。AIは横で候補を出すだけです。でも、最近のエージェントは、ファイルを読み、複数ファイルを変更し、コマンドを実行し、失敗したら自分で直します。

OpenAI Codex の発表でも、タスクごとに独立したクラウド環境で実行し、テスト出力やターミナルログを証拠として提示する流れが説明されています。GitHub Copilot coding agent も GitHub Actions ベースの環境で作業し、Draft PR に変更を積みます。SWE-bench Verified のようなベンチマークも、実GitHub Issueに近い問題を解けるかどうかを見ています。

流れとしては明らかに、AIは「会話相手」から「作業者」に寄ってきています。

作業者が増えた時に必要になるのは、気合いではなく、受け入れ基準です。

人間の新人エンジニアに仕事を渡す時も同じですよね。

「ログイン周りいい感じに直しておいて」だと、受け取る側も困ります。

でも、

  • どの画面で
  • どのユーザー種別が
  • どの操作をした時に
  • 何が起きればOKで
  • 何が起きたらNGか

まで書いてあると、実装もレビューも一気に楽になります。

AIでも同じです。

いや、AIだからこそ、もっと明示した方がいい。

AIは空気を読んでくれるように見えます。でも、その空気は確率的に補完された空気です。現場の事情、過去の意思決定、ユーザーとの約束、運用上の地雷までは、文脈として渡さないと見えません。

だから、僕はAI時代のエンジニアの仕事は、実装者から「評価と文脈の設計者」に寄っていくと思っています。

Eval Gate とは何か

この記事でいう Eval Gate は、AIが作業を完了したと言う前に通す、小さな関門のことです。

難しいものではありません。

構造はこれだけです。

# Eval Gate

## 1. Context
このタスクの背景、対象ユーザー、関連ファイル、守るべき制約を書く

## 2. Acceptance Criteria
完了条件を箇条書きで書く

## 3. Negative Criteria
やってはいけないこと、壊してはいけないことを書く

## 4. Verification Commands
AIと人間が実行すべき確認コマンドを書く

## 5. Human Review Points
最後に人間が見るべき判断ポイントを書く

ポイントは、テストで全部を自動化しようとしないことです。

もちろん自動テストは大事です。でも、UIの違和感、文言のニュアンス、業務上の説明責任、セキュリティ上の違和感などは、人間が見た方がいい場面もあります。

なので、Eval Gate は AIに任せる部分 と 人間が判断する部分 を分けるための境界線です。

たとえば、こんな使い分けです。

項目 AIに任せやすい 人間が見るべき
型エラー yes no
単体テスト yes no
既存仕様との差分整理 yes yes
セキュリティ影響 partly yes
UXの気持ち悪さ partly yes
事業上の優先順位 no yes

AIに全部任せるのではなく、人間が全部抱えるのでもない。

判断の置き場所を設計する。

ここが大事かなと。

実装例1: Markdownで Eval Gate を作る

まずは一番簡単な形です。リポジトリに docs/eval-gates/ を作って、タスクごとにMarkdownを置きます。

# Eval Gate: settings-profile-update

## Context

ユーザー設定画面のプロフィール更新機能を改善する。
対象はログイン済みユーザー。未ログインユーザーは設定画面に入れない。
既存の認証ミドルウェアと API route は変更してよいが、公開プロフィールページの表示仕様は変えない。

## Acceptance Criteria

- 未ログイン状態で `/settings/profile` にアクセスすると `/login` にリダイレクトされる
- ログイン済みユーザーは `displayName` と `bio` を更新できる
- `displayName` は 1〜40 文字
- `bio` は 160 文字以内
- 他人の userId を指定した更新リクエストは 403 になる
- 更新成功時、画面に「保存しました」と表示される
- 更新失敗時、フォーム入力内容は消えない

## Negative Criteria

- public profile page の URL 仕様を変更しない
- DB schema migration は追加しない
- 認可チェックをフロントエンドだけに置かない
- 既存の `UserProfileCard` の props を破壊しない

## Verification Commands

```bash
npm run lint
npm run typecheck
npm run test -- profile
```

## Human Review Points

- エラーメッセージがユーザーに冷たすぎないか
- 保存成功後の導線が自然か
- 認可チェックが API 側にも存在するか

これをAIに渡して、こう依頼します。

あなたはこのリポジトリの開発エージェントです。

次の Eval Gate を満たすように実装してください。
実装前に、関連ファイルと既存仕様を調査し、変更計画を短く提示してください。
実装後は Verification Commands を実行し、結果を要約してください。

重要:
- Acceptance Criteria を満たさない変更は完了扱いにしないでください
- Negative Criteria に触れる場合は、実装前に理由と代替案を提示してください
- 最後に Human Review Points に沿って、人間が見るべき箇所を列挙してください

[ここに Eval Gate Markdown を貼る]

プロンプトのコツは、「実装して」だけで終わらせないことです。

調査 → 計画 → 実装 → 検証 → 人間レビュー観点の提示 までを1つの流れにします。

AIは作業者としては優秀です。でも、作業の終わり方を指定しないと、終わった雰囲気だけ作ることがあります。

そこを Eval Gate で止めるわけです。

実装例2: Acceptance Criteria を TypeScript で検証する

次は、完了条件の一部をコードにします。

たとえば API の認可やバリデーションは、自然言語だけでなくテストに落としやすいです。

// tests/profile-update.acceptance.test.ts
import { describe, expect, it } from "vitest";
import { updateProfile } from "../src/features/profile/updateProfile";
import { createTestUser, createGuestContext } from "./helpers";

describe("profile update acceptance criteria", () => {
  it("rejects guest users", async () => {
    const ctx = createGuestContext();

    await expect(
      updateProfile(ctx, {
        userId: "user_001",
        displayName: "Sample User",
        bio: "hello",
      })
    ).rejects.toMatchObject({ code: "UNAUTHORIZED" });
  });

  it("rejects updating another user's profile", async () => {
    const alice = createTestUser({ id: "user_alice" });

    await expect(
      updateProfile(
        { currentUser: alice },
        {
          userId: "user_bob",
          displayName: "Bob",
          bio: "This should not be allowed",
        }
      )
    ).rejects.toMatchObject({ code: "FORBIDDEN" });
  });

  it("validates displayName and bio length", async () => {
    const user = createTestUser({ id: "user_001" });

    await expect(
      updateProfile(
        { currentUser: user },
        {
          userId: "user_001",
          displayName: "",
          bio: "a".repeat(161),
        }
      )
    ).rejects.toMatchObject({ code: "VALIDATION_ERROR" });
  });
});

このテストは、完璧なE2Eではありません。

でも、AIにとってはかなり強い足場になります。

「認可を忘れないで」と自然言語で言うより、落ちるテストを先に置く 方が、AIは修正しやすいです。Claude Code のベストプラクティスでも、環境設定、明確なコマンド、反復可能なテストが重要視されています。Codex の説明でも、テストやログを証拠として残す流れが出てきます。

つまり、AIに任せるなら、テストは単なる品質保証ではなく、AIへの道案内にもなります。

これ、地味ですがめっちゃ重要です。

実装例3: AIレビュー用のチェックJSONを作る

もう少し運用寄りにするなら、Eval Gate をJSONにして、AIレビューやCIで読みやすくしておくのもありです。

{
  "taskId": "settings-profile-update",
  "riskLevel": "medium",
  "contextFiles": [
    "src/app/settings/profile/page.tsx",
    "src/features/profile/updateProfile.ts",
    "src/server/auth.ts"
  ],
  "acceptanceCriteria": [
    "Guest users are redirected to /login",
    "Authenticated users can update displayName and bio",
    "Users cannot update another user's profile",
    "Validation errors preserve form input",
    "lint, typecheck, and profile tests pass"
  ],
  "negativeCriteria": [
    "Do not remove server-side authorization",
    "Do not change public profile URLs",
    "Do not add database migrations"
  ],
  "verificationCommands": [
    "npm run lint",
    "npm run typecheck",
    "npm run test -- profile"
  ],
  "humanReviewPoints": [
    "Check wording of validation messages",
    "Check UX after successful save",
    "Check whether authorization exists on the API side"
  ]
}

これを使って、AIレビューに次のように投げます。

あなたはPull Requestレビュアーです。
以下の Eval Gate JSON と、変更差分を比較してください。

レビュー観点:
1. acceptanceCriteria が満たされているか
2. negativeCriteria に違反していないか
3. verificationCommands の結果から見て、追加確認が必要か
4. humanReviewPoints として、人間が見るべき箇所はどこか

出力形式:
- PASS / WARN / FAIL
- 根拠
- 修正すべきファイル
- 人間レビューへの引き継ぎ

この形にすると、AIを「実装担当」だけでなく「一次レビュアー」としても使いやすくなります。

ただし、注意点があります。

AIレビューの結果をそのまま正解にしないことです。

AIはレビューもできます。でも、事業判断やユーザー影響の最終責任までは持てません。なので、AIレビューは 人間レビューを軽くするための下ごしらえ と考える方が健全です。

Prompt例: タスク開始前・実装後・レビュー時

ここまでを実務に落とすために、すぐ使えるプロンプトを3つ置いておきます。

プロンプト1: タスク開始前の Eval Gate 作成

あなたはシニアエンジニア兼テックリードです。
次の開発タスクについて、AIコーディングエージェントに渡すための Eval Gate を作成してください。

タスク概要:
[ここにタスクを書く]

出力してほしいもの:
1. Context
2. Acceptance Criteria
3. Negative Criteria
4. Verification Commands
5. Human Review Points

条件:
- 初心者エンジニアでも迷わない粒度にしてください
- 自動テストで確認できるものと、人間が判断すべきものを分けてください
- セキュリティ、既存仕様破壊、データ破壊の観点を必ず含めてください

プロンプト2: 実装エージェントへの依頼

あなたはこのリポジトリの実装担当AIエージェントです。
以下の Eval Gate を満たすように実装してください。

進め方:
1. 関連ファイルを調査する
2. 変更計画を短く書く
3. 実装する
4. Verification Commands を実行する
5. Acceptance Criteria の充足状況を表で報告する
6. Human Review Points を人間に引き継ぐ

禁止:
- Negative Criteria に違反しない
- テストを通すためだけに仕様を弱めない
- 既存テストを理由なく削除しない

[Eval Gate を貼る]

プロンプト3: PRレビューAIへの依頼

あなたはPull Requestの一次レビュアーです。
以下の Eval Gate と差分を比較し、レビューしてください。

確認項目:
- Acceptance Criteria は満たされているか
- Negative Criteria に違反していないか
- テストや型チェックは十分か
- 実装が過剰に複雑になっていないか
- 人間が最終判断すべき点は何か

出力形式:
## 判定
PASS / WARN / FAIL

## 根拠
箇条書き

## 修正提案
ファイル名と内容

## 人間レビューへの引き継ぎ
最終確認すべき観点

この3つだけでも、AI開発の事故はかなり減ると思います。

開発フローに組み込むならこうする

実務で使うなら、僕はこういう流れにします。

Issue作成
  ↓
Eval Gateを書く
  ↓
AIに調査と実装計画を出させる
  ↓
人間が計画だけ確認する
  ↓
AIが実装する
  ↓
Verification Commandsを実行する
  ↓
AIが自己レビューする
  ↓
人間がHuman Review Pointsだけ重点確認する
  ↓
マージ判断

大事なのは、人間が全部レビューしないことです。

全部を見ると、AIを使っているのに疲れます。

でも、何も見ないと危ない。

なので、見る場所を先に決める。

これが Eval Gate の役割です。

人間が設計するもの:

  • ゴール
  • 制約
  • 完了条件
  • 失敗条件
  • 最終判断ポイント

AIに任せるもの:

  • 関連ファイル調査
  • 実装案の比較
  • コード変更
  • テスト追加
  • コマンド実行
  • 一次レビュー

人間が判断するもの:

  • ユーザー体験として自然か
  • 事業上の優先順位に合っているか
  • セキュリティや運用リスクを許容できるか
  • 今マージすべきか、後回しにすべきか

こう分けると、AIはかなり頼れる作業者になります。

逆に、この分担がないと、AIは「速いけど危なっかしい人」になります。

よくある失敗パターン

失敗1: 「テスト通ったのでOK」にする

テストは大事です。

でも、テストが仕様を代表していないなら、通っても意味が薄いです。

たとえば「保存できる」テストはあるけど、「他人のデータを保存できない」テストがない。これは危ないですよね。

テストは合格条件の一部であって、全部ではありません。

失敗2: Acceptance Criteria が抽象的すぎる

「使いやすいUIにする」だけだと、AIも人間も困ります。

こう分解した方がいいです。

- エラー時に入力内容が消えない
- 保存中はボタンが disabled になる
- 保存成功後に toast を表示する
- 画面遷移せず、同じページで編集を続けられる

抽象的な価値を、観測できる条件に落とす。

ここが人間の仕事です。

失敗3: Negative Criteria がない

AIは良かれと思って広めに直します。

これは便利な時もありますが、既存仕様を壊す原因にもなります。

なので、やってほしくないことを書きます。

- 認証方式は変更しない
- DB schema は変更しない
- 既存URLは変えない
- 課金状態の判定ロジックには触らない

AIは「何をするか」だけでなく、「何をしないか」を渡すと安定します。

これ、プロンプトエンジニアリングというより、ほぼ業務設計です。

まとめ

AIコーディングエージェントが強くなるほど、エンジニアの仕事は減るというより、少し場所が変わるんだと思います。

コードを書く量は減るかもしれません。

でも、何を作るべきか。何を守るべきか。どこまでできたら完了なのか。どこから先は人間が判断するのか。

ここは、むしろ重要になります。

AIに実装を任せる前に、評価仕様を書く。

自然言語で Acceptance Criteria を置く。

落とせるものはテストやJSONにする。

最後に Human Review Points を残す。

これだけで、AI開発はかなり「仕事として扱いやすい形」になると思います。

AIにコードを書かせる技術より、AIが書いたコードを 安心して受け取れる状態にする技術。

これからの現場では、こっちの価値がどんどん上がる気がしています。

まずは次のタスクで、1枚だけ Eval Gate を書いてみる。

それだけで、AIへの指示も、レビューも、ちょっと楽になるはずです。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?