Background
Incoming tickets needed someone to read the description, assign a category and priority, and choose a board. Straightforward requests went through the same manual triage as ambiguous ones.
I built a pipeline to handle the categories it could classify consistently and send the rest for review.
What I built
A classification and routing pipeline that runs on ticket creation via a ConnectWise webhook. When a ticket arrives:
- The payload is received and normalised
- The ticket summary and initial description are passed to a classification model
- The model returns a category, suggested priority, and routing board
- If confidence is above threshold, the ticket is automatically routed and assigned
- Low-confidence tickets are flagged for manual review with the classification attached
02
Pipeline
Why LLM classification?
I tried rule-based keyword matching first. It worked for obvious cases but fell apart on anything ambiguous. A ticket titled “can’t get in” could be a physical lock, a VPN, or an application. A model could use more of the description, though the result still needed checking.
03
Live demo: classification & routing
Or start from an example
- Classified
- 0
- Routed
- 0
- Held
- 0
- Auto rate
- N/A
Pick an example or write a ticket, then classify it. The pipeline scores every category, commits when it is confident enough, and hands the rest to a review queue.
Terms matched
What keyword matching does with this ticket
Category
| Category | Score | Share |
|---|
Classifying sends your text to a language model through this site's own endpoint. This site doesn't store it.
Classification model
I used OpenAI’s API with a structured output prompt that returns JSON. The prompt includes:
- The ticket subject and description
- A list of valid categories with descriptions
- Examples of each category (few-shot)
- Instructions to return a confidence score
The model returns something like:
Example response
{
"category": "network_connectivity",
"priority": "high",
"board": "infrastructure",
"confidence": 0.91,
"reasoning": "Ticket describes inability to access company resources remotely, consistent with VPN or firewall issue."
} Classify a ticket above and this becomes the response for it.
Routing logic
ConnectWise’s API handles the actual ticket update. The routing step is a simple API call that sets the board, status, and priority based on the classification result. If confidence is below 0.75, the ticket goes to a review queue with the classification pre-populated. The tech can confirm or override in one click.
Data pipeline
All classifications and outcomes are logged to SQLite. A weekly Polars script computes:
- Classification accuracy (based on technician overrides)
- Distribution by category
- False positive rate by category
- Trends over time
This feedback loop is used to refine the few-shot examples in the prompt.
Key decisions
Structured output over free text. A defined JSON structure gave the routing code fields it could read directly: category, priority, board, and confidence.
A review queue. The system doesn’t try to be 100% automated. Anything below 0.75 confidence gets flagged. This was important for buy-in because the team needed to trust the system before they’d accept it routing tickets without review.
SQLite for the logs. The pipeline runs on a single machine with low write volume, so SQLite kept the storage setup small.
Prompt iteration over model fine-tuning. The few-shot examples in the prompt are stored in a config file and updated based on classification logs. This let me revise the examples without running a training job.
Outcome
After two months in production:
- ~80% of incoming tickets are classified and routed automatically
- Technician override rate stabilised at about 12%
- Two categories, “licensing issues” and “hardware failure”, were identified as too ambiguous and removed from automatic routing pending better prompt examples
The remaining tickets went through manual review.
The classification log also gave us a record of the types of requests coming in. We used that to review recurring problems and inform resource planning.