We are going to build a production-ready sentiment analysis pipeline that reads raw customer feedback and returns structured labels with confidence scores and short explanations. This helps support and product teams prioritize issues without maintaining a dedicated NLP infrastructure or worrying about token costs scaling with long complaint emails.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK:
pip install openai
Step 1: Configure the Oxlo.ai client
Import the SDK and point it at Oxlo.ai. Because the platform is fully OpenAI-compatible, the only changes are the base URL and your Oxlo.ai API key.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY")
)
Step 2: Define the system prompt
The prompt enforces strict output formatting so we can parse it reliably. I describe a JSON schema inside the prompt and ask for a single valid JSON object with no markdown fences.
SYSTEM_PROMPT = """You are a sentiment analysis engine.
Analyze the sentiment of the user message and respond with a single valid JSON object containing exactly these keys:
- label: one of "positive", "negative", "neutral"
- confidence: a float between 0.0 and 1.0
- reasoning: one concise sentence explaining why
Rules:
- Output only the JSON object, with no markdown code fences and no extra text.
- If the message is mixed, choose the dominant sentiment.
- Be conservative with confidence; 1.0 means absolute certainty."""
Step 3: Build the analyzer function
This function sends feedback text to Llama 3.3 70B on Oxlo.ai, then parses the JSON response. I use Llama 3.3 70B here because it follows structured formatting instructions reliably for classification work.
import json
def analyze_sentiment(text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
temperature=0.0,
)
raw = response.choices[0].message.content.strip()
# Guard against occasional markdown fences.
if raw.startswith("
```"):
raw = raw.split("\n", 1)[1].rsplit("```
", 1)[0].strip()
return json.loads(raw)
Step 4: Add batch processing
In production you will analyze more than one message at a time. This wrapper iterates over a list, handles API or JSON errors gracefully, and preserves order.
from typing import List
def analyze_batch(texts: List[str]) -> List[dict]:
results = []
for idx, text in enumerate(texts):
try:
result = analyze_sentiment(text)
result["index"] = idx
result["input"] = text
results.append(result)
except Exception as e:
results.append({
"index": idx,
"input": text,
"label": "error",
"confidence": 0.0,
"reasoning": str(e),
})
return results
Step 5: Test harness
Here is a short list of realistic support messages. We will run them through the pipeline and print a simple table.
if __name__ == "__main__":
samples = [
"The new export feature saved me three hours this week. Great work.",
"I waited 20 minutes for the invoice page to load and then it crashed.",
"Your pricing page is okay but I wish there was an annual discount.",
"Absolutely love the dark mode. Best update in months.",
"I am frustrated that the mobile app still lacks offline support.",
]
for row in analyze_batch(samples):
print(f"{row['label']:10} | {row['confidence']:.2f} | {row['input'][:50]}...")
Run it
Export your key and execute the script.
export OXLO_API_KEY="YOUR_OXLO_API_KEY"
python sentiment.py
Expected output:
positive | 0.95 | The new export feature saved me three hours this ...
negative | 0.92 | I waited 20 minutes for the invoice page to load...
neutral | 0.78 | Your pricing page is okay but I wish there was a...
positive | 0.96 | Absolutely love the dark mode. Best update in mo...
negative | 0.88 | I am frustrated that the mobile app still lacks ...
Wrap-up and next steps
Because Oxlo.ai uses flat per-request pricing, running this pipeline on long customer emails or multi-turn chat transcripts costs the same as a one-word message. For a live deployment, wire the analyze_batch function into a webhook that scores incoming support tickets before they hit your CRM.
Another practical extension is to switch the model to kimi-k2.6 or qwen-3-32b for multilingual feedback, or to deepseek-v3.2 if you also want the model to extract specific product sub-features mentioned in the text. See the Oxlo.ai pricing page to estimate volume costs for your expected traffic.
Top comments (0)