The agent loop (ReAct)
The core cycle of every agent: model decides, host runs a tool, result is appended, repeat until a final answer or a stop condition.
The agent loop is the repeating cycle that turns a language model into an AI agent. Each pass, the model looks at the goal and everything so far and picks an action, usually a tool call. The program runs it and adds the result to what the model will see next.
The loop ends when the model says it is finished, or when a safety limit trips — a maximum number of steps, a time limit or a budget. Those limits are the Stop conditions & step budgets.
Driving to an unfamiliar address with a map app: check where you are, take the next turn, check again — and pull over to ask after too many wrong turns.
Letting the model be the only thing that ends the loop. A confused agent can retry the same failing call for hundreds of turns; caps must be enforced by the host.
The bare loop is ten lines: while True: r = model(ctx); if not r.tool_calls: return r; ctx += [r, run(r.tool_calls)]. It descends from ReAct (Yao et al., 2022), which interleaved reasoning traces and actions; current models emit reasoning and tool calls natively, including several parallel calls per turn.
Production loops add what the bare version lacks: caps on turns, tokens, wall-clock and $; detection of repeated identical calls; tool errors returned as results so the model can recover; context management (trim or compact tool output as the Context window fills); a checkpoint per turn for Durable execution & checkpointing; and pauses for Human in the loop approval. Every turn re-sends the whole history, so turn t costs prefix + (t−1) × Δ input tokens and the run total grows quadratically — Prompt caching with a moving breakpoint turns most of that into 0.1× reads.
Host-enforced caps: 25 turns, 300k cumulative tokens, 10 min, $1. Abort after the same tool+arguments repeats 3 times or 3 consecutive tool errors. Tool errors returned as is_error results with a fix hint. Cache breakpoint moved to the latest turn each call. Checkpoint after each turn. Distinct stop_reason logged on every exit.
Internal-wiki agent answering "Which on-call rotation owns the payments DB?" Turn 1 search_wiki("payments database owner") → 5 hits (1.8k tokens). Turn 2 get_page("svc-catalog/payments-db") → owner team pay-infra (2.2k tokens). Turn 3 get_oncall(team="pay-infra") → this week's primary. Turn 4 answers. Input per turn grew 6k → 7.9k → 10.2k → 11.1k; total 35k tokens, stop_reason final_answer at 4 of a 20-turn cap.
If asked to sketch the loop, write it in five lines and then add, unprompted, the four things that make it production-grade: caps, repeat detection, errors-as-results, and a checkpoint per turn. Say why: "the model deciding to stop is the success path, never the safety path."
The likely follow-up is cost: show the per-turn input formula and that caching the stable prefix plus history is the first lever.
Numbers worth knowing
- Input at turn t
- prefix + (t−1) × Δhistory kept verbatim; Δ = tokens added per turn
- Cumulative input over T turns
- T·prefix + Δ·T(T−1)/28k prefix, Δ 1.5k, T 20 → 445k tokens
- Default turn cap in OpenAI Agents SDK
- max_turns = 10as of Oct 2026; raises MaxTurnsExceeded
How to decide
| When | Do this |
|---|---|
| Successful runs need ≤3 tool calls in a known order | Don't loop; write a chain. |
| Runs routinely exceed ~20 turns | Add compaction and trim tool outputs before raising caps. |
| A turn can trigger an irreversible action | Pause the loop for approval and checkpoint before resuming. |
Cost maths
Cumulative input = T·P + Δ·T(T−1)/2. With P = 8k, Δ = 1.5k, T = 20: 160k + 285k = 445k tokens → $1.34 at $3 / M (illustrative, Oct 2026), plus 20 × 300 output tokens × $15 / M = $0.09. With a moving cache breakpoint, ≈ 36.5k tokens are cache writes (1.25×) and ≈ 408.5k are reads (0.1×): $0.137 + $0.123 = $0.26 input, ≈ 5× cheaper. Doubling T to 40 roughly triples uncached input (≈ 1.49M), which is why loops need caps on tokens, not just turns.
Operating it
- Median turns per successful run rises 50% after a model or prompt change
- Cumulative tokens per run > 50% of the context window
- Repeat-call aborts above 2% of runs
- Turns per run p50/p95 (alert when p95 > 2× baseline)
- Repeat-call aborts (alert > 2% of runs)
- Cumulative input tokens per run p95 (alert at 60% of context window)
- Cache-read share of input tokens (alert if it drops below 70%)
When it goes wrong
A developer-docs agent's monthly bill tripled with no traffic increase.
Cost-per-run p99 alert; traces showed runs of 200+ turns all calling fetch_url on the same URL.
A docs page started returning 429s; the tool returned an empty string instead of an error, so the model kept retrying, and the loop's only cap was a 300-turn limit.
Tool returns is_error with "rate limited, retry after 60 s"; repeat detector aborts after 3 identical calls; added a $1 and 10-minute cap per run.
Related terms
Where it shows up
Sources
- ReAct: Synergizing Reasoning and Acting in Language Models — Yao et al., 2022paper
- Building effective agents — Anthropic (Schluntz & Zhang), 2024blog
- Prompt caching — Anthropic, 2026docs
- Running agents (max_turns) — OpenAI Agents SDK, 2025docs
Check yourself
Three questions. Every option is explained once you answer.