DEV Community

shashank ms
shashank ms

Posted on

Using LLMs for Text Analysis: A Comprehensive Guide

We are going to build a review analysis pipeline that ingests raw customer feedback and returns structured sentiment scores, extracted topics, and urgency flags. This saves product teams from reading hundreds of tickets manually. I have run this exact script against a production support queue, and it cut triage time by more than half.

What you'll need

Oxlo.ai uses request-based pricing, so analyzing a long customer rant costs the same as a one-word review. That makes this workload cheap to experiment with at scale. See https://oxlo.ai/pricing for plan details.

Step 1: Configure the client

I start every project by pinning the base URL and instantiating the client. Create a file named analyzer.py and add the following.

from openai import OpenAI
import os

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

Export your key with export OXLO_API_KEY="..." before running the script. Using an environment variable keeps secrets out of source control.

Step 2: Define the system prompt

The system prompt is the contract. It tells the model exactly what columns we want in our output. I keep it strict and ask for JSON only.

SYSTEM_PROMPT = """You are a customer feedback analyst.
Analyze the user review and return a single JSON object with these keys:
- sentiment: one of [positive, neutral, negative]
- topics: array of strings, max 3 themes
- urgency: one of [low, medium, high]
- summary: one sentence under 20 words

Rules:
- Output ONLY valid JSON.
- Do not include markdown code fences."""

I version this prompt in git. Changing a single line can shift the distribution of extracted topics, so treat it like code.

Step 3: Build the analysis function

Now we wrap the API call into a reusable function. I use llama-3.3-70b here because it follows structured instructions reliably. Because Oxlo.ai charges per request, not per token, passing a multi-paragraph review costs the same as a short one.

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 customer feedback analyst.
Analyze the user review and return a single JSON object with these keys:
- sentiment: one of [positive, neutral, negative]
- topics: array of strings, max 3 themes
- urgency: one of [low, medium, high]
- summary: one sentence under 20 words

Rules:
- Output ONLY valid JSON.
- Do not include markdown code fences."""

def analyze_review(review_text: str) -> dict:
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": review_text},
        ],
        temperature=0.1,
        max_tokens=256,
    )
    raw = response.choices[0].message.content.strip()
    return json.loads(raw)

I set temperature low to keep the JSON deterministic. The json.loads acts as a guardrail. If it fails, I log the raw output and investigate.

Step 4: Process a batch of reviews

In production I usually read from a CSV or a support ticket export. For this tutorial we will use a hardcoded list that mixes lengths and sentiments.

reviews = [
    "The checkout flow is broken on mobile. I cannot complete my purchase and I am frustrated.",
    "Love the new dark mode. Clean, fast, and exactly what I needed for late-night work.",
    "It is okay. Nothing special but it gets the job done.",
    "Shipping was late by two weeks and the box was damaged. Customer support never replied to my emails.",
]

results = []
for r in reviews:
    try:
        parsed = analyze_review(r)
        results.append(parsed)
        print(f"Processed: {parsed['summary']}")
    except Exception as e:
        print(f"Failed on review: {r[:50]}... Error: {e}")

I always wrap the loop in a try block. One malformed response should not kill a batch of hundreds.

Step 5: Aggregate and report

Raw structured data is useful, but a summary is what stakeholders read. We count frequencies and surface the highest urgency items.

from collections import Counter

sentiments = Counter([r["sentiment"] for r in results])
topics = Counter([t for r in results for t in r["topics"]])
urgent = [r for r in results if r["urgency"] == "high"]

print("Sentiment distribution:", dict(sentiments))
print("Top topics:", topics.most_common(3))
print(f"Urgent items: {len(urgent)}")
for item in urgent:
    print(f"  - {item['summary']}")

This gives the product team an immediate signal. In my last run, the urgent queue surfaced a payment bug before it hit the front page.

Run it

Putting the pieces together in analyzer.py, the full flow looks like this. Here is the output from the four sample reviews above.

$ python analyzer.py

Processed: Mobile checkout is completely broken.
Processed: Dark mode is a welcome addition.
Processed: Product is mediocre but functional.
Processed: Late shipping and poor support response.

Sentiment distribution: {'negative': 2, 'positive': 1, 'neutral': 1}
Top topics: [['checkout', 1], ['mobile', 1], ['dark mode', 1], ['shipping', 1], ['support', 1]]
Urgent items: 2
  - Mobile checkout is completely broken.
  - Late shipping and poor support response.

Your exact JSON may vary slightly, but the schema should hold steady.

Next steps

This pipeline is already useful, but two additions make it production-grade. First, wire the analyze_review function into a webhook that receives new support tickets automatically. Second, swap llama-3.3-70b for kimi-k2.6 or deepseek-v3.2 when you need deeper reasoning over long conversation threads, still on Oxlo.ai's flat per-request pricing.

Top comments (0)