agent に自分の進捗を管理させる
「The agent can track its own progress — and I can see it.」モデル自身にリストを作らせ、小さな仕組みでそれを更新し続けさせる。
構造化された自己計画
Claude Code が作業するとき、多くの場合複数のステップが伴う:grep で参照箇所を探す → 複数ファイルを読む → コードを修正する → テストを実行する。「感覚で進めて」とモデルに任せると、最初の数ステップはうまくいくが、途中でやるべきことを忘れ始め、最終的に中途半端に終わる。
s03 の解決策はモデルにリストツールを与えることだ:モデル自身が todo ツールを呼んでタスク項目を追加し、TodoManager が構造の検証・永続化・現在のビュー返却を担う。これには2つのメリットがある:
- モデルが「何をすべきか」を明示的に書き出すことを強制される——書くだけで頭が整理される。
- 人間側からモデルの思考が見える。デバッグ体験が格段によくなる。
# TODO ビュー、各項目は構造化されている [ ] #1: grep "TODO" across src/ [>] #2: read src/app.py and list comments # 進行中 [ ] #3: generate summary markdown [ ] #4: write to TODO_LIST.md (0/4 completed)
一つの硬いルール:同時に in_progress は一つだけ
TodoManager.update() に一つのバリデーションがある:
if in_progress_count > 1: raise ValueError("Only one task can be in_progress at a time")
厳しく見えるが、実はモデルを助けている。複数の「進行中」を同時に許可すると、あちこちに手を出して何一つ完了しない。単一タスクへの強制によって、モデルは一つを終えてから次に進むしかなくなる。
以下の widget でモデルの役を演じ、様々な todo payload を送信し、何が検証を通過して何が拒否されるかを確認しよう。
Nag reminder:3ターン連続で更新がなければつつく
todo ツールを与えても、モデルはときどき更新を「忘れる」——たくさん作業したのに in_progress が2番目のまま止まっているといったことがある。s03 のアプローチは非常にシンプルなカウンターだ:
rounds_since_todo = 0 while True: response = LLM(messages, tools) ... used_todo = any(b.name == "todo" for b in tool_uses) rounds_since_todo = 0 if used_todo else rounds_since_todo + 1 if rounds_since_todo >= 3: results.append({"type":"text", "text":"<reminder>Update your todos.</reminder>"})
3ターン到達で、次のターンの user message に reminder を挿入する。モデルはそれを見て本能的に todo を更新しに行く。これはエンジニアリングの手段でソフトな制約(「更新してください」)を強制的な刺激に変える手法だ。
このパターンの名前は何か
agent 設計の世界では structured self-planning with soft nudges と呼ばれる——モデルが書き込まざるを得ない構造化状態を与え、タイミングよく reminder を補助する。Claude Code の実コードにも類似パターンが使われているが、より控えめだ(頻度が低く、表現が中立的)。
「毎ステップ todo を更新せよ」と system prompt に書けばいいのでは?書くことはできる。しかしモデルは system prompt の汎用的な指示への従順さが会話の長さとともに低下する。指示を「繰り返し注入する reminder」に分解した方が効果がずっと安定する。