Codexの利用量とPrompt Cachingの見方
Posted:
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.sqlite の threads.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_tokens は input_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 の集計である。
| model | events | input | cached input | uncached input | output | reasoning output | total |
|---|---|---|---|---|---|---|---|
gpt-5.5 | 47,269 | 6,224,788,340 | 5,968,438,528 | 256,349,812 | 18,126,507 | 5,212,277 | 6,250,682,119 |
gpt-5.3-codex-spark | 3,205 | 76,520,745 | 64,768,256 | 11,752,489 | 1,655,405 | 1,352,891 | 78,176,150 |
ternary-bonsai-8b | 47 | 505,008 | 115,656 | 389,352 | 4,923 | 0 | 509,931 |
gpt-5.3-codex | 1 | 15,311 | 6,528 | 8,783 | 136 | 129 | 15,447 |
| total | 50,522 | 6,301,829,404 | 6,033,328,968 | 268,500,436 | 19,786,971 | 6,565,297 | 6,329,383,647 |
この snapshot では、input のうち cached input が約 95.7% を占めていた。
別系統の概算として、~/.codex/state_5.sqlite の threads.tokens_used では同時点の 2026-05 合計は次の通りだった。
| metric | value |
|---|---|
| threads | 1,589 |
threads.tokens_used total | 5,566,166,912 |
| first created UTC | 2026-05-02 13:46:39 |
| last updated UTC | 2026-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:
- Prompt caching - OpenAI API
- Prompt Caching in the API - OpenAI
- Prompt Caching 101 - OpenAI Cookbook
- KV cache strategies - Hugging Face Transformers
- KV Cache System - NVIDIA TensorRT-LLM
- Automatic Prefix Caching - vLLM
- H100 GPU - NVIDIA
- H200 GPU - NVIDIA
- NVIDIA DGX B200 System User Guide
- GPUDirect Storage Overview Guide - NVIDIA
- NVIDIA Dynamo KVBM Guide
- How to Reduce KV Cache Bottlenecks with NVIDIA Dynamo - NVIDIA Technical Blog
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:
- Using Codex with your ChatGPT plan - OpenAI Help Center
- Rate limits - OpenAI API
- ChatGPT Pricing - OpenAI
- Rate limits - OpenAI API
- Prompt caching - OpenAI API
- AI Agent向けContext Hygieneの段階導入
- Prompt caching - OpenAI API
- API Usage Dashboard - OpenAI Help Center