Fivexer
Start free

Your AI service is decided at the human handoff

ai agent escalation to humanai agent human handoff routingexception queue routinghuman in the loop ai agentsservice as software

If people finish what your AI agent can't, design that handoff before you connect the agent to a queue. Every exception needs an owner who can actually finish it, a deadline for useful action, a fallback when nobody answers, and a record of what happened. The person also needs the context to pick it up cold.

This post turns those four decisions into a queue spec and a set of failure tests. A customer-service study gives a reason to treat failure types differently. The queue design is our own engineering advice, not something the researchers tested. If you build on Fivexer, the matching concepts explain the task and worker model.

Two operators in blue overalls at a control room desk with monitors behind them. Photo: Sergey Sergeev / Pexels.
Two operators in blue overalls at a control room desk with monitors behind them. Photo: Sergey Sergeev / Pexels.

What the Alibaba study supports

Wang and colleagues' preprint, version 2, revised 1 June 2026, describes an August 2024 randomised deployment on Taobao involving 647 workers and 680,676 chats. AI deployment shortened chats but reduced ratings for AI-eligible conversations.

The escalation analysis uses 11,069 matched treatment chats, not all chats in the experiment:

Category in that matched sample Chats Share
Algorithm-triggered technical escalation 4,879 44.1%
Algorithm-triggered emotional escalation 954 8.6%
Human-initiated escalation 1,362 12.3%
Remainder, not in the three types 3,874 35.0%

How the 11,069 AI-eligible chats split (percent)

Technical escalationEmotional escalationHuman-initiatedRemainder
Share of chats44.1%8.6%12.3%35%

The authors found service quality held up after technical escalations, recovered less well after emotional ones, and that early intervention mattered. Only the AI deployment was randomised. Escalation type and takeover timing were not. So read these as design evidence, not proof that any particular deadline causes better results.

The three escalation types add up to 7,195 chats, 65.0% of this sample (our arithmetic from the table). That isn't a forecast for your queue, and the study can't tell you your staffing, response target or return.

Make four routing decisions

1. Which person can finish this kind of exception?

Start from your own case records. A technical exception may need account permissions and domain knowledge. A frustrated customer needs someone who can talk to them and is allowed to settle the dispute. Set the eligibility rules first, then pick among whoever is available.

Write triggers your service can actually evaluate: an unsupported action, a failed verification, a request for a person, a supervisor stepping in. For anything ambiguous, add an “unclassified” route owned by the triage lead, and test the classifier on its own, apart from the routing.

Send the case ID, the history, what the agent already tried, the open question, the next actions allowed and what the customer was promised. Link to the source records rather than only summarising them, so the person can check before repeating an action.

2. When must someone act, and what counts as acting?

Keep accepting the offer and the first useful human action apart. Accepting a task isn't replying to the customer.

Timestamp creation, offer, acceptance, first human action and completion. Measure the customer-facing deadline from the original escalation, and don't restart it on each hop. Add your own check for cases nobody has been offered yet, because an offer timer doesn't start until someone receives the offer.

Set targets from your service promise, observed waits and the capacity you can staff. Without those, write a provisional target and test it in a supervised pilot before promising anything to customers. Count the misses as well as the completions. A queue looks fast if its parked work is left out.

3. What happens when nobody responds?

Name the next eligible pool and a final action. After the last pool, a named owner reviews the exception and tells the customer what happens next. Parking a case stops the routing. It doesn't tell anyone anything.

Decide what to do with the person who didn't answer. Blocking them from this case stops repeat offers, but it can remove your only specialist. In a small pool a cooldown may suit better. Also plan for the whole pool being unavailable: who is alerted, what the customer sees, who resumes the work.

4. What record proves the handoff happened?

Store the failure reason and the routing decision next to the offer, acceptance, action and outcome events. Note which requirement excluded a candidate, the policy version and any override. Decide who may restart the agent after human work, and how a repeated event avoids creating a duplicate case or action.

A routing trace explains who got the case and why. It doesn't prove the customer's problem was solved or that a chargeable outcome happened. You need records for those too.

A proposed exception flow: offer, deadline, next tier, park

  1. The agent can't finish the request, so it opens a case with the history and what it already tried attached.
  2. The case is offered to the primary tier with a response window. The customer's clock started at the original escalation, not now.
  3. Nobody accepts in time. The primary tier is blocked for this case and it moves up to the backup tier.
  4. The backup tier accepts and the acceptance is recorded. Accepting is not replying: the first useful human action is still watched against the original deadline.
  5. Had the backup tier stayed silent too, the case would go to the duty lead, and after that it would be parked with a named owner who tells the customer what happens next.

Copy the exception-queue specification

Copy this table into a spreadsheet for each failure type. Keep the rule and its owner together so an engineer can implement it and an operations lead can test it.

Field Your rule Filled example: unsupported account action
Trigger and case identity Agent cannot perform the requested change; existing case ID reused
Eligible people Account specialist with permission to make that change
Required context Request, verification result, attempted actions and source-record links
Offer-response window Illustrative pilot setting: one minute per offer
First useful action and deadline Specialist checks the request and replies; target supplied by the service owner, measured from original escalation
No response Next eligible tier; block that non-responder for this case
No eligible person Alert duty lead; retain original deadline; do not wait for an offer timeout
Exhausted ladder Park; duty lead owns review and customer update
Completion and resumption Specialist records outcome; authorised owner decides whether the agent resumes
Evidence and retention Decision, offer, acceptance, action and outcome events; retention period set by service owner

The one-minute window is an example setting, not the study's recommendation or a service-level promise. The first-action target is blank on purpose: you need a real value before the pilot.

Map the offer policy to the engine

Fivexer's open-source assignment-user-matcher supports per-assignment offer-response deadlines, tier changes, non-response blocking and parking. The policy and trace fields used here were checked against published npm version 1.16.1 on 8 October 2026. The following is a configuration fragment for an already initialised matcher. Workers, permissions and eligibility rules must be configured separately; tier labels alone do not establish that someone is qualified.

await matcher.addAssignment({
    id: 'exception-1',
    tags: ['account-action', 'primary'],
    escalation: {
        respondWithinMs: 60_000,
        onNoResponse: 'block',
        tiers: [['primary'], ['backup'], ['duty-lead']],
        onExhausted: 'park',
    },
});

matcher.startMaintenance();

The engine README documents the policy and maintenance sweep. The window governs response to a matched offer. It does not set a creation-to-first-reply deadline, and a sweep must run for timed escalation to occur. Keep the original-deadline monitor in your service.

For allocation evidence, initialise the matcher with enableDecisionTraces: true, then query getDecisionTraces({ assignmentId: 'exception-1' }). Traces are capped: the documented defaults retain approximately 1,000 entries and at most 25 candidates per trace. Export the records your service requires; do not treat the built-in trace stream as unlimited history. Decision-trace documentation.

Run these failure tests before the pilot

Test input Expected result to verify
Primary worker lets an offer expire Next tier is considered; the blocked worker does not receive this case again
Nobody is eligible before any offer Application monitor alerts the owner; case is not silently waiting for an offer timer
Every offered tier times out Case leaves matching and appears as parked; operational owner is notified by your integration
Worker accepts but takes no useful action Original first-action deadline still triggers your service's recovery process
Agent emits the same escalation twice One case ID and one authorised action path remain
Case completes or returns to the agent Outcome, owner and resumption decision are recorded; customer update matches the actual state

Classifying failures, messaging the customer, handling duplicate events and watching the first-action deadline are yours to build; the fragment above doesn't do them. The research doesn't say whether to run a dedicated exception team or mix supervision into other work either. Test an arrangement you can staff for the long run.

Next step: fill in the spec for one failure type, including the first-action target and the owner. Follow the quickstart for the hosted workflow, or the engine README to self-host, and run the failure tests in an isolated pilot before any live customer work.

New guides, when there are new guides

Nothing else. No product news, no sequence, and an unsubscribe link on every one.