Skip to main content

Detect and Handle Conversation Loops in AI Agents

A conversation “loops” when a customer keeps re-asking the same question and the agent keeps replying without moving the thread forward. That pattern is the single most damaging failure an AI concierge can produce — the customer walks away frustrated, and nothing on the agent side noticed. Orbit ships a deterministic loop detector that reads the recent message window and answers “is this conversation stuck?” on demand; the inbox surfaces that verdict as the supervisor “conversation in a loop” banner. This guide shows how to read the evaluation, hand the thread to a person, and gate agent promotions on loop-free behavior. Endpoint paths below are relative. Send them against https://api.orbit.devotel.io/api/v1.

1. Where loop-check fits in the supervisor loop

POST /agents/conversations/:conversationId/loop-check reads the recent message window and returns a LoopEvaluation:
The response payload (below, the data object of the standard data/meta API envelope) carries the verdict plus the evidence your supervisor needs:
The inbox supervisor view polls this endpoint while a banner is visible, which is why “conversation in a loop” can show up before a human reviews the thread. The endpoint is read-only: it never mutates the conversation or the agent. Handoff is a separate, explicit call (section 3), so the detector stays safe to run on a poll cadence. The conversation id can point at either an AI-agent thread or a human-inbox thread — the route resolves both.

2. What the detector looks at

Three signals feed the verdict; any one of them is enough to set isLoop: true. Reason codes stay stable so analytics can group them:
  • semantic_re_ask — two customer turns inside the window share a token-overlap similarity at or above the threshold (default 0.55). This catches “what’s my balance” / “tell me my balance please” / “balance again?” — the customer repeating the same request in slightly different wording while the agent re-answers the same way. The matching pair comes back in reAskPair so the supervisor sees the exact two messages.
  • negative_sentiment_delta — the earliest customer turn in the window scored neutral-or-positive and the latest turn fell to the negative threshold (default −0.3). That is the escalation-from-polite-to-exasperated shape a stuck loop shows.
  • explicit_escalate_keyword — the newest customer turn contains a direct ask to reach a person (“talk to a human”, “real person”, “this isn’t working”). This short-circuits everything else; respect the stated preference immediately.
recommendedAction maps those signals to a next step:
  • none — no loop; keep the agent on it.
  • offer_handoff — re-ask similarity fired; prompt the customer or the supervisor to take over.
  • escalate_now — explicit keyword or a sentiment crater; handoff now.
Signal thresholds are tunable per request (bounded to keep the response budget clean):

3. Operator handoff — take over, override, or mark a ticket

A loop verdict without a handoff path leaves the customer stuck in the same place. Wire the banner and the poll to three actions:
  1. Take over with live-summary. A supervisor opens GET /inbox/conversations/:conversationId/live-summary?window_turns=N to get a rolling 1–2 sentence AI summary of the last turns, then either takes the conversation over in the inbox or releases the thread back to the agent after a fix. The summary is opt-in per tenant for AI features.
  2. Override with the handoff endpoint. When the evaluation is escalate_now (or a human decides anyway), fire POST /conversations/:id/handoff with a reason. That clears the AI assignment, flips the conversation back to the unassigned queue, and stamps the reason category on the row so a report can aggregate loop handoffs separately from arbitrary handoffs. The receiving operator then picks the thread up from the queue rather than from the agent’s surface.
  3. Mark a ticket for review. Not every loop warrants a human interruption. Submit the conversation to the agent’s labeling queue with POST /agents/:agentId/labeling/annotations so QA and fine-tuning pick up the failure later (section 5).
The supervisor polling cadence (30 s while the banner shows) matches the endpoint’s read budget, so a banner-visible poll is the intended pattern — not a new evaluation every message.

4. Gate promotions on loop behavior, not just quality

Loop-free behavior belongs in the pre-promotion gate next to the model and quality checks. The rollout pipeline already runs persona simulation, shadow comparison, and regression tests before a candidate reaches traffic — wire loop-check into the same stage gates so a candidate that loops on the golden conversations halts before the rollout advances. When you run the AI agent rollout pipeline, add loop evaluation to the stage checklist before advancing:
  1. Save the candidate as an agent version (same as for regression tests).
  2. Replay the saved regression conversations against the candidate.
  3. Post the loop-check on each replayed conversation’s id and require isLoop: false before you advance the stage.
A candidate that passes the general evals but loops on the exact conversations you already marked problematic is a worse deploy than a clean reject — the detector turns that into a crisp gate.

5. How labeling picks up the pattern — loops are a symptom, not a bug

Treat a loop as a signal that the agent’s knowledge, prompt, or tooling is missing something the customer needs. The route is deliberately deterministic — it does not ask an LLM “is this a loop,” so it can run on every conversation cheaply — which also means the pattern that produced the loop names its own remedy. Labeling moves the failure into the eval/fine-tune pipeline where the fix actually lands:
Each label gets appended to the agent’s Human-labeled review queue dataset, so an eval run over that dataset, or a fine-tuning export, re-tests the corrected handling automatically. Use the checker’s own reason codes as notes so analytics can group how loops resolve (missing tool, missing knowledge, over-long prompt). The conversation is the symptom, not the bug: once you collect loops from the labeling queue, the eval pipeline shows whether the prompt edit, the knowledge change, or the new tool closed the pattern.

6. Example: poll loop-check, hand off when the verdict lands

A sideband supervisor script polls loop-check on the conversations an agent is handling, and hands the thread to the queue when the verdict says loop:
The pattern stays simple: read the evaluation.isLoop boolean, hand off via the conversations endpoint, and label the failure for the agent’s review queue. Nothing here alters the agent configuration or the conversation row inside the loop-check call itself — the mutation is the explicit handoff and the separate annotation. Keep the poll to the same cadence the supervisor banner uses, and tune the window once (section 2) instead of per request.

Troubleshooting

See also