We are building a support ticket classifier that reads raw customer messages and returns a structured category and priority level. It helps small teams replace a brittle rules engine or a separately hosted ML model with a single LLM call. I will walk through the exact Python script I run in production, wired to Oxlo.ai.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK:
pip install openai
Step 1: Connect to Oxlo.ai
First, I verify that the environment is wired correctly. I instantiate the OpenAI client pointing at Oxlo.ai and send a smoke test request. If this prints a response, the pipeline is open.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Reply with exactly: Connection OK"},
],
)
print(response.choices[0].message.content)
Step 2: Define the classification schema
I keep the taxonomy in plain Python lists so non-engineers can edit it without touching prompts. The classifier will map free text into one of five categories and one of four priority levels.
CATEGORIES = ["billing", "technical", "account", "feature_request", "bug"]
PRIORITIES = ["low", "medium", "high", "critical"]
Step 3: Lock in the system prompt
The system prompt is the only part of the stack that needs a review when we add new categories. I keep it strict about output format so downstream code never has to guess.
SYSTEM_PROMPT = """You are a support ticket classifier.
Your job is to read a customer message and return a JSON object with exactly these keys:
- category: one of billing, technical, account, feature_request, bug
- priority: one of low, medium, high, critical
- reasoning: one sentence explaining the classification
Rules:
- Return ONLY valid JSON. No markdown code fences, no preamble, no postscript.
- If the ticket mentions payment failure, duplicate charge, or refund demand, classify as billing and set priority to high or critical.
- If the ticket describes a complete service outage or data loss, classify as technical and set priority to critical.
- If the ticket is a suggestion or nice-to-have, classify as feature_request and set priority to low."""
Step 4: Build the classifier function
Now I wrap the LLM call in a small function. I set temperature low to keep the output deterministic, and I strip accidental markdown fences because some models still wrap JSON in triple backticks despite instructions. I use Oxlo.ai's llama-3.3-70b here because it follows structured instructions reliably, though qwen-3-32b or kimi-k2.6 are solid alternatives if you need multilingual inputs or longer context.
import json
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a support ticket classifier.
Your job is to read a customer message and return a JSON object with exactly these keys:
- category: one of billing, technical, account, feature_request, bug
- priority: one of low, medium, high, critical
- reasoning: one sentence explaining the classification
Rules:
- Return ONLY valid JSON. No markdown code fences, no preamble, no postscript.
- If the ticket mentions payment failure, duplicate charge, or refund demand, classify as billing and set priority to high or critical.
- If the ticket describes a complete service outage or data loss, classify as technical and set priority to critical.
- If the ticket is a suggestion or nice-to-have, classify as feature_request and set priority to low."""
def classify_ticket(text: str, model: str = "llama-3.3-70b") -> dict:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
temperature=0.1,
max_tokens=256,
)
raw = response.choices[0].message.content.strip()
if raw.startswith("
```"):
raw = raw.split("\n", 1)[1].rsplit("```
", 1)[0].strip()
return json.loads(raw)
Step 5: Add batch processing and error handling
In production, tickets arrive in bursts. I wrap the single classifier in a batch loop that catches JSON decoding errors or unexpected model output and logs them without crashing the pipeline. Because Oxlo.ai charges one flat rate per request, batching long tickets does not inflate the cost the way token-based pricing would. See https://oxlo.ai/pricing for current plan details.
from typing import List, Dict, Any
def classify_batch(tickets: List[str], model: str = "llama-3.3-70b") -> List[Dict[str, Any]]:
results = []
for text in tickets:
try:
result = classify_ticket(text, model=model)
result["input_preview"] = text[:120] + "..." if len(text) > 120 else text
result["ok"] = True
except Exception as e:
result = {
"input_preview": text[:120] + "..." if len(text) > 120 else text,
"ok": False,
"error": str(e),
}
results.append(result)
return results
Run it
Here is the entry point I use to sanity check the pipeline. It runs four representative tickets through the classifier and prints a summary table.
TICKETS = [
"I was charged twice for my subscription this month. Please refund the extra payment immediately.",
"How do I reset my password? I forgot it and the reset email is not arriving.",
"The entire API is returning 503 errors for all users in our organization.",
"It would be nice if the dashboard had a dark mode option for late night shifts.",
]
if __name__ == "__main__":
for r in classify_batch(TICKETS):
if r["ok"]:
print(f"Category: {r['category']:<18} Priority: {r['priority']:<8} Reason: {r['reasoning']}")
else:
print(f"FAIL: {r['error']}")
When I run this against Oxlo.ai, the output looks like this:
Category: billing Priority: high Reason: The customer reports a duplicate charge and requests a refund, which is a billing issue requiring urgent attention.
Category: account Priority: medium Reason: The customer needs help resetting their password, which is an account issue with moderate urgency.
Category: technical Priority: critical Reason: The customer reports a complete service outage affecting all users, which is a critical technical issue.
Category: feature_request Priority: low Reason: The customer suggests adding dark mode to the dashboard, which is a feature request with low urgency.
Wrap-up
This classifier is now a drop-in replacement for a rules engine. Two concrete next steps: wire the classify_batch output into your CRM or help desk API so tickets route automatically, and add a confidence score by asking the model for a confidence key in the JSON, then human-review anything below 0.9.
Top comments (0)