3日前、私は「1ターンあたり23万トークンを読み直していた」という記事を書きました。
**その書き方に不足がありました。**この記事は、その訂正と、
訂正しようとして測り直したら、別の人と結論が分かれた話です。
何が不足していたか
トークンの量を測って、それをコストの大きさとして語っていました。
単価が違います。
入力(非キャッシュ) 1.0 ← これを基準にすると
キャッシュ書込 1.25
キャッシュ読出 0.1 ← **1/10**
出力 5.0
キャッシュ読出は入力の1/10、出力に対しては1/50の単価です。
量で何倍あっても、金額はその比では効きません。
この点は、@Tsutomu_eng さんが
「キャッシュ読出がトークンの81倍」はコストの話ではなかった
で明示的に指摘されています。トークンで81倍のものが、金額では1.62倍だったという測定です。
私はこの型を踏んでいました。
自分のログで測り直した
Claude Code はセッションごとの usage を手元に保存しています。推測せずに数えられます。
対象 ~/.claude/projects/**/*.jsonl 167ファイル
usage を持つターン **25,574**(claude-opus-5 / claude-sonnet-5)
結果です。
種別 トークン 量の% 額の%
入力(非キャッシュ) 51,126 0.0% 0.0%
キャッシュ書込 224,263,066 3.4% **27.7%**
キャッシュ読出 6,402,387,834 96.3% **63.2%**
出力 18,607,112 0.3% 9.2%
キャッシュ読出は、出力の344倍(トークン量)。金額比では6.88倍。
344倍 → 6.88倍 **50倍の開きがある**
「344倍」を根拠に何かを削っていたら、50分の1の効果しか出ない場所を削っていました。
そして、結論が分かれた
同じ測定を、別の環境でやると、こうなります。
読出(額) 書込(額) その人の結論
@Tsutomu_eng 41.6% 32.7% 「コストの話ではなかった」
こちら 63.2% 27.7% **読出が依然として最大**
**どちらの計算も正しいはずです。**環境が違うだけです。
分かれた理由は、使い方だと考えています。
長いセッションを少数 読み直す量が積み上がる → **読出が効く**
短いセッションを多数 毎回書き直しが発生する → **書込が効く**
キャッシュ書込は、assistant のターンのほぼ毎回発生します。
セッションを短く切れば書込の回数が増え、長く続ければ読出の量が増える。
どちらが効くかは、その人の回し方で決まります。
だから、両方に共通することだけが持ち出せる
環境をまたいで成り立ったのは、この2つでした。
1 **トークン量の構成比 ≠ 金額の構成比**
こちら 96.3% → 63.2% / 向こう 81倍 → 1.62倍
**どちらも、量で見ると大きく外す**
2 **キャッシュ書込は、量に対して金額が重い**
こちら 量3.4% → 額27.7%(**8倍**)
向こう 量6.3%(読出比) → 額32.7%
「どちらが最大か」は環境依存です。「量では測れない」は環境依存ではありません。
手元で測る
外部データを使いません。自分のログを読むだけです。
# -*- coding: utf-8 -*-
"""自分のセッションログから、トークンの内訳と金額の構成比を出す。"""
import collections, io, json, os, sys
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
ROOT = os.path.expanduser("~/.claude/projects")
KEYS = ("input_tokens", "cache_creation_input_tokens",
"cache_read_input_tokens", "output_tokens")
LABEL = {"input_tokens": "入力(非キャッシュ)",
"cache_creation_input_tokens": "キャッシュ書込",
"cache_read_input_tokens": "キャッシュ読出",
"output_tokens": "出力"}
# **単価は「比」だけを使う。**絶対額はモデルとプランで変わる
RATIO = {"input_tokens": 1.0, "cache_creation_input_tokens": 1.25,
"cache_read_input_tokens": 0.1, "output_tokens": 5.0}
tot, turns, files = collections.Counter(), 0, 0
for root, _dirs, names in os.walk(ROOT):
for n in names:
if not n.endswith(".jsonl"):
continue
files += 1
for line in io.open(os.path.join(root, n), encoding="utf-8", errors="ignore"):
if '"usage"' not in line:
continue
try:
o = json.loads(line)
except Exception:
continue
u = (o.get("message") or {}).get("usage") or o.get("usage")
if not isinstance(u, dict):
continue
turns += 1
for k in KEYS:
tot[k] += int(u.get(k) or 0)
S = sum(tot[k] for k in KEYS)
cost = {k: tot[k] * RATIO[k] for k in KEYS}
C = sum(cost.values())
print(f"ファイル {files} / usage を持つターン {turns}\n")
print(f"{'種別':<18}{'トークン':>16}{'量の%':>9}{'額の%':>9}")
for k in KEYS:
print(f"{LABEL[k]:<18}{tot[k]:>16,}{100*tot[k]/S:>8.1f}%{100*cost[k]/C:>8.1f}%")
print(f"\n読出は出力の {tot['cache_read_input_tokens']/max(tot['output_tokens'],1):.1f} 倍(量)"
f" / {cost['cache_read_input_tokens']/max(cost['output_tokens'],1):.2f} 倍(額)")
**単価は比だけを使っています。**絶対額はモデルとプランで変わるうえ、
この記事の主張に絶対額は要らないからです。構成比だけで結論が出ます。
定額プランを使っている場合、この金額比はそのまま請求額にはなりません。
測っているのは消費の構成であって、課金の仕組みではありません。
それでも「どこを削ると効くか」の判断には、量ではなく額の構成比を見る必要があります。
訂正したこと
前の記事に追記を入れました。
残した 結論の向き ―― **読出が金額でも最大(63.2%)**。これは自分の環境では正しかった
直した 倍率の書き方 ―― 344倍ではなく **6.88倍**
足した 量と額は別物である、という但し書き
結論が間違っていたのではなく、根拠の単位が間違っていました。
そして単位が間違っていると、たまたま結論が合っていても、次で外します。
まとめ
1 トークン数はコストの代理変数にならない。**単価が50倍違うものを足している**
2 自分のログで測ると、量96.3% のものが額では63.2% だった
3 **同じ測定でも、環境が違えば結論が分かれる**(読出が最大か、書込が重いか)
4 環境をまたいで成り立つのは「**量では測れない**」のほうだけ
5 代理変数を、本体として語らない
5番目が、この件で足した検査です。
トークン数を根拠に何かを主張するときは、必ず単価を掛けてから書く。
この連載は、実際に測った数字だけで書いています。
同じことを試す人の役に立ちそうなら、ストックしておいてください。
この連載
AIエージェントを実際に回して、かかった費用と壊れた箇所を測って書いています。推測は書きません。実測値だけです。
- Claude Code のトークン使用量を実測したら1ターン23万 ― 節約に効いたのは「セッションを切る」だった
https://qiita.com/manabu49-ai/items/2598a30d5140e4445ab6 - 57分間、死んだジョブを誰も見ていなかった ― AIエージェントの見張りを機械に渡す
https://qiita.com/manabu49-ai/items/5c7506c94b5be58c040e - AIに100通り試させたら、効果ゼロなのに5個が「有意」だった
https://qiita.com/manabu49-ai/items/397a018948e1ab7ef29e - 仕様書は2日前から手元にあった ― 読まずに実装した対処が、データを永久に失う設計だった
https://qiita.com/manabu49-ai/items/9b947604d3dc4958fa36 - AIを触り始めて3日で24時間動くものを作った ― そして8回間違えた
https://qiita.com/manabu49-ai/items/acd01b13abe9c8cbea16 - 同じデータを2つのAIに測らせたら、中央値が5通り出た ― 全部、計算は正しかった
https://qiita.com/manabu49-ai/items/dc699a8458b129d6be39 - 本記事 ― トークン数はコストの代理変数にならない
- 次 ― 「できました」の的中率を測り続けた結果(未公開)
番外 ― Qiitaで何が読まれるかを3,478本から探した ― 106通り掃いて、残ったのは6つだけだった
https://qiita.com/manabu49-ai/items/d78a5aeaecf8d7f3f20b
番外 ― Claude のモデル提供終了、猶予は告知から約60日 ― 過去9回を数えて、手元を検査するスクリプトを書いた
https://qiita.com/manabu49-ai/items/bc2a7be2a6ee4ceb6185
**無料記事は結論まで全部書きます。**出し惜しみはしません。