Codexの利用量とPrompt Cachingの見方

Codexの利用量とPrompt Cachingの見方

Codex を ChatGPT plan で使っていると、ローカルログ上はかなり大きな token 数に見えることがある。

ただし、ChatGPT plan の Codex 利用と OpenAI API 課金は同じものではない。ChatGPT plan 側では agentic usage limit と rate limit で制御され、API 側では input / cached input / output の token 単価で課金される。

このメモは、Codex を重めに使っている時に次の点を確認するための整理である。

  • 今月どのくらい使っているように見えるか
  • API 課金だったらどの程度になりそうか
  • cached input は何を意味するか
  • 重い使い方が Codex の想定範囲なのか

参考 URL:

まず見るローカル情報

Codex CLI は ~/.codex 配下にローカル状態と session JSONL を持つ。

概算を早く見るなら state_5.sqlitethreads.tokens_used が使える。

sqlite3 -header -column ~/.codex/state_5.sqlite \
  "select strftime('%Y-%m', created_at, 'unixepoch') as month,
          count(*) as threads,
          sum(tokens_used) as tokens
     from threads
    group by month
    order by month desc;"

モデル別に見る例:

sqlite3 -header -column ~/.codex/state_5.sqlite \
  "select coalesce(model,'(unknown)') as model,
          count(*) as threads,
          sum(tokens_used) as tokens
     from threads
    where created_at >= strftime('%s','2026-05-01')
      and created_at <  strftime('%s','2026-06-01')
    group by model
    order by tokens desc;"

ただし、API 課金の概算に近づけるなら、session JSONL の last_token_usage を呼び出し単位で積み上げる方がよい。

threads.tokens_used は UI / thread 索引用の値として扱い、正式な請求再現には使わない。

session JSONL は追記型のログなので、PC のハング、プロセス停止、並行書き込みの影響で、まれに壊れた行を含むことがある。

実際に 2026-05 の手元ログでは、1 ファイルに JSON として parse できない行が 1 行あった。そのため、集計では「ファイル全体を jq で parse する」よりも、「行単位で parse できる event だけ拾い、壊れた行は件数を記録して skip する」方が扱いやすい。

参考 URL:

API換算で見る時の考え方

API の料金表では、少なくとも次を分ける。

  • uncached input
  • cached input
  • output

cached_input_tokensinput_tokens の内数として扱う。

そのため、API 換算では次のように見る。

uncached_input = input_tokens - cached_input_tokens

estimated_cost =
  uncached_input * input_price
  + cached_input * cached_input_price
  + output_tokens * output_price

reasoning output token は output 側の一部として見る。ローカル JSONL では reasoning_output_tokens として見えるが、料金計算ではモデルの出力 token として扱われる前提で概算する。

注意点:

  • ChatGPT plan の Codex 利用は API billing ではない
  • API 価格は変わる
  • Codex plan 側の usage limit と API の token billing は同じ尺度ではない
  • local log は手元環境の概算で、OpenAI 側の正式な請求データではない

参考 URL:

2026-05の実測スナップショット

2026-05-30T08:06:52Z 時点で、ローカルの ~/.codex/sessions/2026/05/*.jsonl から last_token_usage を呼び出し単位で合算すると次の値だった。

これは OpenAI 側の正式な usage accounting ではない。あくまで、この端末の Codex session JSONL に残っている usage event の集計である。

modeleventsinputcached inputuncached inputoutputreasoning outputtotal
gpt-5.547,2696,224,788,3405,968,438,528256,349,81218,126,5075,212,2776,250,682,119
gpt-5.3-codex-spark3,20576,520,74564,768,25611,752,4891,655,4051,352,89178,176,150
ternary-bonsai-8b47505,008115,656389,3524,9230509,931
gpt-5.3-codex115,3116,5288,78313612915,447
total50,5226,301,829,4046,033,328,968268,500,43619,786,9716,565,2976,329,383,647

この snapshot では、input のうち cached input が約 95.7% を占めていた。

別系統の概算として、~/.codex/state_5.sqlitethreads.tokens_used では同時点の 2026-05 合計は次の通りだった。

metricvalue
threads1,589
threads.tokens_used total5,566,166,912
first created UTC2026-05-02 13:46:39
last updated UTC2026-05-30 08:06:51

API 課金に近い推計では last_token_usage 合算を見る。Codex のローカル UI や thread 一覧での概算を見るなら threads.tokens_used を見る。

参考 URL:

cached inputとは何か

cached input は、最終回答や HTTP response をキャッシュしているという意味ではない。

LLM の推論は大きく分けると、入力 prompt を読む prefill と、出力 token を生成する decode に分かれる。

長い prompt では prefill が重い。各 transformer layer は入力 token から attention 用の key / value tensor を作る。prompt caching は、同じ prompt prefix が再び来た時に、この prefix 部分の key / value tensor を再利用する仕組みと考えると分かりやすい。

request A:
  stable prefix + new tail
  -> stable prefix の KV を作る
  -> cache に載る

request B:
  same stable prefix + another tail
  -> stable prefix の KV を再利用
  -> new tail 以降だけ通常どおり処理

GPU 的には、同じ prefix を毎回 transformer に通して key / value を再計算する負荷を避けられる。出力 token の生成そのものは毎回必要なので、output が無料になるわけではない。

cached inputはどこに載るか

OpenAI の prompt caching docs では、in-memory prompt cache retention は volatile GPU memory に保持されると説明されている。

また extended prompt caching については、GPU memory が埋まった時に key/value tensor を GPU-local storage へ offload することで cache 容量を増やす、と説明されている。ここで保持されるのは attention layer の prefill で作られる key/value tensor であり、元の prompt text そのものではない。

つまり、OpenAI docs から確定的に言えるのは次である。

short-lived hot cache:
  GPU memory

extended retention:
  key/value tensor を GPU-local storage へ offload

cached content:
  prompt text そのものではなく、prefill で生成された key/value tensor

物理的な NVIDIA 系 hardware から推測すると、実際の階層は次のような形が自然である。

GPU HBM / VRAM
  active request と hot prefix
  attention kernel が直接読む最終配置

CPU DRAM
  HBM より遅いが NVMe より速い中間 tier
  hot ではないが再利用可能性のある KV block

local NVMe / GPU-local storage
  24h retention や大量 prefix の backing tier
  hit 時には GPU memory へ戻す、または block 単位で prefetch する

remote memory / networked storage
  大規模 serving では RDMA / object storage / distributed KV cache も候補

H100 は GPU memory bandwidth が 3TB/s 級、H200 は 141GB HBM3e と 4.8TB/s 級である。一方で NVMe SSD は高速な構成でも帯域と latency が HBM と桁違いなので、decode 中の attention が SSD 上の KV tensor をそのままランダムアクセスする設計は考えにくい。

そのため、cached input が hit した時の実行経路は、おそらく次に近い。

cache hit on GPU memory:
  そのまま HBM 上の KV tensor を使う

cache hit on extended storage:
  GPU-local storage / CPU DRAM / remote tier から KV tensor を戻す
  必要 block を GPU memory へ載せる
  suffix 以降だけ prefill し、decode は通常どおり行う

NVIDIA 側の公開情報を見ると、この推測はかなり自然である。GPUDirect Storage は NVMe や NIC 近くの DMA engine から GPU memory へ直接転送する経路を提供する。NVIDIA Dynamo / NIXL / KVBM は、KV block を GPU、CPU、SSD、remote storage などの tier 間で移動・共有する方向の仕組みとして説明されている。

ただし、OpenAI の本番 serving が具体的にどの NVIDIA GPU、どの NVMe、どの routing、どの eviction policy を使っているかは外からは分からない。したがって、ここでの hardware 構成は、OpenAI docs の記述と NVIDIA の公開 hardware / inference stack からの推察である。

参考 URL:

Codexで効きやすい理由

Codex は prompt caching が効きやすい構造を持つ。

毎回の request prefix に、比較的安定した情報が大量に入るためである。

  • system / developer instructions
  • tool 定義
  • MCP / connector / dynamic tool schema
  • sandbox / approval / workspace context
  • AGENTS.md
  • 直前までの会話履歴や要約
  • 同じ repository で繰り返し使う方針や制約

この安定した prefix の後ろに、新しい user request や tool result が足される。

そのため、長い session では input token の大半が cached input になることがある。見かけ上の input token は大きくても、実際の prefill 計算と API 換算コストは uncached input より低くなる。

ただし、cache は意味が同じなら効く、というものではない。token 列の prefix が一致する必要がある。

先頭側に毎回変わる timestamp、random ID、長い一時ログ、順序が揺れる context を入れると、その位置以降の cache hit が落ちる。

参考 URL:

迷惑な使い方かどうか

Codex は、長い coding task、大きな codebase、agentic な調査、tool execution を想定した product である。

大きな context を持つ session や長時間 task は、per message の消費が大きくなる。これは異常ではなく、Codex の設計対象に入っている。

見るべきなのは、token 数そのものより次である。

  • plan 側の limit に実際に当たっているか
  • rate_limit_reached_type が出ているか
  • 複数プロセスで無制御に並列していないか
  • limit 回避のためにアカウントや環境を分散していないか
  • 無限ループや unattended automation になっていないか

ローカルログで rate limit の雰囲気を見る例:

find ~/.codex/sessions/2026/05 -type f -name '*.jsonl' -print0 |
  xargs -0 -n 100 perl -ne '
    while (/"rate_limit_reached_type":(null|"[^"]+")/g) {
      print "$1\n";
    }
  ' |
  sort |
  uniq -c

null 以外が頻繁に出るなら、plan 側の制御に当たっている。

null のままであれば、少なくとも OpenAI 側の制御から見て、その時点では許容範囲にいると考えてよい。

参考 URL:

参考