Start free

Zero to FDE / Blog / What is an AI agent? The agent loop, explained with code

Blog

What is an AI agent? The agent loop, explained with code

An AI agent is a language model running in a loop. The model decides which tool to use, your code runs that tool, the result goes back to the model, and the loop repeats until the model has an answer or a limit is reached.

Tool calling: the model asks, your code acts

You describe each tool to the model with a name, a plain-English description and a JSON schema for its inputs. When the model decides a tool would help, it does not run anything itself. It replies with a structured request: this tool, with these arguments. Your code runs the function, then sends the result back as the next message.

That split matters. The model chooses; your code executes. Everything the agent can actually do is code you wrote and control.

The whole loop, in Python

This uses Anthropic’s Python SDK (pip install anthropic, with ANTHROPIC_API_KEY set). The order lookup is a stand-in for a real database call.

import json, os
import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment
MODEL = os.environ.get("ANTHROPIC_MODEL", "claude-sonnet-5-5")

def get_order_status(order_id: str) -> dict:
    # A stand-in for a real database or API call.
    orders = {"A100": "shipped", "A101": "processing"}
    if order_id not in orders:
        raise KeyError(f"no order with id {order_id}")
    return {"order_id": order_id, "status": orders[order_id]}

TOOLS = [{
    "name": "get_order_status",
    "description": "Look up the current status of a customer order by its ID.",
    "input_schema": {
        "type": "object",
        "properties": {"order_id": {"type": "string", "description": "The order ID, for example A100"}},
        "required": ["order_id"],
    },
}]
FUNCTIONS = {"get_order_status": get_order_status}

def run_agent(question: str, max_steps: int = 5) -> str:
    messages = [{"role": "user", "content": question}]
    for _ in range(max_steps):
        response = client.messages.create(model=MODEL, max_tokens=1024, tools=TOOLS, messages=messages)
        messages.append({"role": "assistant", "content": response.content})
        if response.stop_reason != "tool_use":
            # The model answered instead of asking for a tool: we are done.
            return "".join(block.text for block in response.content if block.type == "text")
        results = []
        for block in response.content:
            if block.type != "tool_use":
                continue
            try:
                output = FUNCTIONS[block.name](**block.input)
                results.append({"type": "tool_result", "tool_use_id": block.id, "content": json.dumps(output)})
            except Exception as err:
                # Report the failure to the model instead of crashing; it can retry or explain.
                results.append({"type": "tool_result", "tool_use_id": block.id, "content": str(err), "is_error": True})
        messages.append({"role": "user", "content": results})
    return "Stopped: the step limit was reached."

print(run_agent("Where is order A101?"))

Read it as four moves on repeat: send the conversation and the tool list; if the model asked for a tool, run it; append the result; go again. When the model stops asking for tools, its text is the answer.

What makes an agent production-ready

  • A step limit. The max_steps guard stops a confused model from looping forever and running up a bill.
  • Errors returned, not raised. A failed tool call goes back to the model marked as an error, so it can retry with better arguments or explain the problem.
  • Logs of every step. Record each tool call, its arguments and its result. When something goes wrong, this is the only way to see why.
  • Human approval for risky actions. Anything that sends money, deletes data or emails a customer should wait for a person to confirm.
  • Evaluation. A fixed set of test questions with expected outcomes, run on every change, catches regressions before users do.

When not to use an agent

If the steps are always the same, you do not need the model to decide them. A plain function or a fixed workflow is cheaper, faster and easier to test. Agents earn their cost when the right next step depends on what the previous one found.

Frameworks come second

Frameworks such as LangGraph add state, branching and checkpoints on top of this same loop. They are much easier to use well once you have written the loop yourself and know what they are doing for you.

That is the order Zero to FDE teaches: Week 2 builds tool calling from scratch, Week 4 the full agent loop by hand, Week 5 LangGraph, and Week 8 evaluation. Start with Week 1, free, or see the full roadmap.

Zero to FDE is a 90-day path, for working engineers and AIML graduates, to the work Forward Deployed Engineers do: backend basics, LLMs, RAG, agents, evaluation and deployment, with a shipped deliverable every week. Week 1 is free and complete, no card needed.

Start Week 1 free

More from the blog