Chapter 1: The Agent Loop & ReAct Foundations
What an LLM agent actually is, the perceive-think-act loop that sits at the core of every modern agent, the ReAct pattern that fused reasoning with action, what early autonomous agents got wrong, and the design space you choose from when building your own.
- Topics
- 5
- Demo
- 1
- Videos
- 3
- Min read
- 25
Chapter Overview
An LLM agent is a system that wraps a language model in a loop: it observes the world, thinks about what to do, takes an action, sees the result, and repeats until a task is complete. That sounds trivial, but it is the single most important shift in how we use LLMs since the introduction of chat. A bare LLM is a function — text in, text out, one shot. An agent is a process — a controller that decides when to call the model, what context to give it, what tools it can invoke, and when the work is finally done.
The central object of study is the agent loop itself. Concretely, at every step the agent's controller composes a context from a system prompt, the user goal, the history so far, and any retrieved memory, then asks the LLM to produce one of two things: another thought ("I should look up the user's order ID first") or a structured action (search_orders(user_id='alice')). If it produced an action, the controller executes the corresponding tool, captures the observation, appends (thought, action, observation) to the history, and runs the model again. The loop terminates when the model produces a special final_answer action — or when the controller hits a step budget.
The paper that crystallized this design is ReAct (Yao et al., 2022): Reasoning + Acting. Before ReAct, prompting research had treated reasoning ("chain-of-thought") and acting ("tool use") as separate techniques. ReAct's contribution was simply to interleave them in the same generation: alternating Thought: and Action: lines in a single transcript. That tiny change made the model grounded — its reasoning could be checked against the world via observations, instead of running open-loop and hallucinating its way to a wrong answer.
This chapter covers:
- What is an agent? — agents vs chatbots vs workflows; when the loop is overkill
- The ReAct loop — the canonical interleaved Thought/Action/Observation pattern
- Thought / Action / Observation — what each primitive does and why you need all three
- Early agent failures — AutoGPT, BabyAGI, and the lessons from open-ended planning
- The agent design space — the decision tree from "just call the LLM" to "deploy a multi-agent crew"
Chapter Roadmap
Click any topic to jump in
What Is an Agent?
Agents vs workflows vs chatbots — the LLM owns the control flow at runtime.
From the abstract definition to the implementation
The ReAct Loop
Interleaved Thought / Action / Observation — the canonical pattern that grounded reasoning in real observations.
Thought / Action / Obs
What each primitive does, and how each one fails independently.
Early Failures
AutoGPT and BabyAGI — what open-ended planning, vector-soup memory, and missing self-critique cost us.
The Agent Design Space
A decision rubric: when a workflow beats a loop, and when a single agent beats a crew.
Topics
5 topics in this chapter
Everyone uses the word agent loosely — a chatbot, a script, a cron job, an LLM with a function call — and that looseness makes the category almost useless for design decisions. Before you can choose an architecture you need a definition sharp enough to exclude things. The one that has held up in practice is behavioural: an agent is a system in which an LLM dynamically directs its own control flow. It decides at runtime which tool to call next, whether to ask for clarification, when to retry a failed step, and when the task is actually finished. Contrast that with a workflow, where you the developer wrote the branches and the model merely fills slots inside a structure fixed ahead of time. This topic draws that line precisely, because the rest of the chapter — the ReAct loop, the three primitives, the early failures, the design rubric — only makes sense once you can tell an agent from the workflow it is so often confused with. Anthropic's Building Effective Agents essay makes the sharp, and initially surprising, case that a workflow is usually what you actually want.
Definition
An agent is a system in which an LLM directs its own control flow at runtime — choosing which tool to invoke, when to ask for clarification, when to retry, and when the task is complete. A workflow, by contrast, has that control flow hard-coded by the developer, with the model confined to fixed, pre-arranged steps.
In this topic
- 1Agent vs Workflow vs Chatbot
- 2The Three Capabilities Required
Agent vs Workflow vs Chatbot
A useful three-way split:
- Chatbot: stateless function. One LLM call per user message. No tools, no loop.
- Workflow: you wrote the control flow. The LLM is called from inside fixed branches and chains — summarize → classify → route — but the structure of the program is determined ahead of time.
- Agent: the LLM writes its own control flow at runtime. Given a goal, it picks the next step from an open-ended menu of tools, possibly for many iterations, until it decides it is done.
The practical implication: agents are slower, more expensive, and harder to test than workflows. Use them only when the task is genuinely open-ended (you cannot enumerate the steps in advance) or when the user input space is so wide that no fixed pipeline can cover it.
Think of an agent as a stochastic policy over an action space that includes both external actions (tool calls) and an internal final_answer action that terminates the episode. A workflow is the degenerate case where at every state — there is no decision to make, only computation to perform. As grows, you gain expressive power but pay for it: variance in the policy goes up, episodes get longer, and the value of a strong base model dominates over any clever orchestration.
You are building "a feature where a user types a question and gets the answer from our internal docs." Should you build an agent?
The Three Capabilities Required
Every modern LLM agent depends on three capabilities that did not exist (or were unreliable) in pre-2023 LLMs:
- Instruction following at depth. The model must obey a multi-page system prompt that lays out the loop, the tool schema, output format constraints, and safety rules — across dozens of turns without drifting.
- Structured output. The model must reliably emit either valid JSON for a tool call or a final answer in the exact shape the controller expects. Function-calling APIs and JSON mode are how this is now done in practice.
- In-context reasoning. Given a long history, the model must extract the relevant facts, plan the next step, and avoid repeating work. This is what chain-of-thought and ReAct give you.
If any of the three is missing, you do not have a working agent — you have a system that appears to work on demos and falls apart in production.
These three capabilities can be cast as constraints on the conditional distribution . Instruction following requires that assigns mass only inside the format constraints implied by the system prompt — measurable as the rate at which sampled outputs parse. Structured output requires to be peaked enough that greedy or low-temperature decoding produces valid JSON. In-context reasoning requires the effective context length to actually be useful — a model with a 200k window but a 10k useful window will fail on long agent traces.
Theory Exercise
Problem:
A team is building a customer-support assistant that can either (a) answer FAQs from a knowledge base, (b) refund an order, or (c) escalate to a human. They are debating: agent loop or fixed workflow?
Hints:
- How many distinct branches does the system actually need?
- What goes wrong if the model picks the wrong tool?
- Could a router-then-workflow design get most of the value without the loop?
Related Problems on PixelBank
Once you accept that an agent is an LLM steering its own control flow, the obvious question is: what does one turn of that loop actually look like? ReAct (Yao et al., 2022) is the canonical answer, and it is the pattern almost every framework still implements under the hood. The idea sounds almost too small to matter. Instead of asking the model for a single tool call, or a single burst of chain-of-thought, you ask it for an interleaved trace: alternating Thought: lines, where it plans and self-corrects in natural language, and Action: lines, which the controller actually executes. Each action produces an Observation: that the controller appends back into the prompt, and the loop repeats until the model emits Action: Finish[answer]. This topic dissects that cycle. The contribution was tiny in code but large in capability: ReAct beat both pure chain-of-thought, which hallucinated confident answers, and act-only baselines, which wandered without a plan, on benchmarks like HotpotQA and ALFWorld — because reasoning and grounding finally shared one context window.
Definition
ReAct (Reasoning + Acting) is an agent loop in which the model emits an interleaved transcript of natural-language Thought steps and executable Action steps. The controller runs each action, appends the resulting Observation, and re-invokes the model, repeating until the model issues a terminating Finish action carrying the answer.
In this topic
- 1The Loop, in One Picture
- 2Why Interleave Reasoning and Action
The Loop, in One Picture
At each step the agent samples a (Thought, Action) pair from the policy, executes the action against the environment (a tool, an API, the filesystem), receives an observation, and appends the whole triple back into the state. The state is literally the prompt — a transcript of every prior (Thought, Action, Observation) triple plus the system instructions and the user goal. The loop terminates when the action is the special token Finish[answer].
The transcript IS the agent's memory. There is no hidden state; everything it knows about the task is in the prompt. That is both the great strength of LLM agents (transparent, debuggable) and the great weakness (the context window is the binding constraint as trajectories grow).
The ReAct policy factorizes as . The thought is a hidden variable that conditions the action — analogous to chain-of-thought in pure-text reasoning, but here the action also gets to influence the world. Because thoughts are observable (they are written into the transcript), the loop is introspectable: every decision the agent makes leaves a trace you can inspect later, unlike the inscrutable hidden states of an RL policy.
An agent is given the task: "What was the population of the city where Napoleon was born, in 2020?" Trace what the ReAct loop produces.
Why Interleave Reasoning and Action
Three failure modes the interleaving fixes:
- Reasoning without acting: chain-of-thought alone produces fluent reasoning that invents facts. "Napoleon was born in Corsica, which had population ~3M in 2020" — confidently wrong, with no way to check.
- Acting without reasoning: an act-only agent will fire off tool calls based on surface features of the prompt, with no plan. It often searches the wrong thing first, then never recovers because there is no notion of "that didn't work, try X".
- Reasoning then acting (separate stages): plan up front, then execute the plan blind. Brittle when the environment surprises you (the search returned nothing; the API is down). The interleaved design lets the model react to observations as they arrive.
ReAct works because the model sees its own prior reasoning AND the latest observation in the same context window, so its next thought can incorporate both.
Decompose the cumulative regret of a trajectory into a planning error (you chose the wrong sub-goal) and an execution error (you executed the right sub-goal badly). Pure chain-of-thought minimizes execution error within a fictional model of the world but makes large planning errors when the model is wrong about reality. Pure action minimizes execution error in the real world but makes large planning errors because there is no internal model. ReAct's interleaving lets the planner and executor share state at every step, bounding both terms simultaneously.
Related Problems on PixelBank
ReAct hands you three primitives — the thought, the action, and the observation — and it is tempting to treat them as a single indivisible ritual. They are not. Each one does distinct work, each one degrades in its own characteristic way, and the difference between someone who can build agents and someone who can only watch them fail is knowing which primitive is responsible when a trajectory goes wrong. A thought is free-form planning the controller never executes; an action is the model's committed, parseable interface to the world; an observation is the only signal the agent gets back about whether that action worked. This topic inspects them one at a time. We will see that a weak thought caps the quality of the action that follows it, that the size and grammar of the action space quietly decide reliability, and that most stuck agents are stuck not because the model is weak but because the observations feeding it are uninformative. Pull the three apart now and the debugging chapters later become a matter of reading the trace and knowing exactly where to look.
Definition
The Thought/Action/Observation cycle is the three-part unit of a ReAct step: a Thought is unexecuted natural-language planning, an Action is the executed tool call, and an Observation is the environment's returned result. Each is a distinct failure surface, and each can degrade independently of the other two.
In this topic
- 1Thoughts: the Plan and the Self-Critique
- 2Actions: the Bounded Interface to the World
- 3Observations: the Reality Check
Thoughts: the Plan and the Self-Critique
A Thought: line is free-form natural language the controller will not execute. Its job is to give the model a place to:
- Plan the next sub-goal ("first I need the user's account ID")
- Reason about prior observations ("the search returned nothing useful, I should rephrase")
- Self-critique ("my last action was wrong because I confused two customers")
- Decide it is done ("I have everything I need; I will Finish")
Good thoughts are short, specific, and change the next action. Long, vague thoughts that read like meditation are a sign your system prompt or model is too weak. The other failure mode is no thought at all — models trained heavily on tool-use traces sometimes skip thoughts and act blind, which costs you the introspectability that made ReAct valuable in the first place.
Treat the thought as a low-bandwidth latent variable that the model summarizes its planning into before sampling the action. By the data processing inequality, — the action can be no more informed by the history than the thought is. So the quality of the action is upper-bounded by the quality of the thought. This is why prompting tricks like 'reason step by step' work: they raise and let more signal flow into .
Actions: the Bounded Interface to the World
An Action: is the model's commitment. Once parsed, the controller executes it — calls a function, hits an API, runs a query. Two design decisions matter:
- The action grammar. Modern systems use either (a) the provider's function-calling API (a JSON schema per tool, the model emits a structured tool-use block) or (b) a model-emitted DSL (e.g., search[query], calculator[expr]). Function calling is now standard because it is enforced at the decoding layer.
- The action space size. Too few tools and the agent is hamstrung; too many and the model picks badly. Empirically, agents start to degrade past 10–20 tools. The fix is hierarchy: organize tools into namespaces or use a router LLM to pre-narrow the menu before the executor LLM picks.
Two designs for a coding agent's tool set: (A) one tool, bash(cmd: str) — the agent can run any shell command. (B) twenty tools, one for each common operation: read_file, write_file, git_status, run_pytest, ... Which is better?
Observations: the Reality Check
An Observation: is whatever the controller writes back into the transcript after executing the action. It is the only signal the agent has about whether its action worked. Three principles:
- Be terse. A 50KB JSON blob from an API will blow the context window in a few steps. Truncate, summarize, or extract the relevant field server-side before injecting.
- Be honest. Show errors verbatim — the model uses error messages to recover. Wrapping a 500 from the API in {success: false, message: 'try again'} discards the actual signal.
- Be structured. A consistent format (e.g., always JSON, always keyed) makes it easy for the model to extract the relevant field on subsequent turns.
Each observation injects bits of new information into the transcript. The context-budget constraint means , so observations compete with thoughts and actions for finite tokens. Compress aggressively: an observation that contains useful bits but tokens is worse than one with bits and tokens, because the surplus tokens crowd out future steps.
Theory Exercise
Problem:
An agent's transcript shows: Thought: 'I should search the docs.' Action: search['docs']. Observation: '[empty]'. Then the model emits Thought: 'I should search the docs.' Action: search['docs']. Observation: '[empty].' What's wrong, and how do you fix it without retraining?
Hints:
- Why is the model repeating itself?
- What information from the prior step did it ignore?
- What kind of observation would have prevented the repetition?
AutoGPT (March 2023) and BabyAGI (April 2023) were the first agents to reach a wide audience, and they arrived wrapped in extraordinary hype: give an LLM a goal, the demos implied, and it would plan, remember, browse, and self-direct its way to done. Running them taught a harsher lesson. They could indeed plan and act, but they failed — reliably, and in ways the whole wave of mid-2023 'autonomous agent' projects went on to repeat. This topic dissects three of those failure modes, because each maps directly onto a design principle you will use in every later chapter. Open-ended planning with no termination signal burns money without ever converging. Memory implemented as undifferentiated vector-database soup pollutes the context and loses what actually matters. And a loop with no self-critique compounds a single early error into fifty steps of downstream nonsense. Understanding why these happened — not merely that they did — is the most reliable inoculation against rebuilding the same broken agent under a new name when you start writing your own.
Definition
The early autonomous agents AutoGPT and BabyAGI exhibited three canonical failure modes: open-ended planning with no termination signal, memory reduced to unstructured vector-database retrieval, and loops lacking any self-critique or recovery. Each maps to a concrete design principle — bounded termination, structured memory, and explicit reflection.
In this topic
- 1Failure Mode 1: Open-Ended Planning Without a Termination Signal
- 2Failure Mode 2: Memory as Vector-DB Soup
- 3Failure Mode 3: No Self-Critique, No Recovery
Failure Mode 1: Open-Ended Planning Without a Termination Signal
AutoGPT was given a goal like "start a profitable e-commerce business." It would generate a top-level plan ("research market → build website → ..."), spawn sub-goals, and recurse. The problem: there was no signal anywhere in the loop telling it whether it was making progress. It would happily generate plausible-sounding plans for hours, run up an OpenAI bill, and finish with a folder of half-broken Python scripts and a Word document.
The lesson: agents need either (a) a measurable termination criterion ("the test suite passes"), (b) a strict budget ("stop after 30 steps"), or (c) a human in the loop every iterations. Goals like "build a business" don't admit a termination signal at all and are a category error for agents.
Without a reward signal that is non-flat over the trajectory, the agent has no gradient — neither in training nor in inference-time decisions about when to stop. AutoGPT's effective reward was constant: every step looked equally productive to the model. The expected number of useful steps under a constant reward is — you might get lucky early, but additional steps add no information.
Failure Mode 2: Memory as Vector-DB Soup
Both AutoGPT and BabyAGI shoved every prior thought, action, and observation into a vector database, then retrieved "similar" snippets to inject into the next prompt. Three things went wrong:
- Recency bias loss. Vector similarity is not the same as recency or relevance. Old, embedded-and-forgotten plans would surface in the middle of unrelated work, derailing the agent.
- Context pollution. With retrieved snippets per step, the prompt filled with off-topic context within a few iterations. The agent forgot what it was doing.
- No structure. A flat blob of text snippets lost the relationships between thoughts (cause→effect, plan→sub-plan) that were obvious in the original transcript.
The lesson: "memory" is not the same as "retrieval". Modern agents (Letta/MemGPT, Mem0) treat memory as structured state — typed blocks (system, user, working, episodic) with explicit eviction rules — not as a soup of past tokens.
You are debugging an agent that 'forgets' the user's stated preference ("please respond in French") after about 20 turns. The system uses a 50-snippet vector store per turn. What's likely wrong?
Failure Mode 3: No Self-Critique, No Recovery
When an action failed, AutoGPT's loop simply moved on — it did not re-plan in light of the failure. So a broken pip install early in the run would silently turn into a 50-step trajectory of code that depended on the missing package. The eventual error message was so far downstream from the cause that the agent could not connect them.
The lesson: agents need an explicit reflection step — at minimum, after a tool returns an error, the model should be prompted to diagnose the failure and revise the plan, not just continue. Reflexion (Shinn et al., 2023) formalized this as "verbal RL": after a failed trajectory, generate a paragraph of self-critique and append it to the next attempt's context. Even without weight updates, this dramatically improves success rates on multi-step tasks.
You now understand the loop and the ways it breaks, which finally puts you in a position to make the most important decision in this whole subject: whether to build an agent at all. Most of the design space is not an agent loop, and the fashionable choice is rarely the right one. This closing topic hands you a decision rubric — a ladder of architectures ordered by how much control flow the LLM owns, from a single one-shot call, through fixed workflows like chains, routing, and orchestrator–worker, up to a genuine ReAct agent and finally a multi-agent system. The governing rule is simple to state and hard to follow under peer pressure: default to the lowest tier that solves your problem, because every rung up the ladder costs latency, money, and reliability. We work through where a workflow beats a loop, and where a single well-prompted agent beats a crew of specialists. Get this choice right the first time and most of the failure modes from the previous topic never get the chance to appear at all.
Definition
The agent design space is a ladder of architectures ordered by how much control flow the LLM owns: one-shot call, prompt chain, routing, parallelization, orchestrator–worker, single ReAct agent, and multi-agent system. The design rule is to default to the lowest tier that solves the problem, since each step up trades reliability for expressive power.
In this topic
- 1The Spectrum, From Simple to Complex
- 2When to Reach for a Multi-Agent System
The Spectrum, From Simple to Complex
Order systems by how much control flow the LLM owns:
- One-shot LLM call. Single prompt, single completion. Use when: the task is bounded and a workflow is overkill.
- Prompt chain (workflow). Fixed sequence of LLM calls. Use when: you can write the steps as Python.
- Routing (workflow). One LLM picks a downstream branch from a small fixed set. Use when: the input space splits into a few qualitatively different cases.
- Parallelization (workflow). Run several LLM calls concurrently and combine. Use when: the sub-tasks are independent.
- Orchestrator–worker (workflow). A planner LLM emits a fixed-shape plan; worker LLMs execute it. Use when: the plan structure is known but the steps need reasoning.
- ReAct agent (single agent). The LLM chooses tools dynamically in a loop. Use when: the trajectory cannot be enumerated in advance.
- Multi-agent system. Multiple agents with distinct roles coordinate. Use when: the task naturally factors into roles AND you have observability to debug it.
Default to the lowest tier that solves your problem. Every step up the ladder costs latency, money, and reliability.
Plot 'expressive power' on the x-axis (the size of the policy's action space at each step) and 'reliability' on the y-axis (the inverse of the trajectory's failure variance). The frontier curves down: each unit of expressive power costs reliability. The lowest-tier system that lies on the frontier for your task is the right answer. Most production teams pick a system above their task's frontier — they pay for expressive power they do not use, and lose reliability they cannot afford.
When to Reach for a Multi-Agent System
Multi-agent (Chapter 8) is alluring because it maps so naturally to org charts ("a Researcher agent, a Writer agent, an Editor agent..."). It is also the design that fails most often in early production, because every additional agent multiplies the failure modes of communication, role drift, and looping.
Reach for multi-agent only when:
- The roles have genuinely different system prompts and tool sets — an Editor that has access to revision-history APIs the Writer does not
- The work decomposes into independent sub-tasks (parallelization wins) or has a natural adversarial structure (debate, critique)
- You have the observability story for tracing N concurrent loops simultaneously, OR your traffic is low enough that you can step through manually
If you cannot tick all three, build a single agent with role-conditional prompting first.
A team wants to build a 'research crew': one agent searches the web, one agent reads PDFs, one agent writes the summary. Should they?
Theory Exercise
Problem:
You inherit a feature where a single ReAct agent has a 12-step average trajectory and a 23% failure rate. What's the first thing you do — change the model, add reflection, narrow the tool set, or convert it to a workflow?
Hints:
- Where does the failure budget go: planning errors or execution errors?
- Does the action space need all the tools the agent has?
- Is the 12-step trajectory because the task requires it, or because the agent is wandering?