DEV Community

shashank ms
shashank ms

Posted on

Using LLM for Sentiment Analysis and Text Classification

We are going to build a support ticket classifier that analyzes customer sentiment and assigns a category in a single LLM call. This helps support teams route issues and prioritize escalations without maintaining separate NLP pipelines. I am using Oxlo.ai because its request-based pricing keeps the cost flat even when I pass long customer messages with full thread history.

What you'll need

Step 1: Set up the client

First, I verify that the SDK can reach Oxlo.ai. I point the OpenAI client at the Oxlo.ai base URL and make a quick health check call to Llama 3.3 70B.

from openai import OpenAI
import os

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

response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[
        {"role": "user", "content": "Reply with OK if you are online."}
    ],
    max_tokens=10
)

print(response.choices[0].message.content)

Step 2: Write the system prompt

I keep the labels in a closed set so the model cannot hallucinate categories. The prompt asks for a JSON object with sentiment, category, confidence, and a short reasoning string.

SYSTEM_PROMPT = """You are a support ticket classifier.
Analyze the customer message and return a JSON object with exactly these keys:
- sentiment: one of [positive, neutral, negative]
- category: one of [billing, technical, feature_request, account]
- confidence: a float between 0.0 and 1.0 representing your certainty
- reasoning: one sentence explaining why you chose these labels
Do not include any text outside the JSON object."""

Step 3: Build the classifier function

I use JSON mode to force valid output, then parse the result with the standard library. I also add a small wrapper that returns a clean dictionary or raises an error.

import json

def classify_text(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"},
    )

    raw = response.choices[0].message.content
    return json.loads(raw)

Step 4: Process a batch of tickets

Now I run the classifier over a realistic set of tickets. I collect the results in a list so I can inspect them or dump them to a database later.

tickets = [
    "I was charged twice this month and I need a refund immediately.",
    "How do I reset my password? The link is not working.",
    "Love the new dashboard. Great work.",
    "Your API returned a 500 error for the last hour and it is blocking our deploy.",
]

results = []
for ticket in tickets:
    try:
        label = classify_text(ticket)
        results.append({"text": ticket, "label": label})
    except Exception as exc:
        results.append({"text": ticket, "error": str(exc)})

for row in results:
    print(row)

Step 5: Add confidence thresholds

Not every prediction should be trusted automatically. I flag anything below 0.8 for human review so the team can focus on edge cases.

flagged = []

for row in results:
    if "error" in row:
        continue

    confidence = row["label"].get("confidence", 1.0)
    if confidence < 0.8:
        row["flag"] = "human_review"
        flagged.append(row)

print(f"Auto-approved: {len(results) - len(flagged)}")
print(f"Flagged for review: {len(flagged)}")

for row in flagged:
    print(" -", row["text"])

Run it

Here is the complete script. When I execute it, the output looks like this.

from openai import OpenAI
import os, json

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

SYSTEM_PROMPT = """You are a support ticket classifier.
Analyze the customer message and return a JSON object with exactly these keys:
- sentiment: one of [positive, neutral, negative]
- category: one of [billing, technical, feature_request, account]
- confidence: a float between 0.0 and 1.0 representing your certainty
- reasoning: one sentence explaining why you chose these labels
Do not include any text outside the JSON object."""

def classify_text(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"},
    )
    return json.loads(response.choices[0].message.content)

tickets = [
    "I was charged twice this month and I need a refund immediately.",
    "How do I reset my password? The link is not working.",
    "Love the new dashboard. Great work.",
    "Your API returned a 500 error for the last hour and it is blocking our deploy.",
]

results = []
for ticket in tickets:
    try:
        results.append({"text": ticket, "label": classify_text(ticket)})
    except Exception as exc:
        results.append({"text": ticket, "error": str(exc)})

flagged = []
for row in results:
    if "error" not in row and row["label"].get("confidence", 1.0) < 0.8:
        row["flag"] = "human_review"
        flagged.append(row)

for row in results:
    print(row)

print(f"Auto-approved: {len(results) - len(flagged)}")
print(f"Flagged for review: {len(flagged)}")

Example output:

{'text': 'I was charged twice this month and I need a refund immediately.', 'label': {'sentiment': 'negative', 'category': 'billing', 'confidence': 0.95, 'reasoning': 'The customer is reporting a duplicate charge and demanding a refund.'}}
{'text': 'How do I reset my password? The link is not working.', 'label': {'sentiment': 'neutral', 'category': 'technical', 'confidence': 0.91, 'reasoning': 'The customer is asking for help with a broken password reset link.'}}
{'text': 'Love the new dashboard. Great work.', 'label': {'sentiment': 'positive', 'category': 'feature_request', 'confidence': 0.88, 'reasoning': 'The customer is praising a recent UI update.'}}
{'text': 'Your API returned a 500 error for the last hour and it is blocking our deploy.', 'label': {'sentiment': 'negative', 'category': 'technical', 'confidence': 0.93, 'reasoning': 'The customer is reporting a service outage that is impacting their deployment pipeline.'}}
Auto-approved: 4
Flagged for review: 0

Next steps

Wire this classifier into a webhook so new tickets are labeled as they arrive. If you accumulate a few thousand verified labels, you can later train a smaller specialist model on Oxlo.ai to drive latency down even further.

Top comments (0)