ループエンジニアリング実験、フィードバックループと検証器が静かに失敗し得ることを示す
重要ポイント
- •この実験では、実際のテスト失敗を使うフィードバックループと、コード生成と最終判断を分離するmaker/checker構成という、2つのループエンジニアリング要素を評価した。
- •最初のテスト実行では、隠しテストハーネスが有用な失敗詳細を含まない素のアサーションエラーを返していたため、実フィードバックの効果は確認できなかった。
- •失敗した入力、期待される出力、実際の結果をハーネスに追加した後、実フィードバックは汎用リトライループでは解けなかった1問を解決した。
- •テスト実行型検証器は、不正解候補8件中3件を誤って受理し、測定された比較では2つの意見ベースのチェッカーより高い誤受理率を示した。
- •最終的な統合システムの改善は主にフィードバックループによるもので、検証器は1件の誤受理を生じ、それは隠しテストによる採点でのみ検出された。

2026年7月27日、編集チームにより最終更新。Originally published on Towards AI。
「私の仕事はループを書くことだ。」
この発言は、AnthropicでClaude Codeを率いるBoris Chernyによるものだ。Chernyは、Claudeに直接プロンプトを与えるのをやめ、現在は自分の代わりにClaudeへプロンプトを出すループの設計に時間を使っていると述べている [1]。この発言と、同種のいくつかのコメントをきっかけに、今年はループエンジニアリングの解説記事が相次いだ [1][2]。私はそのうち6本を読んだ後、自分で1つ作ってみた。
より正確には、ほぼすべての解説記事が説明しているものの、エンドツーエンドで実際に動かしている例は少ない2つの構成要素を作った。1つ目は、完了するまで実行するループだ。失敗後にモデルへ再度推測させるのではなく、モデル自身の実際のテスト失敗をフィードバックする。2つ目はmaker/checker構成だ。コードを書いたモデルが、そのコードが正しいかどうかの最終判断者になることを許さない。
この区別は重要だ。コーディングエージェントのワークフローは、多くの場合、同じ分離に依存している。つまり、あるシステムが変更を提案し、別のツール、テストスイート、またはモデルがその変更を受け入れられるかどうかを判断する。フィードバック経路や検証器が弱ければ、ループは自動化されているように見えても、実質的に安全性が高まるわけではない。
私はこの2つを約600行のPythonで一から実装し、claude-opus-4-8に接続して、MBPP+ [3]で評価した。MBPP+はEvalPlusによる小規模なPythonプログラミング課題のベンチマークであり、リポジトリ規模の複雑さを持ち込まずにループの挙動を切り分けるのに役立った。ここで述べるすべての実験にかかった総費用は2ドル未満だった。2つ目の構成要素、つまりモデルの言葉を信じるのではなく「実際にテストを実行する」ため、より安全な半分として扱われがちな部分は、私の測定では、それらの解説記事が警告していなかった結果を示した。
要約すると、ループエンジニアリングの2つの中核部品は接続するのは簡単だが、静かに間違えるのも簡単だ。私の「実フィードバック」ループは、自分のテストハーネスのバグを見つけるまで、ランダムなリトライと見分けがつかなかった。私の「安全な」テスト実行型検証器は、モデルに自信の度合いを尋ねるだけのチェッカーよりも高い誤受理率を示した。ループを作ることは、簡単な20%にすぎない。
何もないところにループを配線する
ループエンジニアリングに関する多くの記事は、配線図で話を終える。トリガー、検証可能な目標、ツール、状態、停止ルール――5つの箱と、それらを結ぶ矢印。そこには、箱を接続すればループは機能するという含意がある。
それは、煙感知器を設置し、天井に取り付けられて配線されているから家は安全だと宣言するようなものだ。電池が正常に動いているかどうかを確認していない。
私は自分の「実フィードバック」ループで、まさにこの失敗に遭遇した。それは汎用的なリトライ用プロンプトではなく、実際のテスト出力に接続されていた。理論上は、「それは間違っていた。もう一度試して」というメッセージだけを受け取るループを明確に上回るはずだった。だが最初の実行結果は違っていた。
採点器を採点する採点器
ループ自体に触れる前に、他のすべてが依存する構成要素を作った。候補コードを隔離されたサブプロセスで厳格なタイムアウト付きで実行し、隠しテストに対して採点するスコアラーだ。
私は、そのスコアラーが自分自身を採点するまで信頼しなかった。既知の正解を与えたら合格しなければならない。既知の不正解を与えたら失敗し、アサーションエラーを添付しなければならない。無限ループを与えたら、永遠にハングするのではなく、タイムアウトで停止されなければならない。
その後、MBPP+の参照解75件に対してパイプライン全体を検証した。75件すべてが合格した。その後で初めて、ループが出す数値を信頼した。
正しく見えたが正しくなかったループ
ループ自体は非常に単純だった。解を生成し、採点し、失敗した場合には、汎用的な「もう一度試して」ではなく実際のエラーである本物のstderrを、最大3回までフィードバックする。
見出しの数値を基準なしに信頼したくなかったため、対照群も作った。対照群は同一のループを使うが、実際のエラーを「それは間違っていた。別の解を書いて」という汎用的な指示に置き換える。実フィードバックがそれを明確に上回らないなら、配線のどこかが壊れていることになる。
35問に対する最初の実行では、3つのアームすべてが同一だった。それはループが機能している証拠ではない。ループの形をした危険信号だった。
トップラインの指標に注目する代わりに失敗を調べたところ、問題を見つけた。MBPP+の隠しテストハーネスが、素のAssertionErrorで失敗していたのだ。失敗した入力、期待値、実際の値が含まれていなかった。その結果、「実フィードバック」は情報量の面で「もう一度試して」と同一になっていた。モデルが行動に移せる情報を何も受け取っていなかったからだ。
私はハーネスを計装し、失敗した入力、期待される出力、コードが実際に返した値を報告するようにした。同じ35問に対する2回目の実行では、実フィードバックは汎用アームが解けなかった1問を回復した。その代償は、実行全体で約2,500個の追加入力トークンだった。
ループが壊れていたわけではなかった。接続されていた信号が空だったのだ。それを明らかにしたのは対照群だけであり、見出しの指標だけでは分からなかった。
理論が予測しなかった形で失敗した検証器
ループには停止ルールが必要であり、「モデルが完了したと言うこと」は停止ルールではない。そこで私は、仕様から自分でテストを書くチェッカーを作った。このチェッカーは隠しテストを見ることも、自分が判定する解のコードを見ることもない。そのうえで、それらのテストを実際に実行する。方針は、すべてが問題なく通った場合のみ受理し、デフォルトでは拒否するというものだった。
私はこの検証器を、ループが生成した41件の候補、内訳は正解33件、不正解8件に対して、3つのより弱いチェッカーと比較した。測定したのは誤受理率、つまり実際には壊れているコードを各チェッカーがどれだけ通してしまうかだった。
| チェッカー | 誤受理 | 誤拒否 |
|---|---|---|
| すべて信頼する | 8/8 — 100% | 0/33 — 0% |
| モデルに自信があるか尋ねる | 2/8 — 25% | 4/33 — 12% |
| 2つ目のモデルがコードを読む | 2/8 — 25% | 5/33 — 15% |
| テストを書いて実行する | 3/8 — 38% | 1/33 — 3% |
私は、テスト実行型チェッカーが誤受理で明確に勝つと予想していた。そうはならなかった。それは、意見ベースのどちらのチェッカーよりも高い割合で誤ったコードを通してしまった。
理由は数値以上に重要だった。8件の誤った候補はすべて、本当に曖昧な仕様を持つ3つの問題から来ていた。チェッカーと修正役は、同じ曖昧な文を読む同じモデルだった。そのため、チェッカーが自分で書いたテストは、誤ったコードがすでに含んでいた同じ読み違いを符号化しており、その誤ったコードはそれらのテストを問題なく通過した。
意見ベースのチェッカーがこの誤受理比較で「勝った」のは、主に全般的に慎重だったためだ。そして、その同じ慎重さこそが、正しいコードを4~5倍多く誤って拒否した理由でもある。
テストを実行することは、誤受理に対する万能の免許ではない。それは別種の証拠であり、漠然とした印象ではなく、具体的な入力、期待値、実際の値を伴うものだ。だからこそ、その3%の誤拒否率は実際のゲートとして使える。良い作業の15%を拒否するチェッカーは、不適切なマージを防ぐ前に、ワークフローをリトライで埋め尽くしかねない。
2つの部品を組み合わせる
最終的な構成では、まずフィードバックループを実行する。それが失敗した場合、新しい候補をサンプリングし、モデルの自信ではなく検証器に何を提出するかを決めさせる。さらに、どれも基準を満たさない場合の明示的な断念経路も含めた。
私はこの構成を、前述の構成要素を作る際に使っていなかったMBPP+の保留スライスで評価した。採点は、検証器が何を判断したかとは独立に、隠しテストに対して行った。
実質的に仕事のほぼすべてをしたのはループだった。14.2ポイントを上積みし、単発実行で失敗した6件のうち5件を回復し、追加のAPI呼び出しは約10回だった。検証器ステージが発火したのは1回だけで、ループが解けなかった1問に対してだった。その最初にサンプリングされた候補は、自分で書いたテストには合格したが、隠しテストには失敗した。
これは本番の誤受理であり、先の表が予測した失敗モードと一致していた。それが検出されたのは、ランナーが検証器には見えない正解基準に対して提出物を採点していたからにすぎない。検証器自身の判断が最終決定だったなら、そのバグは出荷されていただろう。
このステージの総コストは45回の呼び出し、約13セントだった。
このアプローチが破綻する場所
このアプローチは、目標が本当にテスト可能な場合に機能する。たとえば、隠しテストケースを持つ関数、検証に通るか通らないかが明確なスキーマ、あるいはループが言い逃れできないオラクルがある場合だ。仕様そのものが曖昧な場合には機能しない。同じモデルのチェッカーは、生成器と同じ読み違いを継承し得るからだ。その場合、解決策は必ずしもより巧妙なチェッカーではない。より明確な仕様、またはまったく別のモデルファミリーによる独立したオラクルである。
また、私はこれを小規模でスタンドアロンのMBPP+関数でのみテストした。この実験は、ファイル間依存を持つ大規模コードベースには踏み込んでいない。複数のループを並列で実行するためのworktree分離も構築またはテストしていない。それは現実の問題だが、この実験が測定した問題ではない。
このループは「検証済み」で止まる。変更を自動適用するか、人間にエスカレーションするかは判断しない。実際の書き込み権限を持つものにシステムが触れた瞬間、それは別の、より難しい問題になる。
ここから始める
採点器から始めること。ループのロジックを1行も書く前に、既知の正解、既知の不正解、無限ループというセルフテストを書く。その5分のスクリプトが、架空の見出し数値に対する主な防御策になる。
たとえ少数のユニットテストしかないコードベースでも、次にフィードバックループを配線し、初日から汎用リトライの対照群を並行して作ること。「もう一度試して」を上回るまで、改善を信頼してはいけない。
その後、2つ目のチェッカーを作り、1つ目と比較する。誤受理の表が理論の示唆と食い違ったとき――実際そうなる可能性がある――その理由によって、なぜ基盤となるモデルよりもループが重要なのかが分かるだろう。
参考文献
[1] Rohan Mistry, “Prompt Engineering Is Dead. Loop Engineering Is Here.,” Towards AI, July 2026.
[2] Mehmet Özel, “Loop Engineering for AI Agents : Building Verifiable, Self-Correcting Coding Workflows,” Towards AI, June 2026.
[3] EvalPlus, “MBPP+ Dataset,” Hugging Face Datasets.