Module 2
17 min read

The Agent Loop

Every agent, from a ten-line script to a hosted platform that runs for days, has the same loop at its core. This module takes that loop apart, shows how modern reasoning models fit into it, and covers the patterns and guardrails that turn it into something you can trust.

Perceive, reason, act, observe

An agent is a loop wrapped around a model. On each pass, the model looks at everything it knows so far, decides on one move, and the harness carries that move out and reports back. The cycle repeats until the model decides it is finished or something stops it.

  1. 1

    Perceive

    The harness assembles the context: the system prompt, the user's goal, tool definitions, and everything that has happened so far, including earlier tool results.

  2. 2

    Reason

    The model reads that context and decides what to do. Reasoning models may first think privately for a while; others reason directly in their visible output.

  3. 3

    Act

    The model emits either a tool call (a structured request such as run_tests with arguments) or a final answer. The harness executes the tool call; the model itself never touches the outside world directly.

  4. 4

    Observe

    The tool's result (output, error message, screenshot, or another agent's reply) is appended to the context. The loop goes back to step one with this new information.

The observe step is what makes agents work. A model that writes code without running it is guessing. A model that runs the code, reads the error and tries again is doing something much closer to how a person debugs. Each observation grounds the next decision in reality, which lets the agent recover from its own mistakes.

The model is stateless; the loop is not

A model has no memory between calls. Everything the agent "knows" on a given turn is whatever the harness put in the context. That makes the harness, not the model, responsible for state, and it is why context management (Module 3) matters so much once loops get long.

ReAct: interleaving thought and action

The loop above was popularized by ReAct (Yao et al., 2022), short for Reasoning plus Acting. Before ReAct, two lines of work ran separately. Chain-of-thought prompting showed that models reason better when they write out intermediate steps, but the reasoning was sealed off from the world and could drift into confident nonsense. Action-only agents could use tools but had no explicit plan, so they flailed.

ReAct combined them. The model alternates a Thought (what do I know, what should I try), an Action (a tool call) and an Observation (the result). Reasoning guides the actions, and the observations keep the reasoning honest.

Goal: Why is the checkout test failing on main?

Thought: I should see the actual failure before guessing.
Action: run_command("npm test -- checkout")
Observation: FAIL checkout.test.ts
  Expected total 107.00, received 100.00

Thought: Tax isn't being applied. Let me find where totals are computed.
Action: search_code("calculateTotal")
Observation: src/cart/total.ts:12  export function calculateTotal(items, region)

Thought: Read that function to see how region affects tax.
Action: read_file("src/cart/total.ts")
Observation: ... if (region === "US") { ... }  // test passes "us"

Thought: Case mismatch. The test uses "us" but the code checks "US".
Final answer: The region check in total.ts is case-sensitive ...
An illustrative ReAct-style trace

Modern APIs no longer need the literal "Thought / Action / Observation" text format, because tool calls are structured JSON and reasoning can happen in a dedicated thinking channel. But the shape of the loop is exactly the same, and reading agent transcripts as ReAct traces is still the fastest way to debug them.

Reasoning models and thinking between tool calls

Since late 2024, frontier labs have shipped reasoning models: models trained to think at length before answering, often with a configurable budget for how much thinking to do. Anthropic calls this extended thinking; other providers expose a similar "reasoning effort" setting. For agents this is a big deal, because the hard part of an agent step is usually deciding what to do, not producing the tool call.

The early versions of extended thinking had a limitation for agents: the model thought once at the start of its turn, then made tool calls. Interleaved thinking removes that limit. The model can think, call a tool, think again about the result, call another tool, and so on, all within one turn. That matters whenever a tool result is surprising and the original plan needs to change.

ApproachWhere the reasoning happensGood for
No explicit reasoningImplicitly, inside the next tool callFast, simple steps such as routing or extraction
Chain-of-thought in outputVisible text before each actionOlder or smaller models; easy to inspect
Extended thinking (up front)A private thinking block before the first actionHard planning at the start of a task
Interleaved thinkingThinking blocks between tool callsLong agentic tasks where each result can change the plan

Spend thinking where it pays

More thinking means more tokens, more latency and more cost on every turn. A common pattern is to use a high reasoning budget for planning and difficult decisions, and a low one (or a smaller, cheaper model) for routine steps like reformatting a tool result.

Planning strategies

A pure ReAct loop decides one step at a time. That works for short tasks, but on long ones the agent can lose the thread, repeat itself, or forget parts of the goal. Planning strategies give the loop more structure. None of them is always best; they trade flexibility against focus.

StrategyHow it worksStrengthWeakness
Step-by-step (ReAct)Decide only the next action each turnAdapts instantly to new informationCan wander on long tasks
Plan-then-executeWrite a full plan first, then carry it outFocused, auditable, cheaper per stepBrittle if early assumptions are wrong
Plan and reviseKeep a written plan or to-do list and update it as results arriveBalances focus and adaptabilityPlan upkeep costs tokens
Decompose and delegateSplit the goal into subtasks and hand them to sub-agents or workersParallelism; each worker gets a clean contextCoordination overhead (see Module 6)
Reflect and retryAfter a failure, write a short critique and try again with it in contextLearns from mistakes within a taskNeeds a reliable signal that something failed

In practice, most capable agents in 2026 use plan and revise. Coding agents typically maintain a visible to-do list: they write it at the start, check items off, and add new ones as they discover work. The list does double duty. It keeps the model on track, and it gives the human watching a quick way to see what the agent intends to do next.

Plan-then-execute has a second benefit that has nothing to do with quality: security. If the plan is fixed before the agent reads any untrusted content, a malicious web page or email cannot redirect it to new actions. Module 11 returns to this idea.

Workflow patterns

Not every problem needs a fully autonomous loop. Anthropic's "Building effective agents" catalogs five workflow patterns, where your code fixes the structure and the model handles each step. They remain the best starting vocabulary for designing agentic systems, and real agents often use several of them inside a larger loop.

Prompt chaining

Break a task into fixed sequential steps, each consuming the previous step's output, with optional checks ("gates") between them. Example: outline, check the outline, then write.

Routing

Classify the input first, then send it to a specialized prompt, tool set or model. Example: refunds, technical issues and sales questions each go to a different handler, and easy cases go to a cheaper model.

Parallelization

Run several model calls at once and combine them. Sectioning splits a task into independent parts; voting runs the same task several times and compares answers.

Orchestrator-workers

A central model breaks the task down at run time and dispatches subtasks to workers, then synthesizes their results. Unlike parallelization, the subtasks aren't known in advance.

Evaluator-optimizer

One model produces an answer; another critiques it against clear criteria; the first revises. Repeat until the evaluator is satisfied or a limit is reached.

Autonomous agent

The model runs the loop itself with tools and decides every step. Use this when the path genuinely can't be known in advance.

Orchestrator-workers is the bridge to multi-agent systems. Anthropic's Research feature (described in June 2025) uses a lead agent that plans and spawns parallel sub-agents, each with its own context window. On Anthropic's internal research evaluation it outperformed a single agent by 90.2%, but it used roughly 15 times the tokens of a chat interaction. Module 6 looks at when that trade is worth it.

Evaluator-optimizer needs a real evaluator

This pattern only helps if the evaluator can catch problems the generator missed. It works best when the evaluator has something concrete to check against: test results, a rubric, a schema, or a source document. Asking the same model "is this good?" with no new information tends to produce agreement, not improvement.

Stopping conditions and human-in-the-loop

A loop that never stops is a bug, and a loop that stops too early is useless. Good agents have several independent ways to end, because any single one can fail.

  • Task complete: the model returns a final answer instead of a tool call. This is the normal exit.
  • Success check: an external signal confirms the goal, such as tests passing or a form submitted. This is more trustworthy than the model's own claim.
  • Budget limits: a maximum number of turns, tokens, dollars or wall-clock minutes. Every production agent needs these.
  • No progress: the same tool call with the same arguments keeps repeating, or the same error keeps coming back. Detect this and stop or escalate.
  • Needs a human: the agent hits an action that requires approval, or information only a person has.

Human-in-the-loop design is about putting a person at the right points, not at every point. Asking for approval on every file read makes an agent useless; asking for none on a production database is how incidents happen. The usual approach is to classify actions by risk.

Action typeExampleTypical policy
Read-only, localRead a file, search the codebaseRun automatically
Reversible changesEdit a file in a git repo, create a draftRun automatically, show a diff afterwards
External side effectsSend an email, post a comment, call a paid APIAsk first, or allow from an approved list
Destructive or financialDelete data, deploy to production, make a paymentAlways require explicit human approval

Protocols and frameworks have built-in support for pausing. MCP's elicitation feature lets a tool server ask the user for input partway through a call (Module 4). An A2A task can enter an INPUT_REQUIRED or AUTH_REQUIRED state while it waits for a person (Module 5). Agent SDKs have added approval primitives too: OpenAI's Agents SDK added durable approvals, and Google's ADK 2.0 includes built-in human-in-the-loop support.

Approval fatigue is real

If people are asked to approve dozens of harmless actions, they stop reading and click yes to everything, including the one that matters. Keep approval prompts rare, specific and readable: show exactly what will happen, not just the tool name.

A minimal agent loop

Here is the whole idea in about thirty lines of Python-flavored pseudo-code. Real SDKs add streaming, retries, parallel tool calls and context management, but the skeleton is the same.

MAX_TURNS = 30
NEEDS_APPROVAL = {"send_email", "delete_file", "deploy"}

def run_agent(goal, tools, system_prompt):
    messages = [{"role": "user", "content": goal}]

    for turn in range(MAX_TURNS):
        # Perceive + reason: the model sees the full context
        response = call_model(system=system_prompt,
                              messages=messages,
                              tools=tools)
        messages.append({"role": "assistant", "content": response.content})

        # Act: no tool calls means the model thinks it is done
        if not response.tool_calls:
            return response.text

        results = []
        for call in response.tool_calls:
            if call.name in NEEDS_APPROVAL and not ask_human(call):
                output = "User declined this action."
            else:
                try:
                    output = execute_tool(call.name, call.arguments)
                except Exception as err:
                    # Errors are observations too; let the model adapt
                    output = f"Error: {err}"
            results.append({"tool_call_id": call.id, "content": output})

        # Observe: feed results back for the next turn
        messages.append({"role": "tool", "content": results})

    return "Stopped: turn limit reached before the task was finished."
Pseudo-code: names like call_model and execute_tool are placeholders, not a real SDK

Notice three design choices that matter more than they look. Tool errors are returned to the model as observations rather than crashing the loop, so the agent can try a different approach. Risky tools go through an approval check that the model cannot skip, because it lives in the harness, not the prompt. And the turn limit guarantees the loop ends even if the model never declares itself done.

Key takeaways

  • Every agent runs the same perceive, reason, act, observe loop; the observe step is what lets agents correct their own mistakes.
  • ReAct interleaves reasoning and actions; reasoning models with interleaved thinking now do this inside a single turn, rethinking after each tool result.
  • Plan-and-revise, usually with a written to-do list, is the most common planning approach for long tasks.
  • Prefer the five workflow patterns (chaining, routing, parallelization, orchestrator-workers, evaluator-optimizer) when the structure is known; reach for full autonomy only when it isn't.
  • Give every loop several independent stopping conditions, and enforce human approval for risky actions in the harness, not in the prompt.

Sources & further reading