Jak kontrolować koszty agenta AI na VPS
Dowiedz się, jak uniknąć wysokich rachunków za API poprzez limitowanie tokenów, prompt caching oraz monitorowanie zużycia w pętlach typu unattended.
Jak zapobiec wysokim kosztom w przypadku agenta AI działającego w trybie ciągłym
Kontrola kosztów agenta AI na VPS (virtual private server) polega na ustawieniu limitów przed uruchomieniem agenta, ponieważ procesy te działają bez nadzoru. Należy ograniczyć liczbę tokenów w każdej odpowiedzi za pomocą max_tokens, zdefiniować limit iteracji pętli w kodzie źródłowym, buforować niezmienne części promptu oraz logować zużycie dla każdej odpowiedzi w celu monitorowania wydatków. Koszt wynajmu serwera jest stały i miesięczny. Koszt API modelu jest naliczany za każdy token, a niekontrolowana pętla może generować wysokie zużycie tokenów.
Powyższe założenia dotyczą istniejącego agenta, który wywołuje Messages API z własnego serwera. Budowa agenta AI z Claude na VPS opisuje samą mechanikę działania.
Dlaczego koszt agenta działającego w trybie unattended ma inny charakter
Sesja interaktywna wymaga obecności człowieka. Gdy model wybierze błędną ścieżkę lub przetworzy log o długości 40,000 linii, osoba monitorująca może przerwać proces. Agent w trybie unattended nie posiada takiego mechanizmu kontrolnego: proces trwa do zakończenia pętli, po czym licznik ponownie uruchamia zadanie.
Częstotliwość jest pomijanym przez użytkowników mnożnikiem. Zadanie uruchamiane co 5 minut wykonuje 288 operacji dziennie i około 8,640 operacji miesięcznie. Koszt pojedynczego uruchomienia należy pomnożyć przez tę wartość. Wiele agentów typu "always-on" nie wymaga ciągłego działania. Wymagają jedynie odpowiedzi w określonym czasie, co stanowi harmonogram.
Agent generuje również koszty, których nie generuje okno czatu.
- Definicje narzędzi są dołączane do każdego zapytania. Systemowy prompt narzędzi (tool-use system prompt) kosztuje 290 tokenów w modelu Claude Opus 4.8 przy
tool_choicezautolubnone, oraz 410 tokenów przyanylubtool. Narzędzie bash dodaje dodatkowe 325 tokenów. Każdy serwer MCP podłączony do systemu zwiększa ten koszt o własne schematy (MCP to model context protocol). - Wyniki narzędzi są traktowane jako tokeny wejściowe (input tokens). Polecenie generujące 8,000 linii tekstu przesyła te 8,000 linii w kolejnym zapytaniu oraz w każdym następnym zapytaniu w ramach danej tury.
- Pobrane strony są traktowane jako tokeny wejściowe. Średnia strona internetowa o rozmiarze 10 kB to około 2,500 tokenów, a plik PDF o rozmiarze 500 kB to około 125,000 tokenów.
max_content_tokensdokonuje skracania (truncation) wyłącznie tekstów, ponieważ "dotyczy to treści tekstowej, a nie zawartości binarnej, takiej jak pliki PDF". W przypadku plików PDF należy użyćmax_usesorazallowed_domains. - Wyszukiwanie internetowe jest rozliczane za każde zapytanie, w kwocie 10 USD za 1,000 zapytań, niezależnie od liczby otrzymanych wyników. Błędne zapytanie nie jest fakturowane.
Powyższe koszty nie są wysokie przy pojedynczym wykonaniu. Stają się wysokie przy 8,640 powtórzeniach.
Hard ceilings i soft ceilings rozwiązują inne problemy
Wymuszany jest max_tokens. Jest to sztywny limit całkowitego wyjścia jednego zapytania, obejmujący tekst myślenia oraz tekst odpowiedzi. Claude nigdy nie przekracza tej wartości, a model nie widzi tej liczby. Osiągnięcie limitu skutkuje wystąpieniem stop_reason: "max_tokens" oraz przyciętą odpowiedzią. Kluczowa kwestia dla agentów: każde zapytanie w pętli tool-use posiada własny limit max_tokens, co ogranicza pojedynczą odpowiedź, a nie całe zadanie. Dziesięć wywołań narzędzi po 4,000 tokenów tworzy limit 40,000 tokenów na jedną turę.
Budżet zadania ma charakter doradczy. task_budget znajduje się wewnątrz output_config i informuje model, ile tokenów przysługuje mu na całą pętlę agenticzną, wliczając myślenie, wywołania narzędzi, wyniki narzędzi oraz wyjście.
resp = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
betas=["task-budgets-2026-03-13"],
output_config={"task_budget": {"type": "tokens", "total": 64000}},
messages=messages,
)"Budżety zadań to miękka wskazówka, a nie sztywny limit." Claude może przekroczyć jeden limit w trakcie działania, a wymuszony limit wyjścia nadal wynosi max_tokens. "Odliczanie jest widoczne tylko dla modelu", a odpowiedzi nie zawierają pola z pozostałym budżetem. Minimalna akceptowana wartość task_budget.total to 20,000 tokenów; mniejsza wartość powoduje błąd 400. Zbyt mały budżet w stosunku do zakresu pracy powoduje zachowanie typu refusal, przez co model ogranicza zakres zadania lub przerywa pracę wcześniej.
Jeden szczegół generuje koszty zamiast oszczędności. Jeśli klient odejmuje task_budget.remaining przy każdym kolejnym zapytaniu, zmieniona wartość unieważnia wszelkie pamięciowe prefiksy (cached prefix) zawierające tę wartość. Należy ustawić ją raz, przy pierwszym zapytaniu.
Budżety zadań są w fazie beta w Claude Fable 5, Claude Opus 4.8 oraz Claude Opus 4.7. Claude Sonnet 5 i Claude Haiku 4.5 są wymienione jako Not supported, a budżety zadań nie mają zastosowania do Claude Code, więc sesja Claude Code odłączona w tmux zależy od poprawności zarządzania sesją.
Trzeci limit znajduje się w Claude Console: należy przypisać agentowi własne workspace, a następnie ustawić dla niego miesięczny limit wydatków oraz limity częstotliwości (rate limits) na minutę. "Nie można ustawić limitów w Default Workspace", a "limity organizacji zawsze mają pierwszeństwo, nawet jeśli suma limitów workspace jest wyższa". Należy włączyć powiadomienia o wydatkach, aby próg ostrzegawczy zadziałał przed osiągnięciem limitu.
Wybór modelu dla zadania oraz wpływ nakładu pracy
Wybór modelu zależy od konkretnego zadania. W lipcu 2026 roku ceny za milion tokenów (input, potem output) wynoszą: Claude Fable 5 to 10 $ i 50 $, Claude Opus 4.8 i Opus 4.7 to 5 $ i 25 $, Claude Sonnet 5 to 3 $ i 15 $, Claude Haiku 4.5 to 1 $ i 5 $. Cena Sonnet 5 jest obecnie niższa od standardowej, ponieważ obowiązuje „Wprowadzona cena 2 $/10 $ za milion tokenów input/output do 31 sierpnia 2026”. Zadania służące wyłącznie klasyfikacji linii logów nie wymagają modelu Opus.
Drugim parametrem jest nakład pracy (effort). output_config.effort akceptuje low, medium, high, xhigh oraz max, przy czym domyślną wartością jest high, więc jawne ustawienie high daje ten sam efekt co jego pominięcie. Zmniejszenie nakładu pracy wpływa na więcej czynników niż tylko długość rozumowania: dokumentacja wskazuje, że model Claude wykonuje wtedy mniej wywołań narzędzi (tool calls) i łączy operacje w jedną. W przypadku agentów generuje to większe oszczędności, ponieważ uniknięte wywołanie narzędzia oznacza brak całego zapytania.
Pułapką jest konflikt między parametrem effort a pamięcią podręczną (cache). Zmiana wartości między zapytaniami unieważnia prompt caching. W przykładowym dokumencie zapytanie 2 zgłosiło cache_read_input_tokens: 3546; zapytanie 3, przy zmianie effort z high na medium, zgłosiło cache_creation_input_tokens równe 3546 oraz cache_read_input_tokens równe 0. Należy zatem różnicować parametr effort między różnymi obciążeniami, a nie wewnątrz jednej rozmowy objętej cache. Aby kontrolować głębię analizy bez przerywania cache, należy to zrobić w prompcie: instrukcja typu „Answer directly without deliberating.” w najnowszej wiadomości użytkownika pozostawia wcześniejsze punkty przerwania (breakpoints) nienaruszone.
Tokeny myślowe (thinking tokens) są rozliczane według stawek za output i wliczają się do max_tokens, dlatego skrócenie odpowiedzi często oznacza, że budżet został zużyty na proces myślowy. Dokładną liczbę podaje usage.output_tokens_details.thinking_tokens. Co faktycznie generuje koszty tokenów Claude szczegółowo analizuje te wydatki.
Cache'owanie stabilnego prefiksu i unikanie przypadkowego przerywania jego działania
Koszt zapisu do cache wynosi 1.25 ceny wejściowej dla cache 5-minutowego oraz 2 ceny wejściowej dla cache 1-godzinnego. Koszt odczytu z cache wynosi 0.1, zatem „cache zwraca się już po jednym odczycie dla czasu trwania 5 minut (1.25x write) lub po dwóch odczytach dla czasu trwania 1 godziny (2x write)”.
Przyczyna przydatności dla agentów działających w trybie ciągłym: „Cache jest odświeżany bez dodatkowych kosztów przy każdym użyciu zakodowanej treści”. Zadanie uruchamiane co 2 minuty przy użyciu 5-minutowego cache utrzymuje ciepły prefiks przez cały dzień przy koszcie jednego zapisu.
Trzy sposoby na nieświadome utracenie cache.
Zmieniający się prefiks. „Prefiksy cache są tworzone w następującej kolejności: tools, system, następnie messages”. Każda zmiana bajtu we wcześniejszym etapie unieważnia wszystkie kolejne elementy. Edycja definicji narzędzi unieważnia cały cache. Typowym błędem jest umieszczenie znacznika czasu lub run id w system prompt: każdy request przesyła wtedy inny prefiks, wykonuje nowy zapis przy koszcie 1.25x i nie odczytuje żadnych danych z cache. Objawem jest wartość usage.cache_read_input_tokens równa 0 przy identycznych wywołaniach. Tekst zmienny należy przenieść do najnowszej wiadomości użytkownika.
Zbyt krótki prefiks. Każdy model posiada minimalną długość do cache'owania. Poniżej tej wartości request jest przetwarzany bez użycia cache i „nie jest zwracany żaden błąd”. Wartości te obejmują 1,024 tokeny dla Claude Opus 4.8 i Claude Sonnet 5 oraz 4,096 dla Claude Haiku 4.5, zatem przeniesienie zadania z Sonnet na Haiku może spowodować ciche wyłączenie cache'owania.
Konwersacja przekraczająca okno przeglądania. „Okno przeglądania (lookback window) wynosi 20 bloków”. System sprawdza maksymalnie 20 pozycji na breakpoint, a następnie przerywa operację. W dokumentowanym przykładzie zwrot zawierający 35 bloków z breakpointem na bloku 35 sprawdza bloki od 35 do 16. Wpis z poprzedniego zwrotu na bloku 15 znajduje się poza oknem, więc nie następuje trafienie (hit). Agent dodający kilka bloków tool-use i tool-result na zwrot przekroczy limit 20 bloków w ciągu dwóch lub trzech zwrotów. Na każdy request przysługują cztery breakpointy, dlatego należy przeznaczyć jeden z nich na ostatnie wiadomości.
Przesyłaj zadania odroczone do Batches API
Wszystkie operacje są rozliczane z 50% zniżką względem standardowych cen API, zarówno dla danych wejściowych, jak i wyjściowych. Przetwarzanie wsadowe (batch processing) odbywa się asynchronicznie. Większość zadań kończy się w czasie krótszym niż 1 godzina. Wyniki są dostępne po zakończeniu wszystkich żądań lub po upływie 24 godzin (zależnie od tego, co nastąpi pierwsze). Jest to wartość typowa, a nie gwarantowana.
Należy odpytywać processing_status, aż wartość wyniesie ended. Żądania zwracające errored, canceled lub expired nie są fakturowane. W przypadku stosowania limitów wydatków należy pamiętać, że zadania batch mogą nieznacznie przekroczyć skonfigurowany limit wydatków dla Workspace.
Zniżki sumują się. Ponieważ zadanie batch może trwać dłużej niż pięć minut, dokumentacja zaleca stosowanie 1-godzinnego cache dla zadań współdzielących kontekst. Należy dzielić pracę: zadania wymagające natychmiastowej odpowiedzi człowieka lub webhooka należy realizować w trybie live, natomiast raporty dobowe lub klasyfikację logów z poprzedniego dnia należy przesyłać w trybie batch z 50% zniżką.
Logowanie pól użycia każdej odpowiedzi do własnego magazynu
Nie można przypisać wydatków, których nie zarejestrowano. Każda odpowiedź zawiera informacje o poniesionych kosztach.
u = resp.usage
row = {
"job": job_name,
"model": resp.model,
"uncached_input": u.input_tokens,
"cache_write": u.cache_creation_input_tokens,
"cache_read": u.cache_read_input_tokens,
"output": u.output_tokens,
"stop_reason": resp.stop_reason,
}Do pliku JSON-lines należy dopisywać jeden wiersz na każde wywołanie API, oznaczony nazwą zadania. Po tygodniu można określić, które zadania generują koszty, a które jedynie wykazują wysoką aktywność. Należy monitorować cache_read: kolumna zawierająca same zera to najczęstszy błąd kosztowy w agentach typu self-hosted.
Jedno pole jest podatne na błędną interpretację. input_tokens liczy tylko tokeny po ostatnim punkcie przerwania cache, zatem rzeczywisty rozmiar promptu to total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens. Agent raportujący input_tokens: 400 przy dużym prompcie nie jest tani: pozostała część pochodzi z cache.
Wykonuj liczenie przed wysłaniem żądania. Liczenie tokenów jest bezpłatne, a limity częstotliwości (rate limits) są oddzielne od tworzenia wiadomości. Należy używać count_tokens, aby odrzucić zbyt duże załączniki zamiast płacić za ich przetworzenie. Wynik jest szacunkiem, dlatego należy ponownie mierzyć rozmiar dla każdego modelu i nigdy nie używać wyników z tokenizerów innych dostawców. Modele Claude Opus 4.7 i nowsze modele Opus, Claude Fable 5 oraz Claude Sonnet 5 używają nowszego tokenizera, który „generuje około 30% więcej tokenów dla tego samego tekstu”. Modele Claude Sonnet 4.6 i starsze, w tym Claude Haiku 4.5, używają poprzedniego.
W celu uzyskania wiarygodnych danych Admin API raportuje użycie w https://api.anthropic.com/v1/organizations/usage_report/messages, a koszty w https://api.anthropic.com/v1/organizations/cost_report. Oba parametry wymagają klucza admina (sk-ant-admin01-...) jako x-api-key: $ANTHROPIC_ADMIN_KEY z anthropic-version: 2023-06-01 oraz akceptują bucket_width=1d, group_by[]=model i api_key_ids[]=. Ograniczenie: „Admin API jest niedostępne dla kont indywidualnych”.
Ostatni parametr to prosty sposób na atrybucję: przypisz każdemu zadaniu własny klucz API, filtruj za pomocą api_key_ids[] i dziel raport według kluczy przy użyciu group_by[]=api_key_id. Filtr występuje w liczbie mnogiej, wymiar grupowania w liczbie pojedynczej. Klucze należy przechowywać w zmiennych środowiskowych, a nie w kodzie, tak jak robi to pierwsza aplikacja Claude API na VPS.
Bound the loop, because nothing else will
A bounded iteration count is not optional here. The loop is yours, so the counter is yours:
for step in range(MAX_STEPS): # MAX_STEPS = 12, never "while True"
resp = client.messages.create(...)
if resp.stop_reason != "tool_use":
break
else:
log.warning("job %s hit MAX_STEPS=%d, giving up", job_name, MAX_STEPS)Neither ceiling above does it for you: max_tokens caps one response, and the model is only advised of a task budget.
Put a second brake outside the process. Run the job from a systemd timer instead of a permanent process, and set RuntimeMaxSec= on its service unit. With RuntimeMaxSec=600, a hung run is killed after ten minutes instead of spinning until you notice. Running a program as a systemd service and timer covers the unit files themselves. Read what a run did with journalctl -u triage-agent.service --since "1 hour ago".
Cap retries as well, because a handler that retries forever bills every attempt. A 429 or a 500 deserves a few tries with backoff. A 400 deserves none, since the same request fails the same way.
Kontrola kosztów agentów AI wymaga analizy własnych danych
Koszt agenta działającego w trybie ciągłym jest niemożliwy do precyzyjnego określenia bez analizy danych, ponieważ zależy od liczby tokenów na wywołanie oraz liczby wywołań dziennie. Należy wykonać jedno wywołanie, sprawdzić zarejestrowaną liczbę użytych tokenów, a następnie pomnożyć wynik przez planowaną częstotliwość operacji. Po dwóch dniach należy porównać raport kosztów z uzyskanym wynikiem arytmetycznym. Rozbieżność wynika zazwyczaj z błędów w mechanizmie cache lub z pętli działającej dłużej niż zakładano.
Założeniem jest posiadanie klucza API, ponieważ agent jest programem wywołującym Messages API. W przypadku pracy interaktywnej który plan Claude pasuje do sposobu pracy opisuje kwestie subskrypcji. Wszystkie ceny i limity zostały zweryfikowane z dokumentacją Anthropic w lipcu 2026. Przed przygotowaniem budżetu należy ponownie sprawdzić stronę z cennikiem.
FAQ
Jaki jest koszt utrzymania agenta AI działającego w trybie always-on na VPS?
Występują dwa rachunki, z których tylko jeden jest przewidywalny. Serwer ma stałą miesięczną cenę. API modelu jest rozliczane za tokeny, więc koszt zależy od liczby zużytych tokenów podczas jednego uruchomienia pomnożonej przez częstotliwość uruchomień. Anthropic nie podaje konkretnych danych dla self-hosted always-on agent, więc każda podana wartość jest jedynie szacunkiem. Należy pobrać log usage z jednego rzeczywistego uruchomienia i pomnożyć go przez harmonogram pracy.
Jaka jest różnica między max_tokens a budżetem zadań (task budget)?
max_tokens jest wymuszane i niewidoczne dla modelu. Parametr ten ogranicza wyjście (output) pojedynczego zapytania, wliczając w to myślenie (thinking), a przekroczenie limitu skutkuje błędem stop_reason: "max_tokens". Budżet zadań działa odwrotnie: model otrzymuje tę wartość i dostosowuje do niej pętlę agenticzną, jednak "Task budgets are a soft hint, not a hard cap" i nadrzędnym limitem pozostaje max_tokens.
Dlaczego cache_read_input_tokens zawsze wynosi zero dla mojego agenta?
Ponieważ prefiks zmienia się między wywołaniami lub jest zbyt krótki, aby go zapamiętać. Typową przyczyną jest znacznik czasu lub run id wstawiane do system prompt: pamięć cache jest indeksowana na podstawie prefiksu, więc każda zmiana pojedynczego bajtu unieważnia wszystko, co następuje po nim. Zmiana definicji narzędzi lub wartości effort powoduje ten sam efekt. Innym powodem jest rozmiar, ponieważ krótkie prompty nie są cache'owane, a system nie zwraca błędu.
Jak zapobiec nieskończonemu zapętleniu agenta AI?
Należy liczyć iteracje w kodzie pętli i zatrzymywać proces po osiągnięciu stałego maksimum, ponieważ max_tokens ogranicza jedną odpowiedź, a agent generuje ich wiele. Należy również dodać limit czasu (wall-clock limit) poza procesem: należy uruchomić zadanie za pomocą systemd timer z ustawionym RuntimeMaxSec=, aby zawieszone zadanie zostało zabite zgodnie z harmonogramem. Należy ograniczyć również liczbę ponowień (retries), ponieważ każda próba generuje koszty.
Czy mogę ustawić limit wydatków dla pojedynczego klucza Claude API?
Dokumentowany limit wydatków dotyczy obszaru roboczego (workspace), a nie pojedynczego klucza, dlatego należy przypisać agentowi oddzielny workspace i tam ustawić miesięczny limit. "You cannot set limits on the Default Workspace". Należy włączyć powiadomienia o wydatkach, aby otrzymywać alerty po przekroczeniu progu. W celu rozliczeń należy przypisać każdemu zadaniu osobny klucz, a następnie pogrupować raport użycia za pomocą group_by[]=api_key_id.