Agent burns through its budget in a single run
A daily LLM API limit catches “we overspent over 24 hours” — but a single
autonomous agent can burn $40 in one run if it goes into an expensive
loop: a long context, repeated tool calls, retry after retry. By morning the
daily alert is already useless — the money is spent.
You need a guard inside a single run: it counts cumulative cost as it goes and reacts before the bill grows several-fold. This is not about the daily spend, but specifically about runaway within one run.
Budget guard: counting $ as the run goes
Section titled “Budget guard: counting $ as the run goes”We wrap every model call: convert tokens to dollars, accumulate the total, and at two thresholds (warn / hard) send a push. On hard — raise an exception and stop the agent.
import os, requests
# prices per 1M tokens (example — substitute your own for your model)PRICE_IN = 3.00 / 1_000_000PRICE_OUT = 15.00 / 1_000_000
class BudgetGuard: def __init__(self, run_id, warn_usd=5.0, hard_usd=15.0): self.run_id = run_id self.warn = warn_usd self.hard = hard_usd self.spent = 0.0 self._warned = False
def add(self, usage): # usage — the model response object with input_tokens / output_tokens self.spent += usage.input_tokens * PRICE_IN self.spent += usage.output_tokens * PRICE_OUT
if self.spent >= self.hard: notify("💸🛑 Агент пробил hard-лимит", f"run {self.run_id}: потрачено ${self.spent:.2f} " f"(потолок ${self.hard:.2f}). Останавливаю run.", priority=10) raise RuntimeError(f"budget hard limit: ${self.spent:.2f}")
if self.spent >= self.warn and not self._warned: self._warned = True notify("💸⚠️ Агент близок к лимиту бюджета", f"run {self.run_id}: уже ${self.spent:.2f} " f"из ${self.hard:.2f}. Присматривайте.", priority=6)
def snapshot(self): return round(self.spent, 4)
def notify(title, message, priority): requests.post(f"{os.environ['NOTIFLY_URL']}/message", params={"token": os.environ["NOTIFLY_TOKEN"]}, json={"title": title, "message": message, "priority": priority}, timeout=5)Embedding it in the agent loop:
guard = BudgetGuard(run_id="refactor-auth-2026-07-01")
def call_model(messages): resp = client.messages.create(model="claude-sonnet-4-5", max_tokens=2000, messages=messages) guard.add(resp.usage) # crosses the limit -> raises an exception return resp
# ... the agent runs its loop; on the hard limit the run fails with an alertThe key part: warn sends a push once (the _warned flag) so it doesn’t
spam on every iteration. hard stops the run — a failed run beats a $40
bill.
Burn rate: not just the absolute amount
Section titled “Burn rate: not just the absolute amount”An absolute ceiling catches a long run, but not a sudden spike. Track
$/minute — if the agent suddenly starts burning three times faster than
usual, that’s an early loop signal:
import time
class BurnRateGuard: def __init__(self, run_id, max_usd_per_min=2.0): self.run_id = run_id self.max = max_usd_per_min self.t0 = time.time() self.spent = 0.0 self._fired = False
def add(self, delta_usd): self.spent += delta_usd mins = max((time.time() - self.t0) / 60, 0.1) rate = self.spent / mins if rate > self.max and not self._fired: self._fired = True notify("🔥 Скорость сжигания бюджета выросла", f"run {self.run_id}: ${rate:.2f}/мин " f"(норма ${self.max:.2f}). Возможно, петля.", priority=8)An external ceiling via a billing webhook
Section titled “An external ceiling via a billing webhook”If the agent is a black box (a third-party CLI, someone else’s SDK) and you can’t wrap the model calls from the inside, catch the threshold from the outside. OpenAI/Anthropic have usage webhooks and budget alerts — route them into the Webhook Router and it turns the event into a push. For providers without webhooks, use the Email Inbox: a budget alert arrives as an email → Notifly sends a push.
The precision is lower (billing lag), but it works for any agent without touching its code.
What to put in the push
Section titled “What to put in the push”run_id— which specific run, so you can find it in the logs;- spent / ceiling / burn rate
$/min; - the top-1 “expensive” tool or the longest request in the run;
- a hint about the cause:
retry loop,context ballooned to 180k tokens.
Related recipes
Section titled “Related recipes”- LLM API costs — daily budget, not per-run.
- Stalled agent / loop — a common cause of runaway.
- Agent tool errors — a retry storm burns budget.