Track
Reason · Act · Observe · Repeat
You ask an LLM a question, it answers — that's a single turn. Now imagine you want the LLM to do something more involved: look up information, run a calculation, check a database, then synthesize everything into a final answer. One call won't cut it. You need a loop.
The ReAct (Reasoning + Acting) loop is the simplest pattern that makes this work. The agent thinks about what to do next, picks an action, executes it, observes what happened, and repeats — until it has enough information to answer. This is the foundation every agentic system is built on. Interviewers frequently ask candidates to design or debug one of these loops because it tests whether you understand how model-driven control flow actually works, not just how to call an API.
At its core, a ReAct loop has three phases that repeat: Thought → Action → Observation.
The LLM reasons about the current state — what it knows, what it needs, what to do next. It produces a structured command: a tool name and arguments. The tool's result comes back and gets appended to the conversation.
This loop continues until the agent decides it has enough information and emits a final answer instead of an action.
Without a loop, an LLM can only answer from its training data. It can't look things up, run code, or interact with APIs. A loop turns the LLM from a static knowledge base into an active problem-solver.
Every agent framework — LangChain, CrewAI, AutoGPT, OpenAI Assistants — runs some variant of this loop. The details differ, but the core pattern is identical: think, act, observe, repeat.
Every agent loop needs at least one stop condition; otherwise it runs forever, burning tokens and API credits. The most fundamental condition is Final Answer detection — the agent emits a structured marker like "Final Answer:" and the loop exits. Without this, the agent may keep taking actions even after it has everything it needs.
Production loops layer on additional hard budgets. A maximum step count (MAX_STEPS) prevents runaway reasoning. Cost and time budgets stop the agent when it exceeds a token threshold or latency limit. Repeated action detection — the same tool with the same arguments N times in a row — catches agents stuck in a loop that still produces different surface text each step. A fallback answer provides a graceful exit when every budget is exhausted and the agent still hasn't delivered a valid result.
The most common bug is an infinite loop caused by the agent never emitting a Final Answer. Without a step budget, the loop runs until it hits an API error or token limit. A close second is invalid action format — the LLM generates text that doesn't match the expected regex, producing a silent no-op or a crash. Always log every raw model output so you can see when parsing fails.
Repeated identical tool calls are another frequent failure: the agent calls the same tool with the same arguments over and over, ignoring the observation that comes back. This usually means the observation wasn't appended correctly or the model isn't reading it. Hallucinated tool names — calling a tool that doesn't exist in the registry — signal that the tool descriptions are confusing or the model is guessing.
When interviewers ask you to design an agent loop, they are testing several things at once. Can you keep the control flow clean and explicit? Do you naturally reach for budgets, validation, and observability, or do you assume the model will behave perfectly? The strongest candidates start with the stop conditions, then build the loop body — not the other way around.
Interviewers also probe tradeoffs. Simple ReAct is easy to implement, debug, and test; planned execution (where the agent precomputes a sequence of steps) can be more efficient but is harder to build and maintain. Be ready to discuss when you'd choose each approach.
Concrete Example
import re
MAX_STEPS = 6
ACTION_RE = re.compile(r"Action:\s*(\w+)\((.*)\)")
FINAL_RE = re.compile(r"Final Answer:\s*(.*)")
def run_agent(question, llm, tools):
scratchpad = f"Question: {question}\n"
for _ in range(MAX_STEPS):
output = llm(scratchpad)
scratchpad += output + "\n"
m = FINAL_RE.search(output)
if m:
return m.group(1)
m = ACTION_RE.search(output)
if m:
tool_name, args = m.group(1), m.group(2)
result = tools.get(tool_name, lambda _: "Unknown tool")(args)
scratchpad += f"Observation: {result}\n"
return "I could not find an answer."The scratchpad is a single growing string that holds the entire conversation so far. On each step, we send it to the LLM and get back more text. We check for a Final Answer first. If none, we look for an Action line, extract the tool name and arguments, call the tool, and append the Observation. After MAX_STEPS with no answer, we bail.
A single growing transcript the LLM reads every step. No separate memory store needed.
Extract structured commands from free-form text using simple regex patterns.
Route parsed actions to functions via a dictionary lookup.
Tool results go back into the scratchpad so the agent learns from them.
Always cap the loop so the agent can't run forever.
Explore these deeper articles to master specific topics in Agent Loop.
A practical guide to preventing infinite agent loops using step budgets, repetition detection, and final answer signals.
Read more →Learn to read agent traces, identify common failure patterns, and fix stuck loops systematically.
Read more →Structure agent scratchpads with clear delimiters, token management, and consistent formatting.
Read more →Interview revision
14 problems. Sign in to start solving.
Sign in to open a workspace and solve these problems.