Right. So. On a Tuesday in March I was eating a sandwich at my desk when our billing dashboard did something unusual: it went vertical.
Our support setup at the time was three agents — a triage agent, a billing specialist, and a "human handover" agent. Perfectly sensible design, drawn on a whiteboard by people who felt clever. A customer had written in with a message that was, and I quote, "hi is my invoice the one from march or the other one".
Triage read it, decided it was billing, handed off. Billing read it, decided it was ambiguous, handed back to triage for clarification. Triage read it again. You can see where this goes. 47 handoffs in nine seconds. $18.40 of tokens. One customer who got nothing at all.
Honestly the worst part wasn't the money — it was that I only found out because of the bill. We had zero alerting on handoff depth. That's now the first thing I set up on any agent build.
The five loops we've hit since (in order of how often)
1. The ping-pong loop
Two agents each believe the other owns the request. Almost always caused by overlapping role descriptions. If your triage prompt says "handle general queries" and your billing prompt says "handle account questions", congratulations — you've built a ping-pong machine.
Fix: give every agent an explicit "if you are unsure, you own it" rule, and make exactly one agent the terminal fallback. Ours is a plain-language agent whose only job is to write a holding reply and flag a human.
2. The self-handoff
An agent hands off to a tool that's actually itself, wearing a different hat. Happens a lot when you register agents as tools (the pattern most SDKs encourage). We had a research agent that could call "deep_research", which was… the research agent.
Fix: filter the agent's own name out of its tool list at runtime. One line of code. Embarrassing how long we took to find it.
3. The retry cascade
Tool call fails → agent retries → tool fails again → agent tries a different phrasing → fails → tries the first phrasing again. Each attempt is a full model round trip with a growing context window. This is the expensive one.
Fix: hard cap of three tool attempts per turn, then surface the failure to the user in plain words. "I couldn't reach the billing system just now — I've flagged this to the team" is a completely acceptable answer.
4. The memory echo
The agent's own previous message gets summarised into memory, then read back as if it were a customer statement, and the agent responds to itself. We saw a conversation where the model politely thanked itself twice.
Fix: tag every memory entry with a role and never inject assistant-authored content as user content. Sounds obvious. Was not obvious at 11pm.
5. The clarification spiral
The agent asks a clarifying question, the customer answers vaguely, the agent asks another. Three rounds in, the customer leaves. Technically not a loop between agents, but it kills your resolution rate all the same.
Fix: maximum one clarifying question, then make your best guess and state the assumption out loud. "I'll assume you mean the invoice dated 14 March — tell me if not."
The guardrails that actually stopped it
Five things, in the order we'd add them again:
- A depth counter on every request. Increment on each handoff. At 4, break out to the fallback agent. At 6, page a human. We've never legitimately needed more than 3.
- A per-conversation token ceiling. Ours is 60,000 tokens. Cross it and the conversation gets frozen and queued for a person. This alone would have capped that Tuesday at about $2.20.
- A spend alert at the account level. Anthropic, OpenAI and Azure all support usage alerts. Set one at 130% of your normal daily spend. Free, takes four minutes.
- Structured handoffs, not free-text ones. The handing-off agent must supply a reason code and a one-line summary. Fuzzy handoffs create fuzzy ownership.
- Trace everything, look at it weekly. We use the built-in tracing in the OpenAI Agents SDK docs plus LangSmith for the older stack. Fifteen minutes on a Friday catches most weirdness.
What it cost us to learn this
| Incident | Cause | Wasted spend | Caught by |
|---|---|---|---|
| The Tuesday sandwich incident | Ping-pong loop | $18.40 | Billing dashboard, 3 days late |
| Overnight research run | Self-handoff | $412.00 | Morning standup, sadly |
| CRM sync retries | Retry cascade | $96.70 | Rate-limit email from vendor |
| Memory echo in onboarding bot | Memory echo | $31.20 | A customer screenshotting it on social |
| Total | — | $558.30 | — |
Crew verdict
Multi-agent setups are great when the roles are genuinely different jobs — not when they're the same job sliced thinner. If you can't explain in one sentence why agent B exists and agent A can't do it, merge them. We went from five agents to two and quality went up.
And put the depth counter in on day one. Please. It's twenty lines.
"If you can't draw your agent graph on a napkin and have a colleague understand it in ten seconds, it's too complicated to debug at 2am." — @marla_ops, reply #12
Useful links people dropped in the thread
- Anthropic — Building effective agents (the "start simple" section is the whole lesson)
- OpenAI Agents SDK documentation — handoffs and tracing
- LangSmith docs for tracing older LangChain stacks
- Our own Agents SDK teardown and first-agent guide
Replies (73) — a few of the best
Want to add to this thread?
If you've hit a loop we haven't listed, post it — we keep this thread updated as a running reference and credit everyone who contributes a new failure mode.
Get posting access → Back to all threads