01What is entity extraction?
Entity extraction — also called named entity recognition (NER) or slot extraction — is the step in a chatbot's natural language understanding that finds the specific values inside a customer's message and returns them as structured data. In "Where is order ORD-48213? I'm at 560034 now", the intent is tracking an order; the entities are an order ID (ORD-48213) and a PIN code (560034).
Each entity has a type and a canonical value. System entities cover common shapes — dates, times, numbers, amounts, phone numbers, email addresses — while custom entities cover your own vocabulary: product SKUs, branch names and plan names, each with synonyms ("gold", "gold plan", "premium yearly"). A good extractor returns the original span, the resolved value and a confidence, so "kal shaam 6 baje" becomes {"type": "datetime", "value": "2026-10-20T18:00:00+05:30"} rather than a string the next system has to guess at.
Slot filling is how a bot uses entities across several turns. A task such as rescheduling a delivery declares the slots it needs — order ID, new date, time window — and the bot asks only for the ones the customer has not given yet, keeping collected values in its conversation state. Entity extraction is the detail layer beneath intent recognition: the intent picks the task, the entities complete it. With a large language model, extraction is usually done by asking for structured output against a JSON schema and then validating every value in code.
Key takeaways
- Entity extraction turns free text into typed values — an order ID, a date, a PIN code — that a bot can pass to an API.
- Intent says what the customer wants; entities say which order, which date and which address.
- Slot filling asks only for the entities still missing, one question at a time, until the task can run.
- Every extracted value needs normalising and validating: "kal", "5/6" and "98765 43210" are not yet usable data.
02 · How it works, step by step
How does entity extraction work?
- Step 1
Declare the slots each task needs
List them per intent with type, format and whether they are required:
order_id(ORD-plus five digits),pincode(six digits, never starting with 0),delivery_date(a future working day). Write down synonyms for every custom entity. - Step 2
Detect candidate spans
Use rules for rigid formats (regular expressions for order IDs, PIN codes, IFSC codes), a date and number parser for system entities, and an NER model or LLM for open types such as names, addresses and products described in ordinary words. Button, list and Flow replies already arrive structured, so skip extraction for them.
- Step 3
Normalise to a canonical value
Convert each span to the form your API expects: dates to ISO 8601 in the customer's time zone (
+05:30for IST), phone numbers to E.164, amounts to integer paise, plan names to internal IDs. - Step 4
Validate against business rules
Check that the value exists and makes sense: the order belongs to this sender's
wa_id, the date is in the future, the PIN code is serviceable. A well-formed but wrong value should be treated as missing. - Step 5
Fill slots and ask for what is missing
Store confirmed values in conversation state and ask one targeted question for the next missing slot — with reply buttons or a list where the options are finite. Read high-impact values back ("Reschedule ORD-48213 to Tue 20 Oct?") before acting.
03Entity extraction in code
// Slots the reschedule_delivery intent needsconst SLOTS = {order_id: { required: true, ask: "Which order? The ID looks like ORD-12345." },delivery_date: { required: true, ask: "Which day should we deliver?" },window: { required: true, ask: "Pick a delivery window:" },pincode: { required: false, ask: "What is the 6-digit PIN code of the new address?" },};const PINCODE = /\b([1-9]\d{5})\b/; // 6 digits, first digit 1-9const ORDER_ID = /\b(?:ORD[-\s]?)?(\d{5})\b/i; // "ORD-48213", "ord 48213", "48213"export function extract(text) {const found = {};const pin = text.match(PINCODE);if (pin) found.pincode = { value: pin[1], span: pin[0] };const rest = pin ? text.replace(pin[0], " ") : text; // don't read the PIN as an orderconst order = rest.match(ORDER_ID);if (order) found.order_id = { value: "ORD-" + order[1], span: order[0] };return found; // dates go through a date parser resolved in Asia/Kolkata}export function nextQuestion(state) {for (const [name, slot] of Object.entries(SLOTS)) {if (slot.required && !state.slots[name]) return { slot: name, text: slot.ask };}return null; // every required slot is filled: read it back, then act}
Rules for rigid formats, then ask only for what is still missing.
04Example: One message, three entities, one tap
A customer of a Hyderabad home-appliance retailer writes: "my washing machine order 48213 can u deliver kal evening instead, new address pin 500081". Intent recognition picks reschedule_delivery. Entity extraction returns the order number, normalised to ORD-48213 and matched to the sender's wa_id; the span "kal evening", resolved to the evening of Tuesday 20 October 2026 because "kal" — which means both yesterday and tomorrow in Hindi — sits in a future-tense request; and PIN code 500081, which the logistics API confirms it serves. One required slot is still empty, the delivery window, so the bot sends three reply buttons ("4–6 pm", "6–8 pm", "8–10 pm") instead of asking for free text, receives a structured answer, reads the full change back in one message and calls the courier API. The customer typed one message and tapped once; no agent was involved.
05Entity extraction: key facts and limits
- Indian PIN code
- 6 digits, first digit 1–9
- Indian mobile
- 10 digits starting 6–9; E.164 is +91 followed by them
- Date normal form
- ISO 8601 with +05:30 for IST
- Reply buttons
- Up to 3 per message, titles up to 20 characters
- List message
- Up to 10 rows, row titles up to 24 characters
- Text message body
- Up to 4,096 characters to scan
06 · Common mistakes, and the fix
Common mistakes with entity extraction
Trusting a well-formed value
An order ID that matches the pattern may not exist or may belong to someone else. Look it up and check it is linked to the sender's
wa_idbefore revealing anything about it.Resolving dates without a time zone or tense
"Kal" means both yesterday and tomorrow, and "5/6" is 5 June in India but May 6 to a US-trained parser. Resolve relative dates against the message timestamp in IST, use the verb tense, and confirm when it is still ambiguous.
Asking for finite slots in free text
"Please type your preferred time" invites "evening-ish". When the options are known, send reply buttons or a list so the answer arrives already structured.
Letting an LLM fill the gaps
Asked to return every field, a model may invent a plausible PIN code. Allow
null, validate patterns in code, and never act on a value the customer did not actually provide.Overwriting a confirmed slot
A later "my other order is 51190" can silently replace the slot you were working on. Track which turn filled each slot and ask before switching to a different order.
07Why does entity extraction matter?
Most customer messages already contain the data needed to answer them — the order number, the date, the city — buried in everyday language. Extracting it removes a round of questions per conversation, lets the bot call your order, booking or CRM API straight away and keeps long forms out of the chat. Done badly, it is also where bots fail silently: a misread date reschedules the wrong delivery and a truncated phone number creates a duplicate lead. Precision on entities is what makes automation trustworthy enough to act on its own.
08 · Tips from the bench
Best practices for entity extraction
- Prefer structured inputs — buttons, lists, WhatsApp Flows — for anything with a fixed set of answers; keep extraction for what people naturally type.
- Log the span, resolved value and confidence for every entity so misreads can be audited.
- Build test sets from masked real messages in Hinglish and regional scripts; English-only tests overstate accuracy.
- Read key values back before any irreversible action such as a cancellation or address change.