LLM routing node
The router is the brain of a stateful agent. Every turn starts here. Instead of writing a pile of keyword checks, we ask the LLM to classify the intent and extract any slots the user mentioned, all in a single call.
What the router sees and writes
The router reads the current state and the user message, then merges intent and slot extractions back into the shared state.
async def intent_router(state: BookingState) -> BookingState:
"""Classify the turn and extract any slots the user mentioned."""
system = (
"You are the router for a flight booking assistant. Classify the user "
"turn and extract any trip slots present. Return strict JSON with keys: "
'{"intent": one of [book, confirm, smalltalk], '
'"origin": 3-letter IATA code or null, '
'"destination": 3-letter IATA code or null, '
'"depart_date": ISO-ish date string or natural phrase or null, '
'"return_date": date or null, '
'"passengers": integer or null, '
'"choice_index": 1-based integer or null}. '
"If they respond to a list of options with a choice, set intent=confirm."
)
prompt = (
f"Current slots: origin={state.get('origin')}, destination={state.get('destination')}, "
f"depart_date={state.get('depart_date')}, return_date={state.get('return_date')}, "
f"passengers={state.get('passengers')}, stage={state.get('stage')}\n"
f"User said: {state.get('user_message', '')}\n"
"Return JSON only."
)
data = await _llm_json(prompt, system)
for key in ("origin", "destination", "depart_date", "return_date", "passengers"):
val = data.get(key)
if val not in (None, "", "null"):
state[key] = val
intent = data.get("intent") or "book"
state["_intent"] = intent
if data.get("choice_index"):
state["_choice_index"] = int(data["choice_index"])
return stateA single prompt doing double duty: intent classification plus slot extraction in one LLM call. Private keys like _intent and _choice_index start with underscore so they stay inside this turn and never leak into the public state snapshot.
Latency and cost. Two calls means twice the round trips, twice the tokens, and twice the chance of disagreement between the two answers. When the user says "book me LHR to JFK next Friday", intent and slots come from the same sentence. Asking the model to produce both in one structured JSON response is faster, cheaper, and more coherent than splitting the job.
Quiz: Quiz
Loading practice…