TL;DR
- 単発生成のLLM呼び出しから抜け出すカギは「Observe → Plan → Execute → Verify → Replan の 5段ループ」
- 最小実装は 50行のPython擬似コードで再現できる。難しいのはロジックではなく 停止条件と再計画トリガー
- 自律度は Skill(判断の知識)と Tool(実行手段)の両方を持たせたときに初めて成立する
The Pain: 指示待ちエージェント
スキルファイルや system prompt を定義しても、人間が「実行して」と言わなければ動かないエージェントは「賢いチャットボット」止まりです。OpenAI Codex や Claude Code が“自走”するように見える正体は、単発生成ではなく計画→実行→検証→再計画を自動で回すループが裏で走っているからです。
この記事では、その agent loop を 自前実装する最小構成 を擬似コードまで降ろし、停止条件と失敗パターンを明示します。
1. agent loop の5段階モデル
Codex が公開している agent loop は、実装の粒度で見ると次の5段階です。
flowchart LR
A[Observe現状把握] --> B[Plan手順分解]
B --> C[ExecuteTool 呼び出し]
C --> D[Verify検証/テスト]
D -->|Pass| E[Done]
D -->|Fail| F[Replan差分更新]
F --> C
重要なのは Replan が Plan 全体ではなく、失敗した差分のみを更新する こと。ここを全面再計画にすると context が爆発し、ループが収束しません。
| フェーズ | 入力 | 出力 | 典型Tool |
|---|---|---|---|
| Observe | Goal | 現状サマリー | read_file / list_dir / grep |
| Plan | Goal + Observation | Task list (順序付き) | LLM の structured output |
| Execute | Task | 実行結果 | 任意の MCP / Bash / API |
| Verify | 実行結果 + 期待値 | Pass / Fail + 理由 | run_tests / diff / LLM判定 |
| Replan | Verify結果 + 残Task | 更新後 Task list | LLM + 差分プロンプト |
2. 最小実装の擬似コード
ループ本体は驚くほど短く書けます。
from typing import Callable
MAX_ITER = 20 # 無限ループ防止
MAX_REPLAN = 5 # 再計画回数の上限
def agent_loop(goal: str, tools: dict[str, Callable]) -> dict:
observation = observe(goal, tools)
plan = make_plan(goal, observation)
replans = 0
for step in range(MAX_ITER):
if not plan.tasks:
return {"status": "done", "iterations": step}
task = plan.tasks.pop(0)
result = execute(task, tools) # Tool use
ok, reason = verify(task, result, tools) # 自動検証
if ok:
continue # 次の task へ
replans += 1
if replans > MAX_REPLAN:
return {"status": "escalate", "reason": reason}
plan = replan(plan, task, reason) # 差分更新のみ
return {"status": "max_iter_exceeded"}
ポイント:
MAX_ITERとMAX_REPLANを 別の上限 として持つ。前者は全体の暴走防止、後者は同じ失敗を繰り返さないための仕組みplan.tasks.pop(0)で1件ずつ消化し、plan 全体を再生成しないverifyが LLM 単独判定 だと甘くなる。テスト実行・型チェック・差分比較など決定論的な判定 を混ぜるescalateの戻り値を用意し、ループで解決できない問題は人間に渡す経路を明示的に持つ
3. Skill と Tool の役割分担
ループ本体は上記で完成しますが、各関数の賢さ を左右するのが Skill と Tool です。
- Skill: 何をすべきか、どう判断すべきかの知識。
make_plan/verify/replanの system prompt に埋め込む - Tool: ファイルを読む、コマンドを実行する、APIを叩く能力(MCP / function calling)。
executeが扱う
Skill を分けるメリットは 呼び出しごとに文脈を切り替えられる こと。make_plan には計画用の Skill、verify には検証基準の Skill、と別々に注入すれば、ひとつの巨大プロンプトに全部詰める必要がありません。詳細は プロンプトを「スキル」として資産化する技術 を参照。
Tool 側は function calling または MCP サーバ として公開するのが標準的。OpenAI の Responses API、Anthropic の tool use、MCP いずれも「LLMに渡すtool定義 + 実行結果の受け渡し」という抽象は共通です。
ステップ別:AI と人間の分業
| フェーズ | AI エージェントの動き | 人間の介在余地 |
|---|---|---|
| Observation | コードベースや Issue を読み取り、現状を把握 | 課題(Issue)の投稿 |
| Planning | 解決のための手順を提案 | プランの承認(Approval) |
| Execution | ファイル生成・編集・コマンド実行 | なし(AI が自走) |
| Verification | テストの実行、自己修正ループ | PR の最終マージ |
人間が入るのは Planning の承認 と PR マージ の2点だけ。この2点を設計しておけば、間のループは完全に自動化できます。
4. 各段階の設計判断
Plan: structured output を使う
自然文で計画を返させると、Execute 側が parse に失敗して詰まります。JSON schema で task list を返させるのが安全です。
{
"tasks": [
{"id": "t1", "action": "read_file", "args": {"path": "spec/auth.md"}, "success_criteria": "ファイルが読める"},
{"id": "t2", "action": "run_tests", "args": {"pattern": "auth"}, "success_criteria": "全件pass"}
]
}
success_criteria を task に含めておくと、後段の verify が自動化しやすい。
Execute: tool の失敗と LLM の誤用を分ける
Tool 呼び出しは「Tool 自体が失敗(例: ファイルなし)」と「LLM の引数が間違い(例: path誤り)」の2種類あります。前者は即 Verify へ、後者は同じ step のまま args を修正させると収束が早くなります。
Verify: LLM だけに任せない
LLM 単独で「成功です」と判定されると、楽観的に通ってしまいがち。次の3層を混ぜると誤判定が激減します。
- 決定論的判定: テストが通るか、exit code が 0 か、diff が空か
- 構造判定: 期待スキーマに一致するか、必須フィールドが揃うか
- LLM 判定: 自然文要件の充足確認(最後の砦として)
Replan: 失敗 context を添えて差分だけ更新
Replan プロンプトには「今の plan + 失敗した task + 失敗理由」の3点を渡し、「この task 以降だけを作り直して」と指示します。plan 全体を投げ直すと context が倍々で膨らみ、2〜3周でトークン上限に達します。
5. よくある失敗パターン
失敗A: 無限ループ
Verify が甘く、いつまでも「Fail → Replan → 同じ失敗」を繰り返す。対策は MAX_REPLAN(同一task内)の別枠管理と、直近2回の失敗理由が類似なら即escalate するヒューリスティクス。
失敗B: 過剰計画
Plan が最初から100タスクに分解される。LLM は親切心で粒度を細かくしがちです。system prompt で「5〜10タスクに収める。細かくなりすぎたら上位で束ねる」と明示。
失敗C: context rot(文脈汚染)
ループを回すたびに過去の Observation / 失敗ログが全部残り、判断がブレ始めます。対策:
- 完了した task は要約だけ残し、詳細は落とす
- Observation は各ループで必要な情報だけ再取得
- Replan 時は「直近2ループ分の context」しか渡さない
文脈分離の考え方は Claude Code のコンテキスト層設計 や AIが迷わないリポジトリ設計 と同じ思想です。
失敗D: Tool の副作用が戻せない
ファイル削除や外部API の POST は Replan では戻せません。Execute 前に dry-run もしくは reversible でない操作だけ承認を求める 分岐を用意します。hooks で実行前介入する方法は Claude Code hooks の実践パターン集 を参照。
6. 実装チェックリスト
最小ループを実装する際、次が揃っていれば本番投入できます。
-
MAX_ITERとMAX_REPLANを別々に持つ -
Planは structured output で返させる -
Verifyは決定論的判定を少なくとも1つ含む -
Replanは差分のみ。plan 全体を再生成しない -
escalate出口があり、人間にパスできる - reversible でない Tool は実行前に確認を挟む
- context は各ループで縮約している
The Takeaway
agent loop は 50 行で書けますが、動かし続けるために必要な設計は 停止条件・再計画戦略・context 管理 の3点に集約されます。Codex や Claude Code がやっているのは結局この3点の丁寧な作り込みで、仕組み自体は自前実装で再現可能です。
Skill と Tool を組み合わせ、Plan → Execute → Verify → Replan を愚直に回す。ここまでできて、エージェントは「便利な道具」から「頼れるエンジニアリング・パートナー」になります。
