Skip to content
CodeStoa
AI Engineering · Loop EngineeringBeginner

The Agent Loop: How an LLM Plans, Acts and Knows When to Stop

An agent is a model inside a loop: it reads the goal and the history, picks the next tool, sees the result, and repeats. Loop engineering is designing that loop on purpose, including how it stops.

6 min readPublished
0:00 / 7:29

A swim before ten

Alex wants to swim on Saturday morning and has one rule: it must be before 10:00, because the café next door stops serving breakfast then. The local pool has a booking assistant, so Alex types: "Book me a lane swim on Saturday before ten."

A model on its own can't do this. It can write a friendly reply, but it doesn't know which lanes are free, and it can't press the booking button. To help Alex it has to look at the timetable, act by booking a slot, check whether the booking worked, and only then answer. That's several steps, and each one depends on what the last one found.

Here is the timetable at the moment Alex asks. Keep it in mind: every example in this lesson uses it.

  • sat-0700

    Time
    07:00
    Lanes free
    0
    Before 10:00?
    yes
  • sat-0800

    Time
    08:00
    Lanes free
    1
    Before 10:00?
    yes
  • sat-0900

    Time
    09:00
    Lanes free
    3
    Before 10:00?
    yes
  • sat-1100

    Time
    11:00
    Lanes free
    4
    Before 10:00?
    no
Saturday morning at the pool. The single 08:00 lane is about to go to Bob.

Doing a task in steps, where each step depends on what the last one found, is what people mean by an agent. This is the first lesson of the Loop Engineering module, and loop engineering is the job of designing that repeat-until-done cycle on purpose: what the model sees, what it may do, how results are checked, and when it must stop.

The loop: read, decide, act, observe

Every agent, whatever library it's built with, runs the same cycle. Your code holds a history: the goal plus everything that has happened so far. On each turn of the loop:

  1. Read. Your code sends the goal and the whole history to the model.
  2. Decide. The model replies with one of two things: a final answer, or a tool call, a structured request such as book_slot with the argument sat-0900.
  3. Act. Your code, not the model, runs that tool. The model only asks.
  4. Observe. The tool's result, called an observation, is added to the history, and the loop goes round again.
  • Alex's request (goal + history) to Assistant thinks (model)
  • Assistant thinks (model) to Use a tool (tool call)
  • Assistant thinks (model) to Reply to Alex (final answer)
  • Use a tool (tool call) to Booking system (tool runs in your code)
  • Booking system (tool runs in your code) to What happened (observation)
One turn of the loop. The observation is appended to the history and the next turn starts from the left; a final answer ends the run.

Model APIs from the main providers work this way. You describe each tool with a name, a short description and the arguments it takes, and the model's reply either is text or names a tool to call with arguments. A reply can carry some text too, and many APIs let it ask for several tools at once; this lesson runs one call per turn to keep the loop easy to follow. In a loop, a reply with no tool call is the final answer. The idea was popularised by the 2022 ReAct paper by Yao and colleagues, which interleaved the model's reasoning with actions and the observations they produced, instead of asking for an answer in one go.

One run, step by step

Here is Alex's request going round the loop. Just after the assistant reads the timetable, Bob books the last 08:00 lane from the pool's front desk.

  • 1

    Model decides
    list_slots(sat)
    Observation
    07:00 full, 08:00 has 1, 09:00 has 3, 11:00 has 4
    Why
    It can't book what it hasn't seen
  • 2

    Model decides
    book_slot(sat-0800)
    Observation
    error: sat-0800 is full
    Why
    Earliest free slot before 10:00
  • 3

    Model decides
    book_slot(sat-0900)
    Observation
    booked sat-0900
    Why
    The error is in the history, so it tries the next slot
  • 4

    Model decides
    final answer
    Observation
    none
    Why
    Booked, so there is nothing left to do
Four turns of the loop: three tool calls and one answer.

Step 2 is the important one. The plan was reasonable when the model made it, and the world changed anyway. Because the failure came back as an observation instead of crashing the program, the model could read it and adapt. A one-shot reply would have told Alex "you're booked at 08:00", and Alex would have turned up to a full pool.

Notice also that nobody wrote "if 08:00 is full, try 09:00". The model chose the next step from the history. That flexibility is the reason to use a loop, and it's also the risk: the same freedom lets it choose badly.

Knowing when to stop

The normal way out of the loop is the model's final answer. But you can't rely on it alone, because a loop that only stops when the model decides to stop has no stop at all when the model gets stuck.

Bob builds his own version of the assistant to try it out, and his first test hits a bug: the model calls list_slots(sat), reads the result, and calls list_slots(sat) again, and again. Nothing in his code ends it. Every turn is another paid model call, and Bob only notices when the bill arrives. A loop without guards is an easy first bug to write, so the guards go in before the first test.

  • Final answer

    Limit in this example
    the model says it's done
    What it catches
    The normal, happy ending
  • Step limit

    Limit in this example
    6 turns
    What it catches
    A model that wanders and never finishes
  • Repeated call

    Limit in this example
    same tool and arguments 3 times
    What it catches
    A model stuck asking the same thing
  • Budget

    Limit in this example
    assume 20,000 tokens or 60 seconds
    What it catches
    A long run that costs too much or keeps Alex waiting
Four ways out of the loop. The limits are examples; set yours from your own runs.

In code, the guards are a few lines around the loop. The step limit is simply the loop's range, and the repeat check counts each tool-and-arguments pair. Run on Bob's model, this stops on step 3; run on Alex's request, it returns the answer on step 4, as in the table above.

agent_loop.py
def run(goal, model, max_steps=6):
    history = [{"goal": goal}]
    counts = {}
    for step in range(max_steps):              # guard: step limit
        move = model(history)
        if "answer" in move:                   # normal stop: final answer
            return move["answer"]
        key = (move["tool"], str(move["args"]))
        counts[key] = counts.get(key, 0) + 1
        if counts[key] == 3:                   # guard: same call 3 times
            return "stopped: same call 3 times"
        result = run_tool(move["tool"], move["args"])  # validates, catches errors
        history.append({"call": move, "result": result})
    return "stopped: step limit"
The core loop. model is the model call and run_tool runs one tool safely; both are left out because the loop is the point.

When a guard fires, end the run on purpose: tell the user plainly that the booking didn't finish, and log the history so you can see why. Never let a guard look like success.

Checking what comes back

Two checks sit between the model and the tools, and both live in your code.

  • Validate the arguments before running the tool. If the model asks for book_slot(sat-8am), there is no such slot. Your code rejects it with an observation like unknown slot 'sat-8am' and the model can correct itself on the next turn. Never pass unchecked arguments to something that changes the real world.
  • Turn tool errors into observations. When the booking system says a slot is full, or a network call times out, catch the error and put its message in the history. Some APIs, such as Anthropic's, also let you flag a tool result as an error; others just take the error text as the result. A crash ends the run; an observation gives the model a chance to recover.

Expert corner: where loops break

  • Cost grows faster than steps. Each turn sends the whole history again (or the provider re-reads it for you), so turn ten pays again for everything in turns one to nine. Keep observations small: list_slots should return only the free slots, not the pool's full year.
  • Retries can repeat side effects. If book_slot times out after the booking went through, a retry books Alex twice. Give actions a unique request key so a repeat is ignored, and ask the user to confirm anything that can't be undone, such as a payment.
  • Step limits cut both ways. Too low and good runs fail; too high and stuck runs burn money. Look at how many turns real runs take and set the limit a little above that.
  • Not every task needs a loop. If the steps are always the same, list then book, write them as plain code. Use a loop when the next step depends on what the last one found.

In a system design interview, "design an agent that books appointments" is really a question about this loop. Draw it, then name the stop conditions, where tool errors go, which actions need confirmation, and what you log on every turn so a bad run can be replayed.

Recap

An agent reads the goal and history, decides on an answer or a tool call, lets your code run the tool, and adds the result to the history before going round again. Alex got a 09:00 lane because the failed 08:00 booking came back as an observation, and Bob's stuck loop ended because a guard was waiting for it.

Summary

Key takeaways

  • An agent loop repeats four steps: read the goal and history, decide, run a tool, add the result to the history.
  • The model only asks for a tool call; your code runs the tool and controls what is allowed.
  • A final answer is the normal stop, but every loop also needs a step limit, a repeated-call check and a budget.
  • Tool errors go back to the model as observations, so it can recover instead of the run crashing.
  • Validate tool arguments in code before anything touches the real world.
  • Loop engineering means designing this loop on purpose: inputs, tools, checks and stop conditions.

Practice

Check your understanding

Question 1

01In the agent loop, who actually runs the book_slot tool?

Question 2

02Bob's model keeps calling list_slots(sat) with nothing else changing. Which guard ends this run soonest in the lesson's code?

Question 3

03Step 2 returns sat-0800 is full. Why is it better to add this to the history than to raise the error?

Question 4

04The model asks for book_slot(sat-8am). What should your code do?

Question 5

05Every Friday the pool's newsletter job does the same two steps: fetch the timetable, then email it. What is the better design?

0 of 5 answered

Finished this lesson?

Mark it done to track your progress. Saved in this browser only.

FAQ

Frequently asked questions

What is an agent loop in AI?

It's the cycle an LLM agent runs: your code sends the goal and history to the model, the model either answers or asks for a tool call, your code runs the tool, and the result is added to the history for the next turn. It repeats until the model answers or a guard stops it.

How does an AI agent know when to stop?

Normally the model returns a final answer instead of another tool call. Because a model can get stuck, the loop also needs hard limits in code: a maximum number of steps, a token or time budget, and a check for the same call repeating.

What should an agent do when a tool call fails?

Catch the error and add its message to the history as the tool's result and, where the API supports it, flag it as an error. The model reads it on the next turn and can try another approach, such as a different slot, instead of the program crashing.

Is the ReAct pattern the same as an agent loop?

ReAct, from a 2022 paper by Yao and colleagues, is one well-known form of it: the model alternates reasoning steps with actions and reads each action's observation. Today's tool-calling APIs run the same read, act, observe cycle with structured tool calls.

  • 6:28

    AI Engineering Beginner 4 min read

    LLM Evals: Why "It Looks Good" Isn't Enough

    LLM evals are systematic, repeatable tests that judge an LLM app against clear criteria. Learn why spot checks fail, how evals differ from classic tests, and the workflow to run them.

    Oct 19, 2026

  • 5:38

    AI Engineering Beginner 6 min read

    Failure Points in LLM Applications: Where RAG Apps Break

    A RAG chatbot can fail in its retriever, its generator, the flow between them or the app as a whole. Follow one customer's question to see why checking only the final answer can't tell you which part broke.

    Oct 22, 2026