DEV Community

shashank ms
shashank ms

Posted on

LLM Applications for Natural Language Understanding Tasks

We are going to build a support ticket NLU pipeline that classifies intent and extracts entities from raw customer messages. This gives you a structured feed from unstructured text, which is the first step in any automated support workflow. I run this on Oxlo.ai because the flat per-request pricing stays predictable even when I stuff long ticket threads into the prompt.

What you'll need

Step 1: Configure the Oxlo.ai client

Create a file named nlu_agent.py and initialize the client. Oxlo.ai exposes a fully OpenAI-compatible endpoint, so the only difference is the base URL.

from openai import OpenAI
import json
import os

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

Step 2: Define the NLU system prompt

I treat the system prompt as a strict contract. It tells the model to return only valid JSON with two keys, intent and entities. I keep the entity list open so it generalizes to new products without retraining.

SYSTEM_PROMPT = """You are an NLU engine for customer support. Analyze the user's message and output strictly valid JSON with no markdown formatting.

Required JSON schema:
{
  "intent": "One of: REFUND_REQUEST, TECHNICAL_SUPPORT, BILLING_QUESTION, ACCOUNT_ACCESS, GENERAL_INQUIRY, ESCALATE",
  "entities": {
    "product_name": "string or null",
    "order_id": "string or null",
    "email": "string or null",
    "urgency": "One of: LOW, MEDIUM, HIGH, CRITICAL"
  },
  "reasoning": "Brief 10-word explanation of why this intent was chosen."
}

Rules:
- intent must be exactly one of the listed enums.
- If a value is missing, use null, do not guess.
- urgency is CRITICAL if the user mentions 'down', 'broken', or 'cannot access' and seems blocked.
"""

Step 3: Build the extraction function with JSON mode

I wrap the chat completion in a small function that enforces JSON mode. Oxlo.ai supports this on llama-3.3-70b and other models, so I get parsable output without fragile regex.

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

Step 4: Add the batch processor

Most support queues do not arrive one at a time. I add a small batch runner that processes a list of messages and prints line-delimited JSON. This is the piece I actually ship into my ingestion worker.

def process_batch(messages: list[str]) -> list[dict]:
    results = []
    for msg in messages:
        try:
            parsed = extract_nlu(msg)
            results.append(parsed)
        except Exception as e:
            results.append({"error": str(e), "raw_message": msg})
    return results

if __name__ == "__main__":
    tickets = [
        "My Acme Pro subscription renewed twice this month. Order #ORD-9981. Please refund the duplicate charge.",
        "The dashboard is completely down and I cannot pull reports. This is blocking our quarterly review.",
        "How do I add a new team member to my workspace?",
    ]

    parsed = process_batch(tickets)
    for item in parsed:
        print(json.dumps(item, indent=2))

Run it

Export your key and execute the script. I use Oxlo.ai here because long ticket threads do not inflate the cost, each API call is one flat request regardless of how much prior context I include.

export OXLO_API_KEY="sk-oxlo.ai-..."
python nlu_agent.py

Example output:

{
  "intent": "BILLING_QUESTION",
  "entities": {
    "product_name": "Acme Pro",
    "order_id": "ORD-9981",
    "email": null,
    "urgency": "MEDIUM"
  },
  "reasoning": "User requests refund for duplicate charge."
}
{
  "intent": "TECHNICAL_SUPPORT",
  "entities": {
    "product_name": null,
    "order_id": null,
    "email": null,
    "urgency": "CRITICAL"
  },
  "reasoning": "Dashboard is down and blocking quarterly review."
}
{
  "intent": "GENERAL_INQUIRY",
  "entities": {
    "product_name": null,
    "order_id": null,
    "email": null,
    "urgency": "LOW"
  },
  "reasoning": "User asks how to add team member."
}

Wrap-up

Next, wire this NLU function into your actual support queue via a webhook or message broker like RabbitMQ. If you need to process thousands of tickets daily, switch to Oxlo.ai's request-based plans so your bill stays predictable even when user messages grow into long threads. See https://oxlo.ai/pricing for plan details.

Top comments (0)