Circuit Breakers for Agentic AI Workflows: Controlling Blast Radius in Autonomous Code Review A developer has proposed applying circuit breaker patterns to agentic AI code review workflows to limit the blast radius of autonomous agents that can interpret, execute, and commit code. The approach uses a finite state machine to gate agent actions, tracking failure metrics such as token budget exhaustion, duplicate actions, and security guardrail violations, and falls back to human review when thresholds are breached. Originally published on tamiz.pro https://tamiz.pro/insights/circuit-breakers-agentic-ai-workflows-code-review . The rapid adoption of agentic AI in software engineering has introduced a new class of operational risks: autonomous agents that can interpret, execute, and commit code. While powerful, these systems lack the inherent safety rails of traditional deterministic software. When an LLM agent makes a cascading error in a code review pipeline, the "blast radius" can expand from a single file to a corrupted build, a failing deployment, or even a security vulnerability. This article dissects the architectural necessity of applying Circuit Breaker patterns to agentic workflows, specifically focusing on AI-driven code review. We will move beyond simple retry logic to explore state-machine-based fail-safes that isolate failures, prevent resource exhaustion, and enforce human-in-the-loop gating when confidence levels drop below operational thresholds. Traditional code review tools are deterministic: regular expressions, static analyzers like ESLint or SonarQube , and linters produce predictable outputs for predictable inputs. However, agentic workflows powered by Large Language Models LLMs are probabilistic. An agent might: git commit or trigger CI/CD pipelines that have cascading financial or security implications. In a standard microservices architecture, a circuit breaker opens when a service fails N times in a rolling window, stopping traffic to that service to allow it to recover. In an agentic AI workflow, the "service" is the agent's decision-making capability. The "traffic" is the sequence of actions it takes. If we don't break the circuit, a buggy prompt engineering update or a specific edge-case PR can trigger an autonomous agent to continuously generate bad code, exhaust API tokens, or introduce subtle security flaws into the main branch. In traditional SRE, blast radius refers to the scope of impact when a component fails. In AI engineering, it is multidimensional: We define our circuit breaker not as a simple flag, but as a finite state machine FSM that gates agent actions. The states are: What constitutes a "failure" in an agentic review? We must move beyond HTTP 500 errors. Key metrics for opening the circuit include: eval , hardcoded secrets . Rather than hardcoding checks into every agent prompt, we wrap the agent's execution loop in a CircuitBreakerMiddleware . This middleware intercepts every action the agent requests to perform. python class AgenticCircuitBreaker: def init self, failure threshold=5, recovery timeout=300, token budget=10000, security guardrail=None : self.failure threshold = failure threshold self.recovery timeout = recovery timeout self.token budget = token budget self.security guardrail = security guardrail self.state = "CLOSED" self.failure count = 0 self.last failure time = None self.total tokens used = 0 self.consecutive duplicate actions = 0 async def execute action self, agent, action: AgentAction, context: ReviewContext : """ Guts the agent's action. If circuit is OPEN, blocks and triggers fallback. """ if self.state == "OPEN": if self. should attempt half open : self.state = "HALF-OPEN" logger.info "Circuit Breaker: Transitioning to HALF-OPEN for test" else: raise CircuitOpenError f"Circuit is OPEN. Last failure: {self.last failure time}. " f"Falling back to human review queue." try: 1. Pre-Flight Check: Security Guardrail if self.security guardrail: risk score = await self.security guardrail.evaluate action if risk score 0.8: High risk self. record failure "Security Guardrail Flag" raise SecurityViolationError action 2. Token Budget Check estimated tokens = self. estimate tokens action if self.total tokens used + estimated tokens self.token budget: self. record failure "Token Budget Exhausted" raise TokenExhaustionError 3. Execute the Action e.g., LLM call, git commit, test run result = await agent.execute action 4. Post-Flight Check: Detect Infinite Loops if result.is duplicate of previous: self.consecutive duplicate actions += 1 if self.consecutive duplicate actions = 2: self. record failure "Infinite Loop Detected" raise InfiniteLoopError else: self.consecutive duplicate actions = 0 self. record success return result except Exception as e: self. record failure str e raise e def record failure self, reason : self.failure count += 1 self.last failure time = time.time if self.failure count = self.failure threshold: self. open circuit logger.warning f"Circuit Breaker Failure: {reason}. Count: {self.failure count}" def record success self : self.failure count = 0 self.state = "CLOSED" def should attempt half open self : if self.state == "OPEN": if time.time - self.last failure time self.recovery timeout: return True return False def open circuit self : self.state = "OPEN" logger.error f"Circuit Breaker OPENED after {self.failure count} failures." A major cause of "cognitive blast radius" is context pollution. If an agent reads a 5,000-line file, it may hallucinate dependencies. To mitigate this, the circuit breaker should also enforce Context Sanitization . Before the agent begins its review, a preprocessing step chunks the codebase. The breaker tracks which chunks have been injected into the agent's window and which chunks have triggered context overflow or semantic drift alerts. If the drift metric exceeds a predefined threshold—indicating the agent is losing focus on the actual code structure—the breaker trips the Context Limiter , truncating the prompt history and re-injecting a high-fidelity summary of the relevant architectural layers. This prevents the "lost in the middle" phenomenon where critical logic buried thousands of tokens away is ignored during the review. Static thresholds are insufficient for agentic systems. A monolithic review of a core banking service requires different safety margins than a pull request touching a static documentation generator. We implement an adaptive controller that adjusts breaker parameters based on the repository's historical volatility and the agent's confidence metrics. The core logic resides in a lightweight state machine. Here is a Python implementation using dataclasses and standard library components, designed to be drop-in compatible with LangChain or LlamaIndex agent frameworks. python import time from enum import Enum from dataclasses import dataclass, field from typing import Optional, List, Callable import threading class BreakerState Enum : CLOSED = "closed" OPEN = "open" HALF OPEN = "half open" @dataclass class BreakerConfig: failure threshold: int = 5 recovery timeout: float = 60.0 success threshold: int = 3 context drift limit: float = 0.85 85% drift triggers trip confidence floor: float = 0.60 Below this, count as failure class AgenticCircuitBreaker: def init self, config: BreakerConfig = None : self.config = config or BreakerConfig self.state = BreakerState.CLOSED self.failure count = 0 self.last failure time = 0.0 self.half open calls = 0 self. lock = threading.RLock self.history: List dict = def trip self, reason: str : """Transitions breaker to OPEN state.""" with self. lock: self.state = BreakerState.OPEN self.last failure time = time.time self.failure count = 0 self.history.append { "timestamp": self.last failure time, "state": "OPEN", "reason": reason } In a production system, emit a telemetry event here def attempt reset self : """Transitions from OPEN to HALF OPEN if timeout has elapsed.""" with self. lock: if self.state == BreakerState.OPEN: if time.time - self.last failure time = self.config.recovery timeout: self.state = BreakerState.HALF OPEN self.half open calls = 0 self.history.append { "timestamp": time.time , "state": "HALF OPEN", "reason": "Recovery attempt initiated" } return True return False def execute self, agent call: Callable, args, kwargs : """ Wraps the agent's execution step. Args: agent call: The function representing the agent's next step. args, kwargs: Arguments passed to the agent. Returns: The result of the agent call if successful. Raises CircuitBreakerOpenError if the breaker is tripped. """ Check if in OPEN state and eligible for HALF OPEN if self. attempt reset and self.state == BreakerState.HALF OPEN: In HALF OPEN, we allow limited traffic if self.half open calls = self.config.success threshold: self.state = BreakerState.CLOSED self.half open calls = 0 else: self.half open calls += 1 if self.state == BreakerState.OPEN: raise CircuitBreakerOpenError f"Breaker is OPEN. Last trip: {time.ctime self.last failure time }" try: Execute the agent step result, metrics = agent call args, kwargs Evaluate metrics for soft failures if metrics.get "confidence", 1.0 < self.config.confidence floor: self. handle soft failure "Low confidence score" elif metrics.get "context drift", 0.0 self.config.context drift limit: self. handle soft failure "High context drift detected" else: self. handle success return result except Exception as e: self. handle hard failure str e raise def handle soft failure self, reason: str : with self. lock: self.failure count += 1 self.history.append { "timestamp": time.time , "state": self.state.value, "reason": reason, "failure count": self.failure count } if self.failure count = self.config.failure threshold: self. trip reason def handle hard failure self, reason: str : with self. lock: Hard failures exceptions trip the breaker immediately or contribute more heavily to the count depending on strategy. Here we use a 1-strike policy for critical errors. self.failure count += 1 self.history.append { "timestamp": time.time , "state": self.state.value, "reason": f"Hard Failure: {reason}", "failure count": self.failure count } if self.failure count = 1: Aggressive for autonomous agents self. trip reason def handle success self : with self. lock: self.failure count = 0 if self.state == BreakerState.HALF OPEN: Successful call in half-open state progresses recovery pass Logic handled in execute for state transition check class CircuitBreakerOpenError Exception : pass When the breaker trips, the workflow cannot simply halt; it must degrade gracefully. In an agentic code review pipeline, degradation involves shifting from autonomous generation to Supervised Verification . OPEN , the orchestrator pauses the autonomous loop. It packages the last N interactions, the specific code diff, and the reason for tripping e.g., "High context drift" into a structured handoff payload. This payload is sent to a human reviewer's queue. The agent is effectively "parked." HALF OPEN state, the orchestrator does not retry the original complex task. Instead, it slices the review into smaller, non-overlapping chunks. For example, instead of reviewing an entire UserSession class, it reviews only the validate token method. This reduces the context load and allows the agent to "warm up" its performance metrics before the breaker potentially re-closes. A circuit breaker without telemetry is a black box. Every state transition must be logged to a time-series database. Key metrics to track include: recovery timeout . context drift scores against token count. This often reveals a non-linear relationship where drift spikes exponentially past 40% of the model's context window, allowing you to set hard cap limits on chunk size. Agentic AI systems are powerful, but they are inherently stochastic. They do not fail gracefully; they fail confusingly. By wrapping these autonomous loops in circuit breakers, we shift the safety model from "preventing errors" which is impossible with LLMs to "containing errors." The key insight is that the breaker is not just a failure detector; it is a context governor . It enforces hygiene by forcing context sanitization and preventing the accumulation of hallucinated state. As we build more complex multi-agent systems, where one agent reviews another's code, these breakers become the immune system of the workflow. They allow the system to be aggressive in its exploration while remaining robust in its failure modes. Start small. Implement the breaker around your most critical, least-automated agent. Monitor the trip reasons. You will likely discover that the "failures" are not actually code errors, but context management issues that can be solved by better chunking strategies, not better prompts. The breaker will teach you where the agent's cognitive limits lie, allowing you to design workflows that respect those boundaries rather than fighting them.