How to Replace Keyword Rules in Your Helpdesk Routing
Replacing keyword rules in helpdesk routing: why rules break at scale, running AI alongside them, and which rules to keep as permanent hard overrides.
Your helpdesk started with rules: subject CONTAINS "invoice" → billing. It worked at 200 tickets a month. At 2,000, you have 140 rules, three people who know what half of them do, and a growing pile of tickets that match nothing and everything (illustrative). This is the guide to automated helpdesk routing without keyword rules: replacing them with a model that reads the text. It is not a "delete your rules" guide; some rules should survive.
Why keyword rules break in helpdesk routing at scale
- Synonyms and phrasing. "Charged twice", "double billing", "you took my money twice", "refund the extra charge": five phrasings, one rule each, and the sixth arrives Monday.
- New products and terms. Every launch adds vocabulary before it adds rules.
- Multi-intent messages. "I can't log in and I want a refund for the month this happened" matches the login rule and stops.
- Rule interactions. Rule 12 fires before rule 87, and nobody remembers why rule 12 is first.
- Silent no-matches. The default queue grows, and reading it is nobody's job.
Rules are literal string matching doing a job that needs reading comprehension. The fix is a model that reads; the discipline is keeping rules for the cases that should never depend on a model's confidence.
Run AI alongside rules first
Don't rip rules out on day one. Shadow mode:
- Add the model as a logging-only step: for each ticket, record its route and probabilities, and the probabilities of the rule's route.
- Let rules keep routing for two weeks.
- Analyze: where do they agree (most tickets, usually)? Where the model is confident and the rule fired differently, which was right? Where the rule matched nothing, what did the model do?
This gives you the case file for what to keep, and it costs a model call per ticket and a log. For a fuller shadow-mode and rollback procedure, see how to classify and route support tickets without GPT.
Which rules survive as hard overrides
Keep a rule when you can state it exactly and the stakes are absolute:
- Legal and regulatory keywords: "subpoena", "data deletion request", "GDPR". These must always route to the legal/privacy queue, regardless of what any model scores. Keep the keyword rule, and add a yes/no question to the model step as a second net for requests phrased without the keywords ("please erase everything you hold on me").
- VIP and named accounts: keyed on customer ID, not message text. That's a lookup, not a judgment call.
- Exact-match entitlements: "PRIORITY-" ticket codes from your premium support tier.
- Security triggers: "password reset" to the security queue if your policy says so.
Everything else, the judgment calls, is what the model is for.
The model step
A decision model fits this slot naturally, because your routes become data: the options passed with every request, not prompt text or rule order. Hosted options exist too: a decision API such as OpenAI's GPT-6 Luna Decisions over HTTP, or a chat LLM constrained with structured outputs (where you build the confidence handling yourself). The example below uses Saina Helm, an open-weights decision model you run yourself.
from saina import Saina
client = Saina('https://helm.internal.example', api_key='YOUR_KEY')
result = client.ask(
model='saina-helm-0.8b',
state=ticket_text,
mode='decision',
threshold=0.8, # example, tune on your data (0.8 is also the default)
questions={
'team': {
'type': 'single_choice',
'question': 'Which team should handle this ticket?',
'options': {'billing': 'Charges, invoices, refunds',
'technical': 'Outages, errors, account access',
'security': 'Account compromise, phishing reports',
'other': 'Anything else'},
},
'legal_or_privacy': {
'type': 'yes_no',
'question': 'Is this a legal request or a request to access or delete personal data?',
},
'tags': {
'type': 'multi_choice',
'question': 'Which of these does the ticket ask for?',
'options': {'refund': 'Wants money back',
'login': 'Cannot sign in',
'bug': 'Something is broken'},
'threshold': 0.5, # example, tune on your data; applies per label
},
},
)
team = result['answers']['team']
if team['selection'] is None:
print(team['reason'], team['probabilities']) # goes to the review queue
In decision mode, a ticket whose top option falls below the threshold comes back with no selection and a reason (below_threshold, or tie if the top two are exactly equal). min_margin defaults to 0, and at a 0.8 threshold any accepted answer is already well clear of the runner-up, so you don't need it here. That unselected bucket is your new "default queue", except now it contains only genuinely ambiguous tickets, each with probabilities attached, instead of everything that missed a string.
In n8n, the Saina node (community node, self-hosted n8n only) gives you this split as two outputs: Selected for accepted decisions and Fallback for rejected ones. On n8n Cloud, use the portable HTTP Request template from run-saina/n8n-nodes instead; the n8n routing guide walks through both.
Order of operations per ticket: hard overrides first (exact, cheap, absolute), then the model, then the review queue.
Handling the edge cases
- Multi-intent: the
tagsquestion above returns every label that clears its own threshold, so one ticket can fan out to two queues. - New vocabulary: product launch → update option descriptions → re-run the test set. Descriptions are data; no rule sprawl.
- The no-match queue shrinking to ambiguity-only: review it weekly; each reviewed ticket is labeled data.
- Explaining a route: you get probabilities per option and the option descriptions. Not a rule number, but auditable; if your compliance surface demands exact rules, that's what the overrides are for.
Migration checklist
- Shadow mode: model logs routes alongside rule-based routing for two weeks.
- Disagreement analysis: model-confident vs. rule-fired, who was right.
- Hard overrides identified and kept as exact rules (legal, VIP, codes, security).
- Per-ticket order: overrides → model → review queue.
- Test set of 50–100 tickets with expected routes; re-run on every change.
- Weekly review of the fallback queue; corrections feed the labeled set.