AIに頼んだコードが後半で雑になる理由と、チームで実践したハーネス設計という解決策

この記事の対象者

  • Claude CodeやChatGPTを使って日常的に開発しているエンジニア
  • AIに実装を任せてみたが、後半の品質が落ちると感じている人
  • チームの開発フローにAIをうまく組み込みたいと考えている人
  • 「プロンプトをうまく書く」以外のアプローチを知りたい人

AIに「これ実装して」と頼むと、最初は丁寧なコードが出てきます。でも会話が長くなるにつれて、後半はコピペだらけ・ハードコードだらけになっていきます。そういう経験はありませんか。

これは気のせいでも、プロンプトの書き方が悪いわけでもありません。AIの構造的な問題です。

今回は、Anthropicが提唱する「ハーネス設計」という考え方と、それを自分たちのチームの開発フローに実際に取り込んだ事例を紹介します。

AIには2つの根本的な問題がある

問題① コンテキスト不安(品質劣化)

AIには処理できる情報量に上限(トークン上限)があります。会話が長くなるにつれてその上限に近づき、「早く終わらせよう」とでも言うかのように実装が雑になっていきます。

  • 序盤:丁寧な型定義・コンポーネント分割・一貫した命名
  • 後半:コピペ・重複コード・ハードコード多発

Anthropicはこの現象を「コンテキスト不安」と呼んでいます。そしてこれは、プロンプトの工夫で解決できる問題ではありません。構造レベルで対処する必要があります。

問題② 自己評価バイアス

AIに「この実装、問題ないですか?」と聞くと「完璧です!」と返ってくることが多いです。でも実際にはバグだらけだったりします。

これは作るときと同じ思考・同じ文脈で評価するため、自分の盲点に気づけないからです。人間でも自分で書いたコードのバグは自分では見つけにくいです。だからコードレビューが存在します。AIにも「別の目」が必要です。

ハーネス設計とは何か

Anthropicはこの2つの問題に対して「ハーネス設計」というアプローチを提唱しています。

ハーネスとは馬具のことです。AIを強力な暴れ馬に見立て、檻に閉じ込めるのではなく、力を殺さずに目的地へ導く道具として設計する、という考え方です。

具体的には3つの馬具に対応しています。

馬具 役割 具体例
轡(くつわ) 行動制限 ファイル読み取りは自動許可、書き込み・実行は人間が承認
鞍(くら) 記憶の管理 プロジェクトルールは永続保存、作業ログは都度リセット
手綱(たづな) フィードバック 評価結果を次の実装に自動で反映するループ

3つのAIに役割分担させる

ハーネス設計の核心は、AIを1体で使わずに3つの役割に分けることです。人間の開発チームと同じ構成になります。

📋 プランナー  →  ⚙️ ジェネレーター  ↔  🔍 エバリュエーター
(PM役・企画)     (エンジニア役・実装)   (QA役・評価)
  • プランナー:曖昧な要件を具体的な仕様に変換する。詳細すぎる指示はNG(カスケードエラーの原因になる)
  • ジェネレーター:仕様をもとに実装する。実装前に「これを作ります」と宣言(スプリント契約)してから始める
  • エバリュエーター独立した別のAIが実際にブラウザを操作して検証し、フィードバックを返す。ジェネレーターが修正→また評価、のループを繰り返す

なぜ評価者を分けるのか

同じAIに評価させると、作るときと同じ思考で評価するため自分の盲点が見えません。「完璧です!」と言いながらバグが残る、いわゆる自画自賛ループです。

一方、新しい会話(別コンテキスト)で評価させると、先入観なく客観的に見られます。 同じモデルでもコンテキストを分ければ「別の目」になれます。

これは画像生成で使われるGAN(敵対的生成ネットワーク)と同じ発想です。「作る側」と「批評する側」が競い合うことで品質が上がります。Anthropicの報告では5〜15回のループで品質が大幅に向上したとされています。

補足として、Claude CodeのAgentツールでサブエージェントを呼び出すと、そのエージェントは完全に独立した新しいコンテキストで起動します。実装者が何を考えて実装したかを、評価者は物理的に知る手段がありません。これがハーネス設計の「評価者分離」を自然に実現しています。

自分たちの開発フローへの適用

ここからが実践の話です。上記のハーネス設計の思想を、実際のバグ修正フローに取り込みました。

実装方法:Claude Codeのスキルとして定義する

Claude Codeには「スキル」という仕組みがあります。SKILL.md というMarkdownファイルにフローの手順を定義しておくと、Claude Codeがそれを読み込んで手順通りに動いてくれます。

.claude/
└── skills/
    └── bug-fix/          ← スキルの名前
        └── SKILL.md      ← フローの手順を定義するファイル

SKILL.mdの中には「Step 1でこのエージェントを呼ぶ、Step 2でこのエージェントを呼ぶ」という手順を書くだけです。各ステップで呼び出すエージェントも .claude/agents/ 配下に個別に定義します。

.claude/
├── skills/
│   └── bug-fix/
│       └── SKILL.md          ← フロー全体の司令塔
└── agents/
    ├── issue-fetcher.md      ← Issue情報を取得する役割
    ├── code-investigator.md  ← コードを調査する役割
    ├── plan-reviewer.md      ← 修正計画を作る役割
    ├── implementer.md        ← 実装する役割
    ├── db-preparator.md      ← テストデータを準備する役割
    ├── frontend-evaluator.md ← 独立して評価する役割
    └── pr-creator.md         ← PRを作成する役割

それぞれのエージェントは独立した別のコンテキストで起動します。つまり、実装エージェントが「何を考えて実装したか」を評価エージェントは知りません。渡された情報だけを見て判断するため、自己評価バイアスが構造的に排除されます。

フロー全体像

この構成で実現したバグ修正フローは以下のとおりです。

① Issue取得・分析(プランナー)
      ↓
② コード調査・修正計画の作成(プランナー)
      ↓
③ 人間が修正計画を承認  ← ここで人間が介入
      ↓
④ 実装・テスト・Lint(ジェネレーター)
      ↓
⑤ 操作確認用のテストデータを確認・準備(サポート役)
      ↓
⑥ 独立した評価エージェントがブラウザで動作確認(エバリュエーター)
      ↓
   ❌ FAIL → ④に差し戻し、ループ
   ✅ PASS ↓
⑦ 人間が最終確認  ← ここで人間が介入
      ↓
⑧ PR作成

SKILL.mdにこのフローを定義しておくことで、「IssueのURLを渡す」という一言だけでフロー全体が自動で動きます。エンジニアが介入するのは③修正計画の承認と⑦最終確認の2箇所だけになります。

各ステップの詳細

① Issue取得・分析

GitHubのIssue番号またはURLを受け取り、Issue本文・ラベル・関連リンクを取得して「課題サマリー」を生成します。何を直すべきかを整理するのがこのステップの目的です。

② コード調査・修正計画の作成

課題サマリーをもとに、関連する仕様書・実装ファイル・テストファイルを調査します。どのファイルのどの部分を変更すべきかを特定し、修正計画として出力します。

③ 人間が修正計画を承認

ここが最初の人間介入ポイントです。 AIが出した修正計画をエンジニアが確認し、方向性が正しければ承認します。この承認がなければ実装に進みません。

「何を直すか」に合意してから実装を始めることで、実装後の大幅な手戻りを防ぎます。

④ 実装・テスト・Lint(ジェネレーター)

承認済みの修正計画をもとに、ジェネレーターエージェントが実装を行います。実装完了後はテスト・Lintを実行し、基本的な品質チェックを通過したことを確認します。

実装完了レポートには「操作確認手順」も含めます。次のステップでテストデータを準備するための情報です。

⑤ テストデータの確認・準備(サポート役)

評価エージェントが動作確認をするためには、DBに適切なテストデータが存在している必要があります。

このステップでは専用のエージェントが以下を行います。

  1. 必要なデータがDBに存在するか確認する
  2. 存在しない場合のみ、最小限のデータを作成する
  3. 「確認画面URL・ログイン情報・操作手順・期待する結果」を含む再現可能な操作手順を出力する

毎回データを作り直すのではなく、「なければ作る」という設計がポイントです。

⑥ 独立した評価エージェントが動作確認(エバリュエーター)

ここがハーネス設計の核心です。実装エージェントとは完全に独立した別のエージェントが起動し、以下の4つの観点で評価します。

  1. 動作確認:指定された操作手順通りに画面が動くか(Playwrightでブラウザを自動操作)
  2. 仕様書との照合:修正計画・仕様書の内容と実装が一致しているか
  3. コード品質:既存コードとの整合性・コーディング規約の遵守
  4. UI整合性:画面崩れ・表示の不整合がないか

評価結果は PASS / FAIL で返します。

  • PASS:次のステップ(人間確認)へ進む
  • FAIL:差し戻し理由を添えて④(実装エージェント)に戻す。PASSが出るまでこのループを繰り返す

評価エージェントは実装エージェントが「何を意図して実装したか」を知りません。渡された情報と実際の動作だけを見て判断するため、自己評価バイアスが構造的に排除されています。

⑦ 人間が最終確認

ここが2番目の人間介入ポイントです。 評価エージェントがPASSを出した後、エンジニアが実際に画面を操作して確認します。

問題がなければ「PR作成してください」と一言伝えるだけで次のステップに進みます。問題があれば④に差し戻し、同じブランチに追加コミットとして積みます。

⑧ PR作成

承認済み修正計画・実装完了レポート・評価レポートをもとに、コミット・プッシュ・PR作成を自動で行います。


設計のポイントまとめ

人間が介入するのは2箇所だけ

修正計画の承認(③)と最終確認(⑦)のみ。それ以外はAIが自律的に回します。評価者がPASSを出すまで人間確認に進まない、という品質ゲートが自動化されています。

評価者は独立したコンテキストで起動する

実装エージェントと評価エージェントは別々のAgentとして起動するため、実装者の「意図」を評価者は引き継ぎません。実装の良し悪しだけを見て判断できます。

テストデータの準備を自動化する

「データが存在するか確認し、なければ作成する」という役割のエージェントを挟むことで、評価が常に再現可能になります。手動でテストデータを用意する手間がなくなります。

FAILループで品質を担保する

評価エージェントがFAILを出したら、フィードバックを実装エージェントに渡して差し戻します。PASSが出るまでこのループを繰り返すことで、人間が確認する前に一定の品質が担保されます。


旧フローとの違い

旧フロー 新フロー(ハーネス設計)
評価 実装エージェント自身が確認 独立した評価エージェントが確認
人間確認のタイミング 実装直後 評価エージェントPASS後のみ
テストデータ 手動で準備 自動で確認・準備
品質ゲート なし 評価ループで自動担保

スライドで全体を振り返る

以下のスライドで今回の内容をまとめています。スペースキーまたは矢印キーでページを送れます。

まとめ 道具はある、設計は自分たちでする

Claude CodeはPlaywright MCPやAgentツールなど、ハーネス設計を実現するための道具を提供しています。しかし「どう分業させるか」「評価基準を何にするか」「どこで人間が介入するか」は自分たちで設計する必要があります。

いきなり完全なフローを作る必要はありません。
まずは例として、AIに何か実装させたら → 新しい会話を開いて「この基準で評価して」と貼り付けるだけです。
同じモデルでもコンテキストを分ければ「別の目」になれます。

強い馬には良い馬具を。AIの力を最大限に引き出すのは、プロンプトの工夫ではなく設計の力です。


参考:Anthropic Engineering Blog「Harness Design for Long-Running Apps」