Route and prioritize support tickets with a decision model
Pick the team, set the priority and flag what needs a person, from the ticket text, in one call. How to triage support tickets with Saina Helm 2 instead of keyword rules or a chat-model prompt, with thresholds that send unsure cases to review.
In short: Send the ticket as the state and ask three typed questions: which team, how urgent, does it need a person. Helm scores every option and you set a threshold; everything below it goes to a review queue instead of the wrong team. One request, no prompt to maintain, and it runs on a CPU next to your helpdesk.
Saina Helm 2
Text
Tickets, chats, forms and emails arriving in a helpdesk or an n8n workflow
The step
“We get 700 internal tickets a week and L1 spends most of the morning re-categorizing what the form put in the wrong queue. I don’t want a chatbot answering them. I want the right team to see the right ticket first.”
What a helpdesk lead asks for, paraphrased from the threads we read every dayTriage is the step before any answer gets written: who owns this, how soon, and does it need judgement. It is almost always one of three things today.
- A form the requester fills in. Users pick the category that gets them a reply fastest, not the right one. L1 fixes it by hand.
- Keyword rules or a Switch node. “password” goes to IT, “invoice” goes to billing. They are predictable and they rot: every new product name is a new rule, and a ticket that mentions both goes wherever the first rule fires.
- A chat-model prompt: “reply with billing, technical or other.” It works in the demo. In production the reply is sometimes a sentence, sometimes a label you never defined, and you never learn how sure it was. A borderline ticket is routed with the same confidence as an obvious one.
The job is not writing; it is picking between options you already know. That is what a decision model does, and nothing else.
What the request looks like
{
"model": "saina-helm-2-0.8b",
"state": "Nobody on our team can sign in since this morning. SSO says
'identity provider error'. Customer demo at 2pm.",
"mode": "decision",
"threshold": 0.7,
"min_margin": 0.2,
"questions": {
"team": {
"type": "single_choice",
"question": "Which team should own this ticket?",
"options": {
"it_access": "Accounts, sign-in, SSO, permissions",
"billing": "Charges, invoices, plan changes",
"product": "Bugs and errors inside the product",
"facilities": "Office, hardware, equipment"
}
},
"priority": {
"type": "rating",
"question": "How urgent is this?",
"levels": ["Low", "Normal", "Urgent"]
},
"needs_person": {
"type": "yes_no",
"question": "Does this need a person rather than a self-service article?"
}
}
}
And what comes back:
{
"answers": {
"team": {
"type": "single_choice",
"selection": "it_access",
"reason": "accepted",
"probabilities": {
"it_access": 0.91,
"product": 0.06,
"billing": 0.02,
"facilities": 0.01
},
"confidence": 0.88
},
"priority": {
"type": "rating",
"expected_level": 1.86,
"reason": "accepted",
"probabilities": {
"0": 0.02,
"1": 0.1,
"2": 0.88
},
"levels": [
"Low",
"Normal",
"Urgent"
],
"level": 2,
"confidence": 0.86
},
"needs_person": {
"type": "yes_no",
"yes": 0.83,
"no": 0.17,
"confidence": 0.66,
"selected": true,
"reason": "accepted"
}
}
}
Three answers from one read of the ticket, each keyed by the ID you chose. reason: "accepted" means the pick cleared your threshold and margin. When it doesn’t, you get below_threshold, below_margin or tie instead of a guess, with the scores attached, and the ticket goes to a person. Nothing is dropped and nothing is invented: the model can only score the teams you listed.
Putting it in place
Start from last month’s tickets
You don’t need labels to start, but you need a bar. Take a few hundred closed tickets and use the team that finally resolved each one as the label. Run them through Helm in distribution mode, look at where the top score lands for the ones it got right and the ones it got wrong, and set threshold and min_margin from that. Measure wrong-team transfers and the share sent to review, not just accuracy; a router that sends 20% to review and never mis-routes is often the one the team wants.
Run it in shadow mode first
Let the form or the rules keep routing for a week while Helm scores in parallel and logs its pick. Compare, tune the thresholds, then flip.
Wire it in
In n8n, the Saina Helm node has two outputs, Selected and Fallback: connect Selected to your Switch on team, and Fallback to the review queue. The node is for self-hosted n8n and ships with a “Route support tickets to the right team” template; on n8n Cloud, its “over HTTP” template does the same with the built-in HTTP Request node. From anything else, it is one HTTP request:
curl https://api.saina.run/v1/ask \
-H "Authorization: Bearer $SAINA_API_KEY" \
-H 'Content-Type: application/json' \
-d @ticket.json
Or self-host: pip install 'saina[local,server]' and point the same request at your own server. Helm 2 is 0.8B and runs on a CPU, so the tickets never leave your infrastructure.
What it won’t do
- It does not write the reply. Hand the ticket to your LLM or your agent after Helm has decided where it goes.
- It does not learn your team map on its own. The options are yours; describe them in plain words and keep them current.
- A score is not a guarantee. Set thresholds from your own data and keep a review queue.
Frequently asked questions
Can it classify tickets into my own categories?
Yes. The categories are part of each request, as IDs with a plain-language description. Change them in the next request and Helm follows; there is no training step.
How is this different from asking GPT to classify the ticket?
A chat model writes text that you then parse into a category, and it can answer with a label you never defined. Helm only scores the options you gave it, returns a probability for each, and gives you an explicit fallback when the call is too close. There is no prompt to drift.
Does it need the ticket history or the customer record?
No. It reads the state you send. If the history helps the decision, include it in the state; everything in one request is read once and shared by every question.
Can it run inside n8n?
Yes. The Saina Helm community node (self-hosted n8n) takes the ticket and your questions and has Selected and Fallback outputs; on n8n Cloud the same flow runs through the HTTP Request node. Either targets the hosted API or a server you run.