We are building a customer feedback parsing agent that reads unstructured support tickets and returns structured JSON with intent, sentiment, product mentions, and urgency. This helps support teams route tickets automatically instead of reading every message manually. We will run it on Oxlo.ai, where flat per-request pricing keeps costs predictable even when tickets run long.
What you'll need
Grab an Oxlo.ai API key from https://portal.oxlo.ai. You will also need Python 3.10 or newer and the OpenAI SDK.
pip install openai
Step 1: Connect to Oxlo.ai and verify the endpoint
First, we instantiate the OpenAI-compatible client pointing at Oxlo.ai and make a quick health check call to confirm the key is active.
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": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Reply with OK"},
],
)
print(response.choices[0].message.content)
Step 2: Write the system prompt that defines our NLU schema
The system prompt is the contract. It tells the model exactly what entities and labels to extract from free text.
SYSTEM_PROMPT = """You are an NLU engine that parses customer support tickets into structured JSON.
Extract these fields:
- intent: one of [billing_issue, technical_problem, feature_request, complaint, other]
- sentiment: one of [positive, neutral, negative, very_negative]
- products_mentioned: list of product names, or empty list
- urgency: one of [low, medium, high, critical]
- summary: one concise sentence describing the problem
Rules:
- Output ONLY a JSON object.
- Never wrap the JSON in markdown code fences.
- Never return null for a required field. If unsure, infer the best fit."""
Step 3: Parse a single ticket with JSON mode
We call the model with response_format set to json_object so the output is predictable, then load it into a Python dict.
import json
ticket = ("I was charged twice for my Pro plan last month and now the API dashboard "
"returns 403 errors for every request. This is blocking our entire team.")
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": ticket},
],
response_format={"type": "json_object"},
)
result = json.loads(response.choices[0].message.content)
print(json.dumps(result, indent=2))
Step 4: Harden the pipeline with validation
Production NLU needs to survive malformed outputs and missing keys. We add a thin validation layer that catches parsing errors and schema gaps.
REQUIRED_KEYS = {"intent", "sentiment", "products_mentioned", "urgency", "summary"}
def parse_ticket(text: str) -> dict:
try:
resp = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": text},
],
response_format={"type": "json_object"},
)
data = json.loads(resp.choices[0].message.content)
missing = REQUIRED_KEYS - data.keys()
if missing:
raise ValueError(f"Missing keys: {missing}")
return data
except Exception as exc:
return {"error": str(exc), "raw_input": text[:200]}
# edge case test
print(parse_ticket(""))
Step 5: Batch process tickets and aggregate urgency
Now we process multiple tickets and surface a simple metric for the support queue.
tickets = [
"Love the new design, but the export button is missing on mobile.",
"URGENT: our webhook endpoint is returning 500s since 2am and we are losing orders.",
"Can you add dark mode to the dashboard? Would be a nice touch.",
"I do not understand the invoice from March. Please explain the overage charges.",
]
results = [parse_ticket(t) for t in tickets]
for r in results:
print(r)
critical = sum(1 for r in results if r.get("urgency") == "critical")
print(f"\nTickets needing immediate attention: {critical}")
Run it
Save the complete script as feedback_parser.py and run it from your terminal.
export OXLO_API_KEY="YOUR_OXLO_API_KEY"
python feedback_parser.py
Expected output looks like this:
{'intent': 'feature_request', 'sentiment': 'positive', 'products_mentioned': ['mobile'], 'urgency': 'low', 'summary': 'Customer likes the new design but the export button is missing on mobile.'}
{'intent': 'technical_problem', 'sentiment': 'very_negative', 'products_mentioned': ['webhook endpoint'], 'urgency': 'critical', 'summary': 'Webhook endpoint has been returning 500s since 2am, causing order loss.'}
{'intent': 'feature_request', 'sentiment': 'positive', 'products_mentioned': ['dashboard'], 'urgency': 'low', 'summary': 'Customer requests dark mode for the dashboard.'}
{'intent': 'billing_issue', 'sentiment': 'negative', 'products_mentioned': [], 'urgency': 'medium', 'summary': 'Customer does not understand the overage charges on the March invoice.'}
Tickets needing immediate attention: 1
Wrap-up
You now have a working NLU pipeline that turns raw text into structured ticket data. Two concrete next steps: deploy this as a FastAPI endpoint that ingests webhooks from your support inbox, or swap in kimi-k2.6 on Oxlo.ai for more nuanced reasoning when you start seeing complex multi-issue tickets.
Top comments (0)