この記事は、連載「読まない技術」の第 8 回です。うまくいかない症状と、その対処を一つずつ並べています。各回はファイルやスクリプトを一つ置けば完結します。その仕組みがなぜ要るのかは、置いたあとに解説を読めば分かります。連載の全体像と各回の一覧は序論にあります。
今回は、修正履歴(がAIを軌道修正させてきた記録)の話です。AIが失敗したときの振る舞いを直す方針を、が指示ファイルに書いておいても、AIは次の機会にも同じ振る舞いをします。セッション(AIとの、始まりから終わりまで一続きのやり取り)の始めに読んだ方針があっても、AIは失敗した直後に、同じやり方でもう一度試しました。AIが方針に従ったのは、同じやり方でもう一度試そうとしたところでが止めて、その場で方針を読ませたときでした。
AIコーディングエージェントを使っているなら、次の場面に覚えがあると思います。AIが失敗したとき、同じやり方でもう一度試す場面です。それも失敗すると、AIはまた同じやり方で試します。
は過去に何度もAIを軌道修正させ、そこから得た方針「リトライを繰り返すな、失敗したらアプローチを変えろ」を、指示ファイルにも書いておきましたが、それでもAIは、失敗した直後に、同じやり方でもう一度試しました。
AIが同じ振る舞いを繰り返すと、は、前にどう直したのかを探しに戻っていました。探す先は、AIとの過去のやり取り、そのとき書いた対処、指示ファイルに足した行です。はこの修正履歴を読み返して、指示ファイルに方針をもう 1 行足していました。それでも次のセッションで、AIはまた同じ振る舞いをしていました。
足した方針にAIが従わない理由は、二つ重なっています。一つは、序論で扱った、ルールは足すほど薄まるということです。足した方針は、コンテキスト(AIの作業記憶)の中で、ほかのルールと並んでいます。ルールが増えるほど、この方針の 1 行は、ほかのルールに埋もれていきます。もう一つのほうが本質です。冒頭に書いたとおり、同じ「失敗したらアプローチを変えろ」でも、セッションの始めに読ませたときには、AIは同じやり方でもう一度試し、もう一度試そうとしたその場で読ませたときには、AIは方針に従いました。方針の中身は同じで、違ったのは、読ませた瞬間です。
方針の中身を変えずに、読ませる瞬間だけを変えるやり方は、第 2 回でもとりました。知見メモ(メモリ)を保存する直前に読ませた方針は、AIが語を言い換えて素通りしたので、が移した先は、保存の直後に読ませる形です。
あなたは指示ファイルに「失敗したらアプローチを変えろ」と書いていました。それでもAIは、失敗した直後に、同じやり方でもう一度試しました。この症状に、あなたなら次のどちらで対処しますか。
- 修正履歴を読み返して、指示ファイルに方針をもう 1 行足す
- AIが同じやり方でもう一度試そうとしたところで止めて、その場で方針を読ませる
答えは、止めて、その場で方針を読ませるほうです。指示ファイルの方針をAIが読むのはセッションの始めで、AIが失敗するのは、それよりずっと後です。もう 1 行足しても、その 1 行を読むのはやはりセッションの始めで、しかも足した行は、ほかのルールに埋もれていきます。もう一度試そうとしたところで止めれば、その試行は実行されず、止めた理由と方針が届くのは、失敗の直後、AIが次の操作を決める前です。
理解したことは一文にできます。
セッションの始めに読ませた「失敗したらアプローチを変えろ」があっても、失敗した直後のAIは、同じやり方でもう一度試す。だから、AIが同じやり方でもう一度試そうとしたところで止めて、その場で方針を読ませる。
CC BY 4.0
なぜ、失敗が起きる前に読ませた方針に、AIは従わないのか
方針を先にAIに読ませて覚えさせることは、そもそもできません。AIが学習するのは、使われる前の段階だけだからです。Brown ほかは 2020 年に、勾配の更新も追加学習もなしに、テキストのやり取りだけでAIの振る舞いが決まることを示しました。指示ファイルを読ませても、方針はAIの中に書き込まれず、コンテキストに並ぶ行の 1 つになるだけです。
その行は、セッションの始めに読み込まれたあと、コンテキストの先頭に置かれ続けます。AIが失敗するのは、それよりずっと後です。失敗の瞬間、コンテキストの末尾の近くには、直前に届いたエラーと、進行中の作業があります。だからは、方針を読ませる瞬間を、AIが同じやり方でもう一度試そうとしたところへ移すことにしました。
仕組み: 方針ファイル 1 枚と、問題を検知した瞬間に方針を差し込むhook
まずは、軌道修正の方針を、方針ファイル 1 枚に数行で書きます。中身は、これまでの軌道修正から、がAIに守らせたいことです。
# 軌道修正の方針(問題を検知したときに差し込まれる)
- 1 回失敗したら、同じ方法を繰り返さず、まずアプローチを根本的に変える(分割・別手法)
- やり直しの前に、必ず人間に確認を取る
- 失敗が 2 回続いたら、その手段を中断して代替案を提示する
次には、hookに、検知の条件(どの操作を問題として止めるか)を書きます。hookは、条件に当たる操作を検知すると、その操作が実行される前に、AIの目の前へ方針を差し込みます。の環境での実例は、サブエージェントのリトライ(失敗の直後に、同じやり方でもう一度試すこと)です。サブエージェントは、メインのセッションを引き継がずに、別に立ち上がって働くAIです。個人で運営している typingtube(YouTube の音楽動画でタイピング練習ができる Web サービス)では、翻訳のような数の多い仕事をサブエージェントに任せるので、失敗も、失敗したあとの再開も、サブエージェントで起きます。同じ名前でのサブエージェントの再起動や、起動済みのサブエージェントへの再送信は、機械的に検知できます。
# 起動の記録に同じ名前があれば、それはリトライ。止めて方針を差し込む(手元のコードを短くしたもの)
# 記録は、起動を通すたびに echo "$agent_name" >> tmp/launched_agents.txt で追記しておく
if grep -qxF -- "$agent_name" tmp/launched_agents.txt 2>/dev/null; then
echo "'${agent_name}' has already been launched. This counts as a retry." >&2
cat docs/course_correction.md >&2
echo "Recount what is left, report to the human, then ask for direction." >&2
exit 2
fi
コードが exit 2 で終わっているのは、この終わり方なら、差し込んだ方針がAIに届くからです。Claude Code のドキュメントは、終了コード 2 で終わったhookは操作を止め、標準エラー出力を止めた理由として Claude へ渡す、と書いています。終了コード 1 で終わったhookでは、操作はそのまま進み、差し込んだ方針もAIには届きません。
方針をhookのメッセージに直書きせず、方針ファイルを cat しているのは、方針を更新するときに、方針ファイルだけを書き換えれば済むようにするためです。修正履歴が増えても、が差し替えるのは、修正履歴から絞り込んだ方針ファイルの数行だけです。
この仕組みが働いた実例を、一つ挙げます。この仕組みを置く前、メインのAIが、失敗したサブエージェント 2 体をに確認せずに再開し、そのままセッションの使用量の上限に達しました。は当時から、「リトライ前に必ず確認を取る」をメモリに書いていました。セッションの始めに読み込まれるのはメモリの索引だけで、この 1 行がある本文をAIが開いたのは、失敗の瞬間より後の、2 体とも再開し、が指摘してからでした。いまは、AIが同じ操作をすると、hookがその操作を必ず一度止め、止めた理由として、AIの目の前に方針を差し込みます。hookが作っているのは、AIが必要なものを読んでいなければ動けない構造です。起動済みのサブエージェントに 2 通目を送ろうとしたAIをhookが止めたとき、AIは送り直さず、の指示を待ちました。hookが方針を差し込むのは、が気づくより前の、1 回目の再開の瞬間です。
CC BY 4.0 はここまで
読まなくなったもの
修正履歴です。が「前はどう直したんだっけ」と修正履歴を読み返すことも、AIに読み返させることも、「前も言ったよね」とがAIに繰り返すことも、なくなりました。修正履歴は、方針ファイルの数行に絞り込んであります。その数行を、hookが必要な瞬間にだけAIへ差し込みます。
CC BY 4.0
注意: 方針を差し込むことができるのは、検知できる問題だけ
この仕組みを使うことができるのは、リトライのように、hookに検知の条件を書くことのできる問題だけです。検知の条件を書くことのできない新しい種類の問題には、方針を差し込む瞬間がありません。そうした問題には、別の仕組みが要ります。もう一つ気をつけることは、第 2 回と同じで、方針ファイルを数行に保つことです。軌道修正のたびに、方針ファイルに 1 行足したくなりますが、同じ対象の行は統合し、差し込んでもAIのやり方が変わらなかった行は消します。修正履歴が増えても方針ファイルの行数が増えないことが、この仕組みが働いている証拠です。
検証手順: わざと繰り返させて、止まることを確かめる
前提
方針ファイルを数行で置き、それを cat して差し込むhookを登録し終えておきます。検知の条件(本文の例では「同じ名前でのサブエージェントの再起動」)も、決めておきます。
所要時間: 10 分
手順
- あなたが、AIに、検知の条件に当たる操作をわざと繰り返させます。本文の例なら、1 回起動したのと同じ名前で、サブエージェントをもう一度起動させます。1 回目の起動は、hookに止められずに通ります。確かめるのは 2 回目です
合格条件(すべて満たすこと)
合格の条件は 3 つです。1 つ目は、操作が実行される前に止まることです。2 つ目に、止まった場所に、方針ファイルの全文がそのまま出ていることを確かめます(要約や「方針を読め」という指示だけなら不合格)。3 つ目は、AIが次にすることが変わることで、同じ操作をもう一度試す代わりに、代替案を出すか、あなたに確認してきます。
合格しなかったとき
- 止まらなかった —— 検知の条件が、実際の操作の形と合っていません。あなたが、hookが見ている文字列を、AIが打った通りの形に直します
- 止まったが、AIが同じ操作を繰り返した —— 方針ファイルの文に、「その瞬間に何をすればよいか」が書かれていません。あなたが、方針ファイルに、その瞬間にすることを書き足します
後始末
あなたが、手順 1 で起動したサブエージェントを止め、サブエージェントが途中まで書いた成果物があれば消します。
CC BY 4.0 はここまで
次回は「引き継ぎを読まない技術」。AI が書く完了報告を、は読んでいません。 それでも、報告と実際が食い違えば、その場で気づきます。
連載「読まない技術」
- ← 前回: 第 7 回 共有メモリを整理しない技術
- → 次回: 第 9 回 引き継ぎを読まない技術
- 全回の一覧: 序論 AIの出力を、もうほとんど読んでいない