Włączenie prompt caching nie przyniosło mi żadnych oszczędności – w rzeczywistości mój rachunek za OpenAI-API wzrósł o około jedną czwartą. Winowajcą była pojedyncza linia, która zmieniała się przy każdym zapytaniu: znacznik czasu (timestamp) umieszczony w systemowym prompcie.
Dostawcy LLM pozwalają programistom buforować fragmenty promptów, aby obniżyć koszty przetwarzania tokenów. Odczyt z pamięci podręcznej (tzw. „hit”) kosztuje zaledwie jedną dziesiątą standardowej stawki, podczas gdy zapis do pamięci podręcznej (tzw. „miss”) kosztuje około 1,25 × tyle, co normalna cena. Jeśli dojdzie do zapisu, ale buforowany fragment nigdy nie zostanie odczytany, dodatkowa opłata w wysokości 25% jest marnowana. Dokładnie to stało się w moim przypadku, gdy znacznik czasu uniemożliwiał dopasowanie promptu do jakiegokolwiek istniejącego wpisu w pamięci podręcznej.
Dlaczego buforowanie może przynieść odwrotny skutek
Prompt caching działa poprzez dopasowanie dokładnej sekwencji bajtów buforowanej części. Dostawca haszuje dane wejściowe; jeśli hasz zgadza się z zapisanym wpisem, system ponownie wykorzystuje poprzednie obliczenia i stosuje tanią stawkę za odczyt. Każda różnica – nawet pojedynczy znak – przerywa dopasowanie i wymusza nowe obliczenia, rozliczane według wyższej stawki za zapis.
W moim przypadku systemowy prompt zaczynał się od:
Current session started: 2026-07-14T09:41:07Z
Ponieważ znacznik czasu aktualizował się przy każdym wywołaniu API, pierwsze kilka bajtów zapytania nigdy nie było identycznych. Dostawca traktował każde wywołanie jako nowy wpis w pamięci podręcznej, naliczał premię za zapis i nigdy nie rejestrował odczytu. Rezultatem był stały wzrost cache_creation_input_tokens, podczas gdy cache_read_input_tokens utrzymywało się na poziomie zero – co było jasnym sygnałem, że pamięć podręczna nie była wykorzystywana.
Jak rozpoznać niedziałającą pamięć podręczną
Logi użycia dostarczane przez API zawierają dwa kluczowe liczniki:
- cache_creation_input_tokens – tokeny, które wywołały zapis.
- cache_read_input_tokens – tokeny, które skorzystały z odczytu.
Gdy pierwszy licznik rośnie, a drugi pozostaje na stałym poziomie, pamięć podręczna nie jest ponownie wykorzystywana. Szybkim testem sprawdzającym jest powtórzenie dokładnie tego samego zapytania dwa razy; drugie wywołanie powinno wykazać skok liczby tokenów odczytanych, jeśli buforowanie działa poprawnie.
Rozwiązanie problemu
Rozwiązanie jest proste: upewnij się, że buforowany obszar jest statyczny w kolejnych wywołaniach. Przestrzegaj tych dwóch zasad:
- Umieszczaj niezmienną treść na początku. Systemowe prompty, definicje narzędzi lub wszelkie instrukcje, które nigdy się nie zmieniają, powinny zajmować pierwsze bajty zapytania.
- Dodawaj zmienną treść na końcu. Znaczniki czasu, tekst wygenerowany przez użytkownika, identyfikatory zapytań lub wszelkie dane, które zmieniają się przy każdym wywołaniu, muszą znajdować się po segmencie buforowanym.
Jeśli przesunie się choćby jeden znak, hasz ulegnie zmianie, a brak dopasowania w pamięci podręcznej (cache miss) będzie się powtarzał. Przebudowanie promptu tak, aby znacznik czasu znajdował się na końcu, przywraca wskaźnik trafień w pamięci podręcznej (cache hit rate) i obniża rachunek do oczekiwanego, niskiego poziomu.
Kiedy buforowanie faktycznie pomaga
Prompt caching sprawdza się doskonale w scenariuszach, w których ten sam zestaw instrukcji jest wielokrotnie wykorzystywany:
- Pętle agentów (Agent loops), w których AI wielokrotnie odwołuje się do stałego zestawu narzędzi.
- Sesje czatu, które odnoszą się do długiego, statycznego dokumentu, podczas gdy zmienia się tylko najnowsze zapytanie użytkownika.
- Masowa ekstrakcja danych, gdzie ten sam prompt parsujący jest stosowany do wielu rekordów.
W przypadku pojedynczych wywołań (single-shot), które za każdym razem zawierają nowy kontekst – jak jednorazowe pytanie z unikalnym wstępem – buforowanie nie przynosi korzyści, a może nawet zwiększyć koszty, jeśli zapytanie nieumyślnie wywoła zapis.
Ukryte pułapki
Nawet jeśli sam prompt jest statyczny, zapytanie może zostać zmienione w dalszej części procesu:
- Proxy lub agregatory, które zmieniają kolejność lub wstrzykują białe znaki, mogą przerwać dopasowanie bajt po bajcie.
- Usługi bramowe (Gateway services), które dodają nagłówki uwierzytelniające na początku lub modyfikują formatowanie JSON, mogą nieumyślnie zmienić buforowany fragment.
Testowanie przez bramę (gateway) poprzez wysłanie dwukrotnie identycznego zapytania i sprawdzenie liczników odczytu pomaga zweryfikować, czy ścieżka buforowania pozostaje nienaruszona.
Szerszy obraz kosztów
Dopłata 25% za zapis nie jest karą za korzystanie z buforowania; odzwierciedla ona dodatkową moc obliczeniową potrzebną do przechowywania fragmentu do przyszłego wykorzystania. Gdy następuje trafienie w pamięć podręczną (cache hit), koszt drastycznie spada – często do ułamka standardowej stawki. Kluczem jest umożliwienie systemowi faktycznego trafienia w pamięć podręczną. W przeciwnym razie płacisz premię, nie osiągając żadnych oszczędności.
Kontrargument: buforowanie nie umarło
Niektórzy programiści argumentują, że złożoność zarządzania częściami statycznymi i dynamicznymi promptów przeważa nad oszczędnościami. Takie spojrzenie pomija fakt, że wiele potoków produkcyjnych już teraz oddziela konfigurację (statyczną) od danych użytkownika (dynamicznych). Poprzez odpowiednie strukturyzowanie promptów można bez dodatkowego wysiłku wykorzystać ten sam mechanizm buforowania, który przyniósł oszczędności pierwotnym twórcom API. Kompromisem jest jedynie niewielka dyscyplina w projektowaniu promptów, a nie fundamentalna wada technologii.
Na co zwrócić uwagę
- Monitoruj dwa liczniki cache w swoim panelu użytkowania co tydzień.
- Audytuj konstrukcję promptów, aby upewnić się, że każdy zmienny element znajduje się po zbuforowanym bloku.
- Przeprowadzaj testy A/B z buforowaniem i bez niego na reprezentatywnym obciążeniu, aby określić rzeczywiste oszczędności.
- Waliduj bramę (gateway), porównując surowe ładunki (payloads) żądań przed i po użyciu jakiegokolwiek proxy.
Podsumowanie
Buforowanie promptów może drastycznie obniżyć koszty API LLM, ale tylko wtedy, gdy buforowany segment jest rzeczywiście identyczny w kolejnych wywołaniach. Pojedyncza sygnatura czasowa lub jakikolwiek inny dynamiczny token na początku promptu wymusza kosztowny zapis przy każdym wywołaniu, co zwiększa rachunek. Umieszczając statyczne instrukcje na początku, a zmieniające się dane na samym końcu, pozwalasz buforowi wykonywać jego pracę i utrzymujesz wydatki pod kontrolą.
