DEV Community

Cover image for Day 16/90: Build a Bounded Agent Loop — How Do You Stop an AI Agent from Running Forever?
Rimsha Kanwal
Rimsha Kanwal

Posted on

Day 16/90: Build a Bounded Agent Loop — How Do You Stop an AI Agent from Running Forever?

An AI agent can select the right tool, receive a result, and still fail to complete its task.

It might call the same tool repeatedly, retry an operation that keeps failing, or continue reasoning without making meaningful progress.

The problem isn't always the model's intelligence. Sometimes the application has no reliable stopping boundary.

For Day 16 of my AI engineering journey, I'm exploring bounded agent loops: how to control agent execution, define stopping conditions, and evaluate what happens when an agent reaches its execution limit.

What is an agent loop?

An agent loop is a repeated execution cycle in which an AI model:

  1. Receives the current task and context.
  2. Decides what to do next.
  3. Calls a tool or produces a response.
  4. Observes the result.
  5. Decides whether another step is necessary.

The loop continues until the task is completed or a stopping condition is reached.

For example, a document support assistant might:

  • Receive a question about an order.
  • Retrieve the relevant order information.
  • Check whether additional information is needed.
  • Produce a response.

But what happens if the retrieval tool repeatedly returns incomplete results?

Without an execution boundary, the agent may continue making calls without reaching a useful outcome.

Why does an agent need a maximum step limit?

Anthropic's Building Effective Agents explains that agents operate through repeated interactions with tools and environmental feedback. It also identifies maximum iteration limits as one way to maintain control over execution.

This matters because autonomous execution introduces additional cost and the possibility of compounding errors.

A maximum step limit provides a boundary when an agent cannot reach its completion condition.

However, there is an important distinction:

Reaching the maximum number of steps does not mean the task has been completed.

The application must distinguish successful completion from an execution limit.

Design explicit stopping conditions

For a small agent application, I would define these outcomes:

Condition Expected behavior
Task completed Return the final result
More information required Ask the user for clarification
Tool execution failed Handle or report the failure
Maximum steps reached Stop execution safely
Time or resource budget exhausted Stop further execution

These outcomes should be represented explicitly rather than treating every loop exit as success.

A simple bounded agent loop in Python

A basic implementation can use a maximum number of iterations and explicit terminal states.

def run_agent(agent, task, max_steps=5):
    state = {"task": task}

    for step in range(1, max_steps + 1):
        result = agent.step(state)

        if result["status"] == "completed":
            return {
                "status": "completed",
                "steps": step,
                "output": result["output"]
            }

        if result["status"] in {"needs_input", "failed"}:
            return {
                "status": result["status"],
                "steps": step,
                "output": result.get("output")
            }

        state = result["state"]

    return {
        "status": "step_limit_reached",
        "steps": max_steps,
        "output": None
    }
Enter fullscreen mode Exit fullscreen mode

Here, agent.step() represents one application-defined agent iteration. It must return an explicit status and updated state.

The example demonstrates the control structure, not a complete model or tool integration.

Notice that reaching the final iteration does not automatically return a successful response.

That distinction is important when building production systems.

What existing frameworks teach us

There are useful implementation examples in current agent frameworks.

1. OpenAI Agents SDK

The SDK's runner manages an execution loop involving model calls, tool execution, and agent handoffs.

It also supports max_turns. When the configured limit is exceeded, the runner raises MaxTurnsExceeded.

This is a practical example of enforcing an execution boundary at the runtime level.

2. LangGraph

LangGraph provides a recursion limit that restricts how many graph super-steps can execute during a run.

When a graph reaches the configured limit before reaching a stop condition, it raises GraphRecursionError.

Its documentation also highlights an important debugging lesson: unexpected recursion-limit errors can indicate a cycle in the graph.

These limits are framework-level safeguards. A custom agent loop still needs application-specific completion and failure handling.

How would I evaluate a bounded agent loop?

Simply checking whether the agent stops is not enough.

I would create a small labeled test set with scenarios such as:

Test scenario Expected outcome
Task completed in 2 steps Successful completion
Task requires more than 5 steps Stop at the configured limit
Tool repeatedly returns the same error Stop or apply bounded recovery
User input is incomplete Request clarification
Agent repeatedly calls the same tool Detect and prevent unnecessary repetition
Task completes on the final allowed step Successful completion

Then measure:

  • Task completion rate: How many tasks finish successfully?
  • Step-limit rate: How often does execution reach the maximum?
  • Average steps per task: How much work does the agent perform?
  • Repeated tool-call rate: How often does it repeat an ineffective operation?
  • Latency and cost: What resources does each completed task consume?
  • False completion rate: How often does the agent report success without satisfying the task?

These measurements help distinguish a well-controlled agent from one that simply stops after a fixed number of calls.

A maximum step limit is not the only safeguard

An iteration limit controls how many steps an agent can take, but it does not control every resource.

A practical implementation should also consider:

  • Execution timeouts.
  • Token or model usage budgets.
  • Tool-call limits.
  • Retry limits for transient failures.
  • Cancellation and recovery behavior.

For example, an agent might make only three iterations but execute several expensive tool calls within each iteration.

Therefore, the application should enforce limits at the appropriate execution boundaries.

Connecting this to Day 15

Yesterday, I explored deterministic intent routing: deciding which workflow should handle a request.

Today, the focus moves to what happens after that decision.

Routing determines where the request goes. A bounded agent loop controls how long the agent can continue working toward the task.

Both are important for making agent behavior predictable and testable.

My engineering takeaway: An agent should have a clear definition of success, explicit failure states, and a maximum execution budget. Stopping safely is part of successful agent design.

How do you control agent execution in your applications: maximum iterations, token budgets, timeouts, or a combination of these?

References

Top comments (0)