powered by TechFeed
表示モード
Deep Dive

AIエージェントへの「20ステップ指示書」はなぜ崩壊するのか — 1976年のMakefileが解決策になる理由

10月9日、dev.toの著者gde氏が「Stuart Feldman Was Right in 1976: Why Your AI Agent Needs a Makefile, Not a 20-Step Prompt」と題した記事を公開した。この記事では、AIコーディングエージェントのタスク管理に、逐次的なプロンプト手順書ではなくMakefileの宣言的DAG構造を応用する手法について詳しく紹介されている。

10月9日、dev.toの著者gde氏が「Stuart Feldman Was Right in 1976: Why Your AI Agent Needs a Makefile, Not a 20-Step Prompt」と題した記事を公開した。この記事では、AIコーディングエージェントのタスク管理に、逐次的なプロンプト手順書ではなくMakefileの宣言的DAG構造を応用する手法について詳しく紹介されている。


「20ステップのプロンプト」はなぜ崩壊するのか

自律型コーディングエージェントを構築するとき、多くのエンジニアはまず同じものを書く。番号付きの手順リストだ。

Step 1: 課題トラッカーからissueを選ぶ
Step 2: コードベースを読んでアーキテクチャ計画を書く
Step 3: 人間に承認を求めて一時停止する
Step 4: 失敗するテストを先に書く(TDD)
Step 5: コードを実装する
Step 6: テストと静的解析を実行する
...
Step 17: ボットのレビューをトリアージし、ドキュメントを更新して片付ける

新人インターンへの引き継ぎ書のように整然として見える。だが本番環境では確実に崩壊する。

失敗の原因は2つある。

1つ目は注意力の劣化。会話履歴にコンパイルログ、テスト出力、git diffが積み重なると、リストの先頭は数万トークン前に埋もれる。LLMは「自分が今どのステップにいるか」を見失う。

2つ目は命令型GOTOトラップ。Step 6でテストが失敗したり、Step 9の後にレビューボットがコメントを残したりすると、プロンプトはこう肥大化していく:

「Step 9の後にレビューボットがコメントを残した場合はStep 12.2へ。コード修正が必要な場合はStep 5に戻るが、Step 1のブランチ作成はしないこと。その後Step 8へ進むが新規PRは作成せず、force pushでStep 12.4へ...」

LLMは150ターンにわたるネストした条件分岐とGOTOジャンプを持つ命令型仮想マシンをシミュレートできない。途中のゲートを飛ばし、終了条件を幻覚し、未レビューのコードをマージする。


1976年のMakefileが解法になる

1976年、Bell研究所のStuart Feldmanは全く同じ問題を解いていた。依存関係の追跡と状態の整合だ。UNIXビルドツールとして誕生したmakeはその後半世紀にわたり広く普及し、現在も多くのソフトウェアプロジェクトのビルドインフラを支えている。

Feldmanが気づいたのは、命令型ビルドスクリプトが脆い理由は「現実の構造を正しくモデル化していないから」という点だった。彼が設計したmakeが扱うのは3つの概念だけだ:

  • ターゲット: 生成したい成果物や検証済み状態
  • 前提条件: そのターゲットをビルドする前に存在しなければならない上位成果物
  • レシピ: 前提条件からターゲットを生成する具体的なコマンド

makeはステップ番号を気にしない。有向非循環グラフ(DAG=Directed Acyclic Graph) の依存関係だけを見る。DAGとは、ノード間に向きのある辺が存在し、かつ循環経路を持たないグラフ構造のことで、「AはBに依存し、BはCに依存するが、CがAに依存することはない」という一方向の依存関係を表現するのに適している。

この記事の核心的な主張はシンプルだ。AIコーディングエージェントのワークフローも、本質的にはDAGである。 ソフトウェアの成果物と検証済み不変条件のグラフとして表現できる。


具体的なMakefile構造

20の手順の代わりに、issueからPRマージまでの全ライフサイクルを宣言的Makefileとして記述する:

finish: land codified-scars-consolidated pristine-workbench
land: ready-to-land human-landing-approval
ready-to-land: ci-quiescent changelog-updated
ci-quiescent: push ci-remote-green all-bots-triaged
push: commit human-push-approval
commit: pre-commit-clean human-commit-approval
pre-commit-clean: approved-adversarial-report clean-static-analysis doc-audit-complete
approved-adversarial-report: adversarial-review triaged-blockers human-review-approval
adversarial-review: implementation-diff
implementation-diff: approved-plan tdd-failing-repro human-diff-approval
approved-plan: researched-ticket human-plan-approval
researched-ticket: ticket-assigned candidate-scars git-archaeology
ticket-assigned:

新しいissueでエージェントを起動するとき、トップレベルのゴールは常に同じだ:

make finish

グラフをfinishから逆向きに評価すると、最も深い未充足のリーフが即座に特定され、実行すべき次のターゲットが一意に決まる。

自己修復の仕組み

DAGアプローチの最大の利点は、条件分岐なしの自己修復だ。

ci-quiescentの状態にいるときに、レビューボットが正当なバグ指摘をGitHubに投稿したとする。プロンプトに「Step 5.2に戻れ」というルールを書く必要はない。エージェントがコードを修正すると作業ツリーがダーティになり、commit、push、approved-adversarial-reportが物理的に無効化される。DAGが自動的にエージェントをAdversarial Criticを通るルートに戻す。

エージェントが問うのは常に1つだけだ:「今ビルドしているリーフターゲットの物理的不変条件は成立しているか?」


重要な制約:前提条件は最大2〜3個まで

gde氏が143枚の本番チケットを対象に行った実地テスト(記事によれば著者自身のプロジェクトにおける実運用データ)から導かれた重要な発見がある。1つのターゲットに対する前提条件は最大2〜3個までという制約だ。記事ではこれを「Feldman Triad Invariant(フェルドマン三項不変条件)」と呼んでいる(本記事が独自に命名した概念であり、既存の標準用語ではない)。

# ❌ 前提条件の希薄化トラップ(1行に5つ)
land: push ci-remote-green all-bots-triaged changelog-updated human-landing-approval
    gh pr merge --squash

4つの機械的な前提条件(push → ci-remote-green → all-bots-triaged → changelog-updated)を連続して検証した後、5つ目のhuman-landing-approvalが形式的なチェックボックスとして流され、エージェントが人間の承認なしにPRをマージしてしまうリスクが生じる。

解決策は前提条件をネストした2〜3項のサブターゲットに分解することだ:

# ✅ Atomic Barrier Tuple
land: ready-to-land human-landing-approval
ready-to-land: ci-quiescent changelog-updated

この2項構造では、エージェントの判断は厳密に二値になる:ready-to-landは充足されているか?human-landing-approvalは付与されているか?両方YesでなければSTOP、待機する。


セッション再開がO(1)で解決する

Makefileドリブンなエージェントは、CI待ちで中断した後に再起動されても迷わない。リポジトリとGitHub forgeの物理状態を検査するだけで、make finishの最も深い未充足前提条件を特定できる。以下の表は、git/forgeの物理状態と、その時点でアクティブになるターゲットの対応をまとめたものだ:

物理的なgit/forge状態 解決されるアクティブターゲット
PRオープン、未対応ボットコメントあり ci-quiescent
PRオープン、全チェック緑、ボット対応済み land
ローカルにコミット済み、未push push
承認済みplan.mdあり、コード変更なし implementation-diff

ファイルシステムとgitグラフが状態機械そのものになる。エージェントに「今何ステップ目か」を教える必要はない。


詳細はStuart Feldman Was Right in 1976: Why Your AI Agent Needs a Makefile, Not a 20-Step Promptを参照していただきたい。