Cybersecurity

Why the Agent Loop Matters

Python NLP LLMs AI Agents Git Databases
2,092 words Includes Code
Key Takeaway: An AI agent loop is a repeating cycle: Plan → Act → Observe → Evaluate → Decide (repeat or finish). This is the fundamental mechanism that transforms a language model from a text generator into a system that can take actions, learn from results, and complete multi-step tasks.

Every AI coding agent, research assistant, or autonomous tool follows the same core pattern. Whether it is writing code, searching files, calling APIs, or running tests, the agent moves through a loop:

Plan → Act → Observe → Evaluate → Repeat

This tutorial explains exactly how that loop works, why failure handling matters, and how you can build a safe simulation yourself.

Why the Agent Loop Matters

Without a loop, an LLM is a one-shot system:

Without a loop (chatbot):
User → LLM → Response

With a loop (agent):
User → Plan → Act → Observe → Evaluate → Plan → Act → Observe → Evaluate → ... → Done

The loop allows the system to:

  • Adapt — if the first tool call fails, try a different approach
  • Chain actions — use the output of one step as input to the next
  • Self-correct — detect errors and recover
  • Complete multi-step tasks — tasks that require 5, 10, or 50 actions
  • Stop at the right time — not just execute forever, but know when the goal is reached

The loop is what separates a tool from an agent.

The Five-Step Loop in Detail

Each step in the loop has a specific responsibility:

Step 1: 🎯 Goal

The user provides a goal. This can be a natural language request, a ticket description, or an instruction from a higher-level system. The goal defines what "done" means.

Example: "Calculate 2 + 3 * 4 and read the README file."

Step 2: 📋 Plan

The LLM analyzes the goal and decides what to do first. It selects a tool and constructs arguments. This is the reasoning step.

Example: "First, I'll use the calculator tool with the expression '2 + 3 * 4'."

Step 3: ⚡ Act

The system executes the tool call. The tool receives the arguments and runs its logic. This is where real work happens — computation, file I/O, API calls, database queries.

Example: The calculator tool parses "2 + 3 * 4" and returns 14.

Step 4: 👁️ Observe

The agent reads the tool's result. This observation becomes part of the conversation context for the next planning step. The agent now knows what happened.

Example: "The calculator returned 14."

Step 5: ✅ Evaluate

The agent decides: is the goal complete? If yes, produce the final answer. If not, plan the next step. This decision point is what makes the system autonomous — it can choose to continue or stop.

Example: "I've calculated 14, but I still need to read the README. Plan next step."

The Complete Architecture

Agent Loop Architecture:

┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  GOAL   │───▶│  PLAN   │───▶│   ACT   │───▶│ OBSERVE │
│ (user)  │    │(decide) │    │ (tool)  │    │(result) │
└──────────┘    └──────────┘    └──────────┘    └────┬─────┘
                                                        │
                                                        ▼
               ┌──────────────────────────────────┐
               │       EVALUATE                │
               │ (done? or plan next step)       │
               └──────────┬───────────────────────┘
                         │
               ◀─────────┘
               (loop back to Plan)

Components:
LLM — plans and evaluates
Tool Registry — available actions
Tool Executor — runs tool calls safely
State — conversation history + observations
Loop Controller — manages iterations and limits

What Happens Inside Each Step

Let us trace through a concrete example. The goal is: "Find all Python files that contain TODO comments."

StepInputActionOutput
PlanGoal: find TODOsSelect file_search toolfile_search(pattern="TODO", glob="*.py")
ActTool callSearch filesystemFound in 3 files: app.py, utils.py, tests.py
ObserveTool resultRecord findings3 TODO items in context
EvaluateGoal statusSearch complete?Yes — return results

Now a more complex goal: "Calculate 14, search for config files, then read the README."

IterationPlanToolObserveEvaluate
1Calculate firstcalculator(2 + 3 * 4)14More to do → next
2Search for configfile_search(config)No matchesMore to do → next
3Read READMEread_file(readme.txt)File content...All done → final answer

The agent ran 3 iterations, used 3 different tools, and stopped when the goal was satisfied.

Failure Handling: What Happens When Things Go Wrong

Real agents encounter failures. A tool might fail, a file might not exist, an API might timeout. Good agent loops handle failures gracefully.

Strategy 1: Recover and Retry

When a tool call fails, the agent observes the error and plans a different approach:

Iteration 1: plan → calculator("bad!!!input") → ❌ Error
Iteration 2: plan → calculator("2 + 2") → ✅ Result: 4
Iteration 3: plan → read_file("readme.txt") → ✅ File content...

The agent detected the error, adapted, and continued. This is resilience.

Strategy 2: Abort After Too Many Failures

If an agent keeps failing, it should stop rather than loop forever:

Iteration 1: ❌ Error
Iteration 2: ❌ Error
Iteration 3: ❌ Error
ABORT — 3 consecutive failures, stopping loop

The max consecutive failures limit prevents infinite loops and runaway costs.

Strategy 3: Max Iterations

Every agent loop needs an iteration cap. Even if the agent wants to continue, it stops after a predefined limit:

# Safety limits max_iterations = 20 max_consecutive_failures = 3 for i in range(max_iterations): plan = llm.plan(goal, history) result = execute(plan.tool, plan.args) if result.failed: consecutive_failures += 1 if consecutive_failures >= max_consecutive_failures: return "Aborted" else: consecutive_failures = 0 if goal_complete(result): return result.answer

Python Demo: Build Your Own Agent Loop

Here is a complete, safe agent loop you can run locally. It uses mock tools — no filesystem access, no network, no real LLM. It demonstrates the architecture.

import re, math, json from dataclasses import dataclass, field from typing import Callable # ── Step 1: Define safe tools ── def calculator(expression: str) -> dict: """Safe calculator — blocks injection.""" if re.search(r'[^0-9+\-*/(). ]', expression): return {"success": False, "error": "Invalid characters"} try: result = eval(expression, {"__builtins__": {}}, {}) return {"success": True, "result": result} except Exception as e: return {"success": False, "error": str(e)} # ── Step 2: Define the agent loop ── def run_agent_loop(goal, tools, max_iter=10): history = [] consecutive_failures = 0 for i in range(max_iter): # PLAN: decide which tool to call plan = plan_next_step(goal, history, tools) # ACT: execute the tool result = execute_tool(plan.tool, plan.args, tools) # OBSERVE: record what happened step = {"plan": plan, "result": result} history.append(step) # EVALUATE: decide next action if result.success: consecutive_failures = 0 if goal_complete(goal, history): return AgentResult(completed=True, steps=history) else: consecutive_failures += 1 if consecutive_failures >= 3: return AgentResult(completed=False, steps=history, error="Too many failures") return AgentResult(completed=False, steps=history, error="Max iterations reached")
💡 Try it yourself: Save the full demo as demo.py and run python demo.py to see the agent loop in action. Run python demo.py --test to verify all 15 test cases.

Key Components of an Agent Loop

ComponentRoleExample
GoalWhat the agent should achieve"Fix the failing test in test_login.py"
PlanWhich tool to call and with what argumentsread_file("test_login.py")
ToolExecutes an action in the environmentFile reader, calculator, Git command
ObservationThe result of executing the toolFile contents, error message, computed value
EvaluateDecision: continue, complete, or abort"Got the file — now search for the bug"
StateAccumulated history of all stepsPrevious plans, actions, and results
LimitsSafety bounds on the loopMax 20 iterations, max 3 consecutive failures

How Real Agents Use the Loop

In production AI coding agents, the same loop applies but with real tools:

# Typical AI coding agent loop: Step 1: Read issue description Step 2: Search codebase for related files Step 3: Read relevant source files Step 4: Analyze the code Step 5: Edit the source file Step 6: Run tests Step 7: If tests pass → commit If tests fail → read error → fix → repeat Step 6 Step 8: Create Git commit

The agent might take 10-30 iterations for a real task. Each iteration follows the same Plan → Act → Observe → Evaluate cycle.

State and Context Management

At each iteration, the agent's LLM sees the accumulated state:

  • Original goal
  • Instructions (system prompt)
  • Available tools and their descriptions
  • History of all previous plans, actions, and observations
  • Current step number

This context grows with each iteration. Context management is crucial — too much history wastes tokens, too little causes the agent to repeat itself.

Context StrategyProsCons
Full historyComplete informationToken-heavy, slow
Sliding windowFixed token countLoses early context
Summary + recentBalancedSummary may miss details
Tool-specificRelevant context onlyComplex to implement

Common Failure Patterns

PatternCauseSolution
Infinite loopNo iteration limitSet max_iterations
Repeated failuresAgent retries same failed actionTrack consecutive failures, abort
Goal driftAgent loses track of original goalInclude goal in every context
Context overflowHistory grows too largeSummarize or truncate old steps
OverthinkingAgent plans but never actsEnforce max planning steps
Under-planningAgent acts without reasoningRequire explicit plan before action

Human-in-the-Loop Integration

Production agent loops often include a human approval step for high-risk actions:

⚠️ Security: Before an agent executes a destructive command, modifies production files, or accesses sensitive resources, the loop should pause and request human confirmation.
# Risk-aware agent loop if action.risk_level == "HIGH": # Pause loop, request approval approved = request_human_approval(action) if not approved: continue # skip this action, plan alternative result = execute_tool(action)

When You Need an Agent Loop

Task TypeNeeds Loop?Why
Answer a questionNoOne-shot response is sufficient
Generate code from specMaybeSingle generation might work
Fix a failing testYesMust read → fix → test → verify
Multi-file refactoringYesMany sequential file operations
Debug a complex issueYesHypothesis → test → refine
Build a feature end-to-endYesPlan → implement → test → commit

Agent Loop vs Simple Prompting

AspectSimple PromptingAgent Loop
Interactions1Many
Tool accessOptional (function calling)Core capability
Failure recoveryManual retryAutomatic adaptation
ComplexitySimple tasksMulti-step workflows
CostSingle API callMultiple iterations
AutonomyNoneHigh (within limits)
Human effortManual orchestrationReview and approve

Practical Exercises

Exercise 1: Trace the Loop

Read through the demo output. For each step, identify which part of the loop (Plan, Act, Observe, Evaluate) it corresponds to. Count how many iterations it took.

Exercise 2: Add a Tool

Add a new tool called word_count that counts words in a string. Modify the agent to use it in the loop. What happens if the tool returns an error?

Exercise 3: Handle Failures

Modify the max_consecutive_failures to 1. Run the demo. What changes? Why is having a higher threshold useful?

Exercise 4: Build a Production Loop

Extend the demo to include a risk-level check. Some tools should require "approval" before execution. How would you implement this?

✅ Agent Loop Implementation Checklist

  • ☐ Max iterations defined (prevent infinite loops)
  • ☐ Max consecutive failures defined (abort safety)
  • ☐ Goal included in every planning step (prevent drift)
  • ☐ Tool results validated before passing to LLM
  • ☐ Human approval for high-risk actions
  • ☐ Error handling for each tool
  • ☐ State/history management strategy chosen
  • ☐ Logging of each step for debugging
  • ☐ Final answer validated before returning to user

FAQ

Q: How many iterations does a typical agent take?
A: Simple tasks (1-3 tools): 2-5 iterations. Complex tasks (code changes + tests): 10-30 iterations. Very complex tasks: 50+ iterations.

Q: Can an agent loop run forever?
A: Without limits, yes. Always set max_iterations and max_consecutive_failures. This is a safety requirement, not optional.

Q: What happens when the LLM does not select a tool?
A: The loop should treat "no tool selected" as the agent deciding to produce a final answer. The Evaluate step should detect this.

Q: How is state managed between iterations?
A: Each iteration appends its plan, action, and observation to a history list. The LLM receives the full (or summarized) history in its context window for the next planning step.

Q: Does the loop always converge?
A: Not guaranteed. The agent might oscillate between approaches, retry failed actions, or lose track of the goal. Safety limits handle these cases.

Q: Can multiple agents share a loop?
A: Yes — this is called multi-agent orchestration. A planner agent might delegate to a coder agent, which delegates to a tester agent, each running their own loop.

Further Reading

Continue Learning: Understand the full agent architecture, explore how agents evolved, learn to use agents safely, and discover what developers still need to know.

Discuss this topic on BestWordz Community.

💬 Discuss on BestWordz Community

Join the conversation about Python, NLP, LLMs on the BestWordz Community forum.

Visit Forum →