powered by TechFeed
表示モード
Deep Dive

AIコーディングエージェントのコストの94%は「書く」ではなく「読む」で消えていた — 1,674セッション分析で判明したトークン削減の本質

9月28日、Antoine van der Leeが「How to reduce token usage in Claude Code, Codex, and Cursor」と題した記事を公開した。Antoine van der LeeはRocketSim(Xcodeシミュレータを拡張する開発者向けツール)の作者として知られるSwift/iOS開発者で、AIエージェントを日常的に実プロジェクトへ投入している実践者だ。この記事では、Claude Code・Codex・CursorといったAIコーディングエージェントのトークン消費を自身のプロジェクト群の実データに基づいて分析し、効果的な削減手法を紹介している。

9月28日、Antoine van der Leeが「How to reduce token usage in Claude Code, Codex, and Cursor」と題した記事を公開した。Antoine van der LeeはRocketSim(Xcodeシミュレータを拡張する開発者向けツール)の作者として知られるSwift/iOS開発者で、AIエージェントを日常的に実プロジェクトへ投入している実践者だ。この記事では、Claude Code・Codex・CursorといったAIコーディングエージェントのトークン消費を自身のプロジェクト群の実データに基づいて分析し、効果的な削減手法を紹介している。


1,674セッションの分析で判明した「本当の無駄」

筆者のAntoine van der Leeは、自身のSwiftアプリ(RocketSim、RocketTraceほか)で行った1,674セッション分のエージェント利用を分析した。その結果が衝撃的だった。

  • 全トークンの94.2%がキャッシュ読み込み(エージェントが既に持っているコンテキストを再送信している)
  • 出力トークンはわずか0.6%
  • xcodebuild・swift testの実行13,323回のうち48%が出力フィルターなし
  • ファイル読み込みの53%が全文読み込みで、同一ファイルの重複読み込みが18,683回発生
  • 同一のSKILL.mdが1セッション中に2回ロードされた例が961件

要するに、「エージェントが何を書くか」ではなく、「エージェントが何を読むか」がコストを決める。

なぜこうなるかというと、AIエージェントはステップをまたいで記憶を保持できない。ツールを呼ぶたびに、会話全体(指示・ルール・読み込んだファイル・ビルドログすべて)をモデルへ再送信する仕組みになっている。セッション序盤に取り込んだ40万トークン規模のビルドログが、その後のすべてのステップに乗り続けるわけだ。

なお、本記事でトークン計測に使われているMCPBeastとは、筆者が開発したMCP(Model Context Protocol)サーバーの一種で、AIエージェントのトークン消費量をセッション単位で可視化・記録するツールだ。記事内の計測数値はすべてこのツールによるものである。


最大の無駄:Xcodeビルド出力

Swift開発者固有の問題として、Xcodeのビルド出力は非常に大きい。筆者がMCPBeastで117テストのクリーンビルドを計測したところ、生出力は約18,200トークン。フィルターをかけると32トークンまで圧縮できた。

このフィルターに使うのがxcsiftだ。xcodebuildやSwift Package Managerの出力をコンパクトなサマリーに変換するCLIツールで、Homebrewでインストールできる。

brew install ldomaradzki/xcsift/xcsift
xcodebuild test -scheme MyApp -destination 'platform=macOS' 2>&1 | xcsift -f toon -w

注意:上記のインストールコマンドおよびオプションは元記事執筆時点のものだ。実際に使用する前にxcsiftのリポジトリで最新の手順を確認することを推奨する。

ただし、AGENTS.mdにフィルターを使うよう指示を書いても、エージェントは指示通りに動かないことがある。実際、筆者のRocketSimでは明示的に指示していたにもかかわらず、2,141回のビルドのうち751回が生出力で実行されていた。


全プロジェクトに一括適用できるフックスクリプト

AGENTS.mdへの記述では限界があるため、筆者が採用したのがグローバルフックだ。Cursor・Claude Code・Codexはいずれも、ツール実行前にスクリプトを走らせる「フック」機能をサポートしている。

以下のPythonスクリプトを~/.agents/hooks/xcode-output.pyとして保存する。xcodebuild・swift build・swift testがフィルターなしで実行されようとしていた場合、自動的にxcsift経由にリライトする。すでにフィルターがある場合やxcodebuild -listなどの情報取得コマンドは素通しする。スクリプトの全文は元記事に掲載されているが、処理の骨子は以下の通りだ。

  1. stdinからツール入力(JSON)を受け取り、実行コマンドを取り出す
  2. xcodebuild・swift build・swift testに該当し、かつすでにフィルターが適用されていなければリライト対象とする
  3. -version・-list・-showsdksなどの情報取得系コマンドや、パイプ・サブシェルを含む複雑なコマンドは安全のため素通しする
  4. 対象コマンドを set -o pipefail; <元のコマンド> 2>&1 | xcsift -f toon -w の形に書き換えて返す

set -o pipefailにより、xcsiftがパイプの末尾にいてもビルド失敗時の終了コードが正しく伝わる。

各ツールへの登録方法は以下の通りだ。

Cursor:~/.cursor/hooks.jsonを作成する。

{
  "version": 1,
  "hooks": {
    "preToolUse": [
      {
        "command": "python3 ~/.agents/hooks/xcode-output.py --cursor",
        "matcher": "Shell",
        "timeout": 5
      }
    ]
  }
}

Claude Code:~/.claude/settings.jsonに追記する。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.agents/hooks/xcode-output.py --claude",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

Codex:~/.codex/config.tomlでフック機能を有効化してから~/.codex/hooks.jsonに設定を書く。Codexの場合はコマンドのリライトではなく「ブロック+正しいコマンドをエージェントに提示」という方式を採る(承認済みコマンドのマッチング方式のため)。

スクリプトの完全な実装コードは元記事を参照していただきたい。


その他の削減ポイント

AGENTS.mdは小さく保つ:AGENTS.mdはすべてのステップで毎回コンテキストに含まれる。筆者が9月に整理したところ、RocketTraceのルートファイルが8,677バイト→1,454バイト、MCPBeastが8,166バイト→1,384バイトになった。削除したわけではなく、スコープごとにサブフォルダのAGENTS.mdや別ドキュメントへ分散させた。なお、Codexは32KBを超えたファイルを無告知で途中から切り捨てるため特に注意が必要だ。

Agent Skillsの重複を排除する:同じフレームワークをカバーするスキルが複数あると、エージェントが毎回両方をロードする。筆者の場合、重複していたSwiftUIスキルが削除前に41セッションで読み込まれていた。フレームワークごとに1スキルを原則とすることを筆者は推奨している。

関係のないタスクに切り替えるときは新チャットを開く:前のタスクで読み込んだファイルやビルドログが新しいタスクに引き継がれるのを防ぐためだ。


詳細はHow to reduce token usage in Claude Code, Codex, and Cursorを参照していただきたい。