The autonomous loop

The solution is a while loop: call the LLM, check if it wants to use tools, execute them, add results back, and repeat. The loop ends when the LLM responds with text (no tool_calls) or when we hit a safety limit.

04-agent-loop.ipynb
python
class Agent:
    def __init__(self, model, tools, available_functions,
                 max_steps=5):
        self.model = model
        self.tools = tools
        self.available_functions = available_functions
        self.max_steps = max_steps
        self.messages = []

    def run(self, prompt: str):
        self.messages.append(
            {"role": "user", "content": prompt}
        )

        for i in range(self.max_steps):
            response = completion(
                model=self.model,
                messages=self.messages,
                tools=self.tools
            )
            message = response.choices[0].message
            self.messages.append(message)

            tool_calls = message.get("tool_calls", [])

            # No tool calls = final answer
            if not tool_calls:
                return message.content

            # Execute each tool
            for tool_call in tool_calls:
                name = tool_call.function.name
                args = json.loads(
                    tool_call.function.arguments
                )
                result = self.available_functions[name](
                    **args
                )
                self.messages.append({
                    "role": "tool",
                    "name": name,
                    "content": result,
                    "tool_call_id": tool_call.id
                })

        return "Failsafe: Reached maximum steps."

The Agent class: a for loop up to max_steps, executing tools and feeding results back until the LLM gives a final text response.

Agent loop flowchart

04-agent-loop.ipynb
python
agent = Agent(
    model=DEFAULT_MODEL,
    tools=tool_schemas,
    available_functions={
        "get_weather": get_weather,
        "multiply": multiply,
        "toggle_light": toggle_light
    }
)

result = agent.run(
    "Get the weather in Tokyo, multiply the temperature "
    "by 10, and then turn off the kitchen light."
)
# Step 1: get_weather("tokyo") -> "25"
# Step 2: multiply(25, 10) -> "250"
# Step 3: toggle_light("kitchen", False) -> "lights off"
# Final: "The temperature in Tokyo is 25°C..."

The agent autonomously chains 3 tool calls (weather, multiply, toggle light) in one run() call.

That is why we have max_steps! It acts as a safety limit. If the agent has not finished after max_steps iterations, we return a failsafe message. In production, you might set this to 10-20 and log when it is hit to investigate why the agent got stuck.

04-agent-loop.ipynb
python
# Safety limit prevents infinite loops
agent = Agent(
    model=DEFAULT_MODEL,
    tools=tool_schemas,
    available_functions=available_functions,
    max_steps=5  # Will stop after 5 iterations max
)

Always set max_steps. Without it, a confused LLM could loop infinitely, burning through your API budget.

AI prompt: Try it with AI

Loading practice…

Fill in the blanks: Complete the agent loop

Loading practice…