Agentic AI has quickly become one of the most discussed topics in software engineering. New frameworks appear almost every week, each introducing new abstractions for planning, orchestration, memory and multi-agent collaboration.
These abstractions are valuable – they allow us to build increasingly capable systems without worrying about every implementation detail.
The trade-off, however, is that the underlying execution model becomes less visible.
While exploring different frameworks and architectural patterns, I found it useful to temporarily remove those abstractions and reduce the problem to its simplest form. Rather than asking which framework should I use?, I wanted to answer a more fundamental question:
What execution pattern are these frameworks implementing underneath?
That exercise consistently led back to one simple loop:
Reason ⟶ Act ⟶ Observe ⟶ Evaluate ⟶ Repeat
This sequence, commonly referred to as an Agentic Loop, is the execution pattern behind many modern AI agents. Understanding it provides a useful mental model for reasoning about agent behaviour regardless of which framework sits on top.
To make that pattern tangible, I built a small Streamlit reference application that exposes every iteration of the loop. The application itself is intentionally simple. The goal isn’t to demonstrate sophisticated AI capabilities – it’s to make the execution model visible.
To make this pattern tangible, I built a small Streamlit reference application in Python. The application intentionally solves a very simple problem: basic financial calculations using a calculator tool. The calculator itself isn’t the interesting part. The value comes entirely from watching the loop execute one iteration at a time.
The Loop in Code
Frameworks intentionally abstract the execution engine. Underneath, an agentic loop is simply a control loop that carries state from one iteration to the next.
The heart of my reference implementation is surprisingly small:
def run_loop(self) -> LoopState:
"""Execute the agentic loop: Thought → Action → Observation → Evaluation → Repeat."""
while not self.state.is_done and self.state.iteration < 4:
self.state.iteration += 1
# Phase 1 & 2: Reason + Act
thought, action = self.think()
self.state.thoughts.append(thought)
self.state.actions.append(action)
# Phase 3: Observe (Execute the tool)
success, result, error = self.executor.execute(action)
self.observe(success, result, error)
# Phase 4: Evaluate progress
self.evaluate()
return self.state
Although simple, this loop captures the entire lifecycle of an agent. Each iteration updates the agent’s internal state, performs an action, learns from the result and decides whether another loop is worthwhile.
Note: The hard iteration limit (
self.state.iteration < 4) is highly intentional. Agentic systems are inherently non-deterministic, meaning they should always be bounded by explicit stopping conditions. In production systems, these structural circuit breakers prevent runaway execution, excessive token consumption and unnecessary compute cycles.
Following One Execution
To see why this differs from a traditional prompt-response interaction, let’s trace a complete execution pathway.
Suppose a user asks the agent to calculate Apple’s P/E ratio using a stock price of $180.50 and an EPS of $6.50. During the first iteration, the agent identifies the required calculation and generates the mathematical expression to execute.
def think(self) -> tuple[str, str]:
"""Assess the state and plan the calculation."""
iteration = self.state.iteration
if iteration == 1:
thought = "I need to calculate 180.50 / 6.50."
action = "180.50 / 6.50"
return thought, action
The calculator executes the string action and returns the raw result: 27.7615. At this point, the agent has an answer, but it does not immediately stop. Instead, it evaluates its current confidence and decides that a validation iteration is worthwhile.
Notice what changed. During the second iteration, the input context is no longer just the user’s raw prompt. The agent now reasons using everything it learned during the first pass:

That second iteration highlights the key differentiator. Rather than reasoning solely from the original user prompt, the agent reasons directly from its own execution history. Without that accumulated state, every iteration would simply repeat the exact same work. State allows each iteration to become slightly better informed than the one before it.
In the reference application, that history is maintained inside a small LoopState container:
@dataclass
class LoopState:
"""Maintains an immutable timeline of agentic loop execution."""
iteration: int = 0
thoughts: list[str] = field(default_factory=list)
actions: list[str] = field(default_factory=list)
observations: list[str] = field(default_factory=list)
confidence: float = 0.0
is_done: bool = False
One Loop, Multiple Behaviors
One observation that surprised me while building this sample project was that I never changed the underlying loop code itself. I only changed the scenario context. The same execution engine naturally produced three entirely different runtime behaviors:
- Simple Verification: The agent performs the calculation, verifies the result once, reaches its confidence threshold and exits cleanly. The second iteration acts as a lightweight quality check.
- Building Confidence: Some scenarios require additional iterations before the agent decides it has gathered enough evidence to stop. The answer itself may not change, but the confidence score does.
- Error Recovery: The most interesting scenario intentionally triggers a tool failure (e.g., an unexpected input anomaly). Instead of crashing, the failure becomes an observation. The next iteration adjusts its reasoning, selects a fallback action and successfully completes the task.
This is where the value of an agentic loop becomes obvious. Errors are no longer fatal application crashes. They are simply additional pieces of information that guide the next turn.
Tool Safety Still Matters
Giving an agent the ability to invoke tools also means treating every generated action as completely untrusted input. In the sample application, the calculator strictly validates every expression before allowing execution:
class SafeToolExecutor:
"""Ensures the agent can only execute safe mathematical expressions."""
ALLOWED_PATTERN = re.compile(r'^[\d+\-*/().\s]+$')
# Validation logic runs here...
Whether your tool is a calculator, a SQL database connection, a REST API endpoint or a code executor, strict validation belongs explicitly at the tool boundary – not inside the reasoning loop. The agent should remain free to reason creatively. The tool boundary must remain entirely predictable.
Where You’ll See This Pattern
Once you recognize the loop, you will start seeing it across the entire AI ecosystem.
You’ll find this same execution pattern in frameworks such as ReAct, LangGraph, Semantic Kernel, CrewAI, AutoGPT and many enterprise multi-agent implementations.
While they all differ wildly in orchestration styles, tooling capability and memory management, they all rely fundamentally on the exact same underlying pattern: Reason, Act, Observe, Evaluate, Repeat. Understanding this core execution model first makes those larger frameworks significantly easier to master.
More importantly, it changes how you design AI-powered systems. Instead of thinking in single request-response interactions, you begin designing workflows that can verify, adapt, recover from failures and continue working toward a goal with minimal human intervention.
Closing Thoughts
You may never build an agentic loop from scratch in a production system and that’s perfectly fine. Most teams will rely on frameworks that already implement this pattern well. The value of understanding the loop isn’t replacing those frameworks. It’s recognizing the execution model underneath them.
That understanding changes how you approach AI system design. Instead of thinking only about prompts or framework APIs, you begin asking different architectural questions:
- Where should reasoning happen?
- What actions should the agent be allowed to perform?
- What observations should influence the next decision?
- What state should persist across iterations?
- When should the system decide it has done enough?
Those questions apply regardless of whether you’re building with LangGraph, Semantic Kernel, CrewAI, AutoGen or your own orchestration layer. That was the motivation behind this small Streamlit reference application. Not to build another framework. Simply to expose the execution pattern that many of today’s frameworks quietly implement beneath the surface.
Understanding the loop helps explain how modern AI agents behave. Designing systems around that loop is what ultimately determines whether they become reliable software.
This article intentionally focused on understanding the execution model. Applying that model to design reliable agentic systems introduces a different set of architectural considerations – from workflow design and long-running execution to guardrails and human oversight. That’s a discussion I’d like to explore separately.
The complete, framework-agnostic Streamlit sample used in this article is available on GitHub: https://github.com/sandeep-mewara/agentic-loop.
Happy Looping!
.

