Skip to main content
A LiveKit voice agent for airline customer service that showcases ambient retrieval: instead of giving the LLM a search_booking tool to call, a Moss query fires automatically on every user turn via on_user_turn_completed, injecting the results as a system message before the LLM is ever invoked. One LLM round-trip per turn instead of two.
Full example — see the Airline PNR cookbook for the complete agent, three sample PNR fixtures, index builder, and eval suite.

Tool-driven vs ambient retrieval

Airline customer service is overwhelmingly read-heavy — almost every caller turn needs the booking data. With ambient retrieval, Moss quietly pre-fetches that context before the LLM sees the question. The LLM always has the right data and never has to decide whether to fetch it.
The round-trip counts above are LLM tool-call round-trips and assume LiveKit preemptive generation is off. It is on by default, so this ambient pattern turns it off in the AgentSession below (turn_handling=TurnHandlingOptions(preemptive_generation={"enabled": False})); otherwise the speculative draft is discarded and regenerated on every injected turn. See Retrieval and preemptive generation.

Privacy gate

Ambient retrieval is gated on identity verification. Until verify_caller succeeds, on_user_turn_completed passes through without querying Moss — no booking details reach the LLM before the caller’s identity is confirmed.

What this demonstrates

Required tools

Integration guide

1

Installation

2

Environment setup

.env
3

Define session state

4

Implement ambient retrieval

Override on_user_turn_completed to run a Moss query before the LLM is invoked. The retrieved context is injected as a system message in the chat context. The LLM sees it as part of the conversation — no tool call, no extra round-trip.
5

Add lifecycle and write tools

The split is clean: ambient = reads, tools = writes. load_booking and verify_caller are the only tools that affect retrieval behaviour.
6

Wire up the entrypoint

Run in console mode to test locally:

Per-user indexes

Each booking gets its own Moss index (booking-xkq4p2, booking-wj7bnh, etc.). load_booking switches the active index mid-call, which means one agent can handle a caller asking about multiple bookings in the same session — just call load_booking again with the new PNR and re-verify. The BOOKING_PNR env var lets an IVR system preload the index before the agent’s first turn, so the caller’s very first question is already grounded.