DEV Community

shashank ms
shashank ms

Posted on

Sentiment Analysis, Text Classification, and Named Entity Recognition with LLMs: A Practical Guide

We are building a lightweight text intelligence pipeline that runs sentiment analysis, topic classification, and named entity recognition in a single LLM call. It is useful for support teams, analysts, and developers who need structured insights from unstructured text without maintaining three separate models. Because Oxlo.ai uses flat request-based pricing regardless of input length, you can feed in long support threads or documents without watching costs scale with tokens.

What you'll need

Step 1: Configure the Oxlo.ai client

First, import the SDK and point it at the Oxlo.ai endpoint. I use Llama 3.3 70B here because it follows mixed instructions and JSON mode reliably, but you can swap in Qwen 3 32B, Kimi K2.6, or DeepSeek V3.2 without changing anything else.

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": "Hello world"},
    ],
)
print(response.choices[0].message.content)

Step 2: Write the system prompt

I keep the prompt in a constant so I can tweak labels or categories without touching the Python logic. This instruction forces the model to return a single JSON object containing sentiment, category, and named entities.

SYSTEM_PROMPT = """You are a text analysis engine. Given a user message, output a single JSON object with exactly these keys:
- sentiment: one of "positive", "negative", "neutral", or "mixed"
- category: one of "support", "billing", "sales", or "general"
- entities: an array of objects, each with "text" and "label" (PERSON, ORG, PRODUCT, LOCATION)

Rules:
- Do not include markdown formatting.
- Output only valid JSON.
- If no entities are found, return an empty array."""

Step 3: Implement the analysis function

Now wrap the API call in a function. I enable JSON mode to keep the output structured. On Oxlo.ai, request-based pricing means the cost is the same whether you send a short sentence or a long support transcript, so this pattern stays predictable for bulk jobs.

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 text analysis engine. Given a user message, output a single JSON object with exactly these keys:
- sentiment: one of "positive", "negative", "neutral", or "mixed"
- category: one of "support", "billing", "sales", or "general"
- entities: an array of objects, each with "text" and "label" (PERSON, ORG, PRODUCT, LOCATION)

Rules:
- Do not include markdown formatting.
- Output only valid JSON.
- If no entities are found, return an empty array."""

def analyze_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_output = response.choices[0].message.content
    return json.loads(raw_output)

Run it

Test the pipeline with a couple of real-world snippets. The first sample mixes praise and criticism, while the second is a plain negative support ticket.

if __name__ == "__main__":
    samples = [
        "Sarah from TechFlow said the new analytics suite is a game changer, though she finds the invoice portal confusing.",
        "I am furious that my shipment from Berlin was delayed again with no explanation.",
    ]

    for text in samples:
        result = analyze_text(text)
        print(json.dumps(result, indent=2))

Expected output looks like this:

{
  "sentiment": "mixed",
  "category": "billing",
  "entities": [
    {"text": "Sarah", "label": "PERSON"},
    {"text": "TechFlow", "label": "ORG"},
    {"text": "analytics suite", "label": "PRODUCT"},
    {"text": "invoice portal", "label": "PRODUCT"}
  ]
}
{
  "sentiment": "negative",
  "category": "support",
  "entities": [
    {"text": "Berlin", "label": "LOCATION"}
  ]
}

Wrap-up

You can drop this function into a FastAPI endpoint or a Celery worker to process tickets as they arrive. If you need deeper reasoning for ambiguous text, switch the model to kimi-k2.6 or deepseek-v3.2 on Oxlo.ai and leave the rest of the code unchanged.

Top comments (0)