Foundations, lesson 4
Escalation and handoff
Rules decide who takes over, and the handoff carries the case
Your support agent escalates when a customer sounds angry, and keeps going when a customer asks for a person. The people who do get a ticket receive one line and start from zero. This is the agent at Lumen Supply, an online electronics shop. You will watch it fail, then fix it with three small rules.
Rules run first, then Claude finishes the rest
Three parties split the work. Code routes the ticket first. Claude resolves what the agent can solve. A person takes the rest.
Two triggers send a ticket to a person. The customer asks for one, or the shop has no policy for the request.
A solvable ticket stays with the agent
The customer wants a refund the shop allows. No rule sends it to a person, so Claude calls get_customer. The tool call carries the email it read from the ticket. The result carries the customer and the orders.
Claude reads that result and writes the reply. The code never wrote the reply and Claude never chose the route.
- CustomerHi, I'm dana@example.com. The keyboard from order 1042 arrived with keys missing. Can I…
Show the result
Hi, I'm dana@example.com. The keyboard from order 1042 arrived with keys missing. Can I return it for a refund?
- Claudelooks up: dana@example.com
Show the result
{ "input": { "query": "dana@example.com" }, "output": { "customer": { "name": "Dana Cho", "email": "dana@example.com", "orders": [ { "id": "1042", "item": "USB keyboard", "amount": 89.0 } ] } } } - Rules{'customer': {'name': 'Dana Cho', 'email': 'dana@example.com', 'orders': [{'id': '1042', 'item'…
Show the result
{ "customer": { "name": "Dana Cho", "email": "dana@example.com", "orders": [ { "id": "1042", "item": "USB keyboard", "amount": 89.0 } ] } } - ClaudeI found order 1042 for a USB keyboard ($89.00) on the account for Dana Cho, but the lookup doesn't include our return…
Show the result
I found order 1042 for a USB keyboard ($89.00) on the account for Dana Cho, but the lookup doesn't include our return policy or the status of a refund. I can't issue a refund from here, so please reply with a photo of the missing keys and the packing slip, and our team will review the return and tell you the next steps.
Claude finished the ticket.
Three rules as written
route in the starting code escalates on tone: two exclamation marks or the word "ridiculous". Tone is not difficulty. An angry customer with a simple refund is easy, and a calm customer who wants a policy the shop lacks is hard.
Sentiment does not measure difficulty, and neither does the model rating its own confidence. A rule needs a signal that names the ticket, such as a request for a person.
A prompt line that says not to invent policies only lowers the rate. When the shop has no policy, route to a person in code before the agent answers.
What happens when the customer asks for a person?
Take the ticket that says: "I have asked three times about order 1043. I want to speak to a person." The starting rules only look at tone.
Predict: Does the ticket reach a person?
- AYes. The agent understands the request and hands it over.
- BNo. The starting rule looks for tone, so the agent carries on.
Show the answer
B. The agent looked up the customer and wrote a reply. The customer asked for a person and got a bot again.
The customer asks and is ignored
This is the same ticket with the starting rules. Claude looks the customer up and answers. The result card is red: the ticket needed a person.
This is a real Claude Haiku 5.5 run, recorded once and replayed here. The rules changed nothing, so the ticket stayed with the agent.
- CustomerI'm omar@example.com. I have asked three times about order 1043. I want to speak to a…
Show the result
I'm omar@example.com. I have asked three times about order 1043. I want to speak to a person.
- Claudelooks up: omar@example.com
Show the result
{ "input": { "query": "omar@example.com" }, "output": { "customer": { "name": "Omar Reyes", "email": "omar@example.com", "orders": [ { "id": "1043", "item": "4K monitor", "amount": 640.0 } ] } } } - Rules{'customer': {'name': 'Omar Reyes', 'email': 'omar@example.com', 'orders': [{'id': '1043', 'item'…
Show the result
{ "customer": { "name": "Omar Reyes", "email": "omar@example.com", "orders": [ { "id": "1043", "item": "4K monitor", "amount": 640.0 } ] } } - ClaudeI found your account, Omar Reyes, with order 1043 for a 4K monitor totaling $640.00. I can't transfer you to a person…
Show the result
I found your account, Omar Reyes, with order 1043 for a 4K monitor totaling $640.00. I can't transfer you to a person from here, but I can see your order details, so tell me what's wrong with order 1043 and I'll do my best to help.
The ticket needed a person and the agent carried on.
Three rules replace tone with criteria
Escalate on an explicit request for a person, or on a policy the shop does not have. Ask when two customers match. The text matches in route stand in for a real classifier.
When the model must judge the gray cases, write two to four worked examples, each a sample ticket with the right call and its reason. A reason teaches the boundary, which a bare label cannot. "Be conservative" is not a criterion, because it names no case.
Split a message that holds several asks into items, and decide each one. The routing is plain code, so the same ticket goes the same way every time.
The handoff carries the case
The shop has no price match policy, so a person must decide. With the starting rules the handoff is one line. Press the second button: the handoff holds five fields, which are customer, order, issue, what was tried, and the ask.
A handoff is a data structure, not a sentence. The person who opens it should not have to ask the customer again.
The same care applies to alert flags that tell staff a ticket needs a look. If one flag category fires on 40 percent of tickets, staff stop reading every flag. Switch that category off until its criteria are fixed, and keep the others on.
This part is interactive in the lab: run ./workshop watch escalation-handoff.
The same ticket now goes to a person
Use the switch to run the ticket with the starting rules, then the escalation rules. On the second button, the card marked "This is where the runs split" is where the ticket now goes to a person.
Try the angry ticket too. The starting rules escalate it with a one line summary. The fixed rules leave it with the agent, which can solve it.
Examples earn their place on the ambiguous tickets, so do not fill the prompt with easy ones. Vary the ticket layouts in them, so the model learns the rule and not one channel's format.
This part is interactive in the lab: run ./workshop watch escalation-handoff.
Try it: escalation rules
Change one setting at a time. Pick the price match ticket: the shop has no such policy, so a person must decide. Pick the Two Sam Lees ticket: the shop has two customers with that name, the lookup finds both, and the fixed rules ask for an email.
Every combination is a recorded run, so this works with no internet.
This part is interactive in the lab: run ./workshop watch escalation-handoff.
The same lookup runs in the Agent SDK
The Claude Agent SDK serves tools from an in-process MCP server. The route rule still runs in code first. A ticket for a person gets the tool hand_to_person. Its result is the handoff, and Claude reads that result to write a short reply.
This is a real Claude Haiku 5.5 run through the SDK. With the starting rules, the same ticket goes to the lookup and the agent answers a question only a person can decide.
- CustomerI'm dana@example.com. I paid $89 for order 1042 and a competitor sells it for $69. Can…
Show the result
I'm dana@example.com. I paid $89 for order 1042 and a competitor sells it for $69. Can you price match?
- Rulessent to a person
Show the result
{ "kind": "route", "to": "human" } - Claudehands the ticket to a person
Show the result
{} - Person receivesfields: customer, order, issue, tried, ask
Show the result
{ "customer": "Dana Cho", "order": "1042", "issue": "I'm dana@example.com. I paid $89 for order 1042 and a competitor sells it for $69. Can you price match?", "tried": [ "route rule" ], "ask": "Decide on a price match. The shop has no such policy." } - ClaudeThanks, Dana. A member of our team will follow up with you about your price match request for order 1042. I've passed…
Show the result
Thanks, Dana. A member of our team will follow up with you about your price match request for order 1042. I've passed along your order number, the $89 price you paid, the $69 competitor price, and your question about whether we can match it.
A person took over, with customer, order, issue, tried, ask.
You do: fix the three rules
Copy the starting code and open work/escalation-handoff/handoff.py. It has three planted defects. route() escalates on tone, match() answers about the first of two customers with one name, and handoff() sends a one-line summary.
./workshop start escalation-handoff
./workshop check escalation-handoff
./workshop watch escalation-handoff
The checks send a request for a person and a price match to a human, and keep a solvable angry ticket with the agent. They expect a question when two customers match, and five fields in every handoff.
Check your understanding
Answer each question, then read why every option is right or wrong. The wrong options are the mistakes engineers make on the job.
1. A team escalates every ticket with an angry tone. Of 100 escalations last week, 34 were simple refunds the agent could have finished. What is the right change?
- AEscalate on named criteria, such as a request for a person or a policy the shop lacks.
- BHire more people for the escalation queue, so the extra 34 are handled quickly.
- CAdd more angry words to the rule, so the tone check is more exact.
- DKeep the tone rule and add a sentiment score, escalating only when the score is very low.
Show the answer
Answer: A
- A Correct. A criterion says something about the ticket, such as what is asked or whether a policy exists.
- B More staff clears the queue and leaves the rule unchanged. The 34 simple refunds still reach a person.
- C A longer word list misses calm hard tickets and still catches angry easy ones.
- D A sentiment score is still tone. A calm ticket can be hard, and an angry one can be a simple refund.
2. Select two valid triggers for sending a ticket to a person.
- AThe customer asks for a person.
- BThe sentiment score of the message is below a threshold.
- CThe shop has no policy for what the customer asks.
- DThe model rates its own confidence under 0.8.
Show the answer
Answer: A, C
- A Correct. An explicit request is honoured at once.
- B Sentiment measures tone, not difficulty. A calm ticket can need a person and an angry one may not.
- C Correct. When the policy is silent the agent would have to invent one, so a person decides.
- D A model's rating of itself does not track whether it is right, so it cannot route tickets.
3. A lookup for Sam Lee returns two customers, and the agent answers about the first one. In 50 such tickets, 19 were about the wrong person. What should the lookup do?
- AReturn the first match, because the first record is right more often than not.
- BReturn the account with the newest order, since it is more likely to be active.
- CReturn a question asking for one more identifier, such as the email.
- DSend every name collision to a person, so nobody has to choose.
Show the answer
Answer: C
- A The first record is an arbitrary pick. In the tickets above it was wrong 19 times in 50.
- B Recency is a guess. The customer who wrote in may be the one with the older account.
- C Correct. One more identifier settles it, and the agent never has to guess.
- D A collision can be settled by one question. Sending it to a person spends a person on a simple case.
4. A routing rule sends a ticket to a person when the model rates its own confidence under 0.7. The model rated 0.9 on an answer that was wrong. What does this show?
- AThe threshold is too low, so raising it to 0.95 will catch this kind of miss.
- BThe model should rate its confidence a second time, and the second rating is the one to use.
- CAveraging three ratings will give a number that follows whether the answer is right.
- DSelf-rated confidence does not measure difficulty, so route on explicit criteria.
Show the answer
Answer: D
- A A higher threshold still relies on a number that can be 0.9 on a wrong answer.
- B A second rating comes from the same source and has the same flaw.
- C An average of numbers that do not track correctness does not track it either.
- D Correct. Name the triggers, and check accuracy against labelled tickets instead of trusting a score.
5. A customer writes "I want a person" after three replies from the agent. The agent writes a fourth answer. What should happen instead?
- AThe agent tries one more answer first, since it might solve the ticket.
- BThe ticket goes to a person at once.
- CThe agent asks the customer to confirm that they really want a person.
- DThe agent waits to see whether the next message sounds angry.
Show the answer
Answer: B
- A The customer has already asked. A fourth attempt repeats what they are tired of.
- B Correct. An explicit request is a rule with no judgement in it, so it is honoured at once.
- C A confirmation turns a clear request into one more step the customer did not ask for.
- D Tone is not the trigger. The customer has already said what they want.
6. A customer asks for a price match, which the shop has never offered. The agent quotes a price match policy it made up, in 12 of 40 such tickets. What is the right fix?
- AAdd a line to the prompt that says not to invent policies.
- BLet the agent offer the nearest policy it has, such as a return window.
- CLower the temperature so the agent stays closer to the facts it has.
- DEscalate to a person in code whenever the policy is silent.
Show the answer
Answer: D
- A A prompt line lowers the rate but is still a request, and 12 in 40 shows how often it slips.
- B A different policy is still not the one asked for, and the customer is misled.
- C Temperature changes variety, not whether the agent knows a policy exists.
- D Correct. A named criterion sends the ticket to a person, and no policy gets invented.
7. The prompt says "be conservative about escalating". On 60 borderline tickets, 18 go the wrong way. What should change?
- AMake it stronger, for example "be very conservative about escalating".
- BHave the model rate its confidence and escalate below a threshold.
- CName the categories, what to escalate in each and what to handle.
- DEscalate every borderline ticket, so none are handled wrongly.
Show the answer
Answer: C
- A A stronger word is still not a criterion. The model still has to guess what conservative means.
- B A confidence rating does not track whether the ticket is hard.
- C Correct. Named categories with a clear action each leave the model nothing to guess.
- D This fixes the 18 by sending all 60 to people, which is the cost the agent was built to avoid.
8. One flag category is raised on 40 percent of tickets, and staff have stopped reading any flags. What is the best response?
- ASwitch that category off until its criteria are fixed.
- BAsk staff to read every flag, since the noisy category may hide real ones.
- CReword the flag so it sounds less urgent, so staff take it less seriously.
- DRemove all flagging, so nobody has to sift through them.
Show the answer
Answer: A
- A Correct. Trust is restored by removing the noise, and the category comes back once its criteria are sound.
- B Staff already stopped. A flag nobody trusts costs time and protects no one.
- C A quieter flag on 40 percent of tickets is still noise.
- D This drops the useful flags along with the noisy one.
9. An escalation note reads "customer unhappy". The person who takes the ticket has to ask the customer everything again, and handling time is 11 minutes longer. What is the fix?
- AWrite a longer free-text summary of the conversation.
- BAttach the full transcript and let the person find what matters in it.
- CHand over a structured case: customer, order, issue, tried, ask.
- DAdd a mood score, so the person knows how careful to be.
Show the answer
Answer: C
- A A longer summary can still leave out the order or the ask, and a person has to read it all.
- B A transcript holds the answer but buries it, so the person still starts from zero.
- C Correct. Each field answers a question the person would otherwise put to the customer.
- D A mood score says how the customer feels and not what to do.
10. Select two fields a handoff needs when a person takes over a refund case.
- AThe model's confidence score for its last answer.
- BWhat the agent already tried.
- CA label for the customer's mood.
- DWhat the person is asked to do.
Show the answer
Answer: B, D
- A The score does not say what happened or what to do, and it is not reliable.
- B Correct. It stops the person from repeating a step the agent already took.
- C A mood label does not help the person act on the case.
- D Correct. The ask is the reason the ticket reached a person.
11. One message asks for a refund and an address change. The agent answers the refund and ignores the address in 14 of 30 such messages. What should change?
- ATell customers to send one request per message.
- BAnswer the longer request first, since it is likely the main one.
- CTreat the second request as out of scope, so the agent only takes the first.
- DSplit the message into separate items and handle each one.
Show the answer
Answer: D
- A This moves the work to the customer, and many will not read it.
- B Length does not show which request matters, and the other is still dropped.
- C The address change is in scope. Dropping it means a second ticket and a second wait.
- D Correct. A list of items makes each request visible, so none is dropped.
12. An escalation must carry the case history. The model writes a free summary, and 9 of 30 leave out the order number. How should the handoff be fixed?
- AAdd a sentence to the prompt that says to include the order number.
- BFix the fields in a schema, so a handoff with no order fails.
- CLet the person who takes the ticket ask the model for what is missing.
- DAsk for a summary of exactly 60 words, so the length is always the same.
Show the answer
Answer: B
- A A prompt line lowers the misses but does not stop them, and nothing flags a missing field.
- B Correct. A schema makes a missing field an error the harness can see and reject.
- C The person now has to spot what is missing, which is the work the handoff should save.
- D A word count says nothing about which facts are in the summary.
13. On borderline tickets the same input is escalated on one run and handled on the next, in 15 of 60 repeats. What is the most reliable change?
- AAdd two to four borderline examples, each with action and reason.
- BWrite a longer list of rules that covers every case in words.
- CAdd a stricter instruction, since examples only change the style of the reply.
- DRaise the temperature so the model explores more before it settles.
Show the answer
Answer: A
- A Correct. Examples with reasons settle the cases the words leave open, the same way every time.
- B A long list still leaves the boundary cases to judgement, and the prompt grows.
- C Examples show the model where a line falls, which is more than style.
- D More variety makes the runs differ more, not less.
14. Select two things a few-shot example for a borderline ticket should show.
- AThe ticket as it arrives.
- BThe action chosen and the reason for it.
- CThe probability the model gave to each action.
- DWho wrote the example and when.
Show the answer
Answer: A, B
- A Correct. The model matches new tickets against the inputs it has seen.
- B Correct. The reason tells the model what to weigh, so it can apply it to a new ticket.
- C Probabilities are not part of the pattern the model learns from.
- D Authorship does not help the model decide anything.
15. The prompt holds four examples, and all four are easy tickets. The agent fails on 7 of 20 hard tickets. What is the fix?
- AAdd more easy examples, since more examples help.
- BReplace them with ambiguous cases, each with a reason.
- CMove to a larger model that copes better with the hard tickets.
- DRemove the examples and rely on the written rules alone.
Show the answer
Answer: B
- A More easy cases teach the model the part it already gets right.
- B Correct. Examples earn their place on the tickets where the wording alone is not enough.
- C A larger model can still have no example of where the line falls.
- D This throws away the one part of the prompt that shows the boundary.
16. All the prompt's examples use one ticket layout. A new layout from another channel breaks the routing on 11 of 40 tickets. What is the fix?
- AAdd more examples in the same layout, so the pattern is stronger.
- BReplace the examples with a pattern match on the new channel's header.
- CAdd a special rule that handles only the new layout.
- DVary the layouts, so the model learns the rule and not the format.
Show the answer
Answer: D
- A More of one layout repeats the format and teaches the model nothing new.
- B A header match is a rule for one channel, and the routing still breaks on the next.
- C The next channel needs another special rule, and the list grows with every layout.
- D Correct. Different layouts with the same outcome show what stays fixed and what changes.
Play: spot the bug
This rule sends a ticket to a person when the customer asks for one.
def route(text: str) -> str:
return "human" if "person" in text.lower() else "agent"
route("Please update the personal address on my account.")
Predict: Where does this ticket go?
- ATo a person, because "personal" holds the word person.
- BTo the agent, because nobody asked for a person.
Show the answer
A. A single word matches inside other words and other meanings. Match whole requests such as "speak to a person", and test the rule on tickets that use the word without asking.
References
- Use examples effectively: why two to four examples, each with a reason, teach a rule.
- Be clear and direct: how to state escalation criteria the model can apply.
- Tool use overview: how a handoff tool returns its result to the model.
- Agent SDK custom tools: the handoff tool served in-process by the SDK.
Conclusions
- Escalate on explicit criteria: a request for a person, or a policy the shop does not have.
- Ask for one more identifier when a lookup matches more than one customer.
- Give the model two to four examples with reasons for the gray cases.
- A handoff carries customer, order, issue, what was tried and the ask.
You can now write escalation rules that send the right tickets to a person, with the whole case.
Escalation criteria
Rules that name when a person takes over, such as a request or a policy gap
Handoff
The case a person receives: customer, order, issue, tried and ask
Ambiguous match
A lookup that finds more than one customer, so Claude asks
Policy gap
A request for something the shop has no rule for