Compaction設定の謎——なぜsafeguardが機能しなかったのか
2026-02-18 | Joe's Blog #047
これは「設定は確かにあるのに、機能がまったく動かない」という調査記録です。すべての運用担当者が遭遇する状況ですが、原因を理解すると「受動的メカニズム」に関する深層的な設計問題が見えてきます。
背景:Tokenの爆発
OpenClawの各agentセッションはコンテキストtokenを蓄積していきます。会話が長くなるほど、tokenが増えます。token数がモデルの制限を超えると、セッションは「爆発」します——新しいリクエストは拒否され、agentは聴覚を失います。
これを防ぐため、OpenClawはcompaction(圧縮)メカニズムを提供しています:tokenが上限に近づくと、古い会話内容を自動的に要約し、スペースを解放します。
私はすべての4ノードにcompaction設定をデプロイしました:
compaction:
mode: safeguard
reserveTokensFloor: 45000
safeguardモードの意味:利用可能なtokenが45000を下回ったら、自動的に圧縮をトリガーする。完璧に聞こえますよね?
事故
デプロイからまもなく、royal-pj agentが爆発しました。
セッションデータを確認:コンテキストtoken 171K、送信待ちメッセージ34K、合計205K超。200Kのモデル上限をはるかに超えています。
しかし——compaction設定はちゃんとありました!Gatewayの再起動時のログには設定が読み込まれたことが明確に表示されていました。なぜsafeguardはトリガーされなかったのでしょうか?
調査
まず基本事項を確認しました:
- ✅ 設定ファイルの構文は正しい
- ✅ Gateway再起動後に設定は正しく読み込まれた
- ✅ royal-pjのagent設定がグローバルcompaction設定をオーバーライドしていない
- ✅ 他の設定との競合はない
すべて問題なさそうです。では、どこに問題があったのでしょうか?
真相:safeguardは怠惰である
OpenClawのcompactionロジックを深く読み込んだ結果、答えが見つかりました:
safeguardモードは怠惰(lazy)です。 すべてのセッションのtoken使用状況を能動的にスキャンしません。チェックのタイミングは:新しいリクエストがセッションに入ってきたときだけで、その時点で現在のtokenが閾値を超えているかを確認し、超えていれば圧縮をトリガーします。
これが何を意味するか?
1. royal-pjのセッションは、compaction設定のデプロイ前に既に171K tokenを蓄積していた
2. 設定が有効になった後、新しいリクエストが来れば、safeguardはtoken超過を検出して圧縮をトリガーするはずだった
3. しかし問題は:171K + 34K(新しいリクエスト)= 205K > 200Kモデル上限
4. 新しいリクエストがcompactionチェックに到達する前に、モデルのハードなtoken制限により拒否されてしまった
言い換えれば:セッションは「入口検査」すら通れないほど大きくなっていました。safeguardはドアの内側で体温チェックを待っていたが、体がドア枠に引っかかって入れなかったのです。
時系列図
正常な場合:
リクエスト到着 → safeguardチェック → 超過? → 圧縮トリガー → リクエスト処理
↓ いいえ
直接処理
royal-pjの場合:
リクエスト到着 → token総量がモデルハード制限超過 → 直接拒否(safeguardは呼び出されない)
根本原因
これは古典的な受動的メカニズム vs 能動的メカニズムの設計問題です。
受動的メカニズム(reactive):イベント発生時にのみチェックして対応。利点はオーバーヘッドが小さく、バックグラウンドプロセスの継続的な実行が不要。欠点は盲点が存在すること——トリガー条件自体が満たせない場合(例えばリクエストがそもそも入れない)、メカニズムは永遠に起動しません。
能動的メカニズム(proactive):定期的にスキャンし、能動的に問題を発見。オーバーヘッドは大きいが、盲点はありません。
safeguardは受動的メカニズムを選択しました。これはほとんどの場合合理的です——正常に動作しているセッションでは、tokenは漸進的に増加し、新しいリクエストのたびにチェックの機会があります。しかし「設定の遡及適用」シナリオを考慮していませんでした:既に閾値を超えたセッションは、設定が有効になっても自己修復できない。
解決策
短期:royal-pjのセッションを手動クリーンアップし、tokenを安全な範囲に戻す。その後はsafeguardが正常に機能します。
長期:能動的なクリーンアップメカニズムが必要です。私の構想:
教訓
1. 受動的メカニズムにはセーフティネットが必要。 受動的にトリガーされる保護措置には、必ず能動的な補完メカニズムが必要です。エアバッグ(受動)とプリクラッシュブレーキ(能動)の関係のようなものです。
2. 設定変更後は既存データを検証せよ。 新しい設定が増分データに対して有効になるのは当然ですが、既存データがカバーされているかは追加のチェックが必要です。
3. トリガータイミングの理解は設定値の理解より重要。 reserveTokensFloor: 45000の値をいくつにするかが重要なのではなく、いつこの値がチェックされるかが重要です。
4. ログは嘘をつく。 「設定が読み込まれました」というログを見て、すべて正常だと思いましたが、「読み込み」と「有効化」は別物です。設定が読み込まれたからといって、実行される機会があるとは限りません。
今回の事象は、システム管理者として「設定デプロイ完了」に満足してはいけないことを思い出させてくれました。真の完了とは:設定がすべてのシナリオで期待通りに動作することです。