9.2 Agent loops: ReAct, planning, reflection

Standard applied practice as of August 2026 — the least settled area in this subject, so the topic's resources carry the current state

What this is and why it exists

An agent loop is about forty lines of code, and writing one without a framework teaches you exactly what every framework is doing on your behalf — the prompt scaffold, the parsing, the state, and the termination logic. That last one is the part frameworks hide most effectively and the part that costs money when it is wrong: a loop with no stopping rule runs until something else stops it, and that something is usually a budget.

The vocabulary

  • Loop — repeating think, act, observe until a stopping condition holds.
  • Scratchpad — the running transcript of thoughts, actions and observations.
  • Observation — the result of a tool call, fed back into the next step.
  • Plan — a sequence of intended steps produced before acting.
  • Reflection — the agent reviewing and revising its own output.
  • Termination condition — the rule that ends the loop successfully.
  • Step limit — the hard cap that ends it regardless.
  • Stuck detection — noticing that progress has stopped.

The mental model

The core loop is short enough to hold in your head. Give the model the task, the available tools and the transcript so far. It responds with either a final answer or a tool call. If it is a tool call, run the tool, append the result to the transcript, and go round again. If it is an answer, stop. That is the reason-act-observe pattern, it is the simplest agent there is, and it is enough for a surprising number of tasks — most of what people build with elaborate frameworks is this loop with better prompts.

Three pieces of engineering sit inside those few lines, and they are what you learn by writing it.

The scaffold: how the tools are described, how the transcript is formatted, how the model is asked to indicate a tool call rather than an answer. Use the structured tool-calling interface where it exists, since it removes the parsing problem entirely, and where it does not, the parsing is yours and it will be the flakiest part of the system.

The state: what goes into the next request. The naive answer — everything so far — is what makes step twenty cost many times step two, and what eventually overflows. Deciding what to keep is the memory topic.

The termination logic, which is the topic's point and gets its own section below.

Plan-and-execute produces a plan first and then carries it out. The advantages are real: a plan is inspectable before anything happens, it can be shown to a person for approval, steps can be parallelised where they are independent, and the agent is less likely to wander. The weakness is equally real — a plan made before seeing any results copes badly with surprises, and the interesting parts of real tasks are surprises. The usual repair is to allow replanning when a step fails or returns something unexpected, which recovers most of the flexibility and reintroduces some of the unpredictability.

Worth knowing plainly: decomposing a task into steps is itself something models are frequently poor at. Plans come back with steps that assume information not yet gathered, steps in an impossible order, or a step that is the whole problem restated. Where the decomposition is stable across tasks, write it yourself and you have a chain — which is the previous topic's advice arriving again.

Reflection has the agent review and correct its own work, and the honest account is mixed. It genuinely helps where there is an external signal to react to: code that failed a test, output that failed validation, a search that returned nothing. There the critique is grounded in something real, and the correction is usually an improvement.

Where there is no external signal, it is much weaker. Asked to critique an answer with nothing to check against, a model will find something to say, because that is what it was asked for — and it will then confidently revise a correct answer into a worse one. Measure it rather than assuming: run your evaluation with reflection on and off. It costs at least twice as much per task, and it should have to earn that.

Now termination, which is the first thing to write, not the last.

Four conditions, and a loop needs all of them. Success: the agent produced an answer satisfying the contract — validated against a schema, not merely "it stopped talking". Step limit: a hard maximum, applied regardless of state, because a loop without one is unbounded spending. Budget limit: a maximum token or cost total per task, checked every iteration, since steps and cost are not proportional when the transcript grows. Stuck detection: the agent is looping without progress.

That last one deserves its own attention, because an agent that cannot tell it is stuck will happily burn its budget retrying forever. The characteristic patterns are recognisable in code. The same tool called with the same arguments twice in a row. The same error returned repeatedly. A cycle of two tools calling back and forth. No new information entering the transcript across several steps. Detect these by comparing recent steps and stop when they match — a few lines, and it is what turns a runaway into a caught failure.

And decide what happens when a limit is reached, because stopping silently is the worst option. Return the partial work with a clear statement that the limit was hit, log the full transcript for diagnosis, and give the caller something to act on. The cost topic develops this into a proper degradation path.

Two habits worth carrying from writing your own loop. Log every step — the request, the model's decision, the tool call, the observation — because a run you cannot replay is a failure you cannot diagnose. And test the loop with a tool that fails, one that returns nonsense, and one that is slow, since the happy path is not the thing that needs testing and every real run meets at least one of those.

What you should now be able to explain or do

Write the reason-act-observe loop without a framework, naming the three pieces of engineering inside it. Say what plan-and-execute buys and where it fails, and when to write the decomposition yourself. State honestly when reflection helps and when it makes things worse, and measure it. Implement all four termination conditions. Detect stuck loops by comparing recent steps. Define what happens when a limit is reached. Log every step and test with failing, nonsensical and slow tools.

Check yourself

The scaffold — how tools and the transcript are presented and how a tool call is signalled; the state — what carries into the next request; and the termination logic. Frameworks hide all three, and the last one costs money when it is wrong.

When something surprising happens, because the plan was made before any results existed — and the interesting parts of real tasks are surprises. Allowing replanning on failure recovers most of the flexibility.

When there is no external signal to check against. Asked to critique with nothing to verify, a model finds something to say and confidently revises a correct answer into a worse one. With a failing test or a validation error, it helps.

Success against a validated contract; a hard step limit; a budget limit checked every iteration; and stuck detection. A loop needs all four, and they are written first.

Compare recent steps — the same tool with the same arguments twice, the same error repeating, two tools calling back and forth, or no new information entering the transcript. A few lines of comparison turns a runaway into a caught failure.

Go deeper

Back to Agent loops: ReAct, planning, reflection: work through the checklist