We are going to build a lightweight sentiment analysis pipeline that classifies customer feedback, extracts a confidence score, and returns structured JSON. It runs entirely through the OpenAI SDK pointed at Oxlo.ai, so you get flat per-request pricing and no token math. If you support customers or monitor brand mentions, this gives you a fully working baseline in under fifty lines of Python.
What you'll need
- Python 3.10 or newer
- The OpenAI SDK:
pip install openai - An Oxlo.ai API key from https://portal.oxlo.ai
Step 1: Set up the client and environment
I start by creating a client that talks to Oxlo.ai. Because Oxlo.ai is fully OpenAI-compatible, this is a single line change to the base URL.
import json
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.environ.get("OXLO_API_KEY", "YOUR_OXLO_API_KEY")
)
Step 2: Write the system prompt
The system prompt is the only training we need. I force the model to return raw JSON with a label, score, and short reasoning string.
SYSTEM_PROMPT = """You are a sentiment analysis engine.
Analyze the user provided text and return a JSON object with exactly these keys:
- label: one of [positive, neutral, negative]
- score: a float between 0.0 and 1.0 representing confidence
- reasoning: one sentence explaining why
Return only valid JSON. Do not wrap it in markdown fences."""
Step 3: Build the single-text analysis function
Here is the core function. It sends the text to Llama 3.3 70B on Oxlo.ai and parses the JSON response.
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},
],
)
raw = response.choices[0].message.content.strip()
return json.loads(raw)
Step 4: Add batch processing for long inputs
Because Oxlo.ai charges a flat rate per request regardless of prompt length, we can stuff dozens of reviews into one call without inflating cost. I pass a JSON array of reviews and ask for a JSON array of results back.
BATCH_PROMPT = """You are a sentiment analysis engine.
You will receive a JSON array of customer reviews.
Return a JSON array of objects, one per review, in the same order.
Each object must have:
- label: one of [positive, neutral, negative]
- score: a float between 0.0 and 1.0
- reasoning: one sentence
Return only valid JSON. No markdown fences."""
def analyze_batch(reviews: list[str]) -> list[dict]:
payload = json.dumps(reviews, ensure_ascii=False)
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": BATCH_PROMPT},
{"role": "user", "content": payload},
],
)
raw = response.choices[0].message.content.strip()
return json.loads(raw)
Step 5: Run a local test harness
I add a small harness that feeds a few raw strings through the batch function and prints a neat table.
if __name__ == "__main__":
reviews = [
"The battery life on this laptop is incredible, easily lasts 12 hours.",
"It is okay, nothing special but it works.",
"Waited two weeks for delivery and the box was dented. Not happy.",
"Honestly? Best onboarding experience I have had in years.",
]
results = analyze_batch(reviews)
print(f"{'Review':<50} | {'Label':<10} | {'Score':<6}")
print("-" * 75)
for review, res in zip(reviews, results):
print(f"{review[:48]:<50} | {res['label']:<10} | {res['score']:<6.2f}")
print(f" -> {res['reasoning']}")
Run it
Running the script produces structured output without any token counting. Here is what I see on my end:
$ python sentiment.py
Review | Label | Score
---------------------------------------------------------------------------
The battery life on this laptop is incredible, ... | positive | 0.92
-> The reviewer enthusiastically praises the long battery life.
It is okay, nothing special but it works. | neutral | 0.65
-> The feedback is indifferent and lacks strong emotion.
Waited two weeks for delivery and the box was d... | negative | 0.88
-> The reviewer expresses frustration about shipping and damage.
Honestly? Best onboarding experience I have had... | positive | 0.95
-> The reviewer explicitly calls out the onboarding as the best.
Wrap-up and next steps
This pipeline is already useful, but there are two moves I would make next. First, swap the model to kimi-k2.6 or deepseek-v3.2 if you need sharper detection of sarcasm or mixed sentiment. Second, persist the results by writing the JSON array to a CSV or posting it to a webhook. Because Oxlo.ai uses request-based pricing, you can send large batches of long reviews in a single call without watching token meters tick up. See https://oxlo.ai/pricing for plan details.
Top comments (0)