はじめに
Claude Codeの424本の会話で、料金を種類別に数え直しました。
料金の約6割は、AIが書いた分ではなく、会話の履歴の読み直しでした。
何が起きたか
答えが2通りになったのに元のファイルを見ていなかった
- 症状:同じデータなのに、答えが63.6%と56.9%の2通りになりました
- 原因:手元の表だけでは、預けた時間が5分か1時間か分からず、値段を決められませんでした
- 直し方:5分と1時間が別々に記録された元のファイルを見て、計算し直しました
単価表の1か所が公式とずれていた
- 症状:読み直しの割合が59.0%と出ましたが、正しくは57.1%でした
- 原因:集計用の単価表のSonnet 5.5の読み直しが、公式の料金表と食い違っていました
- 直し方:別のAIの検証で気づき、公式の料金表と突き合わせて$0.10に直し、数え直しました
前提と確かめ方
- 対象:Claude Code 2.1.217〜2.1.299(26版。元のログを読めた会話の範囲。デスクトップアプリ)、Windows 11
- 確かめ方:自分が開いた会話のうち、AIの返事が20回以上ある424本の全件(開いたのは日本時間の2026-07-23〜2026-10-18朝)。返事が20回未満の会話159本と、Claude Codeが裏で動かした子の作業181件は除きました。抜き取りではなく1回の全件集計です
- 数字:料金に占める読み直し57%。数え方は、会話=Claude Codeの記録ファイル1つ分(再開すると別の会話)。返事=AIが1回動くこと(ファイルを読むなどの作業も1回)。読み直し=返事のたびに、預けてある会話の履歴(キャッシュ)を読み出す分。書き込み=履歴をキャッシュに預ける分(5分保管と1時間保管で単価が違う)。出力=AIがその返事で新しく書いた分(書いた文章は次の返事から履歴に入り、書き込みと読み直しに数えられる)。通常入力=キャッシュを使わず新しく読ませた分。金額=トークン数に公式の料金表の単価をモデルごとに掛けたAPI換算の値(使った分だけ払う契約で使った場合の金額)。量の割合=4種類のトークン数の合計に占める割合。金額の割合=4種類の金額の合計に占める割合。1トークンは、AIが文章を数える単位
再現手順
-
Claude Codeの会話の記録を見つけます。記録はWindowsなら
C:\Users\ユーザー名\.claude\projectsの下にある、会話1つにつき1つの.jsonlファイルです。 -
各行の
message.usageからinput_tokens・output_tokens・cache_read_input_tokensを読みます。cache_creationの中のephemeral_5m_input_tokensとephemeral_1h_input_tokensも読みます。同じ
message.idとrequestIdの行は、AIの1回の返事が複数行に分けて書かれたものです。全部を足すと何重にも数えるので、行の間で最大値を1件分として数えます。 -
モデルごとの単価を掛けて合計します。次のプログラムの単価は100万トークンあたりのドルで、公式の料金表で2026年10月19日に確認した値です。
import json, glob, os PRICE = { # 通常入力・出力・読み直し・書き込み5分・書き込み1時間 "claude-sonnet-5": (2, 10, 0.20, 2.50, 4), "claude-sonnet-5-5": (2, 10, 0.10, 2.50, 4), "claude-opus-5": (5, 25, 0.50, 6.25, 10), "claude-opus-5-5": (4, 20, 0.20, 5.00, 8), } KINDS = ("input", "output", "read", "write") dollars = dict.fromkeys(KINDS, 0.0) for path in glob.glob(os.path.expanduser("~/.claude/projects/*/*.jsonl")): best = {} for line in open(path, encoding="utf-8"): row = json.loads(line) msg = row.get("message") or {} usage = msg.get("usage") if row.get("type") != "assistant" or not usage or msg.get("model") not in PRICE: continue cc = usage.get("cache_creation") or {} now = (usage.get("input_tokens", 0), usage.get("output_tokens", 0), usage.get("cache_read_input_tokens", 0), cc.get("ephemeral_5m_input_tokens", 0), cc.get("ephemeral_1h_input_tokens", 0)) key = (msg.get("id"), row.get("requestId")) if msg.get("id") else row["uuid"] old = best.get(key, (msg["model"],) + (0,) * 5) best[key] = (msg["model"],) + tuple(max(a, b) for a, b in zip(old[1:], now)) if len(best) < 20: continue for model, i, o, r, w5, w1 in best.values(): p = PRICE[model] dollars["input"] += i * p[0] / 1e6 dollars["output"] += o * p[1] / 1e6 dollars["read"] += r * p[2] / 1e6 dollars["write"] += (w5 * p[3] + w1 * p[4]) / 1e6 total = sum(dollars.values()) print({k: round(v / total * 100, 1) for k, v in dollars.items()}) -
出てきた割合のうち
readが、金額に占める読み直しの割合です。writeは書き込みの5分と1時間を足した割合です。返事が20回未満の会話は数えず、料金表に無いモデルも数えません。私の手元でこのプログラムを動かすと、読み直しは58.8%でした。記事の57.1%と同じにならないのは、条件が違うからです。このプログラムは、会話を再開して写された履歴も数えます。消えた会話の退避先は読まず、10月18日の朝より後の会話も含みます。
デメリット・注意点
測ったのは私1人の424本です。ほかの人の使い方で数えた結果ではありません。
金額はAPI換算であり実際の支払いではありません。単価は2026年10月19日に公式の料金表と突き合わせました。集計用の単価表は10月1日に取ったものです。Sonnet 5.5の読み直しだけ公式の$0.10に直し、集計表も数え直しました。直す前の単価で数えた424本の合計は$3,024.96です。
424本の書き込みは99.9%が1時間保管でした。5分保管が多い使い方は、この数字に含まれていません。
会話を再開すると履歴が別のファイルへ写されます。私の集計では、同じ返事を一番早く終わった会話にだけ数えました。上の短いプログラムは写された分も数えます。元のログを直接数えると、ログを読めた406本のうち36本が集計より多く出ます。集計のあとも続いた会話の分も含みます。
元のログが無い18本は、集計ファイルに残した記録だけで数えました。424本全体の約4%です。
読み直しが書き込みの46.9倍というのは、会話ごとの値の中央値です。平均は53.9倍で、424本の合計どうしで割ると約50倍です。
元の記事
ふきだしや図、記事を書いた時の会話の記録つきの全文は、元の記事に置いています。