Begin with the problem
The loop is the engine of an agent. Each round observes the current situation, chooses an action, executes it, records the result, and checks whether to stop.
observe → decide → act → inspect result → succeed, recover, escalate, or stop
What you will learn
- Follow one complete reason–act–observe loop step by step.
- Understand success, failure, timeout, iteration-limit, and human-escalation stopping conditions.
- See how tool errors and unexpected observations affect the next action.
- Build a bounded loop that cannot retry forever.
Current real-system grounding: Google’s current Agents overview documents managed agent harnesses with tools, loops, context management, sandboxed execution, and multi-step research.
These official links document available product features. They do not reveal every provider’s private implementation, hidden reasoning, default setting, or internal limit.
1. The problem this module solves
Module 3 named every piece of the agent loop. This module — one of the most important in this entire course — covers the loop’s actual mechanics: why it’s structurally necessary, how it decides to stop, and what happens in the messy, real scenarios where something goes wrong along the way.
2. One-Shot LLM vs. Agent — The Structural Difference
flowchart LR
subgraph OneShotLLM[One-Shot LLM]
U1[User] --> L1[LLM] --> A1[Answer]
end
flowchart LR
subgraph AgentLoop[Agent]
U2[User] --> Ag[Agent]
Ag --> R[Reason]
R --> Act[Action]
Act --> Obs[Observation]
Obs --> R
R --> F[Final Answer]
end
The structural difference is simple to state, but has enormous consequences: a one-shot LLM has exactly ONE opportunity to get things right. An agent has as MANY opportunities as it needs — deciding, after each observation, whether it has enough information to finish, or whether it needs to act again.
3. Why the Agent May Need Multiple Steps
Recall Module 1’s late-order example — the agent cannot know, before checking the order system, whether it will also need to check the shipping carrier. This isn’t a limitation to work around; it’s the entire reason a loop exists:
Some tasks have a UNKNOWN number of steps required, decided
ONLY by what's actually discovered along the way.
A ONE-SHOT system would need to GUESS every possible path in advance
(Module 2's plannability test) -- an AGENT simply keeps going until
IT determines the goal is met.
4. How the Agent Knows What to Do Next
At EVERY iteration, the LLM (Module 5) is given:
- The GOAL (fixed, Module 3)
- The current STATE (what's been learned so far, Module 3)
- The most recent OBSERVATION (Module 3)
- Available TOOLS (Module 6) it could call next
And REASONS: "given all of this, what should I do next --
another action, or am I done?"
This is precisely why Module 3’s context concept matters so much — the agent’s “knowing what to do next” is entirely a function of what it’s actually been given to reason with at that specific iteration.
5. How the Loop Terminates
A loop terminates when ONE of these becomes true:
1. The LLM determines the GOAL has been achieved (the "success" path)
2. A MAXIMUM ITERATION LIMIT is reached (a real safety net,
Section 8)
3. A TIMEOUT is reached (a real safety net, time-based rather
than step-based)
4. An UNRECOVERABLE ERROR occurs and the system decides to stop
rather than retry indefinitely
Notice: only reason #1 is the “intended” outcome. Reasons #2-4 are necessary SAFETY mechanisms — because an agent reasoning about “am I done yet?” is not guaranteed to reach that conclusion correctly or in bounded time. This is precisely why production agent systems NEVER rely on the LLM’s own judgment alone to prevent runaway execution.
6. What Happens When the Agent Makes a Wrong Decision
Wrong decision (e.g., calling the WRONG tool, or misreading an
observation)
↓
The RESULT of that wrong action becomes the NEXT observation
↓
IF the agent can recognize the result doesn't help (e.g., an error,
or irrelevant data): it can course-correct on the NEXT
iteration
↓
IF the agent CANNOT recognize this: it may continue down an
increasingly wrong path -- exactly why Module 9 (Reflection) and
Module 18 (Failure Modes) exist as dedicated topics
A important, honest point: the loop structure itself doesn’t guarantee recovery from a bad decision — it only creates the opportunity for recovery, since the agent gets to reason again with new information. Whether it actually recovers depends on reasoning quality (Module 5) and, often, deliberate reflection mechanisms (Module 9).
7. What Happens When a Tool Fails
Tool call
↓
Tool FAILS (error, timeout, invalid response)
↓
This failure ITSELF becomes an observation the agent can reason
about -- "the tool failed, I should retry, or try a different
approach, or report that I cannot complete this"
This directly connects to Module 6’s tool error handling — a well-designed agent system treats tool failure as information to reason about, not a silent crash.
8. Infinite Loops, Maximum Iterations, and Timeouts
Safety Requirements
Why an agent might LOOP FOREVER without a safety limit:
- Repeatedly calling the SAME tool with the SAME (unhelpful) result,
never recognizing it should try something different
- Oscillating between TWO actions, each one "undoing" what the
previous one accomplished
- A tool that always FAILS, with the agent always deciding to RETRY
MAX ITERATIONS: a hard cap on how many loop cycles the agent may
run, REGARDLESS of whether it believes it's
making progress
TIMEOUT: a hard cap on WALL-CLOCK TIME, independent
of iteration count -- important
when individual steps might be slow
These are not optional hardening for later — they are > required from the very first version of any real agent system.
9. A Real Developer Example
TechCorp’s late-order agent, with real safety limits in place:
| Scenario | What Happens | Termination |
|---|---|---|
| Normal path | Check order → check carrier → decide → done | Goal achieved, loop ends naturally |
| Shipping API is down | Tool call fails repeatedly, agent retries each time | Max iterations reached — agent reports it cannot complete the task, rather than looping forever |
| Agent misreads carrier data as “in transit” when it’s actually “delivered” | Wrong decision, but next observation may reveal the mismatch | Depends on whether the agent’s reasoning catches the mismatch (Module 9’s reflection helps here) |
10. A Simple Agentic AI Connection
This entire module is about agentic AI — it’s the mechanical core of what makes something an agent rather than a single LLM call. Every architecture in Module 13 (Single-Agent Architectures) and every multi-agent pattern in Module 15 is built on top of this exact loop, just with additional structure layered on.
11. How Is This Used in AI?
🤖 How Is This Used in AI?
Every production agent framework (Module 22’s LangGraph, and others) implements exactly this loop internally — a control structure that repeatedly calls the LLM, executes whatever action it decides on, feeds the result back, and checks termination conditions, with configurable max-iteration and timeout safety limits as standard, expected features.
12. Real-World Applications
- Any multi-step agentic task: research, customer support resolution, data analysis
- Designing safety limits for any production agent deployment
- Debugging agents that appear to “hang” or loop unexpectedly
13. Common Mistakes
Incorrect idea: Building an agent loop with no maximum iteration limit.
Why it is incorrect: As shown directly in Section 8, this is a real, real risk — not a theoretical edge case.
Incorrect idea: Assuming the loop structure alone guarantees recovery from a wrong decision.
Why it is incorrect: As shown directly in Section 6, the loop only creates the OPPORTUNITY to recover — actual recovery depends on reasoning quality and, often, deliberate reflection.
Incorrect idea: Treating tool failures as crashes rather than observations.
Why it is incorrect: As shown directly in Section 7, a well-designed agent should be able to reason about a failure, not just halt on it unexpectedly.
14. Limitations
- Even with max iterations and timeouts, an agent can still fail to achieve its goal within those limits — safety limits prevent runaway execution, they don’t guarantee success
- Recognizing “I am stuck” is itself a hard reasoning problem for an LLM — Module 9’s reflection helps, but isn’t perfectly reliable
15. Quick Reference
flowchart TD
Start[Goal] --> Loop{Iterate}
Loop --> Reason[Reason: what next?]
Reason -->|Goal met| Done[Terminate: Success]
Reason -->|Need more info| Act[Take Action]
Act --> Obs[Observe Result]
Obs --> Check{Max iterations<br/>or timeout reached?}
Check -->|Yes| Stop[Terminate: Safety Limit]
Check -->|No| Loop
16. Code — Implementing an AI Agent Loop With Safety Limits
🎯 Target of this example: implement Section 5, 8, and 9’s real developer example directly — a working agent loop with a real max-iterations safety limit, demonstrating both the successful termination path and the “stuck, hits the limit” path.
Example 1 — Simple
def run_agent_loop(goal: str, environment: dict, max_iterations: int = 5) -> dict:
"""A real agent loop -- reasons at EACH iteration about what
to do next, terminating either on goal achievement OR on hitting
max_iterations (Section 5 and 8's safety requirement)."""
state = {}
trajectory = []
for iteration in range(1, max_iterations + 1):
if state.get("order_status") is None:
observation = environment.get("order_system", "no data")
state["order_status"] = "late" if "late" in observation.lower() else "on_time"
action = "checked_order_status"
elif state.get("carrier_status") is None and state["order_status"] == "late":
observation = environment.get("shipping_api", "no data")
state["carrier_status"] = "delivered" if "delivered" in observation.lower() else "in_transit"
action = "checked_shipping_carrier"
else:
action = "goal_achieved"
trajectory.append({"iteration": iteration, "action": action})
return {"trajectory": trajectory, "terminated_reason": "goal_achieved", "final_state": state}
trajectory.append({"iteration": iteration, "action": action})
return {"trajectory": trajectory, "terminated_reason": "max_iterations_reached", "final_state": state}
environment = {"order_system": "Order is LATE", "shipping_api": "Package DELIVERED 2 days ago"}
result = run_agent_loop("Resolve late order", environment)
for step in result["trajectory"]:
print(f"Iteration {step['iteration']}: {step['action']}")
print(f"\nTerminated: {result['terminated_reason']}")
Expected Output:
Iteration 1: checked_order_status
Iteration 2: checked_shipping_carrier
Iteration 3: goal_achieved
Terminated: goal_achieved
What we conclude from this example: the loop reasons at each iteration about what to do next, using the accumulated state (Module 3) — and correctly terminates via the “success” path once both pieces of information have been gathered, exactly Section 9’s normal-path scenario.
Example 2 — Intermediate
def run_agent_loop_with_failing_tool(goal: str, tool_call, max_iterations: int = 3) -> dict:
"""Directly implements Section 8's real safety scenario -- a
tool that keeps failing, so the agent's state never progresses.
Demonstrates WHY max_iterations is a real, real requirement,
not a theoretical concern."""
state = {}
trajectory = []
for iteration in range(1, max_iterations + 1):
result = tool_call()
if result is None:
trajectory.append({"iteration": iteration, "action": "tool_call_failed_retrying"})
else:
state["result"] = result
trajectory.append({"iteration": iteration, "action": "goal_achieved"})
return {"trajectory": trajectory, "terminated_reason": "goal_achieved", "final_state": state}
return {"trajectory": trajectory, "terminated_reason": "max_iterations_reached_stuck", "final_state": state}
def always_failing_tool():
return None # simulates a broken/unavailable shipping API
result = run_agent_loop_with_failing_tool("Resolve late order", always_failing_tool, max_iterations=3)
for step in result["trajectory"]:
print(f"Iteration {step['iteration']}: {step['action']}")
print(f"\nTerminated: {result['terminated_reason']}")
Expected Output:
Iteration 1: tool_call_failed_retrying
Iteration 2: tool_call_failed_retrying
Iteration 3: tool_call_failed_retrying
Terminated: max_iterations_reached_stuck
What we conclude from this example: without the max_iterations safety limit, this agent would retry the failing tool call FOREVER — the loop correctly stops after exactly 3 attempts, exactly Section 9’s “shipping API is down” scenario, and exactly why Section 8 insists this safety limit is non-negotiable, not optional hardening.
Example 3 — Production Grade
from dataclasses import dataclass, field
from enum import Enum
import time
class TerminationReason(Enum):
GOAL_ACHIEVED = "goal_achieved"
MAX_ITERATIONS = "max_iterations_reached"
TIMEOUT = "timeout_reached"
@dataclass
class LoopResult:
trajectory: list = field(default_factory=list)
termination_reason: TerminationReason = None
total_iterations: int = 0
elapsed_seconds: float = 0.0
class SafeAgentLoop:
"""A production-style agent loop implementing BOTH safety limits
from Section 8 -- max_iterations AND timeout -- since either one
alone is insufficient (a fast-looping agent could exhaust its
iteration budget slowly, or a SLOW step could exceed a
reasonable wall-clock time well before hitting max_iterations)."""
def __init__(self, max_iterations: int = 10, timeout_seconds: float = 5.0):
self.max_iterations = max_iterations
self.timeout_seconds = timeout_seconds
def run(self, reasoning_step) -> LoopResult:
start_time = time.time()
trajectory = []
for iteration in range(1, self.max_iterations + 1):
elapsed = time.time() - start_time
if elapsed >= self.timeout_seconds:
return LoopResult(trajectory, TerminationReason.TIMEOUT, iteration - 1, elapsed)
done, action = reasoning_step(iteration)
trajectory.append({"iteration": iteration, "action": action})
if done:
return LoopResult(trajectory, TerminationReason.GOAL_ACHIEVED,
iteration, time.time() - start_time)
return LoopResult(trajectory, TerminationReason.MAX_ITERATIONS,
self.max_iterations, time.time() - start_time)
def reasoning_step(iteration: int) -> tuple:
"""Simulates a real multi-step reasoning process -- 'done'
only after the 3rd iteration."""
if iteration >= 3:
return True, "goal_achieved"
return False, f"gathering_information_step_{iteration}"
loop = SafeAgentLoop(max_iterations=10, timeout_seconds=5.0)
result = loop.run(reasoning_step)
print(f"Termination reason: {result.termination_reason.value}")
print(f"Total iterations: {result.total_iterations}")
print(f"Trajectory: {[step['action'] for step in result.trajectory]}")
Expected Output:
Termination reason: goal_achieved
Total iterations: 3
Trajectory: ['gathering_information_step_1',
'gathering_information_step_2', 'goal_achieved']
What we conclude from this example: the SafeAgentLoop class
enforces BOTH safety limits simultaneously — checking elapsed time on
every single iteration, not just counting iterations — exactly Section
8’s complete safety requirement, implemented as real, structural
protection rather than relying on the agent’s own judgment to prevent
runaway execution.
17. Interview Questions
Q: Explain, structurally, why an agent’s loop gives it a real advantage over a one-shot LLM call for complex tasks.
Ans: A one-shot LLM has exactly one opportunity to produce a correct result, with no ability to gather additional information or correct course based on what it learns. An agent’s loop lets it reason, act, observe the result, and reason again — repeating as many times as needed — so it can handle tasks where the required steps aren’t known in advance and depend on what’s actually discovered along the way, rather than needing to guess correctly in a single attempt.
Q: What are the four ways an agent loop can terminate, and why are three of them considered “safety” mechanisms rather than the intended outcome?
Ans: A loop terminates when the LLM determines the goal is achieved (the intended, successful outcome), when a maximum iteration limit is reached, when a timeout is reached, or when an unrecoverable error causes the system to stop rather than retry indefinitely. The latter three are safety mechanisms because an agent reasoning about “am I done yet” isn’t guaranteed to reach that conclusion correctly or in bounded time — without these safeguards, a stuck agent could loop indefinitely, consuming unbounded time and cost.
Q: Why should both a maximum iteration limit AND a timeout be implemented, rather than just one or the other?
Ans: These protect against different failure modes. A maximum iteration limit bounds how many reasoning cycles occur, but doesn’t account for individual steps taking a long time — a small number of very slow steps could still consume excessive wall-clock time before hitting the iteration cap. A timeout bounds wall-clock time directly, but wouldn’t catch a scenario where an agent loops very quickly through many unproductive iterations within the time budget. Implementing both provides real, complementary protection against both failure patterns.
Q: Does an agent’s loop structure guarantee that it will recover from a wrong decision made at an early step? Explain.
Ans: No — the loop structure only creates the opportunity for recovery, since the agent gets to reason again with new information after each action. Whether it actually recovers depends on the quality of its reasoning at each subsequent step, and specifically on whether it can recognize that a previous result or decision was actually unhelpful or incorrect. This is precisely why dedicated reflection mechanisms (covered in a later module) exist — the loop alone doesn’t guarantee self-correction, it only makes self-correction structurally possible.
18. What You Should Remember
- The agent loop’s real structural advantage over a one-shot LLM call is the ability to reason, act, observe, and reason again as many times as a task requires.
- Termination happens via goal achievement OR safety limits (max iterations, timeout) — the latter are required from day one, not optional hardening, verified directly through a scenario where a failing tool would loop forever without them.
- The loop enables recovery from wrong decisions but doesn’t guarantee it — actual recovery depends on reasoning quality, verified directly by observing that the loop structure alone requires a real mechanism to recognize when something’s gone wrong.
19. Quick Practice
Design a scenario (in your own domain of interest) where an agent loop could get stuck oscillating between two actions, each undoing the other’s progress. Explain what safety mechanism from this module would prevent it from running forever, and what additional mechanism (hint: a later module’s topic) might help it actually recognize and escape the oscillation.
20. Next Step
Next: Module 5 — The LLM as the Agent’s Brain — closing Level 2: precisely what role the LLM plays within this loop, and why the LLM alone is not the entire agent.
- Author
- TechByteByByte Editorial Team
- Reviewed by
- TechByteByByte Admin
- Published
- Last reviewed