What a Callbot Loop Actually Repeats: State Transitions, Not Conversation
One turn in a callbot is a single lap: ASR captures the utterance, NLU/LLM resolves intent, and TTS speaks the reply. When that cycle fails and the same stage runs again, that is a loop iteration — and if turns and iterations get counted as the same metric, there is no basis left for deciding when to step in.
A budget declares upfront caps on that repetition — turn count, wall-clock time, cost per call. A circuit breaker is the runtime mechanism that cuts off retries the moment the same failure crosses a threshold and switches to a fallback path. A retry re-attempts a transient error; a circuit breaker stops attempting altogether in the face of a persistent one. The team needs to share that distinction as one definition, not two loosely related terms.
What Counts as a Stuck Loop: Detecting Repeated Utterances
When the same utterance repeats twice or more in a row, or intent classification keeps returning the same failure code, that is a stuck loop, not a conversation. Keep a separate counter per failure type — no-input, no-match — and once a counter hits its cap (say, two), force a rephrase in different wording so the caller never hears the exact same sentence a third time.
From Design to Escalation: A Callbot Loop Budget and Circuit Breaker Playbook
(a) Planning and target numbers: declare the loop budget across three axes. Turn cap — no-input plus no-match combined, three per page at most. Wall-clock cap — a meaningful first response within 15 seconds of call start, forced branching if the call runs past 90 seconds overall. Cost cap — a ceiling on combined STT, LLM, and TTS spend per call. Crossing any one of the three counts as budget exhaustion and moves the call to the next stage.
(b) Three failure patterns: first, setting retries per stage (ASR, LLM, TTS) independently rather than per turn, so each stage looks fine in isolation while the sum blows through the budget. Second, resetting the no-match counter per page instead of per session, so a caller who wanders across flows hears the same answer more than five times. Third, tripping the circuit breaker with no fallback path ready — no human queue, no DTMF fallback channel — so the trip itself ends the call.
(b') Recovery branches: sum per-stage retries against one shared retry budget (say, four total per call), and once it's exhausted, force a single rephrase before escalating to a human if that also fails. Configure the trip so it can reroute to a DTMF menu or an agent queue without a redeploy — a trip should never be indistinguishable from a dropped call.
(c) Operations checklist: before shipping, replay no-input, no-match, and repeated-utterance scenarios as scripted test cases to confirm the budget caps and escalation triggers actually fire. Log turn count, per-stage retry count, whether the circuit breaker tripped, and the reason for budget exhaustion as standard fields, and mask PII — phone numbers, account numbers — in call recordings and transcripts before they're stored.
(d) The improvement loop: tally the circuit-breaker trip rate and the top intents that trigger it every week. For intents that trip repeatedly, rewrite the rephrase copy or branch to a different flow from the first turn. Treat the budget thresholds themselves as tunable — revisit them whenever the trip rate drifts outside a target band, such as 5% of calls.
Takeaways You Can Use Today
Running a callbot loop safely means declaring turn, time, and cost budgets in code, summing per-stage retries against one shared budget, and always having a fallback path ready before a circuit breaker trips. Just holding the line on Dialogflow CX's recommended cap of three no-match/no-input events is enough to stop a caller from hearing the same question forever.
References
Building Effective AI Agents — Anthropic
Voice agent design best practices — Dialogflow CX, Google Cloud