LLMs for Natural Language Understanding Tasks
We are going to build a support ticket NLU router that classifies intent, extracts entities, and assigns tickets to the right team. This is useful for any company that wants to automate triage without paying per-token fe
We are going to build a support ticket NLU router that classifies intent, extracts entities, and assigns tickets to the right team. This is useful for any company that wants to automate triage without paying per-token fees on high-volume support queues. The finished script runs against Oxlo.ai's flat per-request API.
What you'll need
- Python 3.10 or newer
- An Oxlo.ai API key from https://portal.oxlo.ai
- The OpenAI SDK and Pydantic:
pip install openai pydantic
Step 1: Define the extraction schema
I use Pydantic so the model output has a rigid shape we can validate downstream. The schema captures intent, entities, sentiment, urgency, and routing.
from pydantic import BaseModel, Field
from typing import Optional, Literal
class TicketExtraction(BaseModel):
intent: Literal[
"refund_request",
"technical_issue",
"billing_question",
"product_inquiry",
"other"
] = Field(description="Primary reason for the ticket")
order_id: Optional[str] = Field(description="Order or transaction identifier if present")
product: Optional[str] = Field(description="Product or service mentioned")
sentiment: Literal["negative", "neutral", "positive"] = Field(description="Customer tone")
urgency: Literal["low", "medium", "high"] = Field(description="Estimated urgency")
assigned_team: Literal["Support", "Billing", "Logistics", "Sales"] = Field(
description="Team that should handle this ticket"
)
Step 2: Write the system prompt
The prompt needs to be explicit about the JSON structure and the allowed enum values. I keep it plain and avoid chain-of-thought so the model returns only the JSON object.
SYSTEM_PROMPT = """You are an NLU engine for support ticket triage.
Analyze the user's message and extract the following fields:
- intent: one of [refund_request, technical_issue, billing_question, product_inquiry, other]
- order_id: any order/transaction ID found, or null
- product: product or service name, or null
- sentiment: one of [negative, neutral, positive]
- urgency: one of [low, medium, high]
- assigned_team: one of [Support, Billing, Logistics, Sales]
Rules:
- Return ONLY a JSON object matching the schema.
- Do not include markdown code fences or explanations.
- If the message is vague, assign intent "other" and urgency "low"."""
Step 3: Set up the Oxlo.ai client
Oxlo.ai exposes an OpenAI-compatible endpoint, so the import and initialization are identical to the standard SDK. I point the base URL at Oxlo.ai and load the key from the environment.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.oxlo.ai/v1",
api_key=os.getenv("OXLO_API_KEY", "YOUR_OXLO_API_KEY"),
)
Step 4: Build the extraction function
This helper sends the ticket text to llama-3.3-70b on Oxlo.ai and parses the JSON response into our Pydantic model. I set response_format to JSON mode so the model stays in bounds.
import json
def extract_ticket(ticket_text: str) -> TicketExtraction:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": ticket_text},
],
response_format={"type": "json_object"},
temperature=0.1,
)
raw = response.choices[0].message.content
data = json.loads(raw)
return TicketExtraction.model_validate(data)
Step 5: Batch and route
To make this useful, I loop over a list of incoming tickets, extract structured data for each, and print a routing summary. Because Oxlo.ai charges per request instead of per token, long tickets with attached transcripts do not inflate the cost.
tickets = [
"I was charged twice for my Pro Plan subscription on order #ORD-9981. Please fix this immediately.",
"My smart thermostat keeps disconnecting from Wi-Fi every night. I bought it last month.",
"Can I get a refund for order #ORD-4420? The headphones arrived damaged and I need the money back fast.",
"Just checking if you ship to New Zealand.",
]
for text in tickets:
try:
result = extract_ticket(text)
print(f"Ticket: {text[:50]}...")
print(f" Intent: {result.intent}")
print(f" Team: {result.assigned_team}")
print(f" Order: {result.order_id}")
print(f" Urgency: {result.urgency}")
print()
except Exception as e:
print(f"Failed on ticket: {text[:50]}... Error: {e}")
Run it
Export your key and run the script:
export OXLO_API_KEY="sk-oxlo.ai-..."
python ticket_router.py
Example output:
Ticket: I was charged twice for my Pro Plan subscription on...
Intent: billing_question
Team: Billing
Order: ORD-9981
Urgency: high
Ticket: My smart thermostat keeps disconnecting from Wi-Fi ev...
Intent: technical_issue
Team: Support
Order: None
Urgency: medium
Ticket: Can I get a refund for order #ORD-4420? The headphones...
Intent: refund_request
Team: Logistics
Order: ORD-4420
Urgency: high
Ticket: Just checking if you ship to New Zealand....
Intent: product_inquiry
Team: Sales
Order: None
Urgency: low
Wrap-up
You now have a working NLU router that turns unstructured support messages into structured triage data. Two concrete next steps: wire the assigned_team output into your CRM or helpdesk API to auto-assign tickets, or swap llama-3.3-70b for kimi-k2.6 on Oxlo.ai if you need stronger reasoning on ambiguous multi-turn threads. See https://oxlo.ai/pricing for request-based pricing details.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.