Prompt cache od środka: za co płacimy 10%, a za co zawsze 100%
Model czyta całą rozmowę od zera przy każdym requeście. Co dokładnie zapamiętuje prompt cache, czemu odczyt kosztuje 10% stawki i co unieważnia wpis.
Prompt cache to cache przeczytanego wejścia, nie odpowiedzi. Odpowiedź liczy się od zera przy każdym requeście, zawsze po pełnej stawce. Ten artykuł tłumaczy, co dokładnie jest zapamiętywane, czemu doklejenie nowej tury niczego nie psuje i dlaczego jedna data wstrzyknięta do promptu systemowego potrafi wywalić cały rabat.
Tekst wyrósł z pytań przy okazji raportu o tokenożerności Claude Code. Interaktywna wersja z symulatorem sesji, laboratorium unieważniania i klikanym diagramem uwagi wisi w ICS; tu jest wersja do czytania, z pełną teorią.
Trzy tezy na start
- Cache dotyczy wejścia. Model nie ma pamięci: co request czyta całą rozmowę od zera. Cache zapamiętuje wynik tego czytania, nie odpowiedź.
- Reużywany jest tylko prefiks. Początek identyczny co do bajta czyta się za 10% stawki. Pierwsza zmieniona pozycja unieważnia wszystko za sobą.
- Generowanie zawsze kosztuje 100%. Odpowiedź liczy się na żywo, po stawce wyjściowej, patrząc na cały kontekst. Dlatego bywa inna, mimo cache.
Model nie ma pamięci
API modeli językowych jest bezstanowe. Nie istnieje “trwająca rozmowa” po stronie modelu; przy każdym requeście klient (np. Claude Code) wysyła całość od zera: prompt systemowy, definicje narzędzi, pełną historię tur i na końcu nową wiadomość. Model robi wtedy dwie różne rzeczy.
Czytanie (prefill). Zanim wygeneruje cokolwiek, musi przetworzyć cały wsad: dla każdego tokenu wejścia liczy wewnętrzne reprezentacje. Przy dziesiątkach tysięcy tokenów to jest gruba większość obliczeń całego requestu i główny składnik czasu oczekiwania na pierwszy token odpowiedzi.
Generowanie. Potem produkuje odpowiedź token po tokenie, za każdym razem patrząc przez uwagę na całość tego, co przeczytał. Wynik liczy się na żywo, więc przy innej końcówce będzie inny.
Proporcje są brutalne: wejście w sesji agentowej to dziesiątki lub setki tysięcy tokenów powtarzanych co request, wyjście to zwykle setki. Owszem, token wyjścia jest drogi (w rodzinie Claude 5x stawki wejściowej), ale jest go po prostu mało; to wejście jedzie w kółko. Dlatego jedyne sensowne miejsce na oszczędność leży po stronie czytania i dokładnie tam działa cache.
Przykład na liczbach: bootstrap 40 tys. tokenów (prompt systemowy, narzędzia, CLAUDE.md) i tury po 5 tys. Czwarty request niesie 55 tys. tokenów prefiksu i 5 tys. nowych. Z cache płacisz 10% za 55 tys. i pełną stawkę za 5 tys.; bez cache pełną stawkę za całość. Po czterech requestach oszczędność na wejściu przekracza połowę rachunku i rośnie z każdą turą, bo historia się wydłuża. W wersji interaktywnej można to przeliczać suwakami.
Zasady gry: stawki, TTL, progi
Cache zapamiętuje wynik czytania prefiksu, czyli początku promptu, do wskazanego punktu. Przy kolejnym requeście serwer porównuje początek bajt w bajt: jeśli jest identyczny, odtwarza zapisany stan i świeżo liczy tylko resztę.
| Operacja | Koszt | Kiedy |
|---|---|---|
| świeże wejście | 1x stawki wejściowej | część promptu spoza cache |
| zapis do cache | 1,25x (TTL 5 min) / 2x (TTL 1 h) | pierwszy raz, po zmianie prefiksu, po wygaśnięciu TTL |
| odczyt z cache | 0,1x | identyczny początek, żywy wpis |
| wyjście razem z tokenami rozumowania | stawka wyjściowa (w Claude 5x wejściowej) | zawsze, w całości |
- Zapis zwraca się szybko. Przy TTL 5 minut już drugi request wychodzi na plus (1,25 + 0,1 = 1,35x wobec 2x bez cache); wariant godzinny potrzebuje co najmniej trzech odczytów.
- TTL odświeża się przy każdym trafieniu. Ciągła praca trzyma wpis przy życiu za darmo; przerwa dłuższa niż TTL kasuje go i następny request płaci zapis od nowa.
- Krótkich promptów się nie cache’uje. Po cichu, bez błędu. Próg zależy od modelu: od 1024 tokenów (Sonnet 4.5), przez 2048 (Fable 5, Sonnet 4.6), do 4096 (rodzina Opus, Haiku 4.5).
- Czego cache nie daje: miejsca. Prefiks nadal zajmuje okno kontekstu w całości. Oszczędzasz obliczenia, pieniądze i czas do pierwszego tokenu, nie tokeny w oknie.
Cache to zakład: płacisz 1,25x za zapis, żeby każdy kolejny odczyt kosztował 0,1x. Zakład wygrywa się już przy drugim requeście.
Co unieważnia cache
Prompt renderuje się zawsze w tej samej kolejności i cache czyta od początku do pierwszej zmiany:
Bursztynowe bloki czytają się z cache za 10% stawki, pomarańczowy liczy się świeżo. Granica przesuwa się w lewo do pierwszego zmienionego bajta.
Z tej kolejności wynika cennik typowych wpadek:
| Zmiana | Co zostaje w cache | Co liczysz od nowa |
|---|---|---|
| czysta dograna tura | narzędzia, system, historia | tylko nowa wiadomość (1x) |
| data w prompcie systemowym | narzędzia | system + cała historia (zapis od nowa) |
| zmieniona lista narzędzi | nic | wszystko; najdroższa możliwa zmiana |
| edycja starej tury | narzędzia, system | historia od miejsca zmiany w dół |
| zmiana modelu | nic | wszystko; cache jest per model |
Timestamp w prompcie systemowym wygląda niewinnie, a kosztuje prawie tyle, co zimny start. I to przy każdym requeście.
To samo dotyczy identyfikatorów sesji, losowych wartości i niedeterministycznej serializacji. Jeśli odczyty z cache są zerowe przy pozornie identycznych requestach, szukaj właśnie takiego pasażera na gapę w prefiksie.
Skąd bezstratność: narada Query/Key/Value
Model to stos kilkudziesięciu identycznych warstw. Każdy token wejścia dostaje najpierw wektor startowy (embedding, tani pierwszy krok), a potem ten wektor przechodzi przez warstwę 1, 2 i kolejne, i w każdej jest wzbogacany.
Sercem każdej warstwy jest uwaga, która działa jak narada. Każdy token liczy sobie trzy wektory: Query to jego pytanie do sali (“czego mi brakuje, żeby się doprecyzować”), Key to wizytówka (“o czym jestem”), Value to treść, którą może przekazać dalej. Token porównuje swoje query z kluczami tokenów przed sobą, ocenia dopasowanie i miesza do swojej reprezentacji ich value proporcjonalnie do trafienia. W jednej warstwie “zamek” podciąga informację z pobliskiego “drzwi”, w kolejnej cała fraza już wie, że mowa o mieszkaniu, a w wyższych warstwach reprezentacje robią się coraz bardziej abstrakcyjne: nie litery i gramatyka, tylko fakty, intencje, struktura zadania.
Te policzone wektory Key i Value, dla każdego tokenu w każdej warstwie, to jest dokładnie zawartość cache’a (stąd nazwa KV cache). Gruby koszt czytania bierze się z tego, że w każdej warstwie każdy token ogląda wszystkie przed sobą, więc robota rośnie mniej więcej z kwadratem długości kontekstu. Potoczne “powtarzalne embeddingi” to skrót myślowy: chodzi o wynik całej lektury, nie o pierwszy, najtańszy krok.
Przyczynowość: dlaczego doklejanie niczego nie psuje
Zacznijmy od kierunku, bo o to zdanie łatwo się potknąć: każdy token patrzy wstecz, na to, co już przeczytane, i z tego buduje swoje rozumienie. Tym, czego nie robi nigdy, jest patrzenie w przód. Wstecz tak, w przód nie.
Konkret. Weź zdanie: “Zamek błyskawiczny zaciął się w kurtce”.
- Token “Zamek” (pozycja 1) nie ma nic przed sobą. Jego reprezentacja zostaje wieloznaczna: może budowla, może suwak. I taka już zostanie na zawsze, bo pozycja 1 nigdy nie zobaczy pozycji 2.
- Token “błyskawiczny” (pozycja 2) patrzy wstecz, widzi “Zamek” i buduje u siebie rozumienie “aha, chodzi o suwak”.
- Token “zaciął się” (pozycja 3) patrzy wstecz na oba i wie jeszcze więcej.
Zauważ, co się nie wydarzyło: nikt nie wrócił do pozycji 1, żeby poprawić “Zamek” na “suwak”. Rozumienie całości nie mieszka w pierwszym tokenie, tylko narasta w kolejnych.
Wiedza płynie w modelu jak rzeka: z lewej na prawą, nigdy pod prąd.
Skąd ta zasada? Jedynym zadaniem modelu na treningu było zgadywanie następnego słowa. Gdyby przy nauce mógł podglądać dalszy ciąg tekstu, zadanie byłoby oszustwem (“zgadnij słowo, które właśnie widzisz”), więc architektura ma wbudowaną blokadę, tzw. maskę przyczynową: pozycja N ma fizycznie odcięty dostęp do pozycji N+1 i dalszych. Przy generowaniu to zresztą jedyna możliwość, bo przyszłych tokenów jeszcze nie ma; dopiero powstają.
Stąd bezstratność cache. Skoro reprezentacja tokenu 40 000 zależy wyłącznie od tokenów 1–39 999, to doklejenie czegokolwiek na końcu nie ma prawa jej zmienić w żadnej warstwie. Wynik byłby bit w bit ten sam, gdyby liczyć od zera; dlatego odczyt z cache jest bezstratny, a nie “wystarczająco dobry”.
A co z intuicją, że nowy kontekst reinterpretuje stary? Jest słuszna, tylko ta reinterpretacja nie dzieje się przez poprawianie starych reprezentacji, bo tych nikt nigdy nie aktualizuje wstecz. Dzieje się w nowych tokenach: nowy token sięga swoim query do kluczy i value całej wcześniejszej historii i to on buduje u siebie zrozumienie “aha, tamten zamek to suwak”. Stare stany są biblioteką tylko do odczytu. W analogii narady: dopisanie nowych osób na końcu stołu nie zmienia notatek siedzących bliżej wejścia; nowi mogą te notatki przeczytać i wyciągnąć świeże wnioski, ale cudzych notatek nie poprawiają.
Dobra analogia całości to suma częściowa w długiej kolumnie liczb: po zsumowaniu 80 tysięcy pozycji zapisujesz stan, a gdy ktoś dopisze 500, doliczasz tylko je. Widać z niej też koszt edycji w środku: poprawka na pozycji 50 000 psuje każdy zapisany stan dalej, bo każdy kolejny zawiera w sobie wszystkie wcześniejsze.
I kontrast na dowód, że to nie oczywistość: w modelach dwukierunkowych (typu BERT) uwaga patrzy w obie strony, więc doklejenie tekstu zmieniłoby reprezentacje wcześniejszych tokenów i cache’owanie prefiksu by się posypało. Prompt cache działa, bo modele generatywne czytają jednokierunkowo; to własność wpojona na treningu, nie optymalizacja dokręcona po fakcie.
Najczęstsze wątpliwości
Kontekst za każdym razem jest inny, jak można cokolwiek reużyć? Reużywa się tylko identyczny początek. Dzięki jednokierunkowej uwadze obliczenia dla początku nie zależą od tego, co doklejono później. Nowa końcówka zawsze liczy się świeżo.
Czy cache oszczędza coś na generowaniu odpowiedzi? Nie, ani tokenu. Generowanie biegnie na żywo po pełnej stawce wyjściowej i patrzy na cały kontekst, więc odpowiedź może być inna mimo cache. To cache przeczytanego wejścia, nie odpowiedzi.
Czyli realnie oszczędzamy tylko na embeddingu? Na całym czytaniu wejścia, z którego embedding to najtańszy pierwszy krok; gruby koszt to warstwy uwagi. A “tylko” jest mylące: w pracy agentowej wejście to zdecydowana większość rachunku, bo historia jedzie w całości co request.
Czy doklejenie nowej tury nie zmienia raz policzonego attention? Attention nowych tokenów liczy się świeżo i widzi wszystko. Attention starych się nie zmienia, bo stare tokeny nie patrzą w przód; nowa treść czyta ich stany, ale ich nie przepisuje.
Skoro to takie dobre, czemu rachunki potrafią rosnąć? Rabat działa tylko na stabilnym prefiksie, a zapis kosztuje 1,25 do 2x. Klient, który przepisuje początek promptu w kółko, płaci premium zamiast czytać za 10%. Zmierzyliśmy to na przykładzie Claude Code; liczby są w raporcie w ICS (link niżej).
Co z tym robić na co dzień
- Stabilny początek to pieniądze. Narzędzia, prompt systemowy i CLAUDE.md siedzą z przodu; im chudsze i rzadziej zmieniane, tym więcej requestów czyta je za 10%. Praktyczne nawyki opisuje Claude Code — jak przestać palić tokeny w kontekście, a higienę pliku instrukcji CLAUDE.md i workflow.
- Zmienne rzeczy na koniec. Daty i identyfikatory za ostatnim punktem cache’owania, nie w prompcie systemowym.
- Nie zostawiaj wątku na dłużej niż TTL i nie przełączaj modelu ani konfiguracji w środku zadania bez powodu.
- Po API: punkty cache ustawia
cache_control(maks 4 na request), trafienia widać wusage.cache_read_input_tokens. Zera przy pozornie identycznych requestach oznaczają coś niedeterministycznego w prefiksie.
Pełny raport z pomiarami (ile tokenów wysyła Claude Code zanim przeczyta prompt, ile kosztują subagenci i przepisywanie prefiksu) jest w ICS: Claude Code na diecie tokenowej. Wersja interaktywna tego artykułu, z symulatorami do klikania: Prompt cache od środka w ICS.
Źródła: dokumentacja prompt cachingu Anthropic (stawki, progi, TTL, kolejność renderowania; stan lipiec 2026) oraz Attention Is All You Need (architektura transformera). Uproszczenia świadome: pomijamy pozycyjne osadzenia, multi-head attention i warstwy feed-forward; nie zmieniają wniosków.