Dev.to AI πŸ€– Ai πŸ‘ 0 πŸ“– 4 min read

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.

πŸ“° Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.