We are going to build a support ticket triage agent that reads raw customer messages and returns structured NLP output: sentiment, product mentions, urgency, and a one-line summary. If your team wastes hours manually categorizing inbound text, this turns an LLM into a drop-in classifier and extractor.
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: Connect to Oxlo.ai
I start by initializing the OpenAI SDK against Oxlo.ai and making a smoke test. I pick llama-3.3-70b because it follows instructions reliably for structured tasks.
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": "Reply with exactly the word: pong"},
],
)
print(response.choices[0].message.content)
Step 2: Write the system prompt
The system prompt is the contract. It tells the model to act as a JSON-only parser and sets the schema for sentiment, entities, urgency, and summary. I keep it strict so downstream code does not need fuzzy parsing.
SYSTEM_PROMPT = """You are a support ticket NLP engine. Analyze the user message and respond with a single JSON object. Do not include markdown fences, explanations, or greetings.
Required schema:
- sentiment: string, one of [angry, frustrated, neutral, satisfied]
- product: string, the product mentioned or "unknown"
- urgency: string, one of [low, medium, high, critical]
- summary: string, max 12 words describing the core issue
- entities: list of objects with keys "text" and "type" (person, company, feature)
Rules:
- If no product is mentioned, use "unknown".
- Urgency is critical if words like "down", "broken", "outage", "security" appear.
- Output must be valid, minified JSON.
"""
Step 3: Build the analysis function
Now I wrap the API call in a function that takes raw ticket text and returns a Python dict. I set temperature low to keep output deterministic.
import json
def analyze_ticket(ticket_text: str) -> dict:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": ticket_text},
],
temperature=0.1,
max_tokens=256
)
raw = response.choices[0].message.content.strip()
if raw.startswith("
```"):
raw = raw.split("```
")[1].replace("json", "").strip()
return json.loads(raw)
Step 4: Process tickets in batch
In production, tickets arrive as a list. I process them sequentially here. Oxlo.ai has no cold starts on popular models, so the loop runs without lag.
tickets = [
"Our API integration with your platform stopped responding this morning. We are losing transactions. Please escalate immediately. - Sarah, AcmeCorp",
"Can you add dark mode to the dashboard? It would be nice to have.",
"Invoice #9922 is wrong. We were charged for 3 seats but only have 2. Not urgent, just fix before next billing cycle.",
"SECURITY: we noticed an exposed token in your public docs. Rotate it now."
]
results = []
for t in tickets:
try:
parsed = analyze_ticket(t)
results.append(parsed)
print(f"Processed: {parsed['summary']}")
except Exception as e:
results.append({"error": str(e), "raw": t})
print(f"Failed to parse ticket: {e}")
print(f"\nSuccessfully analyzed {len([r for r in results if 'error' not in r])} of {len(tickets)} tickets.")
Step 5: Handle multilingual input
If your queue contains non-English text, Oxlo.ai hosts qwen-3-32b, which handles multilingual reasoning well. You can swap the model string without changing any other code because the API is fully OpenAI compatible.
def analyze_ticket_multilingual(ticket_text: str) -> dict:
response = client.chat.completions.create(
model="qwen-3-32b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": ticket_text},
],
temperature=0.1,
max_tokens=256
)
raw = response.choices[0].message.content.strip()
return json.loads(raw)
Run it
Save the full script below as ticket_triage.py, replace YOUR_OXLO_API_KEY, and run python ticket_triage.py.
from openai import OpenAI
import json
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
SYSTEM_PROMPT = """You are a support ticket NLP engine. Analyze the user message and respond with a single JSON object. Do not include markdown fences, explanations, or greetings.
Required schema:
- sentiment: string, one of [angry, frustrated, neutral, satisfied]
- product: string, the product mentioned or "unknown"
- urgency: string, one of [low, medium, high, critical]
- summary: string, max 12 words describing the core issue
- entities: list of objects with keys "text" and "type" (person, company, feature)
Rules:
- If no product is mentioned, use "unknown".
- Urgency is critical if words like "down", "broken", "outage", "security" appear.
- Output must be valid, minified JSON.
"""
def analyze_ticket(ticket_text: str, model: str = "llama-3.3-70b") -> dict:
response = client.chat.completions.create(
model=model,
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": ticket_text},
],
temperature=0.1,
max_tokens=256
)
raw = response.choices[0].message.content.strip()
if raw.startswith("
```"):
raw = raw.split("```
")[1].replace("json", "").strip()
return json.loads(raw)
if __name__ == "__main__":
tickets = [
"Our API integration with your platform stopped responding this morning. We are losing transactions. Please escalate immediately. - Sarah, AcmeCorp",
"Can you add dark mode to the dashboard? It would be nice to have.",
"Invoice #9922 is wrong. We were charged for 3 seats but only have 2. Not urgent, just fix before next billing cycle.",
"SECURITY: we noticed an exposed token in your public docs. Rotate it now."
]
for t in tickets:
try:
out = analyze_ticket(t)
print(json.dumps(out, indent=2))
except Exception as e:
print(f"Error: {e}")
Example output:
{"sentiment": "angry", "product": "API integration", "urgency": "critical", "summary": "API integration down, losing transactions", "entities": [{"text": "Sarah", "type": "person"}, {"text": "AcmeCorp", "type": "company"}]}
{"sentiment": "neutral", "product": "dashboard", "urgency": "low", "summary": "Request for dark mode on dashboard", "entities": [{"text": "dark mode", "type": "feature"}]}
{"sentiment": "frustrated", "product": "unknown", "urgency": "medium", "summary": "Incorrect invoice for seat count", "entities": [{"text": "Invoice #9922", "type": "feature"}]}
{"sentiment": "frustrated", "product": "unknown", "urgency": "critical", "summary": "Exposed security token in public docs", "entities": [{"text": "token", "type": "feature"}]}
Wrap up
Two concrete next steps. First, wire this function into a webhook so new tickets are scored as they arrive in your CRM. Second, if your volume grows, compare Oxlo.ai request-based pricing against your current token-based bill. For long tickets, the flat per-request cost often drops the price significantly. You can check the latest rates at https://oxlo.ai/pricing.
Top comments (0)