DEV Community

shashank ms
shashank ms

Posted on

Using LLM for Intent Recognition

Every support team receives messages that range from refund requests to password resets. We are going to build a lightweight intent recognition pipeline that reads incoming tickets, classifies them into predefined categories, and routes them to the right internal queue. It runs entirely on Oxlo.ai, and because the platform uses flat request-based pricing, the cost stays predictable even when tickets arrive as long threads.

What you'll need

Step 1: Define the intent schema

I start by locking down the category list. Giving the model a closed vocabulary prevents it from inventing labels. I also define the JSON shape we expect back.

import json
from enum import Enum

class Intent(str, Enum):
    BILLING = "billing"
    TECHNICAL = "technical_support"
    ACCOUNT = "account_management"
    SALES = "sales_inquiry"
    SPAM = "spam"

# Expected JSON shape for reference
SCHEMA = {
    "intent": "string, one of the allowed values",
    "confidence": "integer 1-10",
    "reasoning": "string, one sentence"
}

Step 2: Write the system prompt

The system prompt is the contract. It describes the allowed intents, the JSON schema, and the strict output format. I keep it in its own variable so it is easy to iterate without touching the rest of the code.

SYSTEM_PROMPT = """
You are an intent classification engine for a customer support system.
Analyze the user's message and respond with a single JSON object.
Do not write markdown, explanations, or text outside the JSON.

Allowed intents:
- billing: refunds, duplicate charges, invoices, payment failures
- technical_support: bugs, errors, API issues, integrations
- account_management: password resets, login trouble, plan changes, deletions
- sales_inquiry: demo requests, pricing questions, enterprise deals
- spam: irrelevant or promotional content

Your JSON must match this schema:
{
  "intent": "",
  "confidence": ,
  "reasoning": ""
}
"""

Step 3: Build the classifier

Now I wire the prompt to Oxlo.ai. I use the OpenAI-compatible client, point it at https://api.oxlo.ai/v1, and enable JSON mode so the model returns valid objects. I set the temperature low because classification should be deterministic.

import json
from enum import Enum
from openai import OpenAI

class Intent(str, Enum):
    BILLING = "billing"
    TECHNICAL = "technical_support"
    ACCOUNT = "account_management"
    SALES = "sales_inquiry"
    SPAM = "spam"

SYSTEM_PROMPT = """
You are an intent classification engine for a customer support system.
Analyze the user's message and respond with a single JSON object.
Do not write markdown, explanations, or text outside the JSON.

Allowed intents:
- billing: refunds, duplicate charges, invoices, payment failures
- technical_support: bugs, errors, API issues, integrations
- account_management: password resets, login trouble, plan changes, deletions
- sales_inquiry: demo requests, pricing questions, enterprise deals
- spam: irrelevant or promotional content

Your JSON must match this schema:
{
  "intent": "",
  "confidence": ,
  "reasoning": ""
}
"""

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

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

Step 4: Add routing and fallback logic

Classification is only useful if we act on it. I add a router that sends high-confidence results to a specific queue and flags low-confidence results for a human reviewer.

import json
from enum import Enum
from openai import OpenAI

class Intent(str, Enum):
    BILLING = "billing"
    TECHNICAL = "technical_support"
    ACCOUNT = "account_management"
    SALES = "sales_inquiry"
    SPAM = "spam"

SYSTEM_PROMPT = """
You are an intent classification engine for a customer support system.
Analyze the user's message and respond with a single JSON object.
Do not write markdown, explanations, or text outside the JSON.

Allowed intents:
- billing: refunds, duplicate charges, invoices, payment failures
- technical_support: bugs, errors, API issues, integrations
- account_management: password resets, login trouble, plan changes, deletions
- sales_inquiry: demo requests, pricing questions, enterprise deals
- spam: irrelevant or promotional content

Your JSON must match this schema:
{
  "intent": "",
  "confidence": ,
  "reasoning": ""
}
"""

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

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

def route_ticket(ticket_id: str, text: str) -> dict:
    result = classify_ticket(text)
    intent = result.get("intent", "unknown")
    confidence = result.get("confidence", 0)

    if confidence < 7:
        queue = "human_review"
    else:
        queue = intent

    return {
        "ticket_id": ticket_id,
        "text": text,
        "intent": intent,
        "confidence": confidence,
        "queue": queue,
        "reasoning": result.get("reasoning", ""),
    }

Step 5: Process a batch of tickets

Here is the complete script with a small batch of realistic tickets. Running this end to end confirms the pipeline handles diverse wording without extra prompt engineering.

import json
from enum import Enum
from openai import OpenAI

class Intent(str, Enum):
    BILLING = "billing"
    TECHNICAL = "technical_support"
    ACCOUNT = "account_management"
    SALES = "sales_inquiry"
    SPAM = "spam"

SYSTEM_PROMPT = """
You are an intent classification engine for a customer support system.
Analyze the user's message and respond with a single JSON object.
Do not write markdown, explanations, or text outside the JSON.

Allowed intents:
- billing: refunds, duplicate charges, invoices, payment failures
- technical_support: bugs, errors, API issues, integrations
- account_management: password resets, login trouble, plan changes, deletions
- sales_inquiry: demo requests, pricing questions, enterprise deals
- spam: irrelevant or promotional content

Your JSON must match this schema:
{
  "intent": "",
  "confidence": ,
  "reasoning": ""
}
"""

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

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

def route_ticket(ticket_id: str, text: str) -> dict:
    result = classify_ticket(text)
    intent = result.get("intent", "unknown")
    confidence = result.get("confidence", 0)

    if confidence < 7:
        queue = "human_review"
    else:
        queue = intent

    return {
        "ticket_id": ticket_id,
        "text": text,
        "intent": intent,
        "confidence": confidence,
        "queue": queue,
        "reasoning": result.get("reasoning", ""),
    }

if __name__ == "__main__":
    tickets = [
        ("T-1001", "I was charged twice for my Pro plan this month. Please refund the extra payment."),
        ("T-1002", "How do I reset my password? I can't log in."),
        ("T-1003", "We are a 500 person fintech team and need an enterprise quote."),
        ("T-1004", "Your API returns a 500 error when I call /v1/batch with more than 100 items."),
        ("T-1005", "Win a free iPhone now!!! Click here!!!"),
    ]

    for tid, txt in tickets:
        out = route_ticket(tid, txt)
        print(json.dumps(out, indent=2))

Run it

Save the final block as intent_router.py, replace YOUR_OXLO_API_KEY with your key from the Oxlo.ai portal, and run the file.

python intent_router.py

You should see output similar to this:

{
  "ticket_id": "T-1001",
  "text": "I was charged twice for my Pro plan this month. Please refund the extra payment.",
  "intent": "billing",
  "confidence": 10,
  "queue": "billing",
  "reasoning": "The user explicitly mentions a duplicate charge and requests a refund."
}
{
  "ticket_id": "T-1002",
  "text": "How do I reset my password? I can't log in.",
  "intent": "account_management",
  "confidence": 10,
  "queue": "account_management",
  "reasoning": "The user is asking about password reset and login issues."
}
{
  "ticket_id": "T-1003",
  "text": "We are a 500 person fintech team and need an enterprise quote.",
  "intent": "sales_inquiry",
  "confidence": 9,
  "queue": "sales_inquiry",
  "reasoning": "The user is requesting pricing information for an enterprise team."
}
{
  "ticket_id": "T-1004",
  "text": "Your API returns a 500 error when I call /v1/batch with more than 100 items.",
  "intent": "technical_support",
  "confidence": 10,
  "queue": "technical_support",
  "reasoning": "The user reports an API error and a specific endpoint failure."
}
{
  "ticket_id": "T-1005",
  "text": "Win a free iPhone now!!! Click here!!!",
  "intent": "spam",
  "confidence": 10,
  "queue": "spam",
  "reasoning": "The message is promotional and irrelevant to support."
}

Next steps

To productionize this, connect the router to your ticketing webhook so new messages are classified as they arrive. You can also swap in qwen-3-32b or kimi-k2.6 on Oxlo.ai if you need stronger multilingual or reasoning performance without changing any client code.

Top comments (0)