コンテキスト管理
長いセッションで費用が非線形に増える理由と、履歴の肥大化を抑えるパターン。
APIはステートレスです。ターンごとに会話全体が再送信されるため、会話履歴が長くなるほど入力トークンが増え、その後の呼び出しごとにコストも増加します。
問題の構造
各ターンでおよそTトークンが追加されるNターンの会話では、入力トークンの合計はNTではなく、およそN²T/2になります。セッションの長さを倍にすると、入力の請求額はおよそ四倍になります。そのため、十分間は安く感じられたエージェントでも、一時間後には驚くほど高額になるのです。
有効な四つのパターン
| パターン | 方法 | トレードオフ |
|---|---|---|
| スライディングウィンドウ | 直近のKターンを残し、それ以外を削除する | 初期のコンテキストが完全に失われる |
| 継続的に更新する要約 | 古いターンを定期的にモデルが作成した要約に置き換える | 追加の呼び出しが一回必要だが、要点は保持できる |
| タスクごとに新しいセッションを開始 | 話題が変わったら新たに開始する | 追加コストがなく、通常は適切な方法 |
| 外部に保存 | 状態をファイルやデータベースに保存し、現在のステップに必要なものだけを読み込む | 最も手間がかかるが、最良の結果が得られる |
過去のターンの要約
def compact(history, keep=6):
class="s">""class="s">"Replace everything but the last `keep` turns with one summary turn."class="s">""
if len(history) <= keep:
return history
old, recent = history[:-keep], history[-keep:]
summary = summarise(old) class=class="s">"c"># one cheap Haiku call
return [{class="s">"role": class="s">"user", class="s">"content": fclass="s">"Summary of earlier discussion: {summary}"}] + recent
要約は低コストのモデルで実行してください。これは圧縮タスクであり、推論タスクではありません。
原因の多くはツールの結果
- ツールが500行を返すと、それ以降のすべてのリクエストに500行が含まれます。行数に上限を設けるか、要約と、必要に応じて詳細を取得するためのハンドルを返してください。
- エージェントが読み込んだファイルの全内容はコンテキストに残ります。ファイル全体ではなく、必要な部分を読み込んでください。
- スクリーンショットや画像も、ほかのコンテンツと同様に再送されます。内容を説明したら削除してください。
- ビルドログとスタックトレース:先頭と末尾の50行を残し、中間部分は破棄してください。
エージェント型ツールでは、無関係なタスクに移る際に新しいセッションを開始することが、最も低コストで実施できる最適化です。Claude Codeでは、その操作は
/clear.