Intent Classification for Chatbots

Learn how to use intent classification for chatbots in this hands-on Applied AI engineering lesson.

Focus: use intent classification for chatbots

Sponsored

Your chatbot answers back even when it has no idea what you meant. Users type "I want a refund" and your bot replies with the weather forecast because every unrecognized message falls into the same default branch. This lesson shows you how to use intent classification for chatbots — the core skill that turns a scripted replier into an assistant that routes every user message to the right handler, even when the phrasing is messy or unexpected.

The problem this lesson solves

Rule-based chatbots rely on exact keywords: if the user types refund, respond with refund logic. But real users don't type keywords. They say "I need my money back", "Can you undo that purchase?", or "Where do I get a reimbursement?". Keyword matching fails on synonyms, typos, and grammar variations — and worse, it misfires when a message contains multiple topics.

The result is a poor user experience: frustration, repeated messages, and support tickets for issues that should have been resolved automatically. Manually maintaining a giant list of regex patterns and keyword rules becomes unmanageable as your bot grows.

Pain point: Hardcoded rules don't scale. Every new intent or phrasing requires code changes, and users notice immediately when the bot misunderstands them.

What you need is a system that understands the meaning of a message — not just its literal words — and maps it to a predefined category (an "intent"). That's exactly what intent classification provides.

Core concept / mental model

Think of intent classification as the router of your chatbot. Every incoming message is a package that must be delivered to the right department. The classifier reads the address (the words) and decides which department (intent) gets it.

  • Intent: A category of user goals, e.g., check_balance, open_account, cancel_order.
  • Classifier: A model or algorithm that takes raw text and returns the most likely intent label.
  • Entity extraction (often paired): pulls specific details like account numbers or dates from the message.

A typical conversation flow looks like:

User message → Intent classifier → Intent label → Dialog handler → Bot response

The classifier doesn't need to understand the world; it only needs to separate messages into buckets. A message like "What's my current balance?" and "How much money do I have?" both belong to check_balance, even though the wording differs.

You can build intent classification with:

  • Classical ML: TF-IDF + Logistic Regression or Naive Bayes — fast, small, interpretable.
  • Embedding-based: Sentence transformers (e.g., all-MiniLM-L6-v2) + cosine similarity — handles synonyms well.
  • Large Language Models (LLMs): Few-shot prompting with models like GPT — flexible but slower and costlier.

How it works step by step

The process for building an intent classifier for your bot follows a repeatable pipeline:

  1. Define intents — list the distinct user goals your bot must handle. Start with your most common queries.
  2. Collect training data — gather example phrases for each intent. Aim for 10–30 varied examples per intent.
  3. Preprocess text — lowercase, remove punctuation, optionally lemmatize. Improves signal-to-noise.
  4. Represent text numerically — convert phrases into vectors (TF-IDF or embeddings).
  5. Train a classifier — fit a model on the labeled examples.
  6. Evaluate — test on unseen sentences to measure accuracy.
  7. Integrate — call the classifier in your bot's message handler and route to the right dialog.

For a hands-on default, use a lightweight embedding model and cosine similarity — no training required, just a list of example phrases per intent.

Hands-on walkthrough

Let's build a working intent classifier using sentence embeddings and cosine similarity. This approach is data-efficient and works well for small to medium intents.

Setup

# pip install sentence-transformers scikit-learn
from sentence_transformers import SentenceTransformer
import numpy as np

# Load a small, fast model
model = SentenceTransformer('all-MiniLM-L6-v2')

Define intents and examples

intent_examples = {
    "check_balance": [
        "What's my current balance?",
        "How much money do I have?",
        "Show me my account balance",
    ],
    "open_account": [
        "I want to open a new account",
        "How do I start a savings account?",
        "Create a checking account for me",
    ],
    "cancel_order": [
        "I need to cancel my order",
        "Please undo my recent purchase",
        "How do I get a refund for my order?",
    ],
}

# Encode all examples
intent_embeddings = {}
for intent, phrases in intent_examples.items():
    intent_embeddings[intent] = model.encode(phrases)

Classify a new message

def classify_intent(message, threshold=0.5):
    embedded = model.encode([message])
    best_intent = None
    best_score = -1
    for intent, vectors in intent_embeddings.items():
        scores = np.dot(vectors, embedded.T).flatten()
        score = max(scores)
        if score > best_score:
            best_score = score
            best_intent = intent
    # Normalize to a rough similarity scale (for this model, ~0.4-1.0 range)
    if best_score < threshold:
        return "unknown", best_score
    return best_intent, best_score

Test it:

for msg in ["What's my balance?", "I need my money back!", "Start a new account please"]:
    intent, score = classify_intent(msg)
    print(f"{msg!r} → intent: {intent}, score: {score:.2f}")

Expected output:

"What's my balance?" → intent: check_balance, score: 0.82
"I need my money back!" → intent: cancel_order, score: 0.71
"Start a new account please" → intent: open_account, score: 0.88

Notice how "I need my money back!" correctly routes to cancel_order even though it lacks the word "cancel". That's the power of semantic understanding.

Adding a fallback

A production bot needs a graceful fallback. If the classifier returns unknown, reply with a clarifying question:

responses = {
    "check_balance": "Your balance is $1,250.32.",
    "open_account": "I can help you open an account. What type would you like?",
    "cancel_order": "I'm sorry to hear that. Let me cancel that order for you.",
}

def bot_reply(message):
    intent, score = classify_intent(message)
    if intent == "unknown":
        return "I'm not sure I understood. Could you rephrase?"
    return responses[intent]

Compare options / when to choose what

Approach Pros Cons Best for
Rule-based (regex/keywords) Instant, transparent, zero training Brittle, high maintenance Very small bots with strict input
Classical ML (TF-IDF + classifier) Fast, small, interpretable Needs labeled datasets, poor with synonyms Data-rich, offline, low-latency
Embedding similarity Handles synonyms, no training needed Requires model download, slower than TF-IDF Small-medium intents, rapid prototyping
LLM prompting Extremely flexible, handles complex intents Costly, slow, non-deterministic Customer support with many intents

How to choose:

  • If you have <5 intents and controlled input → rules are fine.
  • If you have 5–20 intents and want quick deployment → embeddings.
  • If you have >50 intents or nuanced requirements → LLM few-shot prompting.
  • If you have a large labeled dataset → train classical ML for speed and cost.

Troubleshooting & edge cases

1. Low accuracy on similar intents

If two intents often get confused (e.g., cancel_order vs return_item), add more distinct examples to each class. Or adjust the similarity threshold.

2. Messages with multiple intents

"I want to check my balance and also open a savings account." — a single-label classifier will pick one. Use a multi-label approach or split the message on conjunctions before classifying.

3. Out-of-scope queries

Users ask about anything. Always have an unknown fallback and a retrieval-augmented generation (RAG) path if you want to answer general questions.

4. Score thresholds

If your threshold is too low, random messages get routed to a wrong intent. If too high, legitimate ones become unknown. Tune on a validation set.

5. Language and typos

Embedding models handle typos but not always slang. For non-English support, switch to a multilingual model like paraphrase-multilingual-MiniLM-L12-v2.

What you learned & what's next

Today you learned:

  • What intent classification is and why it's essential for any real chatbot.
  • How to build and deploy a simple embedding-based classifier in Python.
  • How to compare different approaches and pick the right one for your scale.
  • Common pitfalls like multi-intent messages and out-of-scope queries.

You've now covered the #1 building block of conversational AI. In the next lesson, you'll extend this into full dialogue management — deciding not just what the user wants, but how to respond across multi-turn conversations.

Keep experimenting: add more intents, test with real user messages, and watch your classifier improve.

Practice recap

Open a new Python file and build a mini intent classifier with at least 3 intents (e.g., greet, order_status, complaint). Add 5 example phrases per intent, then test it with several messages, including one that should trigger the unknown fallback. Experiment with the similarity threshold and observe how it changes classification accuracy.

Common mistakes

  • Setting the similarity threshold too high and sending every message to the unknown fallback — tune it on real user data, not gut feeling.
  • Using a single-label classifier on messages with multiple intents, causing one of the intents to be lost — detect multiple intents or split the message first.
  • Forgetting to test with out-of-scope queries; without a fallback, the bot will confidently misroute random questions to an unrelated intent.

Variations

  1. Use classical ML with TF-IDF and a logistic regression classifier — simpler, faster, and more transparent if you have a labeled dataset.
  2. Use LLM few-shot prompting to classify intents via an API call — best for complex or ever-expanding intent sets.
  3. Combine intent classification with named entity recognition to extract parameters like account numbers or dates from the same message.

Real-world use cases

  • Customer support chatbots that route tickets to billing, technical, or sales teams based on user intent.
  • Banking virtual assistants that handle balance checks, fund transfers, and account opening requests contextually.
  • E-commerce shopping bots that distinguish between order status, returns, and product recommendations.

Key takeaways

  • Intent classification maps user messages to predefined categories (intents) — it's the router of your chatbot.
  • Embedding-based similarity classification requires no training data — just 10–30 example phrases per intent.
  • Always include an unknown fallback to handle out-of-scope queries gracefully.
  • Choose your approach based on scale: rules for tiny bots, embeddings for small-medium, LLMs for complex.
  • Filter messages for multiple intents before classification to avoid losing part of the user's request.
  • Tune your similarity threshold on real validation data, not arbitrarily.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.