Ask one question at a time

Dumping every missing field on the user at once is how you turn an agent into an interrogation. Instead, we split collection into small, focused nodes that each ask for one thing. The graph routes to whichever slot is missing, and the router picks up the answer on the next turn.

Slot-collection routing

Each missing slot routes to its own focused node. The next turn comes back to the router.

booking_graph.py
python
async def collect_origin(state: BookingState) -> BookingState:
    pairs = list_route_pairs()
    origins = sorted({p["origin"] for p in pairs})
    state["assistant_reply"] = (
        "Sure, I can help you book a flight. Which city are you flying from? "
        f"We currently serve: {', '.join(origins)}."
    )
    state["stage"] = "collecting"
    return state


async def collect_destination(state: BookingState) -> BookingState:
    origin = state.get("origin") or "your origin"
    pairs = list_route_pairs()
    dests = sorted({p["destination"] for p in pairs if p["origin"] == state.get("origin")})
    hint = f" Available from {origin}: {', '.join(dests)}." if dests else ""
    state["assistant_reply"] = (
        f"Great - flying from {origin}. Where are you headed?{hint}"
    )
    state["stage"] = "collecting"
    return state


async def collect_dates(state: BookingState) -> BookingState:
    origin = state.get("origin")
    dest = state.get("destination")
    state["assistant_reply"] = (
        f"Got it: {origin} to {dest}. What depart date works for you, "
        "and how many passengers? A return date is optional."
    )
    state["stage"] = "collecting"
    return state

Each collector is small and focused: read what you know, write a reply asking for what you do not know, set stage to "collecting". The router pulls the answer out on the next turn and deposits it back into state.

Matching exercise: Match each collector to what it asks for

Loading practice…

Quiz: Quiz

Loading practice…