Skip to Content

My CrewAI agent keeps calling the same tool. Why?

Rius shows a repeating tool as a run of identical tool spans in one trace, and its Tool Loop alert fires when the same tool gets identical arguments three or more times in a row. Open the trace, read the model call before each repeat, and you can see what the agent was given and what it asked for. The fix is then in your task wording, your tool’s output or your tool’s schema.

How it works

The CrewAI integration records what the framework does through the OpenAI client, and one thing you add yourself:

  • Model calls arrive as LLM spans with model, tokens and cost. Their names are generic (ChatCompletion).
  • Tool calls arrive as TOOL spans only where you wrapped the tool body with observe and the TOOL kind. A tool you did not wrap leaves no tool span.
  • Crews and tasks produce no spans of their own, so a trace does not show which task a repeated call belongs to.

A loop therefore reads as a repeating pair in the trace: an LLM span where the agent decides to call the tool, then the TOOL span, then the LLM span again.

The Tool Loop alert reads those TOOL spans. It fires when the same tool is called with the same normalized arguments at least 3 times in a row inside one trace within 10 minutes. At most one other tool call may sit between neighboring repeats, so a tool the agent returns to after other work does not count. It fires once per trace and tool. The pre-defined alerts page lists the causes it is built to catch:

  • A search repeated with the same query because no result satisfies the stop condition.
  • A broken tool schema, where the model retries the identical call and never gets a different outcome.
  • A planner and executor cycling on the same lookup.

This is part of watching agents in production; see Monitor AI agents in production.

Set it up

  1. Make the tool visible. Install the integration as the CrewAI page shows, then wrap each tool body with observe and the TOOL kind. Keep @tool outermost and observe on the function body.
import rius from crewai import Agent, Crew, Task from crewai.tools import tool from rius import SpanKind rius.init(api_key="ri_...", service_name="my-agent") @tool("account_status") @rius.observe(kind=SpanKind.TOOL) def account_status(email: str) -> str: """Fetch a customer's account standing by email.""" return lookup(email)
  1. Open Traces in the console and click the slow or expensive run. A tool loop does not collapse. The trace page groups repeated calls into one N attempts row only when every attempt but the last failed, so a loop of successful calls shows as separate spans. Read them one by one, or list them on the Spans tab.

  2. Read the arguments. Select the repeated TOOL spans and compare their inputs. If every attempt is identical, the agent is not learning from the result. Note that the alert and this comparison need captured arguments, so a run with content capture off is never counted as a loop.

  3. Read the model calls between the repeats. On an LLM span with captured messages, open Input / Output and switch to Since previous llm call. It marks what was added, removed or changed since the last call, so you can see whether the tool result came back empty, malformed or ignored. Above the tree, the context growth strip plots input tokens per call, and a steadily rising bar shows the history growing with each repeat.

  4. Find the pattern across runs. On the Spans tab, choose Tool in the All kinds menu and search for the tool’s span name, such as execute_tool account_status. Sort by time or cost to see how often and how expensively the tool repeats.

  5. Check the alert. Tool Loop is a pre-defined alert. Open it to see its firing history and attached channels, and raise or lower the identical-calls threshold (3 is the minimum). Its details page cannot be narrowed to one service, so it watches the whole workspace.

See Exploring traces for the filters and views used above.

What you get

  • A trace that shows each repeat as its own TOOL span, with the model call that triggered it.
  • The exact arguments of every attempt, so you can tell a true repeat from a tool called with changing input.
  • A cost and token total for the loop, plus the context growth strip showing the prompt swelling.
  • A Tool Loop firing the next time any run repeats a tool three times in a row, sent to the channels you attached, so you hear about it before the token bill does.
  • A way to compare the looping run against another run of the same agent, to see which steps changed.

When something else fits

  • If the repeated calls have different arguments, or more than one other tool call sits between them, Tool Loop does not fire. Use the trace waterfall and the Spans tab to inspect them, or a custom alert on cost or LLM calls to catch the runaway run.
  • If you need to know which crew task a call belongs to, the CrewAI integration records no task spans. Wrap per-task entrypoints with observe so the trace shows them. See Integrations for how other frameworks are covered.

Still stuck? Get help

Last updated on