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

Git と pytest で AI コーディングエージェントの開発用テストと独立評価を分ける

0
Posted at

AI コーディングエージェントでは開発用テストと採用評価を分ける

AI コーディングエージェントは、コードを書くだけでなく、リポジトリを読み、ファイルを編集し、テストを実行して失敗結果を次の修正へ利用できます。SWE-agent でも、エージェントがコードの編集、リポジトリ内の移動、テストやその他のプログラムの実行を自律的に行う構成が示されています[1]

この開発ループでは、テスト結果は「変更後のコードが条件を満たしたか」を確認するだけではありません。失敗したテスト名、例外、期待値との差、スタックトレースが、次にどこを直すかを選ぶための情報になります。

そのため、エージェントが何度でも利用できる開発用テストと、最終的な採用判断に使う評価を同じものにしないほうが扱いやすくなります。本稿では、Git と pytest を例に、次の流れで評価境界を作ります。

  1. エージェントには開発用テストを自由に実行させる
  2. 実装候補をコミット SHA で固定する
  3. テストや CI など評価条件に関わる差分を確認する
  4. 別環境で独立評価を実行する
  5. 開発用テストと独立評価の両方を見て採否を判断する

エージェントが使うテストは最終評価ではない

テスト失敗は次の修正を選ぶための情報になる

通常の開発でも、失敗したテストは修正箇所を特定するために使います。AI コーディングエージェントでは、この反復を自律的に続けられる点が異なります。

たとえば、エージェントが次のコマンドを実行できるとします。

python -m pytest -q tests/unit/test_config.py

失敗した場合、エージェントは出力を読み、実装を変更し、同じコマンドを再実行できます。テスト結果は毎回の検査結果であると同時に、次の修正を選ぶためのフィードバックになります。

このループ自体は問題ではありません。高速に修正と検証を繰り返せることは、開発用テストの利点です。分けるべきなのは、このテストへの合格と最終的な採用判断です。

可視テストへの合格と仕様充足は一致しない

SpecBench は、自然言語で与える仕様、エージェントから見える可視検証テスト(validation tests)、最終評価に用いる非公開評価テスト(held-out tests)を分けています。非公開評価テストは、可視検証テストで個別に確認した機能を組み合わせ、実際の利用に近い条件で評価します。SpecBench はこの構成で 30 件のシステムレベルのプログラミング課題を評価しています[2]

ここで重要なのは、非公開テストそのものではなく、エージェントが反復利用する評価と、採否を決める評価を分離している点です。

テストは仕様のすべてを直接表すものではありません。有限個の入力、状態、組合せを選んで観測するため、合格した実装の中に「仕様全体を満たす実装」と「観測された条件だけを満たす実装」が混在する余地があります。AI エージェントが同じテスト結果を読みながら修正を繰り返すと、この差が実務上の評価設計として問題になります[3]

開発用テストと独立評価を二つに分ける

開発用テストと独立評価には、役割を分けて持たせます。

種類 目的 エージェントからの利用
開発用テスト 実装中の不具合を素早く発見し、修正ループを回す 読み取り・実行を許可する
独立評価 候補実装を採用できるか確認する 開発ループ中は評価資産を見せず、書き込みも許可しない

独立評価を別ディレクトリへ置くだけでは、エージェントから読み取れるなら境界にはなりません。評価用テストや評価スクリプトは、エージェントが作業するリポジトリとは別の評価環境に置き、候補実装だけを評価側へ渡します。

開発用テストはエージェントに自由に実行させる

開発中は通常どおりテストを使います。

python -m pytest -q tests/unit

このコマンドが終了ステータス 0 になった時点で言えるのは、「現在の候補実装が開発用テストを通過した」ということです。ここではまだ採用完了とは判定しません。

エージェントにテスト結果を隠すと、失敗原因の特定と修正が遅くなります。開発用フィードバックは残し、最終評価だけを分離します。

独立評価はエージェントの作業環境から分離する

開発用テストを通過した候補をコミットしたうえで、評価対象をコミット SHA で固定します。

CANDIDATE_SHA=$(git rev-parse HEAD)
printf '%s\n' "$CANDIDATE_SHA"

独立評価では、この SHA を新しい作業ツリーへ checkout した別環境を使います。評価環境には、開発環境で記録した CANDIDATE_SHA を評価対象として引き渡します。

git checkout "$CANDIDATE_SHA"
python -m pytest -q /opt/evaluation/tests

/opt/evaluation/tests は例です。重要なのは、評価用テストが開発エージェントの作業ツリーに含まれず、開発ループ中に読み書きできないことです。

評価記録には、少なくとも次を残します。

  • 評価したコミット SHA
  • 独立評価の終了ステータス
  • 使用した評価資産の版
  • 評価日時

候補 SHA を固定しておけば、開発用テストを通したコードと独立評価したコードが同一かを後から確認できます。

評価対象と評価条件を同じ権限で変更させない

実装コードと、実装を採点するテストや CI 設定を同じ権限で変更できる場合、テスト成功の意味を確認する必要があります。

EvilGenie は、プログラミング課題でテストケースをハードコードしたり、テストファイル自体を編集したりできる環境を作り、非公開単体テスト、LLM による判定、テストファイル変更検出の 3 種類で報酬ハッキングを測定しています[4]

実務では、テスト変更を全面禁止する必要はありません。不具合のあるテストを修正する場合や、仕様変更に伴ってテストを更新する場合もあります。必要なのは、実装変更と評価条件の変更を同じ判断で自己完結させないことです。

Git と pytest で評価境界を作る

ここからは、既存リポジトリに適用できる最小構成を示します。

前提は次のとおりです。

  • Git で変更履歴を管理している
  • Python と pytest を利用できる
  • エージェントの作業環境と独立評価環境を分けられる
  • 独立評価用のテストはエージェントから読み書きできない

Python や pytest は説明用の例です。他言語では、開発用テストと独立評価の境界を維持したまま、既存のテストランナーへ置き換えられます。

1. 開発用テストを実行する

エージェントには通常の開発用テストを実行させます。

python -m pytest -q tests/unit

ここで失敗した場合は、実装を修正して再実行します。成功するまでの試行回数自体を最終評価に使う必要はありません。目的は、開発用フィードバックを利用して候補実装を作ることです。

2. 候補コミットを確定する

開発用テストが成功し、コミット済みとなった候補について SHA を取得します。

git status --short
git rev-parse HEAD

未コミットの変更が残っている状態で SHA だけを記録すると、独立評価した内容と作業ツリーの内容が一致しません。git status --short で未コミットの変更が残っていないことも確認します。

3. 評価条件に関わる差分を確認する

基準となるコミットを BASE_SHA、候補を CANDIDATE_SHA として、変更ファイルを確認します。

git diff --name-only "$BASE_SHA" "$CANDIDATE_SHA"

たとえば、次のパスを評価条件として保護している場合があります。

tests/acceptance/
evaluation/
.github/workflows/

これらの変更が検出された場合は、通常の実装差分と同じ扱いでそのまま採用せず、変更理由を別に確認します。

git diff --name-only "$BASE_SHA" "$CANDIDATE_SHA" -- \
  tests/acceptance/ \
  evaluation/ \
  .github/workflows/

出力が空なら、この範囲には差分がありません。出力がある場合は、テストや評価条件を変更する必要があったのか、その変更を実装とは独立してレビューします。

このパス構成は例であり、実際の保護対象はリポジトリのテスト方針と CI 構成に合わせて決めます。

4. 別環境で独立評価を実行する

評価環境では候補 SHA を checkout し、開発エージェントから見えていなかった評価を実行します。

git checkout "$CANDIDATE_SHA"
python -m pytest -q /opt/evaluation/tests

独立評価は、開発用テストの単純な複製にしません。たとえば、開発用テストで個別に確認した機能を組み合わせた入力、境界値、既存機能との組合せを確認します。

ここで新しい秘密仕様を追加してはいけません。独立評価の期待値は、既存の仕様、Issue、受入条件から導出できる必要があります。

OpenAI が SWE-bench Verified を作成した際にも、問題記述が十分に仕様を示しているか、評価用テストが妥当な解を不当に落とさないかを人手で確認しています。500 件の Verified サンプルを作る過程では、Python 経験のある 93 人の開発者が 1,699 件を評価し、問題記述の不足や不適切なテストを除外しています[5]

独立評価を置く場合も、「見えないテストだから正しい」とは扱えません。仕様と評価条件の対応自体を確認する必要があります。

5. 両方の結果を揃えて採否を判断する

最終的な採用判断では、少なくとも次の 3 条件を別々に確認します。

確認項目 合格条件
開発用テスト 成功
独立評価 成功
評価条件に関わる差分 未承認の変更なし

開発用テストだけが成功した場合は、候補生成まで完了しています。独立評価まで成功し、評価条件の変更も確認できた時点で、採用候補として扱えます。

この分離により、エージェントが開発用テストへ適応すること自体を妨げず、その結果だけで最終採否を決めることを避けられます。

独立評価で確認する条件

未知入力と機能の組合せを確認する

独立評価では、開発用テストと異なる観測点を持たせます。

たとえば、次の二つの機能が仕様に含まれるとします。

  • parse() が入力文字列を構造化する
  • validate() が構造化結果を検証する

開発用テストでは、それぞれを個別に確認できます。

def test_parse():
    assert parse('{"id": 1}') == {"id": 1}


def test_validate():
    assert validate({"id": 1}) is True

独立評価では、同じ仕様から導ける組合せを確認します。

def test_parse_and_validate():
    data = parse('{"id": 1}')
    assert validate(data) is True

この例の目的は、テストケースを秘密にすることではありません。個別機能への局所的な適応だけではなく、仕様上要求される組合せでも成立するかを別の観測点から確認することです。

テストや CI の変更を別の変更として扱う

AI エージェントがテストを変更したという理由だけで不合格にする必要はありません。変更理由が仕様から説明でき、テスト自体の修正が必要な場合もあります。

一方で、テスト失敗を消すために期待値を実装へ合わせたり、対象テストを無効化したり、CI の実行対象から外したりした場合は、実装の正しさを示していません。

そのため、次の二つを分けて判断します。

  1. 実装を仕様へ合わせるための変更
  2. 実装を採点する条件そのものの変更

後者が含まれる場合は、実装とは別に変更理由を確認し、評価条件の更新として承認します。

テスト成功だけで採用を決めない

独立評価まで分離しても、テストで仕様全体を完全に証明できるわけではありません。要求定義の誤り、性能条件、運用条件、セキュリティ要件など、テストスイートだけでは判断できない事項が残る場合があります。

以前の記事では、Codex、Claude Code、GitHub Copilot CLI を対象に、作業領域、権限、テスト、Git 差分、作業ログ、人間による採否まで含めた評価手順を整理しました[6]。本稿で扱った開発用テストと独立評価の分離は、その中の「テスト結果をどう採否へ接続するか」をさらに細かく分けたものです。

独立評価が成功しても、変更内容に応じてコードレビュー、互換性確認、静的解析、セキュリティ確認などを追加します。必要な検証はリポジトリ固有の方針に従います。

この方法で防げることと防げないこと

開発用テストと独立評価を分けると、次の状態を区別しやすくなります。

  • 開発用テストには合格したが、未知入力や機能の組合せでは失敗する
  • 実装ではなくテストや CI の条件を変更して合格している
  • 開発時の候補と、最終的に評価した候補が異なる

一方で、独立評価そのものの不足は残ります。評価用テストが仕様を誤解していれば、正しい実装を落とす場合があります。要求に書かれていない条件を独立評価へ追加すれば、候補実装に不可能な課題を課すことにもなります。偶然すべての独立評価を通過する不完全な実装もあり得ます。

AI コーディングエージェントに開発用テストを自由に使わせることと、そのテストだけで成果物を採用することは別の判断です。開発用テストは修正ループのために使い、候補をコミット SHA で固定し、評価条件の差分を確認したうえで、別環境の独立評価へ渡します。

この境界を設けることで、AI エージェントの反復能力を開発へ利用しながら、同じ評価への適応結果だけを最終的な正しさとして扱うことを避けられます。

参考文献

  1. Yang, J. et al., SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering(2024-05-06). https://arxiv.org/abs/2405.15793
  2. Zhao, B. et al., SpecBench: Measuring Reward Hacking in Long-Horizon Coding Agents(2026-05-20). https://arxiv.org/abs/2605.21384
  3. id774, AI がテストを通しても、「正しい」とは限らない(2026-09-01). https://blog.id774.net/entry/2026/09/01/5534/
  4. Gabor, J., Lynch, J., Rosenfeld, J., EvilGenie: A Reward Hacking Benchmark(2025-11-26). https://arxiv.org/abs/2511.21654
  5. OpenAI, Introducing SWE-bench Verified(2024-08-13). https://openai.com/index/introducing-swe-bench-verified/
  6. id774, Codex・Claude Code・GitHub Copilot CLI を評価する実行・検証・権限チェックリスト(2026-07-19). https://qiita.com/ynakayama/items/b16925801f150568658e
0
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
0
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?