Building AI agentsMiddleLesson 1967 min read

The agent loop in code

An agent is a loop: the model looks, decides, acts, and looks again. Write that loop yourself in about 30 lines of Python, with stop conditions and a step limit.

Lesson in motion

In 60 seconds

The agent loop in code

An agent is a loop: the model looks, decides, acts, and looks again. Write that loop yourself in about 30 lines of Python, with stop conditions and a step limit.

1/5
In simple words
Think of a cook making dosa for the first time. She looks at the pan, decides "too hot", turns the flame down, and looks again. She keeps going until the dosa is done, or until she gives up and orders food. An agent works the same way: look, decide, act, look again, and stop at the right time.
You already know from From chatbot to agent that an agent is a model plus a goal, tools, memory and a loop. This lesson is about the loop itself. Most agent frameworks hide it, but the core is small. Once you have written it by hand, every framework becomes easier to understand and debug.

The three steps, again and again

  1. 1

    Observe

    Collect what the agent knows now: the task, earlier messages and the latest tool result.
  2. 2

    Think

    Send all of that to the model. It answers with either a tool call or a final answer.
  3. 3

    Act

    If it asked for a tool, your code runs the tool and adds the result to the messages.
  4. 4

    Check the stop conditions

    Final answer? Step limit reached? Error that cannot be fixed? If not, go back to Observe.
Notice who does what. The model only writes text: a request like "call get_weather with city Chennai". Your code decides whether to run it, runs it, and decides when to stop. That split is the most important idea in agent building.

A complete loop you can run offline

The model below is fake, so the code runs without an API key. It always asks for the weather, then answers. In a real agent you replace call_model() with a call to your provider's chat API with tools enabled, and turn its reply into the same small dictionary.
agent_loop.py: observe, think, act, with a step limitpython
def get_weather(city: str) -> str:
    fake = {"Chennai": "34 C and humid", "Shimla": "12 C and clear"}
    return fake.get(city, "error: unknown city " + city)

TOOLS = {"get_weather": get_weather}

def call_model(messages: list) -> dict:
    # Placeholder model. Plug in your provider here and convert its reply to
    # {"tool": name, "args": {...}} or {"answer": text}.
    last = messages[-1]
    if last["role"] == "user":
        return {"tool": "get_weather", "args": {"city": "Chennai"}}
    return {"answer": "It is " + last["content"] + " in Chennai. Carry water."}

def run_agent(task: str, max_steps: int = 5) -> str:
    messages = [{"role": "user", "content": task}]
    for step in range(max_steps):
        reply = call_model(messages)                # think
        if "answer" in reply:                       # stop: model is done
            return reply["answer"]
        name, args = reply.get("tool"), reply.get("args", {})
        if name not in TOOLS:
            result = "error: there is no tool called " + str(name)
        else:
            try:
                result = TOOLS[name](**args)        # act
            except Exception as err:
                result = "error: " + str(err)
        messages.append({"role": "tool", "content": result})   # observe
    return "Stopped: reached the step limit without an answer."

print(run_agent("Do I need to carry water in Chennai today?"))

Stop conditions: the part people forget

A loop without good stop conditions can run forever, burn money, or keep repeating the same failing call. Give every agent several ways to stop:
Stop conditionWhy you need it
The model gives a final answerThe normal, happy ending.
Step limit (max steps)Stops runaway loops. Pick a number from real tests, not a guess.
Budget limit (tokens, money or time)Stops one task from using far more than it should.
Repeated identical tool callIf the same call with the same arguments fails three times, it will not work the fourth time.
A risky action needs approvalPause and ask a person instead of acting (see Keeping a human in the loop).
Note
When the loop stops early, say so clearly. "Stopped: step limit reached" is far more useful to a user and to you when debugging than a made-up answer.

Errors go back to the model

In the code above, a crash inside a tool does not crash the agent. The error becomes a tool result, and the model sees it on the next step. Often it can fix the problem itself, for example by trying a different city spelling. Only stop when the error clearly cannot be fixed by the model.
A fragile loop
  • No step limit: while True
  • A tool exception crashes the whole run
  • The model's tool name is trusted and called directly
  • Stops silently and returns nothing
A sturdy loop
  • A step limit and a budget limit
  • Tool errors become readable tool results
  • Only names in your TOOLS table can run
  • Every stop has a clear reason
Watch out
Tool results come from the outside world, so they are untrusted. A web page or email the tool returns can contain instructions aimed at the model. The loop above adds results as tool messages, never as system instructions. See Indirect injection: the invisible note.
Try this. Change the fake model so that it asks for the weather in "Mumbai" every time and never answers. Run it. Which stop condition saves you?

Watch and read more

Lab

A tiny agent that runs offline with a fake model and a fake train-status tool, with three stop conditions.

~30 min

The problem

Build a small agent that answers questions like "Is train 12345 running late?" without any API key.

  1. Copy the starter. It has a fake train_status tool and a fake model.
  2. Finish run_agent: call the model, run the tool if asked, add the result as a tool message, and return the final answer.
  3. Add three stop conditions: final answer, max_steps, and "the same tool call with the same arguments happened 3 times".
  4. Test three cases: a known train, an unknown train (the tool returns an error), and a fake model that loops forever. Print the reason each run stopped.

Practice lab

Edit the code and run it. Python runs in your browser — nothing is sent to our server.

Output

No output. Add print(...) to see values.

You are done when

Hard questions

Try to answer before you reveal. If you can answer these, you understood the lesson.

Q1Your step limit is 10, but one step can use very different amounts of tokens. Why is a step limit alone not enough to control cost?Reveal

One step can be a short call, and another can include a huge tool result (a long web page or file) that fills the context. Later steps then resend all that text. So cost grows with context size, not only with step count. Add a token or money budget per task and trim or summarise big tool results.

Q2Why is "the same call three times" a better loop detector than "the same tool three times"?Reveal

Calling one tool several times with different arguments is often normal work, for example checking three trains. Calling it with identical arguments and getting the same error means the agent is stuck. Comparing the full call avoids stopping good runs while still catching loops.

Please sign in to continue.

Questions people ask

Do I need a framework to build an agent?

No. A basic agent is a loop, a model call and a table of tools, as you saw. Frameworks add useful things such as tracing, retries and many ready-made tools. Write the loop yourself once, so you understand what the framework does for you.

How do real APIs return a tool call?

Most chat APIs with tool or function calling return a structured part in the reply: a tool name and arguments as JSON, often with an id. You send the tool result back with the same id. The exact format differs by provider, so check your provider's current docs and convert it to a simple shape like the dictionary above.

What is a good max_steps value?

It depends on the task. Run your agent on realistic tasks, see how many steps successful runs take, and set the limit a little above that. A simple lookup might need 3 to 5 steps; a long research task may need more. Also add a budget limit, because steps can differ a lot in cost.

Can the model call a tool that is not in my list?

It can write any name, including made-up ones. That is why your code checks the name against your own table and returns an error for anything else. The model never runs code directly.

Lesson test

5 questions. Get 3 right (60%) to pass and complete this lesson.

Sign in to take the test and save your progress