CTCaliberTek
Course: AI Agents: End to End · Lesson 3 of 7Log in to track your progress and earn a certificate when you finish the course.
AI & Machine Learning

Building an AI Agent Loop in Python

Published October 8, 2026·Updated October 29, 2026·9 min read
Like SaveLog in to like, save, and track progress.

Introduction

With tools defined, the agent is a loop: call the model, run any tools it asks for, feed back the results, and repeat until it gives a final answer. This lesson implements that loop in about forty lines of Python, including a turn limit and proper error handling, using the order-support example.

Prerequisites

  • The function calling lesson
  • The TOOLS list from that lesson

Step-by-Step Guide

Step 1: Implement the tools

These are ordinary Python functions backed by a fake data store. Raising an exception for bad input lets the loop turn it into an error result for the model.

import json

ORDERS = {
    "1042": {"status": "delivered", "total": 39.99, "refunded": False},
    "1043": {"status": "shipped", "total": 12.50, "refunded": False},
}

def lookup_order(order_id: str) -> str:
    order = ORDERS.get(order_id)
    if order is None:
        raise ValueError("Order " + order_id + " not found.")
    return json.dumps(order)

def issue_refund(order_id: str) -> str:
    order = ORDERS.get(order_id)
    if order is None:
        raise ValueError("Order " + order_id + " not found.")
    if order["status"] != "delivered":
        raise ValueError("Only delivered orders can be refunded.")
    order["refunded"] = True
    return "Refund issued for order " + order_id

Step 2: Dispatch tool calls safely

Map tool names to functions, run the requested one, and return the output together with an error flag. Unknown tool names and exceptions become error results instead of crashing the loop.

FUNCTIONS = {"lookup_order": lookup_order, "issue_refund": issue_refund}

def run_tool(name: str, args: dict) -> tuple[str, bool]:
    function = FUNCTIONS.get(name)
    if function is None:
        return "Unknown tool: " + name, True
    try:
        return function(**args), False
    except Exception as error:
        return "Error: " + str(error), True

Step 3: Write the loop

Each turn calls the model. If it did not request a tool, return its text. Otherwise append the assistant's content, run every requested tool, send all results back in a single user message, and continue. The turn limit stops runaway loops.

import anthropic

client = anthropic.Anthropic()
MODEL = "claude-opus-5-5"
SYSTEM = (
    "You are an order-support agent. Use the tools to look up orders and "
    "issue refunds. Only refund delivered orders. Be concise and polite."
)

def run_agent(user_input: str, max_turns: int = 10) -> str:
    messages = [{"role": "user", "content": user_input}]

    for _ in range(max_turns):
        response = client.messages.create(
            model=MODEL,
            max_tokens=16000,
            system=SYSTEM,
            tools=TOOLS,
            messages=messages,
        )

        if response.stop_reason != "tool_use":
            return next((b.text for b in response.content if b.type == "text"), "")

        messages.append({"role": "assistant", "content": response.content})

        results = []
        for block in response.content:
            if block.type == "tool_use":
                output, is_error = run_tool(block.name, block.input)
                result = {"type": "tool_result", "tool_use_id": block.id, "content": output}
                if is_error:
                    result["is_error"] = True
                results.append(result)
        messages.append({"role": "user", "content": results})

    return "Stopped: the agent used too many steps."

Step 4: Try it

Ask something that needs one tool, and something that needs several in sequence. Watch how the agent chooses tools and recovers from an error such as an unknown order.

print(run_agent("Where is order 1042?"))
print(run_agent("Please refund order 1042 and then confirm its status."))
print(run_agent("Refund order 9999."))   # tool error: the agent should explain

Step 5: Know the shortcuts and the limits

SDKs offer helpers that run this loop for you, which are convenient once you understand it. Whichever you use, keep a turn limit, handle errors, and check the stop reason, since a response can also end because it ran out of tokens or was declined.

FAQs

Why send all tool results in one message?
When the model requests several tools in one turn, returning all results together keeps the conversation well-formed and encourages the model to keep calling tools in parallel.
Why append the assistant's content unchanged?
It may contain blocks the API needs to see again, such as reasoning, so the next request must include the previous turn exactly as returned.

Summary

An agent is a loop: call the model, run requested tools, return results, repeat. Add a turn limit, convert failures into error results, and you have a working agent core.

Related tutorials

Comments

Log in or create a free account to join the discussion.

  • No comments yet. Be the first to comment.