AI Engineering Learning Hub

AI Agents & the Agent Loop

What an AI agent really is: an LLM in a loop with tools, a step limit and state. ReAct, planning, and when not to build one.

What it is

An agent is a program that lets a model decide what to do next, do it through tools, look at the result and decide again, until a goal is reached. Strip away the marketing and that is the whole definition: a loop around function calling with some memory and a stop condition.

The canonical shape is ReAct, short for reason and act. Each iteration the model writes a short thought, picks an action (a tool call), the code executes it, and the observation goes back into the context. The loop ends when the model decides it can answer, or when the step limit says it must.

My voice agent is a small agent by this definition. The model has a search tool and a screen-control tool. A visitor asks about my AWS work, the model calls search_portfolio, reads the chunks, calls show_on_screen to display the experience card, then speaks the answer. Three steps, two tools, one loop.

Why it's needed

A single prompt cannot look things up, cannot check its work and cannot take actions in the world. The moment a task needs 'find out X, then based on X do Y', you need a loop. Agents are how LLMs stop being a text box and become software that gets things done.

The loop is also where most of the engineering risk lives. Each extra step multiplies latency, cost and the chance of a wrong turn. Understanding the loop is what lets you decide when a plain pipeline with fixed steps is better than an agent, which is more often than the hype suggests.

How it works

  • Give the model a goal, a system prompt describing its tools and limits, and the conversation so far.
  • Call the model with the tool schemas. It either answers or returns one or more tool calls.
  • Execute each tool call in your code, validate the arguments, and append the results as tool messages.
  • Repeat. Track the step count, elapsed time and tokens used; stop at a hard limit and return a partial result rather than running forever.
  • Keep state outside the context where possible: a scratchpad of findings, a list of completed sub-tasks, files on disk. Context is expensive memory.
  • For bigger tasks, plan first: ask the model for a numbered list of sub-tasks, then run the loop per sub-task. Planning cuts wandering.

Code example

import json, time
from openai import OpenAI

client = OpenAI()
MAX_STEPS, MAX_SECONDS = 8, 30

def run_agent(goal: str, tools: list, funcs: dict, system: str) -> str:
    messages = [{"role": "system", "content": system},
                {"role": "user", "content": goal}]
    start = time.time()
    for step in range(MAX_STEPS):
        if time.time() - start > MAX_SECONDS:
            return "Stopped: time budget exceeded."
        r = client.chat.completions.create(model="gpt-4o-mini",
                                           messages=messages, tools=tools)
        msg = r.choices[0].message
        if not msg.tool_calls:
            return msg.content                      # agent decided it is done
        messages.append(msg)
        for call in msg.tool_calls:                 # act
            args = json.loads(call.function.arguments)
            try:
                result = funcs[call.function.name](**args)
            except Exception as e:                  # observation, not a crash
                result = f"Tool error: {e}"
            print(f"step {step}: {call.function.name}({args}) -> {str(result)[:60]}")
            messages.append({"role": "tool", "tool_call_id": call.id,
                             "content": str(result)})
    return "Stopped: step limit reached. Partial findings above."

Where I used this

My voice agent runs a small agent loop inside Pipecat: the LLM has search_portfolio and show_on_screen tools, calls them as the conversation needs, and a hard session timer plus a cheap model keep every call bounded in time and cost.

Use cases

  • Research assistants that search, read and summarise across several sources
  • Support agents that look up an order, check policy and issue a refund through APIs
  • Voice concierges that answer and control a screen at the same time
  • Coding assistants that read files, run tests and edit based on the output
  • Data tasks: query a database, inspect the result, refine the query

Common mistakes

  • No step limit or time limit. An agent that cannot stop will eventually loop on a failing tool and run up the bill.
  • Building an agent for a fixed workflow. If the steps are always the same, write the pipeline in code and call the model only where judgement is needed. It is faster, cheaper and testable.
  • Letting tool errors crash the loop. Return the error text as the observation; the model usually recovers.
  • Giving the agent twenty tools. Selection accuracy drops; group tools or route to specialised sub-agents with a few each.
  • Trusting the final answer without logs. Record every step so you can replay a bad run and see where it turned.

Interview questions

What is the difference between an LLM pipeline and an agent?
A pipeline has fixed steps decided by the developer: retrieve, then prompt, then answer. An agent lets the model decide the steps at run time by choosing tools. Pipelines are predictable and cheap; agents handle open-ended tasks. Use the simplest one that solves the problem.
What is ReAct?
A prompting and loop pattern where the model alternates reasoning ('I should check the knowledge base') with acting (calling a tool) and observing the result. The visible reasoning improves tool choice and makes the trace debuggable. Modern function-calling APIs implement the act and observe parts natively.
How do you stop an agent from running forever?
Hard limits on steps, wall-clock time and tokens, enforced in code rather than asked of the model. When a limit is hit, return what was found so far with a clear message. In my voice agent the equivalent is a session timer that ends the call regardless of the conversation state.
How do you test an agent?
Mock the tools and assert on the trajectory: which tools were called, in what order, with what arguments, and what the final answer was. Keep a set of goals with expected trajectories and rerun it after every prompt change. Add a few live runs as smoke tests. Testing only the final text hides wrong turns that happened to end well.
When would you use multiple agents?
When one agent would need too many tools or too much context. A router agent with a few specialised sub-agents, each with a small tool set and focused prompt, usually beats one giant agent. The cost is coordination logic and more calls, so I only split when a single agent measurably picks wrong tools.
What state should live outside the context window?
Anything large or long-lived: documents retrieved so far, intermediate results, a task checklist, user preferences. Keep a compact summary in the context and the full data in memory or on disk, retrieved by tool when needed. Context is the most expensive and least reliable place to store state.
Ask the AI assistant about this topic

Get new topics by email

One short, practical AI-engineering lesson whenever a new topic is published. No spam, unsubscribe any time.

Need this built for your product?

I build production RAG pipelines, LLM automations and voice agents. Open to freelance projects and full-time roles.