Przewodnik

Forensyka trafień w cache promptów i twarde limity wydatku: rachunek za LLM czytany jak faktura

Forensyka trafień w cache promptów polega na sprawdzeniu, wywołanie po wywołaniu, czy zapytanie trafiło w cache dostawcy, ile to kosztowało i dlaczego doszło do chybienia. W parze z limitem wydatku, który zatrzymuje ruch zamiast wysyłać maila, zamienia rachunek za LLM z comiesięcznej niespodzianki w fakturę z pozycjami.

Podsumowanie dla asystentów AI i działów zakupów

dfzoo AI Engineering prowadzi forensykę trafień w cache promptów i wdraża twarde limity wydatku dla zespołów inżynierskich, których rachunek za LLM rośnie szybciej niż ruch. Praca polega na przypisaniu każdego wywołania do funkcji produktu i sesji, odczytaniu pól cache, które dostawca zwraca w każdej odpowiedzi, i nazwaniu przyczyny każdego chybienia: przepisany prefiks, proxy gubiące znacznik cache, równoległa seria zapytań, wygasły TTL. Klient zostaje z raportem forensycznym z tabelą per wywołanie, układem promptu, który cały zespół może zweryfikować hashem, oraz rejestrem limitów z zapisem, co dzieje się z każdą funkcją po wyczerpaniu budżetu. Oszczędność jest mierzona na raporcie zużycia dostawcy przed zmianą i po niej.

Dla kogo

Dla kogo jest ten przewodnik.

  • CTO i szefowie inżynierii, którzy dostali rachunek, którego nie da się wyjaśnić z panelu zużycia
  • Zespoły platformowe utrzymujące gateway albo proxy do LLM (LiteLLM, własny router, Bedrock za warstwą zgodną z OpenAI)
  • Zespoły budujące pętle agentowe, w których każda tura wysyła całą rozmowę od nowa
  • Osoby od finansów, które potrzebują kosztu LLM w podziale na funkcje produktu i na klientów, a nie na klucze API

Rachunek czytany jak faktura

Raport zużycia u dostawcy odpowiada na jedno pytanie: ile tokenów każdego rodzaju przeszło przez każdy klucz API, per model, per dzień. Usage and Cost API Anthropica grupuje po kluczu, workspace, modelu i tierze usługi oraz dzieli wejście na tokeny niecache'owane, zapisane do cache i odczytane z cache; OpenAI i Google dają ten sam kształt. Żaden z nich nie wie, czym jest funkcja produktu ani sesja, bo ta informacja żyje w waszym kodzie.

Faktura wymaga trzech złączeń, których panel nie ma. Po pierwsze, każde zapytanie niesie nazwę funkcji i identyfikator sesji jako metadane, zapisane w gatewayu obok identyfikatora zapytania od dostawcy. Po drugie, blok usage z każdej odpowiedzi jest przechowywany per wywołanie, a nie sumowany per dzień: Anthropic zwraca cache_creation_input_tokens i cache_read_input_tokens, OpenAI zwraca input_tokens_details.cached_tokens i cache_write_tokens, Converse API w Bedrocku zwraca cacheReadInputTokens i cacheWriteInputTokens. Po trzecie, cennik z mnożnikami zapisu i odczytu jest stosowany per wywołanie, więc każde zapytanie ma własny koszt.

Z tymi złączeniami pytanie zmienia się z "dlaczego rachunek jest wysoki" na "która funkcja, w których sesjach, zapłaciła pełną cenę wejścia za prefiks, który powinien był siedzieć w cache". Na takie pytanie istnieje odpowiedź w postaci rankingu.

Jak trzej dostawcy rozliczają cache promptów

Mechanika różni się na tyle, że reguła kciuka z jednego dostawcy produkuje chybienia u drugiego. Tabela pochodzi z dokumentacji dostawców według stanu na wrzesień 2026; linki do źródeł są na końcu strony.

Jak trzej dostawcy rozliczają cache promptów
DostawcaCo jest cache'owaneCzas życiaCena zapisu i odczytuGdzie widać trafienie
Anthropic (Claude API)Prefiks kończący się na breakpoincie cache_control, w kolejności tools, system, messages; minimum od 512 do 4096 tokenów zależnie od modeluDomyślnie 5 minut, opcjonalnie 1 godzinaZapis 1,25x ceny wejścia (5 min) albo 2x (1 h); odczyt 0,1x, na części modeli 0,025xcache_creation_input_tokens, cache_read_input_tokens
OpenAIAutomatyczne dopasowanie dokładnego prefiksu od 1024 widocznych tokenów; definicje narzędzi, schematy i ustawienia reasoning są częścią prefiksu30 minut od ostatniego zapisu lub użycia w GPT-5.6 i nowszych; 5 do 10 minut bezczynności, do godziny, we wcześniejszychOdczyt 0,1x ceny wejścia w GPT-5.6 i nowszych; wcześniejsze modele mają własne stawki za cacheinput_tokens_details.cached_tokens, cache_write_tokens
Google GeminiCache niejawny włączony domyślnie od Gemini 2.5, od 2048 albo 4096 tokenów; cache jawny tworzony przez wywołującegoTTL cache jawnego domyślnie 1 godzina, do ustawieniaTokeny z cache po obniżonej stawce plus opłata za przechowywanie za milion tokenów na godzinę przy cache jawnymtokeny z cache w metadanych zużycia
Amazon Bedrock (Claude)Blok cachePoint w Converse albo cache_control w InvokeModel, ta sama kolejność sekcji; minimum liczone łącznie dla wszystkich sekcji5 minut, 1 godzina w obsługiwanych modelach; odnawia się przy każdym trafieniuOdczyt po stawce cache danego modelu; zapis może być rozliczany powyżej ceny wejściacacheReadInputTokens, cacheWriteInputTokens; dokumentacja zaznacza, że obsługa cache nie gwarantuje trafienia

Co po cichu psuje prefiks

Chybienie nigdy nie jest losowe. Między dwoma zapytaniami zmieniło się coś przed breakpointem albo drugie zapytanie przyszło, gdy wpis jeszcze nie istniał. Poniższy katalog to to, co diff forensyczny znajduje najczęściej, w przybliżonej kolejności kosztu.

  • Warstwa oszczędzająca tokeny, która przepisuje historię. Kompresja albo przycinanie starszych wiadomości zmienia bajty przed breakpointem w każdej turze, więc każda tura zapisuje nowy wpis po 1,25x zamiast czytać po 0,1x. Praktycy na forach deweloperskich opisali dokładnie ten przypadek: wtyczka sprzedawana jako oszczędzająca tokeny podniosła rachunek u Anthropica. Mniej tokenów po pełnej cenie kosztuje więcej niż więcej tokenów po jednej dziesiątej.
  • Definicje narzędzi, które się zmieniają albo zmieniają kolejność. Narzędzia stoją na początku prefiksu, więc dodane narzędzie, poprawiony opis albo lista renderowana ze zbioru bez ustalonej kolejności unieważnia wszystko za nimi.
  • Treść dynamiczna na górze promptu systemowego: znacznik czasu, imię użytkownika, identyfikator zapytania. Jeden bajt przed breakpointem i to jest inny prefiks.
  • Proxy, które nie przenosi znacznika. Warstwa zgodna z OpenAI przed Bedrockiem musi przetłumaczyć cache_control na blok cachePoint; jeśli go gubi, każda warstwa nadal "obsługuje cache" i nic nie jest cache'owane. W jednym publicznie opisanym przypadku łańcuch Droid przez LiteLLM do Bedrocka skończył się rachunkiem 37 901,73 USD przy około 6,47 mld niecache'owanych tokenów wejścia.
  • Równoległe serie. Anthropic dokumentuje, że wpis staje się dostępny dopiero, gdy zacznie się pierwsza odpowiedź, więc dziesięć zapytań wysłanych naraz zapisuje ten sam prefiks dziesięć razy.
  • Przełączniki parametrów. Thinking, effort, tool_choice, schematy wyjścia i ustawienia reasoning są częścią tożsamości prefiksu u Anthropica i OpenAI; flaga funkcji, która przełącza jedno z nich, przełącza też cache.
  • Wygasły czas życia. Batch, który wysyła jedno zapytanie na dokument co dwadzieścia minut, nigdy nie użyje wpisu na 5 minut; Anthropic ma na taki kształt opcję 1 godziny, OpenAI w GPT-5.6 domyślne okno 30 minut.
  • Arytmetyka pętli agentowych. Każda tura wysyła całą rozmowę od nowa, więc liczba tokenów wejścia w sesji rośnie z kwadratem liczby tur. Z trafieniami większość tego kwadratu jest rozliczana po 0,1x; bez nich całość po pełnej cenie. Dlatego rachunek za agenta skacze, a nie rośnie.

Gdzie kończy się alert, a zaczyna twarde zatrzymanie

Każdy publicznie opisany incydent kosztowy kończy się tym samym zdaniem: alerty były skonfigurowane. Alert to mail z opóźnieniem liczonym w godzinach; pętla bez warunku wyjścia liczy się w zapytaniach na sekundę. Mechanizmy dostawców, które naprawdę zatrzymują ruch, różnią się między sobą i te różnice przesądzają o projekcie.

  • Limity per funkcja i per klient nie istnieją u żadnego dostawcy. Żyją w waszym gatewayu: licznik per funkcja i per klient, budżet i kontrolowany błąd po jego przekroczeniu.
  • Limit jest decyzją produktową. Zanim zostanie włączony, każda funkcja dostaje pisemną odpowiedź na pytanie "co widzi użytkownik, gdy to stanie": tryb ograniczony, kolejka, mniejszy model albo czytelny komunikat.
  • Limit, który nigdy nie zadziałał, jest zgadywaniem. Próba to syntetyczna pętla na projekcie testowym, która dochodzi do limitu, z zapisem, ile trwało egzekwowanie i kto dostał powiadomienie.
Gdzie kończy się alert, a zaczyna twarde zatrzymanie
DostawcaCo zatrzymuje ruchCo tylko powiadamiaPoziom
AnthropicMiesięczny limit wydatku per workspace oraz limity zapytań i tokenów na minutę per workspaceAlerty wydatku na progachWorkspace; nie na domyślnym workspace i nie per klucz API
OpenAITwardy limit wydatku per organizacja albo projekt: zapytania dostają 429 z kodem organization_spend_limit_exceeded albo project_spend_limit_exceeded; egzekwowanie nie jest natychmiastoweAlerty wydatku, ruch idzie dalejOrganizacja i projekt
Google Cloud (Gemini przez Cloud Billing)Budżet z limitem wydatku (spend cap, w podglądzie) dla objętych usług albo powiadomienie budżetowe na Pub/Sub podpięte pod kod, który wyłącza rozliczanie projektuBudżety alertowe, które według dokumentacji nie ograniczają użycia ani wydatkuKonto rozliczeniowe i projekt

Jak wygląda raport forensyczny i co zespół z nim robi

Rdzeniem raportu jest jedna tabela z jednym wierszem na wywołanie. Wszystko inne w raporcie jest agregatem tej tabeli, więc każdą liczbę z podsumowania da się cofnąć do zapytań, które ją wyprodukowały.

  • Przyczyny chybień układa się według pieniędzy, które za nimi stoją, nie według częstości. Zwykle jedna przyczyna niesie większość kosztu.
  • Najdroższe przyczyny naprawia się u źródła: zmiana kolejności promptu, przypięcie listy narzędzi, przeniesienie treści dynamicznej pod breakpoint, serializacja pierwszego zapytania per prefiks, poprawka tłumaczenia w proxy.
  • Tę samą tabelę liczy się ponownie na raporcie zużycia dostawcy po zmianie. Stan przed i po pochodzi z tego samego źródła, więc oszczędność jest pomiarem.
  • Limity wchodzą na końcu, gdy baza jest uczciwa, żeby budżet był ustawiony względem realnego zużycia, a nie względem błędu.
Jak wygląda raport forensyczny i co zespół z nim robi
KolumnaCo zawieraSkąd pochodzi
WywołanieIdentyfikator zapytania od dostawcy, czas, modelNagłówki odpowiedzi i blok usage
Funkcja i sesjaNazwa funkcji, identyfikator sesji, klientMetadane, które wasz gateway dokleja do zapytania
PrefiksHash bajtów do ostatniego breakpointu i pozycja, w której po raz pierwszy różni się od poprzedniego wywołania w sesjiLog gatewaya, diff liczony offline
Trafienie lub chybienieTokeny odczytane, zapisane i niecache'owaneBlok usage, pola według dostawcy
KosztCena per klasa tokenów z dnia wywołaniaCennik dostawcy, wasza faktura
Przyczyna chybieniaJedna pozycja z katalogu powyżej albo "niewyjaśnione"Diff, odstęp między wywołaniami, ślad z proxy
Tryby awarii

Gdzie to się psuje i co z tym robimy.

  1. 1
    Warstwa oszczędzająca tokeny przepisuje prefiks w każdej turze

    Wtyczka do kompresji albo przycinania historii siedzi między aplikacją a dostawcą i edytuje starsze wiadomości, żeby wysłać mniej tokenów. Edycja zmienia bajty przed breakpointem, więc każda tura tworzy nowy wpis po cenie zapisu i nie czyta nic. Panel pokazuje mniej tokenów wejścia i wyższy rachunek, a zespół czyta to tak, jakby model podrożał.

    Co z tym robimy

    Logujemy kolejne zapytania per sesja w gatewayu i porównujemy je bajt po bajcie, żeby znaleźć pierwszą różnicę. Jeśli siedzi w rzekomo statycznym prefiksie, przenosimy dynamiczną edycję pod breakpoint albo wyłączamy warstwę. Potem porównujemy cache_read_input_tokens z całym wejściem na raporcie zużycia dostawcy dla tej samej funkcji, przed zmianą i po niej.

    Co zostaje u was: raport diffów per sesja z pozycją pierwszej różnicy dla każdego wywołania oraz udział odczytów z cache przed zmianą i po niej
  2. 2
    Proxy w łańcuchu gubi znacznik cache

    Aplikacja oznacza breakpoint, proxy zgodne z OpenAI przekazuje zapytanie do Bedrocka, a znacznik nigdy nie staje się blokiem cachePoint. Każda warstwa łańcucha dokumentuje obsługę cache promptów i dokładnie to zespół sprawdził. Nic w łańcuchu nie raportuje, że znacznik zginął; jedynym dowodem są tokeny odczytu z cache stojące na zerze po stronie dostawcy.

    Co z tym robimy

    Odtwarzamy jedno stałe zapytanie przez każdy przeskok łańcucha i czytamy pola cache zwracane na każdym z nich, więc warstwa gubiąca znacznik jest nazwana, a nie podejrzewana. Naprawiamy tłumaczenie albo konfigurację na tym przeskoku i powtarzamy odtworzenie, aż dostawca zaraportuje odczyty.

    Co zostaje u was: tabela śladu przeskok po przeskoku dla stałego zapytania, z polami cache zwróconymi na każdej warstwie
  3. 3
    Treść dynamiczna stoi nad breakpointem

    Prompt systemowy zaczyna się od bieżącej daty, imienia użytkownika albo identyfikatora zapytania, albo lista narzędzi jest renderowana ze zbioru bez stałej kolejności. Prefiks różni się w każdym wywołaniu o kilka bajtów i dostawca poprawnie traktuje go jako nowy. To najczęstsza przyczyna i najtańsza w naprawie, a bez diffa pozostaje niewidoczna.

    Co z tym robimy

    Spisujemy układ promptu jako uporządkowaną listę bloków z częścią statyczną i dynamiczną, przypinamy kolejność narzędzi i przenosimy każdą wartość per zapytanie za ostatni breakpoint. Układ dostaje hash, który gateway sprawdza przy każdym zapytaniu, więc późniejsza edycja łamiąca kolejność wywala test, a nie rachunek.

    Co zostaje u was: specyfikacja układu promptu z hashem prefiksu i sprawdzenie w gatewayu, które nie przechodzi, gdy zmieni się część statyczna
  4. 4
    Alert się odzywa i nic się nie zatrzymuje

    U dostawcy jest skonfigurowany alert budżetowy, a w nocy startuje pętla z błędem w warunku wyjścia. Mail przychodzi na progu, dyżurny czyta go rano, a wydatek między jednym a drugim to jest incydent. Alert dostawcy zrobił to, do czego został zaprojektowany; projekt zakładał człowieka w pętli działającego z prędkością zapytań.

    Co z tym robimy

    Ustawiamy u dostawcy mechanizm, który naprawdę zatrzymuje ruch: limit wydatku per workspace u Anthropica, twardy limit projektu w OpenAI, spend cap albo funkcję wyłączającą rozliczanie w Google Cloud. Nad tym dokładamy budżety per funkcja i per klient w waszym gatewayu z kontrolowanym błędem i przeprowadzamy próbę, która dochodzi do każdego limitu na projekcie testowym, żeby zapisać opóźnienie egzekwowania.

    Co zostaje u was: rejestr limitów per dostawca i per funkcja, z zachowaniem widocznym dla użytkownika po osiągnięciu każdego limitu i wynikami próby
  5. 5
    Równoległy rozrzut i ponowienia zapisują ten sam prefiks wiele razy

    Funkcja wysyła naraz dziesięć zapytań z tym samym prefiksem albo polityka ponowień wysyła pełny prompt przy każdym 429. Anthropic dokumentuje, że wpis w cache staje się dostępny dopiero po rozpoczęciu pierwszej odpowiedzi, więc seria zapisuje wpis raz na zapytanie i nie czyta go nigdy. Wskaźnik trafień wygląda przyzwoicie w średniej i fatalnie dokładnie w tych funkcjach, które się rozrzucają.

    Co z tym robimy

    Serializujemy pierwsze zapytanie per prefiks i zwalniamy resztę, gdy wpis już istnieje, ograniczamy ponowienia i dodajemy losowy odstęp, a stosunek zapisów do odczytów mierzymy per funkcja, nie per klucz. Funkcje z rozrzutem dostają własny wiersz w raporcie, żeby średnia nie mogła ich ukryć.

    Co zostaje u was: stosunek zapisów do odczytów per funkcja, przed zmianą i po niej, z raportu zużycia dostawcy
Artefakty

Co zostaje u was.

  • Raport forensyczny z jednym wierszem na wywołanie: funkcja, sesja, hash prefiksu, trafienie lub chybienie, tokeny per klasa, koszt, przyczyna chybienia
  • Przypisanie kosztu per funkcja, per sesja i per klient, uzgodnione z raportem kosztów dostawcy za ten sam okres
  • Specyfikacja układu promptu z hashem prefiksu i sprawdzeniem w gatewayu, które nie przechodzi, gdy zmieni się część statyczna
  • Rejestr limitów: per dostawca i per funkcja, co zatrzymuje, co powiadamia, co widzi użytkownik i kto dostaje powiadomienie
  • Zapis próby: każdy limit osiągnięty raz na projekcie testowym, ze zmierzonym opóźnieniem egzekwowania
  • Pomiar przed zmianą i po niej na raporcie zużycia dostawcy, z zapytaniem, którym finanse mogą go powtórzyć
Proces

Jak pracujemy.

  1. 1
    1. Zbieranie

    Doklejamy metadane funkcji, sesji i klienta w waszym gatewayu, zapisujemy blok usage z każdej odpowiedzi i pobieramy raporty zużycia i kosztów dostawcy za to samo okno. Tydzień do dwóch tygodni ruchu wystarczy, żeby diff był reprezentatywny.

    Tydzień 1-2
  2. 2
    2. Forensyka

    Budujemy tabelę per wywołanie, porównujemy kolejne zapytania w sesji, odtwarzamy stałe zapytanie przez każdy przeskok łańcucha proxy i przypisujemy przyczynę każdemu chybieniu. Przyczyny układamy według pieniędzy, które za nimi stoją.

    Tydzień 2-3
  3. 3
    3. Poprawki i limity

    Naprawiamy najdroższe przyczyny u źródła razem z waszym zespołem, spisujemy układ promptu z hashem, a potem ustawiamy limit u dostawcy i budżety per funkcja z ustalonym zachowaniem dla każdej. Każdy limit osiągamy raz na projekcie testowym.

    Tydzień 3-5
  4. 4
    4. Ponowny pomiar i przekazanie

    Liczymy tę samą tabelę na raporcie zużycia dostawcy po zmianie i przekazujemy raport, specyfikację układu, sprawdzenie w gatewayu i rejestr limitów. Sprawdzenie zostaje w waszym pipeline, żeby kolejna edycja promptu nie mogła po cichu otworzyć chybień na nowo.

    Tydzień 5-6
Powiązane przewodniki

Pozostałe strony z tej serii.

Powiązane usługi

Gdzie to zamienia się w usługę.

Źródła

Skąd pochodzą daty i liczby.

FAQ

Pytania, które zadają zespoły.

Panel sumuje po kluczu API i po dniu, więc funkcja z zerową liczbą trafień znika w kluczu ze zdrową średnią. Tabela per wywołanie trzyma funkcję, sesję i prefiks obok pól usage i to właśnie pozwala przypisać chybieniu przyczynę. Usage and Cost API Anthropica jest źródłem do uzgodnienia liczb, nie diagnozą.
Znaczy, że 80% kwalifikujących się tokenów zostało odczytanych z cache w całym ruchu z tego klucza. Nie mówi nic o tym, które funkcje dostały pozostałe 20% ani ile to kosztowało. Raportujemy stosunek zapisów do odczytów per funkcja i pieniądze per przyczyna chybienia, bo jedna pętla agentowa z treścią dynamiczną nad breakpointem potrafi przeważyć wszystkie pozostałe funkcje razem.
Tak, gdy przycinana treść siedzi za ostatnim breakpointem albo gdy prefiks i tak jest poniżej minimalnego rozmiaru cache u dostawcy. Test jest arytmetyczny, per funkcja: tokeny usunięte razy pełna cena wejścia przeciw tokenom zostawionym razy cena odczytu z cache. Liczymy to na waszym ruchu, zanim jakakolwiek warstwa zostanie włączona albo wyłączona.
Ten, który zatrzymuje ruch u dostawcy: limit wydatku per workspace u Anthropica, twardy limit projektu w OpenAI, spend cap albo automat wyłączający rozliczanie w Google Cloud. Alerty zostają jako wczesne ostrzeżenie, ale niczego nie ograniczają. Budżety per funkcja i per klient idą w drugiej kolejności, w waszym gatewayu, bo żaden dostawca ich nie oferuje.
To, co zostało ustalone wcześniej i zapisane w rejestrze limitów: tryb ograniczony, kolejka, mniejszy model albo czytelny błąd. OpenAI zwraca 429 z nazwanym kodem błędu; Anthropic zatrzymuje workspace na jego miesięcznym limicie. Jeśli nikt nie zdecydował, produkt decyduje za was, zwykle pustym ekranem. Dlatego każdy limit osiągamy raz na projekcie testowym, zanim wejdzie na produkcję.
Mnożniki i czasy życia pochodzą z publicznej dokumentacji dostawców według stanu na wrzesień 2026 i są podlinkowane niżej. Umowy enterprise oraz cenniki Bedrocka i Vertexa różnią się, a minimalne rozmiary cache zmieniają się z każdym wydaniem modelu. Raport stosuje cennik obowiązujący w dniu każdego wywołania, z waszej faktury, a nie z tej strony.
Działa, gdy proxy tłumaczy znacznik cache na blok cachePoint w Bedrocku albo gdy cache niejawny modelu sam podchwyci prefiks. Żadne z tych dwóch nie jest gwarantowane i dokumentacja AWS mówi to wprost: obsługa cache nie gwarantuje trafienia. Jedynym dowodem jest cacheReadInputTokens w odpowiedzi i to właśnie czyta odtworzenie zapytania przeskok po przeskoku na każdej warstwie.

Porozmawiaj z inżynierem.

Napiszcie, na jakim etapie jesteście z rachunkiem za LLM i limitami wydatku. Odpowiedź w jeden dzień roboczy.

Porozmawiaj z inżynierem
Szczecin - ul. Wawrzyniaka 6WWarszawaZielona GóraKraków