Routing tickets, emails and leads
Routing is the most common thing to hand a model, and the easiest to get wrong quietly. The shape that works: one multiple-choice question whose options are your actual queues, a probability threshold that decides whether to route automatically, and a person for everything else.
Write the queues as options
Start from the queues you really have, the ones with an owner and a process, not the categories you wish you had. Give each option a name your system already uses, and a one-line description of what belongs there. The model reads both; your code gets the name back and can route on it without a lookup table.
Descriptions do most of the work. "billing" is a word; "Invoices, charges, refunds and payment methods" draws a boundary. Where two queues touch, say which side a common case falls on: if refunds live with billing rather than support, write that down, because the model can't know your org chart.
Always leave a way out
The probabilities are shared out among the options you list, so a message that fits none of them still gets assigned to one. Add an explicit option — "none of the above, or not enough information to tell" — and route it to triage. Without it, every out-of-scope message lands in whichever queue was closest, and nobody finds out until someone complains.
{
"state": "Our invoice for March was charged twice and we need the duplicate refunded before month end.",
"questions": {
"queue": {
"type": "category",
"text": "Which queue should handle this message?",
"options": {
"billing": "Invoices, charges, refunds and payment methods",
"technical": "The product not working as it should",
"sales": "Buying, upgrading or renewing",
"other": "None of the above, or not enough information to tell"
}
},
"time_critical": {
"type": "yes_no",
"text": "Does the message give a deadline in the next seven days?"
}
}
}
{
"answers": {
"queue": {
"type": "category",
"answer": "billing",
"probabilities": {
"billing": 0.94,
"technical": 0.01,
"sales": 0.02,
"other": 0.03
},
"certainty": 0.7925
},
"time_critical": {
"type": "yes_no",
"answer": "yes",
"probabilities": {
"yes": 0.88,
"no": 0.12
},
"certainty": 0.4706
}
}
}
Billing at 0.94 clears any sensible threshold, so this one routes itself. The second question is what turns routing into triage: a deadline inside a week at 0.88, so it can go to the top of the billing queue rather than the bottom, and nobody had to read it first.
Ask everything you need in one call
The message is read once and billed once however many questions you attach, so a routing call can do more than choose a queue. Useful companions: how upset the writer sounds, whether they mention cancelling, which product line it concerns, whether a deadline is named, whether there's enough information to act at all. Each answer is independent, so adding one can't change the others, and you get everything your queue needs in a single round trip.
Set the threshold where the mistake hurts
Route automatically when the leading queue clears a threshold you measured, and send the rest to triage. Where to put it depends on what a wrong turn costs: a message moved between two support queues is a minor delay, while one routed away from a security inbox is not. Pick the number by labelling a couple of hundred real messages and sweeping it, which the guide on thresholds walks through.
A practical detail: measure per queue, not just overall. One badly-described option can be wrong most of the time while the average still looks healthy.
Close the loop
Routing gives you free labels: when a person moves a ticket out of the queue the model chose, that's a corrected example. Log the chosen queue and the probabilities alongside each ticket, and review the moves weekly. Most of them point at two options whose descriptions overlap, and a sentence of clarification fixes more than any threshold change.
Keep a couple of guardrails: never let an automatic route be invisible, so people can see and undo it, and re-run your labelled set after any wording change, since moving a description moves the probabilities.
Leads and other inboxes
The same shape covers inbound sales. Replace queues with stages, add a rating for how well the sender matches your target customer, and a yes-or-no for whether they asked about price. The answers decide who picks it up and how fast, and the ratings give you something to sort the day's list by.
Using one
SeaCat answers a routing call in one request: the message, up to 64 questions about it, and every answer with its probabilities. It's $0.20 per million input tokens, and the message is billed once however many questions you ask.
More guides
- What is a system one model? What a system one model returns, how the answer is computed, what it's good at and what it isn't for.
- Typed decisions instead of text Why an answer drawn from your own options, with a probability on each, beats parsing a written reply.
- Probabilities and thresholds: when to let code decide What the probabilities mean, how to choose a threshold from your own data, and what to do below it.
- Grading model outputs against a rubric Turn a rubric into ordered levels, score one criterion per question, and get a number you can sort by.