Advanced

Intent & entity extraction

Turn a messy message into a structured goal plus its details. A model returns JSON instead of a paragraph, and your code can branch on it cleanly.

What you will see

Intents found: refund, cancel_subscription

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

A message is messy until you turn it into structure. I parse a JSON blob into an intent and a value, ask for the one detail that is missing, and read a message that asks for two things at once.

1

The model gives back JSON instead of a paragraph, and I decode it before trusting what it says, printing the intent and the number it carries.

raw = '{"intent": "refund", "amount": 42}' try: out = json.loads(raw) print(out["intent"]) print(out["amount"]) except ValueError: print("Malformed output from the model")

Before you run it, say out loud what it will print. Then open the answer.

What it prints
refund 42
Never trust the model output without parsing it first. Wrap the decode in a try/except so a messy reply breaks instead of slipping into your code.
2

A request may leave out what it needs. I know two fields are required, check which one is missing, and print that I should ask for just that one thing now.

entities = {"intent": "refund", "amount": 42} required = {"amount", "reason"} missing = [k for k in required if k not in entities] print("intent: refund") print("Missing details: " + ", ".join(missing))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
intent: refund Missing details: reason
Do not dump a whole form. Ask for the single missing detail and keep moving.
3

One message can hold more than one goal. I read a list of intents and print each one so I can act on all of them instead of missing half.

model_out = '["refund", "cancel_subscription"]' try: intents = json.loads(model_out) print("Intents found: " + ", ".join(intents)) except ValueError: print("Malformed list from the model")

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Intents found: refund, cancel_subscription
A message can mix several intents. Detect them all and address each, so nothing is left half done.

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

A message is parsed into intent and entities, gaps are filled over turns, then the flow runs.
1 Ask the model for intent + entities
↓
2 Validate and merge into session state
↓
3 Ask for any missing details
↓
4 Run the flow when complete
Why this works
Structured outputs

Modern models can emit JSON via a response_format or function-calling tool. This lets you build reliable flows:

Raw text  ->  {intent, entities}  ->  branch logic

Always validate the JSON before trusting it. A model can forget a field or add extra text. Wrap parsing in a try/catch.

Multi-turn memory

A real agent remembers what came before. Store the extracted state in a dict and update it each turn:

state = session.get("state", {})
state.update(entities)          # fill in new details
session["state"] = state

Turn 1: "refund"      -> {intent: refund}
Turn 2: "for $42"     -> {intent: refund, amount: 42}

State accumulation turns a one-shot parser into a conversation.

Examples

Extracting intent

What does the user want?

out = model.generate(
    "Extract intent from: {msg}",
    response_format="intent, entities"
)
# {"intent": "refund", "amount": 42, "reason": "broke"}

The model returns structured data instead of a paragraph. That makes the next step easy to code.

Why it works: a JSON output is a contract you can branch on.

Filling in the gaps

Missing details need asking

required = {"amount", "reason"}
missing = required - entities.keys()
if missing:
    reply(f"What is your {', '.join(missing)}?")
else:
    process_refund(entities)

If the agent cannot complete the goal, it asks one focused question at a time.

Don't dump a form. Ask what's missing now.

Handling multiple intents

One message can want several things

out = model.generate(
    'Extract all intents from:', message,
    response_format='list'
)
# ['refund', 'cancel_subscription']

Users often combine requests. Detecting every intent lets you address them all instead of missing half.

Why it works: a list of intents maps directly to a list of actions.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Safe auto-reply design
Previous Lesson
Safe auto-reply design
Next Lesson
Tool calling
Tool calling →