DEV Community

shashank ms
shashank ms

Posted on

Using LLMs for Text Classification Tasks

We are going to build a support ticket classifier that reads unstructured customer messages and returns structured category, urgency, and confidence scores. This replaces fragile keyword rules and removes the need to train and deploy a separate model for every new classification schema. I run it on Oxlo.ai because one flat cost per request, not per token, means a five-word subject line and a five-paragraph error log cost exactly the same (https://oxlo.ai/pricing), which keeps batch processing predictable.

What you'll need

Step 1: Configure the Oxlo.ai client

I keep the API key in an environment variable and instantiate the client with Oxlo.ai's base URL. A quick smoke test confirms the endpoint is alive and that there are no cold starts on the model.

from openai import OpenAI
import os

client = OpenAI(
    base_url="https://api.oxlo.ai/v1",
    api_key=os.environ.get("OXLO_API_KEY")
)

# Smoke test
resp = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[{"role": "user", "content": "hello"}]
)
print(resp.choices[0].message.content)

Step 2: Design the system prompt

The system prompt is the entire classifier. It defines the categories, the urgency scale, and the exact JSON keys the application will parse, so I treat it as a config file I version control.

SYSTEM_PROMPT = """You are a support ticket classifier.
Analyze the user's message and return a single JSON object with exactly these keys:
  category: one of ["Technical", "Billing", "Feature Request"]
  urgency: one of ["Low", "Medium", "High", "Critical"]
  summary: a concise summary of the issue in 12 words or fewer
  confidence: a float between 0.0 and 1.0 representing classification certainty

Classification rules:
- Technical covers bugs, crashes, errors, and integration problems.
- Billing covers invoices, refunds, failed charges, and plan changes.
- Feature Request covers asks for new functionality or improvements.
Return only raw JSON. Do not wrap the output in markdown fences."""

Step 3: Build the classifier function

I use JSON mode so the model is constrained to valid JSON, then parse it with the standard library. A low temperature keeps the output deterministic.

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)

# Single test
ticket = "I was charged twice on March 1st and I need a refund."
result = classify_ticket(ticket)
print(json.dumps(result, indent=2))

Step 4: Process a batch

In production you will classify more than one ticket, so I loop over a list and print a simple report. Because Oxlo.ai bills per request, the cost of this batch is simply the number of tickets, regardless of how verbose each ticket is.

tickets = [
    "The API returns a 500 error when I upload files larger than 1MB.",
    "Can you add webhook signatures so I can verify events?",
    "My invoice shows the wrong company name and tax ID.",
    "Dashboard is completely blank after I log in. I cleared cache already.",
]

for t in tickets:
    out = classify_ticket(t)
    print(f"{out['urgency']:8} | {out['category']:15} | {out['summary']}")

Step 5: Add confidence guardrails

LLMs can hallucinate categories on ambiguous input. I wrap the core call with a confidence threshold and a generic exception handler so low-confidence or malformed outputs land in a human review queue instead of the wrong automation path.

def classify_safe(text: str, min_confidence: float = 0.85) -> dict:
    try:
        out = classify_ticket(text)
        if out.get("confidence", 0.0) < min_confidence:
            out["category"] = "Needs Review"
            out["urgency"] = "Medium"
        return out
    except Exception as exc:
        return {
            "category": "Error",
            "urgency": "Medium",
            "summary": str(exc),
            "confidence": 0.0,
        }

# Re-run with guardrails
for t in tickets:
    out = classify_safe(t)
    print(f"{out['category']:15} | conf={out['confidence']} | {out['summary']}")

Run it

Save the script as classifier.py, export your key, and execute it.

$ export OXLO_API_KEY="sk-oxlo.ai-..."
$ python classifier.py

Expected output:

High     | Billing         | Double charge refund request
High     | Technical       | API 500 error on large uploads
Low      | Feature Request | Add webhook signatures
Medium   | Technical       | Dashboard blank after login

Wrap-up and next steps

This classifier is now a drop-in replacement for brittle regex rules or expensive per-token classification pipelines. On Oxlo.ai, you can swap llama-3.3-70b to deepseek-r1-671b or kimi-k2.6 when you need deeper reasoning for ambiguous edge cases, and the cost structure stays flat per request. Two concrete next steps: wire the classify_safe output into a Slack webhook for human review, or extend the schema with a custom taxonomy and feed the results into your CRM.

Top comments (1)

Collapse
 
marcusykim profile image
Marcus Kim

This is where AI-assisted development gets interesting to me: the faster the code appears, the more important the review criteria become. I want the tool to know the expected behavior, edge cases, and failure signs before it starts changing files, otherwise speed can hide fragility.