AI Agent Circuit Breakers: Stop Runaway Tool Loops in Production
Retries keep ordinary software alive. In tool-using AI agents, they can multiply side effects and cost. Circuit breakers put a hard boundary around failure.
An AI agent gets a timeout while updating a ticket. It retries. The first request actually succeeded, so the second creates a duplicate. The agent notices two tickets, tries to merge them, loses context, and starts another tool loop.
Traditional retry logic assumes a failed response often means a failed operation. Tool-using agents cannot make that assumption. A timeout may hide a successful side effect, a model may reinterpret the goal between attempts, and each retry can consume money or change external state.
A circuit breaker gives the system permission to stop.
The Failure Mode Is Larger Than an API Error
Agent failures usually span three layers:
- The provider layer can time out, rate-limit, or return malformed output.
- The reasoning layer can choose the wrong tool, repeat a completed action, or oscillate between plans.
- The side-effect layer can create duplicate records, send repeated messages, or spend beyond the user’s intent.
A useful breaker watches all three. It should not only count HTTP 500 responses. It should count repeated semantic actions, uncertain side effects, cost growth, elapsed time, and failed validation.
The unit of protection is the user task, not just the network call.
Define a Small State Machine
Use the familiar closed, open, and half_open states, but scope them carefully.
In the closed state, actions are allowed while budgets and validation remain healthy. The breaker opens when a threshold is crossed. In the open state, risky tools are blocked and the agent must return a structured stop reason. After a cooldown or an explicit operator decision, a half-open probe can test whether the dependency or plan is safe again.
type BreakerState = "closed" | "open" | "half_open";
type TaskBudget = {
maxToolCalls: number;
maxRepeatedAction: number;
maxCostUsd: number;
deadlineMs: number;
};
function shouldOpen(metrics: Metrics, budget: TaskBudget) {
return (
metrics.toolCalls >= budget.maxToolCalls ||
metrics.repeatedAction >= budget.maxRepeatedAction ||
metrics.costUsd >= budget.maxCostUsd ||
Date.now() >= budget.deadlineMs ||
metrics.uncertainSideEffects > 0
);
}
The final condition is intentionally strict. If the system cannot determine whether an external write succeeded, another write is not a safe probe.
Fingerprint Actions Before Execution
Detecting a loop requires more than comparing tool names. Normalize the intended operation into a semantic fingerprint:
tool=send_email
recipient=customer-1842
template=renewal_notice
business_key=renewal-2026-08
Hash that representation and store it in task state. If the same action reappears without new evidence, increment the repetition counter. For mutating tools, attach an idempotency key derived from the business key whenever the destination supports it.
Arguments need canonicalization. Sort object keys, strip volatile timestamps, and avoid including the model’s prose explanation in the fingerprint. You want two equivalent intentions to collide even if the model phrases them differently.
Separate Read and Write Budgets
Five repeated searches are annoying. Five repeated refunds are an incident. Use tool risk classes:
- Read-only tools can have a generous count with a time and cost ceiling.
- Reversible writes need tighter limits and post-action verification.
- Irreversible or human-facing actions should require an explicit authority check and often approval.
Every write should move through plan -> authorize -> execute -> verify -> record. If verification fails, mark the result unknown, open the write breaker, and investigate with a read-only status check. Do not silently repeat the mutation.
Make the Stop Useful
An open breaker should produce an operator packet, not “something went wrong.” Include the task ID, last confirmed state, attempted action fingerprint, external identifiers, budget counters, and the exact condition that opened the breaker. Mask secrets and avoid dumping raw prompts containing private data.
The agent can still do safe work after a write breaker opens. It may summarize completed steps, query status endpoints, or draft a recovery plan. The boundary is around actions that could compound the failure.
Test the Breaker With Adversarial Scenarios
Inject timeouts after the server commits a write. Return malformed success payloads. Alternate two tools so a simple identical-call detector misses the loop. Let the model generate slightly different arguments for the same business action. Simulate a provider outage after nine successful steps.
Then verify three outcomes: the breaker opens before material damage, the task state remains understandable, and resumption does not repeat completed work.
The best agent is not the one that always keeps going. In production, reliability means knowing when continued autonomy has become the risk.
Sources
> Want more like this?
Get the best AI insights delivered weekly.
By subscribing, you agree to our Privacy Policy. You can unsubscribe at any time.
> Related Articles
AI Agent State Snapshots: Resume Long Jobs Without Repeating Side Effects
Durable agents need more than chat history. Snapshot plans, tool results, permissions, and idempotency state so a crash can resume safely instead of replaying the world.
Embedding Model Migration: Change Vectors Without Breaking Search
Embedding upgrades change the geometry of your index. Use versioned vectors, dual writes, shadow queries, and measured cutover instead of mixing incompatible representations.
LLM Request Coalescing: Stop Paying Twice for the Same Answer
When identical LLM requests arrive together, single-flight execution can collapse them into one upstream call—if cache keys, streaming, failures, and tenant boundaries are designed correctly.
Tags
> Stay in the loop
Weekly AI tools & insights.