DEV Community

shashank ms
shashank ms

Posted on

LLM Text Classification Tutorial

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

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)