AI AI-09.02
The agent loop (ReAct)
An agent is a model in a loop: reason, act with a tool, observe the result, repeat. How the ReAct loop works, when it stops, and how to budget it.
The big idea
In Function calling and tool use the model made one tool call and answered. Many tasks need more: search for fares, notice the date format was wrong, search again, compare, book, confirm. You cannot write that sequence in advance because each step depends on what the last one returned.
So put the model in a loop. On each turn it thinks about the goal and what it knows so far, picks an action, and your code runs it and feeds the result back. Then it thinks again. The loop ends when the model decides it is done, or when you stop it. That is an agentA system in which a model repeatedly chooses actions, such as tool calls, observes their results and decides what to do next until it judges the goal is met or a limit is reached., and the reason, act, observe pattern is called ReActReasoning and Acting: a prompting pattern in which a model interleaves written reasoning steps with actions such as tool calls, and reads each action's result before reasoning again..
It is how you cook an unfamiliar recipe. Read the next step, do it, look at the pan, adjust. You do not plan every stir in advance, and you stop when the dish is ready, or when the smoke alarm goes off.
How it works
- Reason The model reads the goal plus everything so far (the scratchpad) and writes a short thought about what to do next.
- Act It emits a tool call, or a final answer. Your code validates and runs the tool.
- Observe The tool's result, including any error, is appended to the scratchpad so the next thought can use it.
- Check Your code, not the model, checks the stop conditions: finished, step limit, token or time budget, repeated failures.
Reason
Each iteration starts with the model reading the goal and the whole history so far, and writing a short thoughtA short piece of reasoning the model writes before choosing an action, such as 'the search failed because of the date format; retry with an ISO date'.: what it has learned, what is missing, what to try next. Thinking before acting is chain of thought ( Chain of thought and step-by-step reasoning ) applied one step at a time, and it makes the trace readable when you debug. Many current models do this reasoning internally, but the pattern is the same.
Act
Then it chooses an action, which is a tool call exactly as in Function calling and tool use , or a final answer. Your code validates the call and runs it. In the ReAct paper the actions for question answering were just three: search for a Wikipedia page, look up a string in it, and finish with an answer.
Observe
The result goes back into the context as an observationThe result of an agent's action, such as a tool's output or error message, appended to the context for the next reasoning step.. Errors are observations too, and often the most useful ones: "date must be YYYY-MM-DD" lets the model fix its next call. Thoughts change nothing in the world; actions do, and observations are how the model learns what they did.
Check: stopping conditions
The model stops by giving a final answer instead of a tool call. But you cannot rely on that alone, because a model can loop forever: retrying a broken tool, searching for something that does not exist, or never quite satisfied. Your loop needs stop conditions in code:
- Finished: the model returns an answer, ideally checked by a verifier or a test.
- Step limit: a maximum number of iterations, such as 10 or 25, depending on the task.
- Budgets: maximum tokens, cost and wall-clock time per task.
- No progress: the same failing action repeated, or no new information for several steps.
- Hand-off: when stopped early, return what was done and why, or ask a person.
The scratchpad
The scratchpadThe running record of an agent's thoughts, actions and observations, kept in the context so each step can see what came before. Also used for notes or a to-do list the agent maintains. is the agent's working memory: the goal plus every thought, action and observation, kept in the context so the next step can see what was tried. Some agents also keep explicit notes, such as a to-do list they update each iteration, which helps on long tasks. Because the scratchpad lives in the context window, it is also what makes long runs expensive.
Try it
- Run "clean run" with Step. How many iterations did it take, and how many tokens were sent in total compared with the size of the final context?
- Switch to "recovers from an error". What in the first observation let the model fix its call?
- Choose "tool keeps timing out" and press Run to end, first with the repeated-action check on, then off. Which condition stops it each time? Now lower the token budget to 4k with the check off.
The token count grows faster than the context because every model call re-sends the whole history. The same loop in code, with a scripted model in place of an LLM:
# A ReAct loop with three stop conditions: the model finishes, a step limit, and a
# repeated failing action. The "model" is a scripted policy so the example runs offline.
def search_flights(date):
if date != "2026-05-12":
return "error: date must be YYYY-MM-DD"
return "FR 1234 95 dollars; AZ 611 180 dollars"
def hold_fare(flight):
return f"held {flight}, reference H-77"
TOOLS = {"search_flights": search_flights, "hold_fare": hold_fare}
def scripted_model(scratchpad): # stands in for an LLM reading the whole scratchpad
last = scratchpad[-1] if scratchpad else ""
if "error: date" in last:
return "Fix the date format.", ("search_flights", {"date": "2026-05-12"})
if "held" in last:
return "Goal met.", ("finish", {"answer": last})
if "FR 1234" in last:
return "FR 1234 is cheapest. Hold it.", ("hold_fare", {"flight": "FR 1234"})
return "I need fares first.", ("search_flights", {"date": "12 May"})
def run_agent(goal, model, max_steps=6):
scratchpad, seen = [f"Goal: {goal}"], []
for step in range(1, max_steps + 1):
thought, (tool, args) = model(scratchpad)
print(f"{step}. Thought: {thought}\n Action: {tool}({args})")
if tool == "finish":
return args["answer"]
seen.append((tool, str(args)))
if seen[-3:].count(seen[-1]) == 3:
return "stopped: same action 3 times, handing off to a person"
obs = TOOLS[tool](**args)
print(f" Observation: {obs}")
scratchpad += [thought, f"{tool}({args})", obs]
return f"stopped: no answer within {max_steps} steps"
print("Result:", run_agent("Hold the cheapest Oslo to Rome fare on 12 May", scripted_model))
print("\nA model that never adapts:")
print("Result:", run_agent("Same goal", lambda pad: ("Try again.", ("search_flights", {"date": "12 May"}))))Output
1. Thought: I need fares first.
Action: search_flights({'date': '12 May'})
Observation: error: date must be YYYY-MM-DD
2. Thought: Fix the date format.
Action: search_flights({'date': '2026-05-12'})
Observation: FR 1234 95 dollars; AZ 611 180 dollars
3. Thought: FR 1234 is cheapest. Hold it.
Action: hold_fare({'flight': 'FR 1234'})
Observation: held FR 1234, reference H-77
4. Thought: Goal met.
Action: finish({'answer': 'held FR 1234, reference H-77'})
Result: held FR 1234, reference H-77
A model that never adapts:
1. Thought: Try again.
Action: search_flights({'date': '12 May'})
Observation: error: date must be YYYY-MM-DD
2. Thought: Try again.
Action: search_flights({'date': '12 May'})
Observation: error: date must be YYYY-MM-DD
3. Thought: Try again.
Action: search_flights({'date': '12 May'})
Result: stopped: same action 3 times, handing off to a person The first run recovers from the date error and finishes in four steps. The second model never adapts, and the repeated-action check stops it at step three instead of letting it burn through the step limit.
Going deeper
Budgets and cost
If each iteration adds tokens to a context that starts at tokens, then call sends about tokens, and iterations send about tokens in total. That grows with the square of the number of steps. With a 1,500-token start and 380 tokens per step, 3 steps send about 5,600 tokens, but 20 steps send about 102,000. Prompt caching ( Prompt caching and cost control ) cuts the price of the repeated prefix, and compaction or sub-agents keep the context small ( Context engineering ), but the step limit is your first line of defence.
Planning first
A common variant asks the model to write a plan before acting, then executes it step by step, re-planning when an observation contradicts it. A plan makes progress easier to check and helps long tasks stay on track. Pure ReAct adapts better when the next step is unknowable until you see the last result.
When the loop goes wrong
The ReAct paper itself lists failure modes: the model can get stuck repeating the same thoughts and actions, and an uninformative search result can derail the reasoning. Errors also compound: a wrong early observation shapes every later step. That is why Making agents reliable evaluates whole trajectories, not just final answers, and why Workflows vs agents: the patterns argues for fixed workflows whenever the steps are predictable.
Trade-offs
| Option | Wins when | Loses when |
|---|---|---|
| Single tool call | Cheap, fast, predictable | Cannot adapt when one step depends on another's result |
| ReAct loop | Handles open-ended, multi-step tasks and recovers from errors | Cost and latency grow with steps; can loop or drift |
| Plan, then execute | Easier to check progress; fewer aimless steps | Plans go stale; re-planning adds calls |
| Tight step limit | Bounded cost and latency | Hard tasks stop before finishing |
Common mistakes
- No step limit or budget, so one stuck task runs up a large bill.
- Hiding tool errors from the model, so it cannot correct its call.
- Letting the model alone decide when to stop, with no stop conditions in code.
- Returning nothing useful when stopped early; return what was done and why it stopped.
- Using an agent loop for a task with fixed, known steps, where a simple workflow is cheaper and more reliable.
In the wild
Yao et al., 2022 (paper)
ReAct: Synergizing Reasoning and Acting in Language Models (opens in a new tab)The paper prompts a model to interleave written reasoning traces with actions, where thoughts change nothing in the environment and actions return observations. On question answering (HotpotQA) and fact verification (Fever), it acts through a simple Wikipedia API with search, lookup and finish actions, which reduces the hallucination and error propagation seen with chain of thought alone. On the interactive benchmarks ALFWorld and WebShop it beats imitation and reinforcement learning methods by 34 and 10 points of absolute success rate, prompted with only one or two examples.
Check yourself
-
What are the three parts of one ReAct iteration?
Show answer
B. Reason, act, observe The model writes a thought, takes an action such as a tool call, and reads the observation before the next thought.
-
An agent keeps calling the same search, which times out every time. What should stop it?
Show answer
B. Stop conditions in your code: a step limit, a budget, and a repeated-failure check Never rely on the model alone to stop. Code-level limits bound the cost and turn a stuck run into a clear hand-off.
-
Each step adds about 400 tokens of history. Why does total cost grow faster than the number of steps?
Show answer
B. Each model call re-sends the whole growing history, so tokens grow roughly with the square of the steps Call i carries all earlier steps, so the sum over n calls has an n squared term. Caching and compaction reduce it.
-
The tool returns an error message. What should your loop do with it?
Show answer
B. Append it as the observation so the model can adjust Errors are information. A clear error often tells the model exactly how to fix the next call.
Recap
- An agent is a model in a loop: reason, act, observe, until done or stopped.
- Observations, including errors, are how the model learns what its actions did.
- Stop conditions live in code: finish, step limit, token, cost and time budgets, no-progress checks.
- The scratchpad is working memory, and re-sending it makes cost grow roughly with the square of the steps.
- Use a loop when each step depends on the last; use a fixed workflow when the steps are known.