CrewAI Tutorial (Python): debugging agent loops for intermediate developers

By Cyprian AaronsUpdated 2026-04-21
crewaidebugging-agent-loops-for-intermediate-developerspython

This tutorial shows you how to diagnose and fix agent loops in a CrewAI Python project without guessing. You’ll build a small setup that logs agent behavior, detects repeated tool calls, and stops runaway runs before they burn tokens or hang your workflow.

What You'll Need

  • Python 3.10 or newer
  • crewai
  • crewai-tools
  • python-dotenv
  • An OpenAI API key in OPENAI_API_KEY
  • A terminal with pip and a virtual environment
  • Basic familiarity with CrewAI agents, tasks, and crews

Install the packages:

pip install crewai crewai-tools python-dotenv

Step-by-Step

  1. Start by creating a minimal project with explicit logging and a simple environment loader. The main debugging move here is to make every run observable before you try to “fix” anything.
import os
import logging
from dotenv import load_dotenv

load_dotenv()

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s - %(message)s"
)

logger = logging.getLogger("crewai-debug")

if not os.getenv("OPENAI_API_KEY"):
    raise RuntimeError("OPENAI_API_KEY is not set")
  1. Next, define a tool that records each call. Agent loops often show up as repeated tool invocations with the same arguments, so this gives you a clean signal in the logs.
from crewai_tools import tool

CALL_HISTORY = []

@tool("echo_debug")
def echo_debug(text: str) -> str:
    """Echo text and record every call for loop debugging."""
    CALL_HISTORY.append(text)
    logger.info("echo_debug called with: %s", text)
    return f"echo: {text}"
  1. Now create an agent and task that can expose looping behavior. Keep the task narrow and force the agent to use the tool once; if it starts repeating itself, you’ll see it immediately in the logs and history.
from crewai import Agent, Task, Crew, Process

debug_agent = Agent(
    role="Debugging Agent",
    goal="Answer using the tool once and avoid repeated calls",
    backstory="You are strict about avoiding redundant tool use.",
    tools=[echo_debug],
    verbose=True,
)

debug_task = Task(
    description=(
        "Call echo_debug exactly once with 'loop-check', then provide "
        "a one-line summary of what happened."
    ),
    expected_output="A short summary with one tool call only.",
    agent=debug_agent,
)
  1. Run the crew and inspect both the output and the call history. If you see more than one identical entry in CALL_HISTORY, you’ve got an agent loop or at least repeated tool usage worth investigating.
crew = Crew(
    agents=[debug_agent],
    tasks=[debug_task],
    process=Process.sequential,
    verbose=True,
)

result = crew.kickoff()

print("\n=== RESULT ===")
print(result)

print("\n=== TOOL CALL HISTORY ===")
print(CALL_HISTORY)
  1. Add a hard guard for repeated calls when you need protection in production. This does not “solve” bad prompting by itself, but it stops infinite retries from becoming expensive incidents.
from crewai_tools import tool

SEEN_INPUTS = set()

@tool("guarded_echo")
def guarded_echo(text: str) -> str:
    """Reject duplicate inputs to surface looping behavior early."""
    if text in SEEN_INPUTS:
        logger.warning("Duplicate input detected: %s", text)
        return f"duplicate blocked: {text}"

    SEEN_INPUTS.add(text)
    logger.info("guarded_echo accepted: %s", text)
    return f"accepted: {text}"
  1. If the loop persists, tighten the task instructions and remove ambiguity from the agent goal. Most loops come from vague success criteria, too much freedom in the prompt, or tools that look useful for every step.
strict_agent = Agent(
    role="Strict Analyst",
    goal="Use guarded_echo once, then stop",
    backstory="You never repeat a completed action.",
    tools=[guarded_echo],
    verbose=True,
)

strict_task = Task(
    description=(
        "Use guarded_echo once with 'single-pass'. "
        "Do not call any tool more than once."
    ),
    expected_output="One concise sentence confirming completion.",
    agent=strict_agent,
)

strict_crew = Crew(
    agents=[strict_agent],
    tasks=[strict_task],
    process=Process.sequential,
)

print(strict_crew.kickoff())

Testing It

Run the script from a clean shell after exporting OPENAI_API_KEY. First verify that the task completes and that CALL_HISTORY contains one entry; that tells you your baseline is stable. Then deliberately loosen the task wording, rerun it, and watch whether repeated tool calls appear in the logs or history. If they do, tighten the prompt again or keep the duplicate guard in place for safety.

Next Steps

  • Add structured JSON logging around task inputs, outputs, and tool calls.
  • Wrap crews in timeout handling so stuck runs fail fast.
  • Learn how max_iter, task design, and tool scope affect loop behavior in multi-agent crews.

Keep learning

By Cyprian Aarons, AI Consultant at Topiax.

Want the complete 8-step roadmap?

Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.

Get the Starter Kit

Related Guides