Preventing Infinite Loops in AI Agents
Most AI agent infinite loop prevention fails because it guards the wrong signal. Here's a loop that spins forever, why the obvious fix doesn't work, and the check that actually stops it.
You are a research agent. Use search(query) to gather facts, then answer the user's question thoroughly. Keep searching until you have enough to give a complete answer.
Here's a number that should worry anyone running agents in production: a single agent stuck in a loop can generate more API calls in ten minutes than your entire user base does in a normal day. Not because it's doing anything useful — because it's asking the same question, getting the same answer, and asking again. AI agent infinite loop prevention is the difference between a bad afternoon and a bad invoice, and the surprising part is how often the standard defense doesn't defend anything. I've seen a single stuck agent quietly rack up four figures overnight while every dashboard read "healthy" — because a busy agent and a productive one look identical until you check whether it's actually converging.
An infinite loop in an agent almost never looks like a crash. It looks like productivity — the agent is busy, tokens are flowing, tool calls are firing. It just never converges. And the most common guard against it, a max-step cap, treats the symptom (too many steps) while ignoring the disease (no forward progress). Let's tear a real one apart.
Before: The Weak Prompt
This is a research agent, simplified to the shape that loops:
You are a research agent. Use search(query) to gather facts,
then answer the user's question thoroughly.
Keep searching until you have enough to give a complete answer.What this does: tells the agent to keep searching until it has "enough" — a threshold the model defines subjectively, with no external signal for when to stop.
Give it a hard question and watch: search, read, "I need a bit more context," search again — often re-running near-identical queries because "enough" never feels reached. The loop has no floor. The model is the judge of its own completion, and an anxious model never rests.
Why It Fails
The prompt outsources the stop decision to the model's feelings. "Enough" is not a measurable condition; it's a vibe, and the vibe drifts. On an easy question the agent stops fine. On a hard one — exactly when you need it to be reliable — it spirals, because "not enough yet" is always a defensible next thought.
The obvious fix is a step cap:
max_steps=20There are actually two flavors of loop, and they need different detectors. The exact-repeat loop calls the same tool with the same arguments — trivial to catch by hashing the call. The semantic spin is nastier: the agent rephrases the same failing search five different ways, so no two calls are identical, yet no new information arrives. Hashing catches the first and misses the second entirely. That's why progress — new facts learned — is the more reliable signal than repetition: it catches both flavors, because both share one trait, they've stopped teaching the agent anything new.
⚠️ Common mistake: Treating a step cap as loop prevention. A cap limits damage; it doesn't detect the failure. An agent that hits its cap on most hard questions isn't protected — it's silently failing at full cost, and your logs just say "step_limit" every time with no hint that the real problem is a stop condition the model can never satisfy.
⚡ Pro tip: Before adding any limit, ask what observable thing changes when the agent makes progress. If nothing does — no new file, no new fact, no state change — you can't detect a loop, only time it out. Making progress observable is step zero of loop prevention.
After: The Improved Prompt
Two changes: give the model a concrete stop definition, and back it with code that watches for real progress.
You are a research agent. Use search(query) to gather facts.
STOP when you can name 3 distinct sources that answer the question,
OR when a new search returns no facts you didn't already have.
Track what you know in a running list. Before each search, state
what specific gap it fills. If it fills no gap, do not search — answer.What this does: replaces the subjective "enough" with two objective stop conditions and forces the model to justify each search by the gap it closes, so a search that adds nothing becomes a signal to finish rather than to continue.
[object Object], ,[object Object],(,[object Object],):
,[object Object], ,[object Object],(after.known_facts) > ,[object Object],(before.known_facts)
,[object Object], ,[object Object], made_progress(prev, cur):
stall += ,[object Object],
,[object Object], stall >= ,[object Object],:
,[object Object], finalize(cur) ,[object Object],
,[object Object],:
stall = ,[object Object],What this does: counts consecutive searches that add no new facts and forces a finish after two — turning "no new information" from an excuse to keep going into a hard stop.
Breaking Down Each Element
Three parts do the work.
The objective stop condition ("3 distinct sources") gives the model a target it can actually reach, replacing the bottomless "enough." The gap justification ("state what gap this search fills") makes the model's reasoning inspectable and often prevents the redundant search before it happens. And the progress detector in code is the safety net: even if the model ignores its own rules, two fact-free searches end the run.
Belt and suspenders. The prompt discourages spinning; the code makes spinning impossible. You need both, because prompts influence and code enforces, and loop prevention is a place you want enforcement.
There's a hierarchy worth remembering. The prompt is your first line — cheap, but the model can ignore it. The progress detector is your second — reliable, but task-specific. And a hard token ceiling is your last — crude, but absolute. Real prevention layers all three, cheapest-but-weakest to strongest-but-crudest, so a loop has to defeat every layer to survive. Most agents ship with only the crude last layer and then wonder why loops still cost them money.
⚡ Pro tip: Define progress in terms of new information, not activity. An agent re-reading a page it already read is active but not progressing. If your detector counts activity, it'll never fire; if it counts new facts, it fires exactly when the agent stops learning.
Variations for Different Contexts
The same pattern adapts across roles.
A legal researcher's agent defines progress as new citations found, and stops after two searches yield only citations already in its list. A security analyst's triage agent defines progress as new indicators-of-compromise surfaced, stopping when the well runs dry rather than when a step counter expires. A product manager's competitive-research agent caps distinct sources rather than searches, so ten searches against one source count as one unit of progress and don't fool the detector into continuing.
A customer-support lead's answer-drafting agent defines progress as the draft changing meaningfully between turns, stopping when two consecutive revisions barely differ — polishing that stops improving is its own quiet kind of loop. Same skeleton, four definitions of "progress" — each matched to what "learning something new" means in that domain.
⚡ Pro tip: For agents that legitimately need to repeat an action — paginating results, polling a job — whitelist that specific pattern in your loop detector. Otherwise honest repetition trips the same wire as a true infinite loop, and you'll suppress useful work chasing a phantom.
Save and Reuse This
The progress-detector-plus-objective-stop pattern is not research-specific. Any agent that "keeps going until done" needs a code-level definition of done, or it will eventually spin. Swap the definition of progress — new facts, new files, new citations, new indicators — and the machinery is identical.
One more reason to standardize this: loop bugs are invisible in testing and expensive in production. They rarely trigger on the short, easy tasks you test with; they trigger on the long, hard, real ones — at 3am, at scale, on someone else's budget. A prevention pattern applied by default to every agent is the only way to make sure the one agent that would have spun is the one that doesn't. Opt-in safety is the safety you forget to add.
⚡ Pro tip: Cap the cost, not just the steps, as your final backstop. Even good progress detection can miss an exotic loop; a hard token ceiling underneath everything guarantees no single run can ever exceed a known dollar amount, whatever creative way it finds to spin.
I keep the
made_progressContinue Reading
Save the prompts from this post
PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.
