This chapter urges developers to make voice interactions feel like human conversations by honoring conversational norms and context. It revisits Grice’s Maxims (quality, quantity, relation, manner) and emphasizes that successful dialog also depends on shared, often unspoken context—who’s speaking, what was said before, and what the exchange is “about.” To move beyond stiff, linear exchanges, the chapter advocates frame-based flows over graph-based ones, letting users jump among tasks without rigid sequences. Through a simple “Name Info” example, it shows how remembering the last subject lets users use pronouns and ellipsis (e.g., “How do you spell it?”) and suggests pragmatic heuristics like resolving ambiguous references to the most recently discussed entity.
Practically, the chapter demonstrates how to capture and reuse context across intents by persisting the user’s last-mentioned item (e.g., first name) and supporting both explicit and shorthand utterances. It cautions about slot-only samples (which can misroute single-word inputs) and recommends designing for shortcuts while keeping a clear default path. It then expands context into time and preference: use decaying context with timestamps to decide when to confirm or forget prior assumptions, and learn user favorites over time by tracking request history and applying thresholds before assuming “the usual.” At response time, state assumptions when ambiguity might surprise users. Overall, prioritize explicit requests first, then recent context, then learned favorites, to streamline follow-ups while keeping users oriented.
To keep implementations clean and reliable, the chapter introduces request and response interceptors as cross-cutting hooks: response interceptors centralize saving persistent attributes just before replies are sent, and request interceptors preload persistent data and place it into per-request attributes for handlers to use. This reduces duplication, enforces consistency, and helps manage latency by avoiding unnecessary work on every turn. Finally, it advocates unit testing with Bespoken’s “virtual Alexa,” using concise YAML scripts to emulate conversations and assert prompts and reprompts—useful for catching issues (like missing reprompts) early. Together, context handling, smart defaults, interceptors, and focused tests form a set of VUI best practices that lower user effort and raise skill robustness.
Figure 6.1. Graph versus frame interactions
Figure 6.2. Flow of data inside the Name Info skill flow for the SpellingIntent.
Figure 6.3. Flow of data inside the Name Info skill flow for the SpellingIntent, with request and response interceptors.
Summary
Remembering context to ease the conversation makes users comfortable by coming to them and not forcing them to be explicit with every reply.
Context can be enhanced by decaying it over time so that the recent subject is assumed to be the subject of conversation for a limited amount of time.
Some skills benefit from using favorites, either explicitly provided by the user, or assumed over time to allow the user to invoke intents more implicitly.
Data must enter and exit the fulfillment, and interceptors can capture it at each point to centralize common actions.
Unit tests, using tools such as Bespoken, mimic conversations and ensure the conversation goes as we expect.
FAQ
What does “context” mean in a voice UI and why is it important?Context is the unspoken information a conversation relies on (the last thing discussed, who/what “it” refers to, recent requests, user preferences). Using context lets people speak naturally—shorter, more fluid follow-ups—while your skill fills in missing pieces, reducing friction and clarifications.How do frame-based interactions differ from graph-based flows in voice apps?Graph-based flows push users through fixed steps. Frame-based flows group tasks into independent “frames” and let users jump between them in any order. Voice experiences work better as frame-based: support shortcuts, accept inputs out of sequence, and handle follow-ups seamlessly.How can my skill handle pronouns like “it” without heavy AI?Use simple heuristics and stored state. Save the most recently discussed entity (for example, the last name) and assume pronouns refer to it unless the user provides a new one. Persist it between turns, and reset or confirm when the context might be stale.Should I allow slot‑only utterances (e.g., just saying a first name)?Yes—optimize for user ease. But protect against misclassification. If you allow slot‑only samples, also add explicit samples for common one‑word requests (like “spelling”) so they won’t be mistakenly treated as slot values.What is “decaying context” and how do I decide when to forget it?Decaying context means previously set context expires after a sensible period. Store the last referenced item plus a timestamp; on new requests without explicit parameters, reuse it only if it’s “recent enough.” Pick thresholds that feel natural for your domain (minutes for buses, longer for sports), and consider dynamic decay when possible (e.g., until the next bus arrives).How can I learn and apply a user’s favorites safely?Track what users ask for and count occurrences. Promote an item to “favorite” only after a minimum count (and optionally a share of requests). Use favorites as a fallback after explicit or recent context. Let users set favorites directly and tell them when “the usual” will be assumed to avoid surprises.
What are request and response interceptors and when should I use them?Interceptors are cross‑cutting hooks. Use request interceptors to prepare shared data (e.g., load persistence, set up localization, logging) before handlers run. Use response interceptors to perform common cleanup (e.g., save persistence) just before sending the response, centralizing boilerplate and reducing handler clutter.How do I pass data from interceptors to my handlers safely?Use request-scoped attributes. Load persistent data in a request interceptor, store it on request attributes, and read it from handlers. Avoid globals (unsafe with reused runtimes) and don’t overuse session attributes if the data doesn’t need to go back to the Alexa service.What should I do if users jump ahead and skip earlier steps?Support the relevant slot in multiple intents and handle missing info gracefully. If a required slot is absent, reprompt or route to a handler that collects it (often the same prompt used at launch). Never force users to “go back”; accept new explicit values at any time to reset context.How can I unit test my skill’s conversation flows effectively?Use tools like Bespoken to write YAML tests that mimic real dialogs, assert prompts/reprompts, and mock services (e.g., DynamoDB). Test both static and dynamic responses, shortcut paths, context decay, favorites selection, and error cases to catch regressions early.
pro $24.99 per month
access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!