We are going to build a support ticket classifier that reads raw customer messages and assigns a category and urgency level. This replaces manual triage and feeds directly into downstream automation like routing or alerting. I will walk through the exact code I run against Oxlo.ai.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Configure the Oxlo.ai client
Oxlo.ai exposes an OpenAI-compatible endpoint, so the official SDK works once you point the base URL at https://api.oxlo.ai/v1. I use llama-3.3-70b because it follows structured instructions reliably and starts instantly with no cold starts.
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": "Say hello"},
],
)
print(response.choices[0].message.content)
Step 2: Lock down the classification schema
The prompt is the entire interface. I constrain the output to a JSON object with category, urgency, and a one-line reasoning string so downstream code can parse it without guesswork.
SYSTEM_PROMPT = """You are a support ticket classifier.
Analyze the user's message and respond with a single JSON object containing exactly these keys:
- category: one of ["Billing", "Technical", "Account", "General"]
- urgency: one of ["Low", "Medium", "High"]
- reasoning: one sentence explaining why
Rules:
- Return only valid JSON.
- Do not wrap the JSON in markdown code fences."""
Step 3: Build the classify function
I wrap the API call in a small function that injects the system prompt and forces JSON mode. Oxlo.ai supports JSON mode on llama-3.3-70b, so setting response_format keeps the output machine-readable.
import json
def classify_ticket(text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
temperature=0.1,
)
raw = response.choices[0].message.content
return json.loads(raw)
# sanity check
print(classify_ticket("I was charged twice this month."))
Step 4: Batch and defensive parsing
Real pipelines deal with malformed inputs and network blips. I iterate over a list of strings, catch JSON or API errors, and return a safe fallback so the pipeline stays alive.
from typing import List
def classify_batch(tickets: List[str]) -> List[dict]:
results = []
for t in tickets:
try:
results.append(classify_ticket(t))
except Exception as e:
results.append({
"category": "Error",
"urgency": "Unknown",
"reasoning": str(e),
})
return results
tickets = [
"My login fails every morning after the update.",
"Can I get a refund for last quarter?",
"The dashboard looks weird on mobile.",
"I need to add two seats to my plan before Friday.",
]
classified = classify_batch(tickets)
for c in classified:
print(c)
Step 5: Route based on urgency
Classification is only useful if we act on it. I add a small router that escalates any ticket tagged High urgency and queues the rest by category. Because Oxlo.ai charges per request rather than per token, long paste-in logs cost the same as short messages, which keeps pricing predictable for queues that mix both.
def route_ticket(original: str, result: dict):
if result.get("urgency") == "High":
print(f"[ESCALATE] {original}")
else:
print(f"[QUEUE {result.get('category', 'General')}] {original}")
for ticket, result in zip(tickets, classified):
route_ticket(ticket, result)
Run it
Putting it all together, the script reads raw strings and prints structured decisions. You can drop in a heavier model like deepseek-v3.2 or qwen-3-32b if you need stronger reasoning on ambiguous tickets.
if __name__ == "__main__":
tickets = [
"My login fails every morning after the update.",
"Can I get a refund for last quarter?",
"The dashboard looks weird on mobile.",
"I need to add two seats to my plan before Friday.",
]
for ticket in tickets:
result = classify_ticket(ticket)
print(f"Ticket: {ticket}")
print(f"Result: {result}")
print()
Expected output:
Ticket: My login fails every morning after the update.
Result: {'category': 'Technical', 'urgency': 'High', 'reasoning': 'Login failure after an update indicates a potential bug or regression.'}
Ticket: Can I get a refund for last quarter?
Result: {'category': 'Billing', 'urgency': 'Medium', 'reasoning': 'Refund requests are standard billing inquiries.'}
Ticket: The dashboard looks weird on mobile.
Result: {'category': 'Technical', 'urgency': 'Low', 'reasoning': 'UI rendering issue on mobile is non-critical.'}
Ticket: I need to add two seats to my plan before Friday.
Result: {'category': 'Account', 'urgency': 'Medium', 'reasoning': 'Plan expansion request with a specific deadline.'}
Next steps
Swap in kimi-k2.6 if your tickets include screenshots or mixed-language content, since it handles vision and multilingual reasoning well. If you plan to run thousands of these daily, check the Oxlo.ai pricing page at https://oxlo.ai/pricing to see how request-based billing compares to token-based providers for your typical input lengths.
Top comments (0)