本文へスキップ

Skills

chimera-budget-the-context

実際のウィンドウより低く設定した予算に対して消費し、毎ステップ再送信するツールスキーマを数に入れてください——それは圧縮では到達できない下限です。

パターン来歴: cleanステータス: activev0.1.0 · Apache-2.0

カードを読んだレビュアーが与えるものであり、ファイルが自分について主張するものではありません。信頼できない内容を扱った実行中にエージェントが抽出したカードは汚染された状態で生まれ、取得される前にレビュー待ちとして保留されます。

どんなときに思い出すか

  • コンテキスト超過で実行が落ちた
  • max-steps を上げる
  • エージェントが作業内容を忘れた
  • MCP サーバーをもう一つ追加する
  • プロンプトから何を削るか決める

価値はたいてい「回避」と「確認」にあります。「実施」は誰でも書ける節です。

上のカード本文は翻訳です。CLI が取り込み、エージェントが実行時に読み、下のハッシュが証明するのは英語の原文です。

トリガー

毎ステップごとにメッセージリストへ追記していくループ——ReAct エージェント、コーディングのターン、ツール呼び出し型のアシスタント——を動かしており、そのリストが増える一方である場合に当てはまる。症状は、プロバイダーがコンテキスト長でエラーを投げるか、あるいは実行自体は生き延びるものの、長く続いた後で間違ったファイルに対して作業を始めることだ。

自分で組み立てて一度測ればよい、単発の呼び出しには当てはまらない。何も蓄積しないところに、設計すべき退避ポリシーは存在しない。

実施

  1. ループに手を入れる前に、2つの数字を書き出す。モデルが公称しているウィンドウと、そのうちプロンプトに費やす割合だ。Chimera は 0.6 を費やす(chimera/core/context_budget.pyDEFAULT_BUDGET_FRACTION)。残りは completion と、自分のトークン推定値とプロバイダーの実際のカウントとのずれを賄うためのものだ。
  2. 圧縮(compaction)はウィンドウの割合ではなく、予算の割合で発火させる——Chimera は予算の 0.8 で発火する。圧縮には圧縮先の余地が必要であり、ウィンドウに合わせて設定されたトリガーは、その余地が残っていない時点で発火することになる。
  3. 固定の下限を、増えていく部分とは別に測る。システムメッセージと tools= のペイロードはステップ再送信され、どれだけメッセージを圧縮してもそこには手が届かない。履歴が高くついているのだと決めつける前に、chimera schema-bench を実行する(あるいは自分で JSON を数える)こと。冗長な MCP や OpenAPI のインポートは、実行中のあらゆる1ステップの下に数万トークンを敷き詰めうる。
  4. その下限が問題なら、下限そのものを縮める。注釈にすぎないスキーマキー(examplestitledefault$comment)を取り除き、パラメータの説明文を最初の一文に切り詰める。その際、ツール選択と引数の妥当性が変わらないよう typepropertiesrequiredenum はそのまま残す。chimera/tools/schema_compact.py が行っているのがこれだ。それでも大きすぎるなら、公開するツールの数を減らす。
  5. 退避の順序を明示的に決める。システムメッセージは決して落とさない、直近のターンはそのまま残す(Chimera は6ターン)、それより古い範囲は要約または事実の記録で置き換える。システムメッセージを書き換えてはならない——それはプロンプトキャッシュのキーとなる安定した接頭辞であり、編集すればその後ろのキャッシュ済みターンがすべて無効になる。
  6. 圧縮の後、その実行が実行のままであり続けるために必要なものを再注入する。タスクの原文そのまま、計画、ステータス付きのタスク一覧、そして現在編集中のファイルだ。ファイルは記憶していたコピーを復元するのではなく、ディスクから読み直すこと。
  7. トークンサイズを自分で見積もる場合は、content だけでなく tool_calls のペイロードも数える。ツールの引数はアシスタントメッセージに乗っており、content の中にはない。content しか読まないサイズ推定は、まさに肥大したメッセージを過小報告する。

回避

タスクが終わらなかったからといって --max-steps を上げること。それは思いつきやすい手であり、そして実行を殺す手でもある。ステップが増えるとは、同じウィンドウに対してメッセージリストが長くなるということだ。

タスクの記述を落とすこと。それは先頭のユーザーメッセージとして届くため、素朴な圧縮器が真っ先に退避する対象であり、しかもエージェントがそれなしには最も作業できないものだ。結果として、目的を削除された計画を実行するエージェントができあがる——自信たっぷりのまま、編集を出し続け、どこにもエラーは出ない。ファイルなら読み直せるが、指示は読み直せない。

残す末尾部分の先頭に tool メッセージを置いたままにすること:

older, recent = body[:-keep_recent], body[-keep_recent:]   # can orphan a tool result

これに対して:

older, recent = body[:-keep_recent], body[-keep_recent:]
while recent and recent[0].get("role") == "tool":
    older.append(recent.pop(0))                            # tail starts on a legal turn

ほとんどのプロバイダーは、対応するアシスタントの tool_call が失われた tool メッセージを拒否する。つまり、実行を救うはずだった圧縮こそが実行を終わらせることになる。

圧縮率の最大化を先に調整することも避けること。まずは recall を優先して較正する。残しすぎればトークンを消費する——それは請求書だ。削りすぎれば後で必要になる文脈を失い、そのメッセージはもう戻らない。一方はコストであり、もう一方は回復不能である。

確認

意図的にウィンドウを低く設定し——予算を 4K の偽ウィンドウに向けるか、長いと分かっているタスクを実行する——次の3点を確認する。圧縮が発火したこと、実行がそれを越えて続いたこと、そしてその後に続いたメッセージに元のタスク文字列が含まれていたことだ。圧縮の後、組み立てられたプロンプトを、タスク中の特徴的な語句で grep すること。それが無いなら、ログが何と言おうと復元は機能していない。

次に下限を、二者択一の問いで確認する。履歴が空の状態で、1ステップ分のプロンプトがすでに閾値を超えていないか。超えているなら、圧縮では決して助けにならない——compact() は縮められないリストに対して changed=False を返すのであり、何も起きなかったという結果の誠実な読み方は「これでは助からなかった」であって、「同じ壁にもう一度突っ込んで再試行する」ではない。

リスク

予算を低く設定しすぎると、必要のなかった実行まで圧縮してしまう。そして圧縮のたびにプロンプトの後半が書き換えられ、その背後にあったキャッシュヒットが捨てられる。長時間のコーディングセッションでは、それは現実の請求額であり、起きもしなかったオーバーフローを避けるために支払われることになる。

スキーマ圧縮にも固有の落とし穴がある。パラメータの説明を一文に切り詰めるのは引数の妥当性という点では安全だが、そのツールをいつ使うべきかをモデルに伝えていた一文を取り除いてしまうことがある。これはバリデータが検査するどのスキーマも変えないままツール選択の挙動を変えるため、エラーとしてではなく「わずかに悪いツール選択」という形で失敗する。A/B として測定すること。トークンを節約するからという理由で有効にしないこと。

そしてこのパターン全体は、そのタスクがモデルにとって本当に大きすぎる場合には何ももたらさない。予算管理は硬い天井を柔らかい天井に変えるだけであり、そこにない余地を生み出しはしない。

使い方

カードはデータです。リポジトリをクローンし、パスで取り込んでください。ネットワーク経由で届いたものは汚染扱いとなり、承認されるまで保留されます。それが望ましい挙動であり、ここにワンライナーのインストーラーがない理由です。

git clone https://github.com/brcampidelli/chimera-agent.git
chimera skills-import chimera-agent/skills/chimera-budget-the-context/SKILL.md

完全性

公開された状態のファイルの SHA-256。取り込む側は、受け取ったものがこのページに表示されたものと同じか確認できます。

63f202117c1ffb79dcc016edf37d12760ef2edd00274900bf5177dc1ee6b33f2

リポジトリでカードを読む