chimera-carry-the-failure-forward
フィードバック用の変数を上書きするリトライループは、3回目の試行に2回目の失敗しか見せません——だから1回目がすでに試したパッチを導き直してしまいます。
カードを読んだレビュアーが与えるものであり、ファイルが自分について主張するものではありません。信頼できない内容を扱った実行中にエージェントが抽出したカードは汚染された状態で生まれ、取得される前にレビュー待ちとして保留されます。
どんなときに思い出すか
- リトライループを書く
- エージェントが同じ修正を繰り返す
- 検証器の出力をモデルに戻す
- 毎回同じ形で失敗する
- 試行ごとにワークスペースを戻す
価値はたいてい「回避」と「確認」にあります。「実施」は誰でも書ける節です。
上のカード本文は翻訳です。CLI が取り込み、エージェントが実行時に読み、下のハッシュが証明するのは英語の原文です。
トリガー
試行を1回実行し、それを判定し、フィードバックを添えてもう1回実行するループがある場合に当てはまる。検証器付きのエージェント、テストスイートに対するコード修正器、生成してチェックするパイプラインなどだ。予算は2回を超える試行があり、各試行がきれいな状態から始まるよう、試行の間にワークスペースは巻き戻される。
不安定なトランスポート上での冪等なリトライ——送った内容とは無関係な理由で失敗したネットワーク呼び出し——には当てはまらない。そこでは試行1から学べることは何もなく、それを持ち越すのは単なる余計な積荷である。
実施
- 試行は再代入する変数ではなくリストに保存する。1試行につき1レコードとし、検証器の出力、その試行が実際に書いたパッチ、そして最初にエラーを出したツールステップを含める。
- パッチは巻き戻しの前に、ワークスペースのスナップショットから取得する——モデルによる変更の説明ではなく、本物の差分をだ。この手順が必要になるのは巻き戻しがあるからである。ツリーが巻き戻されてしまえば、その誤った経路もディスク上のどこにも記録されておらず、次の試行が同じ経路を再び導き出すことを妨げるものは何もない。
- リトライ用のプロンプトは全レコードから、古い順に組み立てる。各レコードには試行番号と判定を付し、これらはすでに試され巻き戻されたものだと述べる見出しの下に置く。
- 各レコードに上限を設ける。Chimera はフィードバックする差分を2000文字で打ち切り、マーカーを付けて切り詰める。上限のない3試行分の履歴はプロンプトを占領してしまう。
- 失敗のシグネチャで重複を除く。2つの試行が同じ形で失敗したなら、1つだけ残し、それが再発したことを記録する——繰り返されたという事実こそが信号であり、2つ目のコピーは新しい情報ではない。
- シグネチャが繰り返されたら、追記をやめて構造的な何かを変える。蓄積された原因をプランナーのコンテキストとして計画を立て直す(
TaskLedger.context()はそれらを "Why earlier attempts failed (do NOT repeat these):" の下にレンダリングする)か、より強力なモデルへエスカレーションする。同じ袋小路についてのフィードバックを増やしても、その袋小路からは出られない。 - 履歴を注入するたびに数えられるイベントを発行し、ベンチマークの各群が、そもそも注入が発火したことを証明できるようにする。
回避
上書きすること。chimera/core/autonomous.py では、ループのフィードバックがラウンドごとに作り直される:
feedback = "\n\n".join(p for p in (fb, _verify_fb) if p) or "The attempt did not pass verification."
そのため試行3は試行2の失敗をもとに組み立てられ、試行1からは何も入らない。持ち越すとは、代わりに構造体へ追記することを意味する——引用ではなくスケッチなのは、蓄積していく版は、このファイルが現在行っていることではなく、このカードが主張していることだからだ:
records.append(record_for(index, verdict, patch)) # one entry per attempt
feedback = render(records) # every attempt, oldest first
これを Chimera の中で読むとき、どちらの半分がすでに存在するのかは正確に捉えること。フィードバックの内容はよくカバーされている——--diff-feedback はリトライに対して、実際に書かれたパッチを見せ(chimera/core/autonomous.py、_DIFF_FEEDBACK_MAX_CHARS = 2000 で打ち切り)、TaskLedger はプランナー向けに原因を蓄積する。カバーされていないのは、上の行にある試行をまたいだ蓄積の方だ。そのすべてが欠けていると提示するカードは、すでに済んでいる仕事に反論することになる。
リトライに対して、何を書いたかを見せずに失敗したという事実だけを伝えることも避けること。「試行は検証を通らなかった」に失敗したテストを添えれば、モデルにもう一度試させるには十分だが、違うことを試させるには足りない——誤ったパッチはモデルからは見えず、ワークスペースにももはや残っていないため、それを再び導き出すのが最も抵抗の少ない道になる。
また、検証器の出力を落としてマネージャーの文章だけを持ち越すことも避けること。失敗した assert はループ全体で最も行動につながる一行であり、それについてのレビュアーの一段落は、厳密により少ない情報の言い換えでしかない。
確認
組み立て部分に計測を入れ、3回失敗すると分かっているタスクを実行し、試行3のプロンプトを、試行1にしか存在しない文字列——その試行が触ったファイル名、その差分に含まれる識別子——で grep する。あるかないかであり、部分点はない。
2つ目の確認も同じく二者択一だ。注入回数を数えること。ガードが誤っていたため、あるいは差分リストが空だったために履歴が一度も組み立てられなかった実行は、何一つ測定していない——そしてその上に組まれたベンチマークの群は、アイデアではなく配管を測っている。カウンタがゼロを示しているなら、成功率が何を言っていようとその結果は無効である。
リスク
アンカリングは仮定の話ではなく、登録済みの対立仮説である。モデルに誤ったパッチを見せると、その注意がそのパッチに固定され、別のアプローチではなく死んだアプローチの変奏を生み出しうる。だからこそ Chimera ではこの挙動がデフォルトで有効ではなく、オプトインで測定される形になっている(--diff-feedback)。決着のついた改善としてではなく、自分のタスクで検証すべき主張として扱うこと。
2つ目のコストはコンテキスト予算だ。3つの差分、3つの検証器の出力、そしてマネージャーのレビューは、プロンプトを圧縮の閾値の向こうへ押しやりうる——そして復元を持たない圧縮器は、まさに苦労して積み上げた蓄積履歴を落とすことになる。これを有効にする前にレコードに上限を設け、自分の予算を把握しておくこと。さもないと2つの仕組みが互いに争い、目に見える症状はそのどちらでもないものになる。
使い方
カードはデータです。リポジトリをクローンし、パスで取り込んでください。ネットワーク経由で届いたものは汚染扱いとなり、承認されるまで保留されます。それが望ましい挙動であり、ここにワンライナーのインストーラーがない理由です。
git clone https://github.com/brcampidelli/chimera-agent.gitchimera skills-import chimera-agent/skills/chimera-carry-the-failure-forward/SKILL.md完全性
公開された状態のファイルの SHA-256。取り込む側は、受け取ったものがこのページに表示されたものと同じか確認できます。
62dcc2aa830e5eb35c554bebf2c1a24454a054bf17bf152ccd59f3497b5e043d