CLIワークフローでエージェントのトークンコストを削減する方法
出力の圧縮、コマンドの整理、コンテキストの管理を活用して、CLIワークフローにおけるエージェントのトークンコストを削減するための実践的なガイド。
私はDoraです。先月、Claude Codeでnpm testを1回実行しただけで、エージェントが一言返す前にセッションが約12,000入力トークンを消費しているのを目の当たりにしました。テスト出力は400行。重要だったのはせいぜい30行。残りは非推奨警告、依存関係のノイズ、Jestのプログレスドット——それらすべてがモデルのコンテキストに直接流れ込んでいきました。私はバイト単位でお金を払っていたのです。
そのとき、私はトークンを「モデルが処理するもの」として扱うのをやめ、積極的に漏らしているバジェットとして扱い始めました。Claude Code、Gemini CLI、あるいは類似のツールでエージェント型CLIワークフローを実行しているなら、これはおそらくあなたの最大のコスト項目です——そして解決策はより良いモデルではなく、より良い衛生管理です。Anthropicのコスト管理ドキュメントはこう明言しています:トークンコストはコンテキストサイズに比例してスケールし、ほとんどの最適化はモデルがデータを見る前に行われる、と。この記事は、必要なデバッグ信号を失わずに、CLIワークフローにおけるエージェントのトークンコストを削減する方法についてです。
CLIワークフローがトークンを無駄にする場所
何かを修正する前に、漏れがどこにあるのかを把握する必要がありました。2つのパターンが際立っており、それ以来私が監査したほぼすべてのCLIワークフローに現れています。
冗長なコマンドと無関係な出力
ターミナルコマンドは、LLMがバイト単位で読むためではなく、人間が画面をざっと確認するために設計されています。git statusはモデルが必要としないANSIコードを出力します。npm installはモデルがすでに知っている依存関係ツリーを千行ダンプします。next buildは15秒間自分の進行状況をエコーし続けます。それらのどれもコンテキストウィンドウの中で役割を果たしていません。
数字は紙の上で見るよりも悪い状況です。中規模のRustプロジェクトでのcargo test実行1回で、8,000〜15,000トークンの出力が生成されることがあります。そのほとんどはコンパイルノイズです。エージェントが1つの失敗したアサーションを見つけるためにそれをすべて読むとき、あなたはビルドログをストリーミングする特権のためにOpusレートで料金を払っています。
これがrtkやtokfのようなコミュニティプロジェクトが存在する理由でもあります——それらはシェルとエージェントの間に座り、コンテキストに到達する前にボイラープレートをフィルタリングし、一般的なコマンドで70〜90%の節約を報告しています。ラッパーを使用するかどうかにかかわらず、原則は変わりません:生のターミナル出力はLLM対応データではありません。
コンテキストの持ち越しと繰り返し読み取り
2番目の漏れはより微妙です。エージェントが行うすべてのツール呼び出し——ファイル読み取り、grep、bashコマンド——は会話履歴に残ります。10ターン目までに、モデルはすべてのリクエストで9ターン分の古い出力を再処理しています。Anthropicの4月のポストモーテムでは、Claude Codeの品質問題について、キャッシュバグが思考履歴をターンをまたいで複合させ、誰かが気づく前にトークン使用量が10〜20倍に膨らんだと正確に説明しています。バグがなくても、これはデフォルトの動作です。長いセッションは高コストのセッションです。
1週間前の自分のセッションを確認しました。エージェントは同じpackage.jsonを4回読んでいました。それらの再読み取りはどれも情報を追加していませんでした——ファイルは変更されていなかったのです。それらは単に、エージェントが自分がすでに知っていることを知らないことの産物でした。
ステップ1:ノイズの多い出力を圧縮する
最も安価な修正は、ジャンクがそもそもコンテキストに入るのを防ぐことです。3つのルールを、この順序で:
フィルタリングは事後ではなくソースで行う。 npm testの代わりに、エージェントはnpm test —silent 2>&1 | grep -E “(FAIL|PASS|Error)“を実行します。git statusの代わりに、git status —shortを実行します。cargo buildの代わりに、cargo build —quiet 2>&1 | tail -20を実行します。これは賢い方法ではありません。単なる規律です。エージェントは失敗したテスト、変更されたファイル、実際のエラーを取得します——それ以外は何もありません。
ハーネスレベルでツール出力を制限する。 Claude Codeでは、最大ツール出力サイズを設定できます。私は呼び出しごとに8,000文字まで下げました。コマンドがそれを超えると、エージェントは切り捨て通知を受け取り、クエリを絞り込むかどうかを決定します。この1つの設定だけで、他のすべての変更を合わせたより多くのトークンを節約できました。
上流ツールが黙らない場合はCLIプロキシを使用する。 一部のコマンドには使える—quietフラグがありません——next build、webpack、Javaベースのもの。これらには、既知のボイラープレートを取り除くラッパーが設定時間に値します。rtk/tokfファミリーのツールはこれを汎用的に処理します;最も困る3つのコマンド用に30行のbash関数を書くこともできます。
ここには本当のトレードオフがあります。積極的な圧縮はデバッグ信号を隠す可能性があります。 フィルターが取り除いた理由でビルドが失敗した場合——エラーになった非推奨警告、847行目に埋もれた不明瞭な設定問題——エージェントはより短く、あまり有用でない画像を受け取ります。私は2回経験しました。どちらの場合も、修正は戦略を放棄することではなく、1つのフィルタールールを緩めることでした。
ステップ2:モデルに到達する前にコンテキストを制限する
出力フィルタリングは各ターンに入ってくる新しいトークンを処理します。コンテキスト規律はセッション内に既にある蓄積されたトークンを処理します。異なる問題です。
重要な2つのコマンド——どちらもAnthropicのClaude Codeベストプラクティスから直接取得——は/clearと/compactです。/clearはセッションを完全にリセットします——無関係なタスクに切り替えるときに便利です。/compactは重要な決定と現在の状態を保持しながら以前の履歴を要約します——タスクは継続するが初期の探索がもはや重要でない場合に便利です。Claude Codeはコンテキスト制限に近づくと自動コンパクトしますが、そのトリガーを待つのは通常遅すぎます。その頃にはすでに数ターン分の膨れ上がったレートを支払っています。
私の現在の習慣:すべての自然なタスク境界で/compact Focus on the failing test and the recent file editsのような指示とともに/compactを実行します。指示が重要です。それなしでは、コンパクションはすべてをおおまかに要約します。それによって、エージェントは次のフェーズで重要な部分を保持します。
APIベースのエージェント(CLIサブスクリプションではない)の場合、Anthropicのコンテキスト編集ドキュメントはより厳格なメカニズムを説明しています:clear_tool_uses_20250919は、コンテキストが閾値を超えて成長すると古いツール結果を自動的にクリアします。エージェントは会話を保持しますが、すでに処理した生の出力は失います。長期のエージェント型タスクでは、これが正しいデフォルトです。
1つ指摘したいこと:膨れ上がったCLAUDE.mdは永続的な税金です。毎ターン、毎セッション、永遠にロードされます。私のものを約280行から約90行に削減しました。ターンごとのトークン数は目に見えて減少し、エージェントの動作は測定できる形では変わりませんでした。
ステップ3:低い無駄のためにエージェントツーリングを再設計する
最初の2つのステップは戦術的です。これは構造的であり、持続的な節約が生まれる場所です。
LLMフレンドリーな出力を出すツールを設計する。 コミュニティ主導のCLI Specは私よりもこの主張をうまく伝えています:エージェントを対象としたコマンドは—outputフラグをサポートし、データ(stdout)と診断(stderr)を分離し、無制限のJSONをダンプするのではなくページネーションを提供すべきです。エージェントが呼び出す内部CLIを構築している場合は、その仕様に従ってください。従わない外部CLIを使用している場合は、ラップしてください。
幅広いツールよりも狭いツールを好む。 3つの構造化フィールドを返すgit_status_summary関数は、エージェントに生のgit statusを実行させて出力を解析させるよりも優れています。モデルが行う必要のあるすべての解析レイヤーは、推論ではなく翻訳のためにトークンが消費されるレイヤーです。最もよく使う4つのコマンドをJSONを返す薄いPythonラッパーに変換しました。それらの操作のラウンドトリップトークン使用量は約60%減少しました。
読み取り量の多い作業にはサブエージェントを使用する。 Claude Codeのサブエージェント機能は、「リポジトリをスキャンして認証フローを要約する」などのタスクに別のコンテキストを実行します。結果はコンパクトな要約として戻ってきます——サブエージェントが実際に読んだ40ファイルではなく。メインの会話は生のデータを見ることはありません。探索量の多いタスクでは、これが利用可能な最大の構造的な勝利です。
モデルを作業に合わせる。 Opus 4.7は印象的で高価です。ほとんどのCLI作業——ファイル編集、テスト修正、ルーティンなリファクタリング——はOpusのトークンあたりコストの約40%でSonnetで問題なく動作します。知っておく価値があること:Opus 4.7の新しいトークナイザーは、以前のモデルと比較して同じテキストに対して最大35%多くのトークンを生成する可能性があり、それがコストの差を複合させます。
正直な注意点:最適化する前に測定し、その後も測定する。 何かを変更する前に1週間、/cost(API)または/usage(サブスクリプション)でベースラインを設定し、各変更後に再測定しました。私の「最適化」のうち2つは、測定可能な効果がないことがわかりました。ベースラインなしでは、推測しているだけです。
FAQ
なぜターミナルワークフローはこれほど多くのトークンを消費するのですか?
ターミナル出力は人間向けに設計されており、エージェントはバイト単位で料金を払うからです。典型的なビルドコマンドは、モデルが必要としない進行状況、警告、ボイラープレートの数千行を出力します。それにリセットされない会話履歴とターンをまたいで蓄積するツール結果を組み合わせると、実際の作業が始まる前にコンテキストバジェットを使い果たすセッションが生まれます。
出力圧縮はどれだけ役立ちますか?
私の測定では、コマンドレベルのフィルタリングと出力キャップを組み合わせると、テスト実行、ビルド、git操作でターンごとの入力トークンが40〜60%削減されました。rtkのようなコミュニティラッパーは特定のコマンドで80〜90%の削減を報告していますが、それらの数字は最悪ケースの冗長出力を前提としています。現実的な効果は、エージェントが最も実行するコマンドによって異なります。上位5つを監査し、それらを修正すれば、節約のほとんどがすぐに現れます。
チームは何を最初に最適化すべきですか?
この順序で:ツール出力キャップ、/clearと/compactの規律、モデル選択。出力キャップは継続的なコストがゼロの一回限りの設定変更です。セッション衛生は習慣ですが、一度身につければ無料です。モデル選択は見落としやすい最も簡単な勝利です——ほとんどのタスクがSonnetで問題なく動作するのにすべてをOpusで実行することは、静かで大きな漏れです。
トークン最適化はいつデバッグ品質を損なうのですか?
エージェントが何が壊れたかを確認できない点まで圧縮したときです。切り捨てられたスタックトレース、フィルターで除外された非推奨警告、実際のエラーを隠す—quietフラグ——これらすべてで私は実際の時間を無駄にしました。私が従うパターン:ルーティンコマンド(git status、npm install、成功したテスト実行)では積極的に圧縮し、既知の失敗または不慣れな操作では冗長な出力を保持する。フィルターなしでコマンドを再実行してデバッグしている場合、問題はフィルターであって戦略ではありません。
結論
CLIワークフローにおけるトークンコストはモデルの問題ではありません。配管の問題です。支出のほとんどは、ターミナルコマンドが出力するものとモデルが実際に推論するために必要なものの間のギャップに消えていきます——そのギャップは出力フィルタリング、コンテキスト規律、そして反対側のエージェントを尊重するツーリングで修正できます。
私はこの設定を約6週間実行しています。Claude Codeの日次トークン消費量は約55%減少し、エージェントのレイテンシはより小さなコンテキストの副作用として改善し、ワークフローはデバッグするのにノイズが少なく感じます。これらの数字はどれも普遍的ではありません——あなたのベースラインとトップ5コマンドは異なって見えるでしょう。しかしパターンは変わりません:コンテキストに入るものを制御し、コンテキストに残るものを制御し、モデルがビルドログを読む代わりに推論にバジェットを使えるようにする。
これが私のデータの終わりです。圧縮レイヤーは進化し続けており、Anthropicのトークナイザーの変更はこれらの数字に賞味期限があることを意味します。四半期ごとに再ベースライン化する価値があります。
過去の記事:





