Three Nights of Autonomous Tasks, Doubled Bill: We Started Keeping a Ledger for Token Spending
At the beginning of this month, our autonomous delivery tasks ran continuously for three nights straight. Checking the bill in the morning, we found that the av

Three Nights of Autonomous Tasks, Doubled Bill: We Started Keeping a Ledger for Token Spending
At the beginning of this month, our autonomous delivery tasks ran continuously for three nights straight. Checking the bill in the morning, we found that the average daily token consumption for the month was nearly double that of the previous month.
The incident itself was short: a subtask repeatedly failed against a given interface contract. The model retried on its own for an hour, making 21 API calls. Each call carried a context of over 40,000 tokens—notes from previous failures were stuffed back into the prompt, making the context thicker with every retry. In the end, the task remained red, and the tokens were burned up.
The post-mortem conclusion was straightforward: the model didn’t go off the rails; rather, there was no ledger to track the loop. Costs had only been estimated at the project level, leaving individual tasks free to spend as much as they wanted. There was no cap on retry logic, and no alerts for process consumption. The most troublesome aspect was the illusion that “a single failure is cheap.” A single 40,000-token call costs only a few dozen yuan, but when stacked hundreds of times a day, it becomes hard for anyone to stop it in the early hours. Any overnight task is simply waiting for an ugly bill.
Afterward, we built a set of “Three Sticks” guardrails, each corresponding to a lesson learned the hard way.
**First Stick: Every task gets a meal ticket; consumption is calculated based on API return values, not self-estimates.**
Before an autonomous task starts, it must apply for a single-task budget: how many tokens it is allowed to burn. The scheduler also sets a daily total cap. This creates a two-layer ledger: a task ledger and a daily ledger. Whichever layer hits its limit first dictates the outcome. The daily cap is not simply a multiple of the task budgets—we set it at 1.5 times the sum of all daily budgets. If this limit is exceeded, it indicates that scheduling itself has gone awry; what needs waking up is a human, not just the billing system.
We stumbled on self-estimation. The first version estimated costs based on character count and even spontaneously compressed prompts to save money. However, the actual API billing metrics differed from our estimates by up to 20%. We eventually decided to rely solely on the `usage` field in the API response. Estimation is only used during the initial budget application step; once the task is running, the API keeps the books.
**Second Stick: Stop at the limit, don’t just notify.**
The first version was too polite: at 80% of the budget, it sent an alert but let the task continue running, assuming someone would naturally intervene upon notification. The result? An alert at 11 PM went unnoticed, and the task ran on its own until 7 AM the next day, overshooting the budget by another 30%. After the change: an alert is sent at 80%, but at 100%, further scheduling is rejected, the task is terminated, and the failure reason is recorded in the ledger.
This is the harshest rule, and also the one most likely to be softened by our own team: guardrails must have the power to fail tasks. A system that only notifies without braking isn’t a guardrail; it’s a signpost. A task that cannot fail itself is not qualified to run overnight.
**Third Stick: Retries belong to the same entity; accounts are tracked by task ID, not by attempt.**
We had an old habit: if the previous attempt overspent, a retry would reset the counter. Out-of-control tasks could bypass throttling simply by restarting repeatedly. Now, the unique key for the ledger is the Task ID. Attempts reuse the same “meal ticket” without additional funding. We also added a per-attempt cap, set at approximately one-third of the task budget, ensuring a single attempt cannot burn through an entire afternoon’s allowance. Tasks that exceed their budget enter a review queue, requiring manual verification and re-issuance of budget before restarting, making it impossible to bypass controls.
The numbers: The guardrails were finalized around August 15th. In the following two weeks, no task exceeded its spending limit before hitting the 80% alert threshold. Alerts were triggered only four times, each resolved within ten minutes. Average daily consumption dropped to about 70% of pre-implementation levels. What I value more, however, is a smaller detail: the question “Should this task really spend this much?” used to require human judgment at 2 AM. Now, the answer exists the moment the task starts, written directly into the ledger.
Budgeting is not a cost-saving tool; it is the entry ticket that allows autonomous tasks to be truly autonomous.
Comments
Share your thoughts!
Loading comments…