Analiza kosztów LLM: trafienia w cache promptów i twarde limity wydatku
Analiza przypisuje koszty LLM do funkcji i sesji, wskazuje wywołania bez odczytu z cache i sprawdza przyczyny dodatkowych kosztów, a limity blokują kolejne wywołania po wyczerpaniu budżetu. Cache promptów to mechanizm dostawcy, który zapisuje niezmienny początek żądania (prefiks) i przy kolejnych żądaniach rozlicza go taniej; znacznik cache wskazuje, gdzie prefiks się kończy. Analizę czyta się wywołanie po wywołaniu: trafienie albo chybienie, koszt, przyczyna chybienia.
23Minds prowadzi analizę trafień w cache promptów i instaluje twarde limity wydatku dla zespołów inżynierskich, których rachunek za LLM rośnie szybciej niż ruch. Praca przypisuje każde wywołanie do funkcji i sesji, odczytuje pola cache zwracane przez dostawcę w każdej odpowiedzi i wskazuje potwierdzone przyczyny chybień, oddzielając przypadki do dalszych testów: przepisany prefiks, proxy gubiące znacznik cache, seria równoległych żądań, wygasły czas życia wpisu. Klient zatrzymuje raport z tabelą dla każdego wywołania, układ prefiksu, który cały zespół może sprawdzić skrótem, oraz rejestr limitów mówiący, co dzieje się z każdą funkcją po wyczerpaniu jej budżetu. Oszczędność mierzy się na raporcie użycia dostawcy przed poprawkami i po nich, przy porównywalnym obciążeniu.
Kto skorzysta z tego przewodnika.
- CTO i wiceprezesi ds. inżynierii, którzy dostali rachunek, którego nie umieli wyjaśnić z panelu użycia
- Zespoły platformowe prowadzące bramę albo proxy do LLM (LiteLLM, własny router, Bedrock za warstwą zgodną z OpenAI)
- Zespoły wdrażające pętle agentów, w których każda tura wysyła ponownie całą rozmowę
- Partnerzy z działu finansów, którzy potrzebują kosztu LLM w podziale na funkcje produktu i na klientów, a nie na klucze API
Rachunek czytany jak faktura
Raport użycia dostawcy odpowiada na jedno pytanie: ile tokenów każdego rodzaju przeszło przez każdy klucz API, na model, na dzień. Usage and Cost API Anthropic grupuje po kluczu API, workspace, modelu i poziomie usługi oraz dzieli wejście na tokeny bez cache, zapis do cache i odczyt z cache; Usage API OpenAI i Cloud Billing Google dają podobny podział, z własnymi polami i zasadami rozliczeń. Żaden z nich nie wie, czym jest funkcja ani sesja, bo ta informacja żyje w waszym kodzie.
Faktura potrzebuje trzech złączeń, których panel nie ma. Po pierwsze, każde żądanie niesie nazwę funkcji, identyfikator sesji i klienta (tenant) jako metadane, logowane w bramie obok identyfikatora żądania od dostawcy. Po drugie, blok usage z każdej odpowiedzi jest zapisywany dla każdego wywołania, a nie sumowany na 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 za zapis i odczyt jest stosowany do każdego wywołania, więc każde żądanie 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ł być w cache. Na takie pytanie istnieje odpowiedź w postaci rankingu.
Jak trzej dostawcy rozliczają pamięć podręczną promptów
Mechanika różni się na tyle, że ogólna zasada od jednego dostawcy daje chybienia u drugiego. Tabela poniżej pochodzi z dokumentacji dostawców sprawdzonej we wrześniu 2026; odnośniki do źródeł, po jednym na dostawcę, są na końcu strony.
| Dostawca | Co jest buforowane | Czas życia | Cena zapisu i odczytu | Gdzie widać trafienie |
|---|---|---|---|---|
| Anthropic (Claude API) | Prefiks kończący się na punkcie cache_control, w kolejności: narzędzia, system, wiadomości; minimum od 512 do 4 096 tokenów zależnie od modelu | 5 minut domyślnie, 1 godzina opcjonalnie | Zapis 1,25x ceny wejścia (5 min) albo 2x (1 godzina); odczyt 0,1x, w niektórych modelach 0,025x | cache_creation_input_tokens, cache_read_input_tokens |
| OpenAI | Automatyczne dopasowanie dokładnego prefiksu od 1 024 widocznych tokenów; definicje narzędzi, schematy i ustawienia rozumowania są częścią prefiksu | 30 minut od ostatniego zapisu albo użycia w GPT-5.6 i nowszych; 5-10 minut bezczynności, do godziny, we wcześniejszych modelach | Odczyt 0,1x ceny wejścia bez cache w GPT-5.6 i nowszych; wcześniej stawki zależne od modelu | input_tokens_details.cached_tokens, cache_write_tokens |
| Google Gemini | Cache niejawny włączony domyślnie w Gemini 2.5 i nowszych, od 2 048 albo 4 096 tokenów; cache jawny tworzony przez wywołującego | Domyślny czas życia cache jawnego 1 godzina, konfigurowalny | Tokeny z cache po obniżonej stawce plus cena przechowywania za milion tokenów na godzinę dla cache jawnego | tokeny z cache w metadanych użycia |
| Amazon Bedrock (Claude) | Blok cachePoint w Converse albo cache_control w InvokeModel, ta sama kolejność sekcji; minimum liczy wszystkie sekcje razem | 5 minut, 1 godzina w obsługiwanych modelach; odnawia się przy każdym trafieniu | Odczyt po stawce cache danego modelu; zapis może być rozliczany powyżej ceny wejścia | cacheReadInputTokens, cacheWriteInputTokens; dokumentacja mówi, że obsługa nie gwarantuje trafienia |
Co po cichu psuje prefiks
Analiza sprawdza trzy rzeczy: zmiany prefiksu między żądaniami, wygaśnięcie wpisu i moment wysłania żądań; nie zawsze pozwala ustalić przyczynę, bo dostawcy nie gwarantują trafienia. Katalog poniżej to przyczyny, które diff w analizie potrafi potwierdzić.
- Warstwa oszczędzająca tokeny, która przepisuje historię. Kompresja albo przycinanie starszych wiadomości zmienia bajty przed punktem podziału w każdej turze, więc każda tura zapisuje nowy wpis po 1,25x zamiast czytać po 0,1x. Praktycy na forach programistów opisali dokładnie to: wtyczka sprzedawana jako oszczędzająca tokeny podniosła rachunek w Anthropic. 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 leżą na początku prefiksu, więc dodane narzędzie, zmieniony opis albo lista renderowana z nieuporządkowanego zbioru unieważnia wszystko za sobą.
- Dynamiczna treść na górze promptu systemowego: znacznik czasu, nazwa użytkownika, identyfikator żądania. Jeden bajt przed punktem podziału i to już 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 deklaruje obsługę cache, a nic nie jest buforowane. Jeden publicznie opisany przypadek: Droid przez LiteLLM do Bedrocka, koniec na 37 901,73 USD i około 6,47 mld tokenów wejścia bez cache.
- Serie równoległych żądań. Anthropic dokumentuje, że wpis staje się dostępny dopiero po rozpoczęciu pierwszej odpowiedzi, więc żądania wysłane naraz mogą zwiększyć liczbę płatnych zapisów tego samego prefiksu; analiza sprawdza to w danych użycia.
- Przełączniki parametrów. Parametry extended thinking i effort, tool_choice, schematy wyjścia i ustawienia rozumowania są częścią tożsamości prefiksu w Anthropic i OpenAI; flaga funkcji, która przełącza jeden z nich, przełącza cache.
- Wygasły czas życia. Zadanie wsadowe, które wysyła jedno żądanie na dokument co dwadzieścia minut, nigdy nie użyje ponownie wpisu pięciominutowego; Anthropic oferuje na taki kształt opcję godzinną, a domyślne okno OpenAI w GPT-5.6 to 30 minut.
- Arytmetyka pętli agentów. Przy przesyłaniu pełnej historii i podobnej długości kolejnych tur łączna liczba tokenów wejścia w sesji rośnie w przybliżeniu kwadratowo z liczbą tur. Z trafieniami większość tych tokenów jest rozliczana po 0,1x; bez nich całość po pełnej cenie.
Gdzie kończy się alert, a zaczyna twardy stop
Alert to e-mail z opóźnieniem liczonym w godzinach; rozpędzona pętla liczy się w żądaniach na sekundę. Kontrole u dostawców, które naprawdę zatrzymują ruch, różnią się między sobą, a te różnice decydują o projekcie.
- Limity na funkcję i na klienta nie istnieją u żadnego dostawcy. Żyją w waszej bramie: licznik na funkcję i na klienta, budżet i kontrolowany błąd po jego osiągnięciu.
- Limit to decyzja produktowa. Zanim zostanie włączony, każda funkcja dostaje spisaną odpowiedź na pytanie, co widzi użytkownik, gdy to się zatrzyma. Po wyczerpaniu budżetu funkcji w bramie: tryb ograniczony, kolejka albo mniejszy model. Po blokadzie u dostawcy: czytelny komunikat, bo wtedy tańszy model też nie odpowie.
- Limit, który nigdy nie zadziałał, jest domysłem. Próba to syntetyczna pętla na projekcie testowym, która dochodzi do limitu, z zapisem, ile trwało egzekwowanie i kto został wezwany.
| Dostawca | Co zatrzymuje ruch | Co tylko powiadamia | Zakres limitu |
|---|---|---|---|
| Anthropic | Miesięczny limit wydatku na workspace oraz limity zapytań i tokenów na minutę na workspace | Alerty wydatku przy progach | Workspace; nie na domyślnym workspace, nie na klucz API |
| OpenAI | Twardy limit wydatku na organizację albo projekt: żądania zwracają 429 z organization_spend_limit_exceeded albo project_spend_limit_exceeded; egzekwowanie nie jest natychmiastowe, więc koszt może przekroczyć próg do czasu blokady | Alerty wydatku, ruch trwa dalej | Organizacja i projekt |
| Google Cloud (Gemini przez Cloud Billing) | Budżet z limitem wydatku (podgląd) dla kwalifikujących się usług albo powiadomienie budżetowe przez Pub/Sub podpięte pod kod, który wyłącza rozliczanie projektu | Budżety tylko alertowe, które według dokumentacji nie ograniczają użycia ani wydatku | Konto rozliczeniowe i projekt |
Jak wygląda raport z analizy 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ę ze streszczenia da się prześledzić do żądań, które ją wytworzyły.
- Przyczyny chybień szeregujcie według pieniędzy, które za nimi stoją, a nie według częstości. Ranking pokazuje, ile kosztu niesie każda przyczyna.
- Najdroższe przyczyny naprawiajcie u źródła: zmieńcie kolejność promptu, przypnijcie listę narzędzi, przenieście dynamiczną treść pod punkt podziału, wysyłajcie pierwsze żądanie na prefiks pojedynczo, naprawcie tłumaczenie w proxy.
- Po zmianie uruchomcie tę samą tabelę na raporcie użycia dostawcy jeszcze raz przy porównywalnym obciążeniu i zapiszcie warunki pomiaru: ruch, modele, ceny, długość odpowiedzi. Stan przed i po pochodzi wtedy z tego samego źródła.
- Limit awaryjny u dostawcy ustawcie przed analizą, a budżety funkcji dopasujcie po pomiarze, żeby były ustawione wobec prawdziwego zużycia, a nie wobec błędu.
| Kolumna | Co zawiera | Skąd pochodzi |
|---|---|---|
| Wywołanie | Identyfikator żądania od dostawcy, znacznik czasu, model | Nagłówki odpowiedzi i blok usage |
| Funkcja i sesja | Nazwa funkcji, identyfikator sesji, klient | Metadane, które wasza brama dołącza do żądania |
| Prefiks | Skrót bajtów do ostatniego punktu podziału i pozycja, na której po raz pierwszy różni się od poprzedniego wywołania w sesji | Log bramy, porównany offline |
| Trafienie albo chybienie | Tokeny odczytane, zapisane i bez cache | Blok usage, według nazw pól dostawcy |
| Koszt | Cena za klasę tokenów w dniu wywołania | Cennik dostawcy, wasza faktura |
| Przyczyna chybienia | Jedna pozycja z katalogu powyżej albo: niewyjaśnione | Diff, odstęp między wywołaniami, ślad z proxy |
Co może pójść nie tak i co z tym robimy.
- 1Warstwa oszczędzająca tokeny przepisuje prefiks w każdej turze
Wtyczka kompresująca albo przycinająca historię siedzi między aplikacją a dostawcą i edytuje starsze wiadomości, żeby wysłać mniej tokenów. Edycja zmienia bajty przed punktem podziału cache, więc każda tura tworzy nowy wpis po cenie zapisu i nic nie czyta. Panel pokazuje mniej tokenów wejścia i wyższy rachunek, a zespół czyta to jako model, który zdrożał.
Co z tym robimyLogujemy kolejne żądania z sesji w bramie i porównujemy je bajt po bajcie, żeby znaleźć pierwszą rozbieżność. Tam, gdzie leży ona wewnątrz rzekomo statycznego prefiksu, przenosimy dynamiczną edycję pod punkt podziału albo usuwamy warstwę. Potem porównujemy cache_read_input_tokens z całym wejściem na raporcie użycia dostawcy dla tej samej funkcji przed zmianą i po niej.
Co zostaje u was: raport diffu dla każdej sesji z pozycją rozbieżności dla każdego wywołania oraz udział odczytów z cache przed zmianą i po niej - 2Proxy w łańcuchu gubi znacznik cache
Aplikacja oznacza punkt podziału, proxy zgodne z OpenAI przekazuje żądanie do Bedrocka, a znacznik nigdy nie staje się blokiem cachePoint. Każda warstwa w łańcuchu dokumentuje obsługę pamięci podręcznej promptów i właśnie to zespół sprawdził. Nic w łańcuchu nie raportuje, że znacznik zginął; jedynym dowodem jest to, że tokeny odczytane z cache po stronie dostawcy zostają na zerze.
Co z tym robimyOdtwarzamy jedno stałe żądanie przez każdy przeskok w łańcuchu i odczytujemy pola cache zwracane na każdym z nich, więc warstwa, która gubi 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 żądania, z polami cache zwracanymi na każdej warstwie - 3Dynamiczna treść leży nad punktem podziału
Prompt systemowy zaczyna się od bieżącej daty, nazwy użytkownika albo identyfikatora żądania, 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, a dostawca słusznie traktuje go jako nowy. To częsta przyczyna i tania w naprawie, a bez diffu pozostaje niewidoczna.
Co z tym robimySpisujemy układ promptu jako uporządkowaną listę bloków ze stroną statyczną i dynamiczną, przypinamy kolejność narzędzi i przenosimy każdą wartość zależną od żądania za ostatni punkt podziału. Układ dostaje skrót, który brama sprawdza przy każdym żądaniu, więc test wykrywa zmianę statycznego prefiksu przed wdrożeniem.
Co zostaje u was: specyfikacja układu promptu ze skrótem prefiksu i kontrola w bramie, która nie przechodzi przy zmianie części statycznej - 4Alert się odzywa i nic się nie zatrzymuje
Alert budżetowy jest skonfigurowany u dostawcy, a pętla z błędem w warunku wyjścia rusza w nocy. E-mail przychodzi przy progu, dyżurny czyta go rano, a wydatek pomiędzy jest incydentem. Alert dostawcy zrobił to, do czego był zaprojektowany; projekt zakładał człowieka w pętli przy prędkości żądań.
Co z tym robimyUstawiamy u dostawcy kontrolę, która naprawdę zatrzymuje ruch: limit wydatku na workspace w Anthropic, twardy limit projektu w OpenAI, limit wydatku albo funkcję wyłączającą rozliczanie w Google Cloud. Nad tym dodajemy w waszej bramie budżety na funkcję i na klienta 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 dla każdego dostawcy i każdej funkcji, z zachowaniem widocznym dla użytkownika po osiągnięciu każdego limitu i wynikami próby - 5Równoległe rozgałęzienie i ponowienia zapisują ten sam prefiks wiele razy
Funkcja wysyła naraz dziesięć żądań 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 może zapisać wpis raz na żądanie i nie odczytać go ani razu; dane użycia to potwierdzają albo nie. Wskaźnik trafień wygląda akceptowalnie w średniej i fatalnie dokładnie w tych funkcjach, które się rozgałęziają.
Co z tym robimyWysyłamy pierwsze żądanie na prefiks pojedynczo i zwalniamy resztę, gdy wpis już istnieje, ograniczamy ponowienia i dodajemy losowy odstęp, a stosunek zapisów do odczytów mierzymy dla każdej funkcji, nie dla klucza. Funkcje, które się rozgałęziają, dostają własny wiersz w raporcie, żeby średnia nie mogła ich ukryć.
Co zostaje u was: stosunek zapisów do odczytów dla każdej funkcji, przed zmianą i po niej, z raportu użycia dostawcy
Co zostaje u was.
- Raport z analizy z jednym wierszem na wywołanie: funkcja, sesja, skrót prefiksu, trafienie albo chybienie, tokeny według klas, koszt, przyczyna chybienia
- Przypisanie kosztu do funkcji, sesji i klienta, uzgodnione z raportem kosztów dostawcy za ten sam okres
- Specyfikacja układu promptu ze skrótem prefiksu i kontrola w bramie, która nie przechodzi przy zmianie części statycznej
- Rejestr limitów: dla każdego dostawcy i każdej funkcji, co zatrzymuje, co powiadamia, co widzi użytkownik i kto jest wzywany
- Zapis próby: każdy limit osiągnięty raz na projekcie testowym, ze zmierzonym opóźnieniem egzekwowania
- Pomiar przed i po na raporcie użycia dostawcy, przy porównywalnym obciążeniu i z zapisanymi warunkami, z użytym zapytaniem, żeby dział finansów mógł go powtórzyć
Jak pracujemy.
- 11. Zbieranie
Ustawiamy limit awaryjny u dostawcy, dołączamy metadane funkcji, sesji i klienta w waszej bramie, zapisujemy blok usage z każdej odpowiedzi i pobieramy raporty użycia i kosztów dostawcy za to samo okno. Okres zbierania zależy od ruchu i musi objąć typowe zadania oraz okresy zwiększonego obciążenia.
Tydzień 1-2 - 22. Analiza
Budujemy tabelę dla każdego wywołania, porównujemy kolejne żądania w sesji, odtwarzamy stałe żądanie przez każdy przeskok łańcucha proxy i przypisujemy potwierdzoną przyczynę każdemu chybieniu, które da się wyjaśnić. Przyczyny szeregujemy według pieniędzy, które za nimi stoją.
Tydzień 2-3 - 33. Poprawki i limity
Najdroższe przyczyny naprawiamy u źródła razem z waszym zespołem, spisujemy układ promptu z jego skrótem, a potem dopasowujemy limit u dostawcy i ustawiamy budżety na funkcję ze zdefiniowanym zachowaniem dla każdego. Każdy limit osiągamy raz na projekcie testowym.
Tydzień 3-5 - 44. Ponowny pomiar i przekazanie
Uruchamiamy tę samą tabelę na raporcie użycia dostawcy po zmianie przy porównywalnym obciążeniu i przekazujemy raport, specyfikację układu, kontrolę w bramie i rejestr limitów. Kontrola zostaje w waszym potoku, żeby następna edycja promptu nie mogła po cichu otworzyć chybień na nowo.
Tydzień 5-6
Pozostałe strony z tej serii.
Pomiar efektu AI w zespole
Dlaczego samo szybsze zamykanie zgłoszeń nie dowodzi efektu AI i jak go zmierzyć: punkt odniesienia sprzed wdrożenia, miary w parach, grupa porównawcza.
Porównanie narzędzi do AI code review
Porównanie narzędzi do AI code review na waszym kodzie: wykryte błędy, błędne komentarze i koszt na pull request, z protokołem do powtórzenia po zmianie modelu.
Polityka wnoszenia kodu pisanego z AI
Polityka wnoszenia kodu pisanego z AI do wdrożenia w tydzień: kto go podpisuje, gdzie zapisać deklarację w pull requeście i jak sprawdzić każdą regułę.
Usługi, które to wdrażają.
Optymalizacja kosztów modeli językowych
Audyt kosztów modeli językowych wskazuje źródła wydatków i zmiany, które mogą je obniżyć: cache promptów, dobór modeli, kompresja promptów. Raport porównuje koszty i jakość przed zmianami i po nich.
LLM Observability
Tracing, procesy ewaluacji i wykrywanie dryfu: prześledzicie wywołania modeli i znajdziecie źródła błędów, opóźnień i kosztów.
Skąd pochodzą daty i liczby.
- Anthropic, Prompt caching: breakpointy, kolejność, czas życia, mnożniki cen, pola usage, uwaga o równoległości
- Anthropic, Workspaces: miesięczne limity wydatku i limity zapytań per workspace
- Anthropic, Usage and Cost API: grupowanie po kluczu API, workspace i modelu; klasy tokenów z cache i bez
- OpenAI, Prompt caching: dopasowanie prefiksu, minimalna długość, czas przechowywania, rabat za tokeny z cache, pola usage
- OpenAI, Spend limits: twarde limity per organizacja i projekt, kody błędów 429, alerty
- Google, Gemini API context caching: domyślny cache niejawny i minimalne liczby tokenów
- Google, Gemini API cache jawny: domyślny TTL 1 godzina i składniki rozliczenia
- Google, cennik Gemini API: context caching i opłata za przechowywanie na godzinę
- Google Cloud, budżety Cloud Billing: budżety alertowe nie ograniczają wydatku
- AWS, Amazon Bedrock prompt caching: cachePoint, kolejność sekcji, TTL, brak gwarancji trafienia
- Przypadek opisany przez autora na Hacker News: rachunek 37 901,73 USD na Bedrocku po chybieniach cache w łańcuchu proxy
Pytania przed rozpoczęciem współpracy.
Porozmawiajmy o AI w waszej firmie.
Napiszcie, na jakim etapie jesteście z rachunkiem za LLM i limitami wydatku. Odpowiedź w ciągu jednego dnia roboczego.