Napsal jsem 192 tokenů z deseti milionů
Pustil jsem audit spotřeby tokenů na svůj Claude Code. Cache read je 96 % a moje vstupy 0,002 %. Skript který to změření a co z rad kolem nesedí.
Když jsem tady v srpnu psal článek o pluginu pis-cesky, spotřebovala ta session 9 969 294 tokenů. Z toho jsem klávesnicí naťukal 192. Necelé dvě tisíciny procenta.
Ta čísla nejsou odhad. Leží v logu na disku a za chvíli ukážu, jak si je vytáhneš taky.
Podnět přišel z videa o spotřebě tokenů v Claude Code. Autor tam tvrdí, že za jeho limity nemůže to, co píše, ale to co se kolem toho všechno nabalí, jako důkaz přikládá audit prompt. Pustil jsem si ho na vlastní stroji, protože cizí čísla mi jsou k ničemu.
Proč to takhle roste
Model nemá paměť. Každý požadavek na API nese celou konverzaci od začátku, jinak by nevěděl, o čem se bavíš. Soubor přečtený ve čtvrtém kroku čtyřicetikrokové session tedy zaplatíš sedmatřicetkrát.
Že tě to nezruinuje, je jen tím, že se prefix konverzace cachuje. Čtení z cache stojí zhruba desetinu ceny běžného vstupu, zápis 1,25násobek při pětiminutové TTL a dvojnásobek při hodinové. Odtud plyne bod zvratu: u pětiminutové cache se ti to vrátí od druhého požadavku, u hodinové až od třetího.
V mém logu to vypadá takhle:
| položka | tokeny | podíl |
|---|---|---|
| cache_read_input_tokens | 9 575 016 | 96,05 % |
| cache_creation_input_tokens | 325 606 | 3,27 % |
| output_tokens | 68 480 | 0,69 % |
| input_tokens | 192 | 0,0019 % |
Kontext během té session narostl z 49 201 tokenů na 133 649. Nic velkého jsem nedělal, jen napsal jeden článek a průběžně ho opravoval.
Změř si to sám
Claude Code loguje každou session do ~/.claude/projects/<projekt>/*.jsonl, jeden JSON na řádek, a řádky s odpovědí modelu nesou objekt usage. Stačí ho sečíst přes všechny řádky:
import json, sys, os
for path in sys.argv[1:]:
tot = {'cache_read_input_tokens': 0, 'cache_creation_input_tokens': 0,
'input_tokens': 0, 'output_tokens': 0}
ctx = []
with open(path) as fh:
for line in fh:
try:
rec = json.loads(line)
except ValueError:
continue
usage = (rec.get('message') or {}).get('usage')
if not isinstance(usage, dict):
continue
for key in tot:
tot[key] += usage.get(key, 0) or 0
ctx.append(sum(usage.get(k, 0) or 0 for k in
('cache_read_input_tokens',
'cache_creation_input_tokens', 'input_tokens')))
total = sum(tot.values())
if not total:
continue
print(f"\n### {os.path.basename(path)} ({len(ctx)} turnů)")
for key, value in sorted(tot.items(), key=lambda x: -x[1]):
print(f" {key:32} {value:>12,} {100 * value / total:5.2f} %")
print(f" kontext: první turn {ctx[0]:,}, poslední {ctx[-1]:,}")
Spustíš to na konkrétní soubory:
python3 tokeny.py ~/.claude/projects/-Users-ty-projekt/*.jsonl
Vyjde ti vlastní číslo místo mého. Rozdíly mezi nastaveními jsou velké, takže tohle je jediná část článku, kterou opravdu doporučuju udělat, než budeš cokoli přenastavovat.
Můj vzorek má svoje meze. Obě session, které jsem proměřil (ta srpnová a jedna starší), byly psaní textu, ne čtení cizího kódu, a cache read u nich vyšel na 96,05 % a 94,61 %. Práce, při které agent čte stovky souborů, může vypadat jinak.
Co našel audit u mě
Prompt z popisu videa prochází sedm oblastí: paměťové soubory, MCP servery, model, hooky, subagenty, naplánované úlohy a cache. Celý ho dávám na konec článku.
Nejsilnější nález: globálně připojený MCP server godot-ai s padesátkou nástrojů a nahrával se mi i do Laravel projektu, který s Godot engine nemá co do činění. Vedle toho playwright a projektový laravel-boost.
Instrukční soubory dělají 21 KB: CLAUDE.md má 11 785 bajtů, AGENTS.md dalších 9 464. To se nahraje do každé session.
Naopak past s naplánovanými úlohami, kterou video označuje za nejhorší, se mě netýká vůbec. Můj crontab -l je prázdný. A žádný proxy ani gateway nastavený nemám, takže odložené načítání nástrojů běží tak, jak má.
Mám tři hooky, ale ani jeden neořezává výstup příkazů. Když si nechám pustit testy, spadne mi celý výpis do konverzace a veze se tam do konce session.
Co z rad platí
Přepínání modelu uprostřed session opravdu bolí a je to nejméně intuitivní věc na celém tématu. Cache je vázaná na model. Přepneš z Opusu na Sonnet, protože ti dochází limit, a celá dosavadní historie se přepočítá za plnou cenu místo desetinové. Chceš ušetřit ale zaplatíš víc. Totéž udělá změna úrovně effortu - ta cache zpráv zneplatní vždycky.
Compact je na tom podobně. Aby ti model napsal shrnutí konverzace, musí tu konverzaci ještě jednou celou přečíst. Kupuješ si tím kontinuitu, ne úsporu. /clear je zdarma, protože nic neposílá.
Co mi nesedí
Ve videu zazní, že vypínat a zapínat nástroje za běhu session nic nestojí, protože se prý jen připojují na konec. Anthropic to v dokumentaci k prompt cachingu píše jinak: definice nástrojů stojí na začátku promptu, a jejich přidání, odebrání nebo přeházení zneplatní celou cache. Kromě změny modelu je taková změna nástrojů jediné, co zahodí i cache nástrojů a systémového promptu, ne jenom historii zpráv.
Tak jsem si to změřil. Projel jsem všech pět session, co v tom projektu mám - tedy i ty dvě, ze kterých jsou procenta výš - dohromady 223 odpovědí modelu, a hledal turn, ve kterém cache_read_input_tokens propadne pod předchozí hodnotu. Nenašel jsem ani jeden. Prefix pokaždé rostl dál a cache_creation k němu jen přisypal, co přibylo.
Zkusil jsem rebuild i vynutit schválně. Načtení celého skillu do běžící session zapsalo 41 336 tokenů, a cache_read u téhož turnu zůstal na 97 178 - obsah se připsal na konec, prefix se nečetl znovu. Načtení schématu odloženého nástroje dopadlo stejně, cache_read pokračoval z 173 670 na 175 100.
Obojí tvrzení tedy platí. Dokumentace mluví o poli tools v požadavku na API, kde nástroje opravdu stojí na začátku. Claude Code s odloženým načítáním do toho pole podle všeho nesahá pokaždé, když se objeví nový nástroj, ale materializuje ho až na konec promptu, kam cache nedosáhne.
Jednu věc jsem neověřil: samotné připojení a odpojení MCP serveru přes /mcp. Na to bych musel sáhnout do konfigurace a session restartovat, čímž bych o měřený stav přišel. U tohohle kroku tedy pořád nevím.
Druhá věc, kterou bych nebral doslova: /usage prý pojmenuje konkrétní skill, nástroj nebo agenta, který ti sežral limit. Ve skutečnosti ukazuje jen spotřebu plánu. Rozpis podle nástrojů v něm nehledej.
Audit prompt
Tenhle text je z popisu videa, nechávám ho v originále tak, jak je:
Audit this setup for token waste. Do not fix anything. Report only.
Use your shell and file tools to measure each item. If you cannot invoke slash
commands yourself, ask me to run /context and /usage and paste the output, then
continue.
1. MEMORY
Find every CLAUDE.md in scope: this project, parent directories, the user
level one, and anything pulled in with @imports. Report each file's size in
tokens. Flag any single file over 5k and any total over 10k.
2. TOOLS
List connected MCP servers and how many tools each exposes. State plainly
whether tool deferral is ACTIVE or NOT. Then check for a proxy or gateway
(ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, any gateway variable) and say so
loudly if you find one, because routing through a proxy silently turns
deferral off and nothing warns you.
3. MODEL
Report the current model and effort level and where each is set. Flag any
mode that changes model automatically during a session, because every
switch rebuilds the whole cache.
4. HOOKS
List any PreToolUse hooks that rewrite noisy commands to produce less
output. If there are none, say so, because unfiltered test and build output
lands in context verbatim and is re-sent for the rest of the session.
5. SUBAGENTS
List every agent file in the project and user agent directories. For each,
report whether it sets an explicit model in frontmatter or inherits the
main session's model.
6. SCHEDULED WORK
List every cron, scheduled task and background job with its interval.
Compare each interval against the prompt cache lifetime. Flag every one
whose interval is longer, because those miss cache on every single fire.
7. CACHE
Parse the newest session log under the projects directory. For every
assistant turn, sum usage.cache_read_input_tokens,
cache_creation_input_tokens, input_tokens and output_tokens. Report each as
a percentage of the total. Also report the context size on the first turn
and on the last turn.
Output one table, sorted by cost, highest first:
FINDING | SEVERITY | EVIDENCE | WHAT IT IS COSTING ME
Severity is RED, AMBER or GREEN. Evidence is a number or a file path, never an
adjective.
Then one final line: the single highest-leverage change I should make. One
line, nothing else.
Rules: measure, do not estimate. Write UNKNOWN rather than guessing. Change no
file and no setting.
Bod 7 si klidně vyřeš skriptem výš, agent na to nepotřebuje číst půlmegový log do kontextu.
Já jdu opravit ten nález s Godotem. Snad vám ten článek a video pomůže tak jako pomohl mě👍.