
Cost Control for Agent Loops: Budgets & Kill Switches
Implement token budgets, depth limits, and kill switches to control agent loop costs and prevent runaway spending.
Cost Control for Agent Loops: Budgets, Depth Limits, and Kill Switches
Agent architectures introduce a fundamental shift from deterministic function calls to probabilistic control flow. In a standard API call, the input defines the output. In an agent loop, the output defines the next input. This recursive nature creates a feedback cycle where the agent decides whether to continue acting based on its previous observations. Without explicit structural constraints, this cycle is unbounded. An agent can enter an infinite loop, repeatedly calling a tool with identical parameters because the previous failure was misinterpreted as a need for retry, or it can exhaust the context window by accumulating irrelevant history, leading to exponential agent cost growth and eventual system failure.
For backend engineers and platform operators, managing these loops requires treating them not as simple functions, but as stateful processes with strict resource caps. The three primary mechanisms for cost control are token budgets, depth limits, and kill switches.
Understanding the Failure Mode
Before implementing controls, it is essential to understand why agent loops fail. The root cause of runaway costs is typically a lack of termination conditions or unbounded context growth. By analyzing these failure modes, engineers can design more robust safeguards.
The Mechanism of Runaway Loops
To control cost, one must first understand the failure mode. Agent loops typically follow a "ReAct" pattern: Reason, Act, Observe. The agent reasons about the current state, selects an action (usually a tool call), executes it, and observes the result. It then repeats this cycle.
The runaway scenario occurs when the termination condition is weak. LLMs are optimized to be helpful, not frugal. If an agent fails to retrieve data from an API, it may interpret the empty response as a signal to "try again with different parameters" or "search again." If the underlying issue is a misconfigured tool or a persistent network error, the agent will loop indefinitely, generating new tokens for reasoning and potentially new tokens for tool arguments, even if the tool output remains static.
Furthermore, context window management is a hidden cost driver. Each iteration adds the previous conversation history to the prompt. If the agent does not prune irrelevant history, the input size grows linearly with the number of steps. Since LLM inference cost is roughly proportional to the square of the context length due to the self-attention mechanism (as described in Attention Is All You Need, Vaswani et al., 2017), a long-running agent becomes exponentially expensive per step.
Token Budgets as Hard Limits
A token budget imposes a hard cap on the total number of tokens consumed by an agent session. This is distinct from the model's maximum context window; it is a business logic constraint.
Implementation requires two layers of budgeting:
- Global Budget: The total tokens allowed for the entire agent run.
- Per-Step Budget: The maximum tokens allowed for a single iteration (reasoning + tool execution + observation).
The global budget acts as the primary circuit breaker. Before each LLM call, the system calculates the cumulative token count of the conversation history plus the estimated tokens for the next response. If the sum exceeds the global budget, the loop terminates immediately.
class TokenBudgetManager:
def __init__(self, max_tokens=10000):
self.max_tokens = max_tokens
self.current_usage = 0
def check_budget(self, prompt_tokens, estimated_response_tokens):
total = self.current_usage + prompt_tokens + estimated_response_tokens
if total > self.max_tokens:
raise BudgetExceededError(f"Budget exceeded: {total} > {self.max_tokens}")
return True
def record_usage(self, prompt_tokens, response_tokens):
self.current_usage += prompt_tokens + response_tokensThis mechanism prevents runaway spending by ensuring that even if the agent enters an infinite loop, the cost is capped. The estimated_response_tokens should be derived from the model's typical output length or a conservative upper bound (e.g., 500 tokens) to avoid underestimating costs.
Depth Limits and Recursion Control
While token budgets control cost, depth limits control logical complexity. Depth limits are particularly effective against infinite recursion caused by tool failures.
A depth limit tracks the number of iterations the agent has completed. If the agent exceeds the maximum depth, the loop terminates regardless of whether the task is complete. This is a "fail-safe" rather than a "cost-saver," but it indirectly controls cost by preventing endless loops.
Depth limits should be implemented using a stack or a counter that increments with each iteration. The counter is reset only when the agent reaches a definitive "terminal" state, such as returning a final answer to the user.
class DepthLimit:
def __init__(self, max_depth=10):
self.max_depth = max_depth
self.current_depth = 0
def increment(self):
self.current_depth += 1
if self.current_depth > self.max_depth:
raise RecursionError(f"Max depth {self.max_depth} exceeded")
def reset(self):
self.current_depth = 0It is critical to distinguish between logical steps and API calls. One logical step may involve multiple API calls (e.g., fetching data from three different sources). The depth limit should count logical steps, not individual API calls, to allow for complex reasoning within a single iteration.
Kill Switches and Circuit Breakers
Kill switches are reactive mechanisms that terminate the agent loop when specific error conditions are met. Unlike budget and depth limits, which are proactive, kill switches respond to anomalies.
Common scenarios for kill switches include:
- Repeated Tool Errors: If the same tool fails three times in a row, the agent is likely stuck in a loop. A kill switch terminates the loop and returns an error message.
- Invalid Tool Arguments: If the agent consistently generates invalid arguments for a tool, it may be misconfigured. A kill switch prevents further wasted tokens.
- Human Intervention: In production systems, a kill switch may be triggered by a human operator via an admin dashboard.
The implementation of a kill switch involves monitoring the agent's history for patterns. For example, a sliding window of the last N iterations can be analyzed for repeated errors.
class KillSwitch:
def __init__(self, max_errors=3):
self.max_errors = max_errors
self.error_count = 0
self.last_error_tool = None
def record_error(self, tool_name):
if tool_name == self.last_error_tool:
self.error_count += 1
else:
self.error_count = 1
self.last_error_tool = tool_name
if self.error_count >= self.max_errors:
raise LoopTerminatedError(f"Tool {tool_name} failed {self.max_errors} times")Integration and Tradeoffs
Combining these mechanisms creates a robust cost control framework. The agent loop should check all constraints before each iteration:
- Check depth limit.
- Check token budget.
- Check kill switch conditions.
If any constraint is violated, the loop terminates. The agent should return a structured error message indicating which constraint was violated, allowing the user or upstream system to handle the failure appropriately.
There are tradeoffs to consider. Aggressive token budgets may force the agent to truncate its reasoning, leading to lower-quality outputs. Strict depth limits may prevent the agent from completing complex multi-step tasks. Kill switches may terminate legitimate but lengthy processes. Therefore, these limits should be tuned based on the specific use case and historical performance data.
Common Pitfalls
Engineers often fall into traps when implementing cost controls. Here are common pitfalls to avoid:
- Setting Budgets Too Low: If the token budget is set arbitrarily close to the expected usage, legitimate complex queries may fail prematurely. Always add a buffer (e.g., 20-30%) above the average usage.
- Ignoring Context Window Growth: Focusing only on output tokens while neglecting the growing input context. As noted, attention complexity scales quadratically with input length. Pruning history or using sliding windows is essential.
- Failing to Handle Kill Switch Errors Gracefully: When a kill switch triggers, the system must handle the abrupt termination cleanly. Returning a generic "System Error" provides no value to the user. Instead, return a specific error code (e.g.,
LOOP_TERMINATED) so the frontend or client can display a meaningful message like "We couldn't complete this task after multiple attempts." - Hardcoding Limits: Setting depth limits or error thresholds in code without external configuration makes tuning difficult. Use feature flags or configuration files to adjust these values based on real-world performance.
Practical Takeaways
To effectively manage agent costs, remember these key principles:
- Use Token Budgets for Financial Caps: Define a hard ceiling on spending per session to protect against runaway token consumption.
- Apply Depth Limits for Logical Safety: Prevent infinite recursion and ensure agents do not get stuck in local minima by limiting the number of logical steps.
- Deploy Kill Switches for Error Handling: Terminate loops early when specific error patterns are detected, saving resources and improving user experience.
- Tune Based on Data: Start with conservative limits and adjust based on historical performance metrics. No single set of limits works for all agent types.
FAQ
How do I determine the right token budget? Start by profiling your agent's average token usage for successful tasks. Set your budget to approximately 1.2x to 1.3x this average. Monitor failures and adjust upwards if legitimate tasks are being cut off, or downwards if costs are excessive.
What happens if a kill switch triggers?
When a kill switch triggers, the agent loop terminates immediately. The system should return a structured error response indicating the reason (e.g., MAX_ERRORS_REACHED). This allows downstream systems or users to decide whether to retry, escalate, or abandon the task.
Can I combine these methods? Yes, combining token budgets, depth limits, and kill switches is the recommended best practice. They provide layered defense: depth limits catch logic errors, kill switches catch operational errors, and token budgets catch cost overruns.
Related posts
Context Engineering Is the New Prompt Engineering
Explore how context engineering optimizes token budgets and context windows, evolving beyond basic prompt engineering for better LLM outcomes.
SGLang's RadixAttention, Explained
An examination of SGLang's RadixAttention mechanism, focusing on prefix caching, radix trees, and throughput optimization for ML infrastructure.
Prompt Caching Across Providers: A Practical Comparison
A practical comparison of prompt caching mechanisms across major AI providers, focusing on cache TTL, cost savings, and prefix matching strategies for backend developers.