Every morning on my way to work, I stop by the same coffee shop to buy a green tea latte. The barista knows what I want from past experience and starts making my order as soon as I set foot inside the store. I joke about switching up my order to throw them off, but I don’t want them to waste that good green tea.
The simplicity of the personalized experience helps keep me coming back to this store and, similarly, good Alexa skills deliver personalized customer interactions to inspire these kinds of repeat engagements.
The new dynamic entities capability helps you personalize Alexa skill experiences by adapting your interaction model at runtime without edits, builds, or re-certification. Now your skill can handle customer, context, and conversational changes by updating existing slot values from data structures in your code, a database, or a RESTful API call. Contextualizing slot values and synonyms personalizes the experience based on user preferences and previous interactions just like at the coffee shop. Today persistent attributes can help your skill programmatically remember things between skill sessions, but this requires engineering effort that may mean manual updates to your interaction model and corresponding certification. Implementing dynamic entities doesn’t require any model rebuild or re-certification, and your skill starts customizing slots as soon as the directive is updated in your AWS Lambda code.
Adding dynamic entities is straightforward.
Let’s continue with the coffee shop example. Ordering a drink with a skill requires a drink slot with slot type drinkType. We initially defined it with two values: coffee and black tea. Now we’ve expanded our offerings to include green tea and oolong tea. Rather than updating our model manually and resubmitting for certification, dynamic entities can do it for us on the fly.
Our skill will need to return the Dynamic.UpdateDynamicEntities directive. We can set the updateBehavior value to either CLEAR or REPLACE and use the types field to set the dynamic entities. Upon returning the directive, the Alexa Service will register our new slot values and synonyms for drinkType. This process is silent and does not require the customer to do anything but interact with our skill.
Once the new slot values and synonyms have been registered, requests to our skill containing slots associated with our dynamic entities will contain the resolved values based on both the statically and dynamically defined values for the drinkType. From our skill code we can check if what the customer said matched with either the static or dynamic slot value. When your customer finishes interacting with your skill the dynamic entities expire, so you’ll need to re-register them the next time the skill launches.
Let’s start with the response and the request.
Registering dynamic entities for our drinkType returns this directive in our response.
...
'directives': [
{
'type': 'Dialog.UpdateDynamicEntities',
'updateBehavior': 'REPLACE',
'types': [...]
}
]
...
The type and updateBehavior are pretty straightforward. On the other hand, the types field is an array of complex objects that represent the slot types. Skill can have many slot types. We may dynamically set the values and synonyms for one or more of our slot types, which is why types is an array. Let’s take a look at a singular slot type object that will appear in the types array:
{
'name': '<slotType>',
'values': [
{
...
},
...
]
}
There are two fields, name and values. The name field is the name of the slot type you wish to update. Since slot types can have multiple values, the values array allows you to provide a list of complex objects that represent the slot values and its synonyms. Let’s zoom into one of our slot value objects contained in our values array.
{
'id': '<slotValueId>',
'name': {...}
}
Each slot value object must contain a name which is an object and can define an optional id. Although id is optional you should define one if you plan to use a slot value to look something up in a database or with a RESTful web service (like Amazon DynamoDB). Doing so will eliminate the need to create a dictionary in your code that matches slot values to database id values.
Lastly, the name field is a complex object, that contains the value and an array of synonyms.
{
'value': '<slotValue>',
'synonyms': [
'<synonymA>',
'<synonymB>',
...
]
}
Putting it all together, to add green tea and oolong tea to our drinkType the directive will look like:
...
'directives': [
{
'type': 'Dialog.UpdateDynamicEntities',
'updateBehavior': 'REPLACE',
'types': [
{
'name': 'drinkType',
'values': [
{
'id': 'grnTea',
'name': {
'value': 'green tea',
'synonyms': [
'matcha',
]
}
},
{
'id': 'oolTea',
'name': {
'value': 'oolong',
'synonyms': [
'chinese tea',
'black dragon tea',
]
}
}
]
}
]
}
]
...
Once the dynamic entities have been registered, the request sent to your skill code contains both the statically and dynamically defined resolutions in an array called resolutionsPerAuthority. NOTE: if you’ve used entity resolution to map synonyms to slot values before, you‘ll recognize the resolutionsPerAuthority array. Previously, there was only one item that would appear in this array so I used to hardcode resolutionsPerAuthority[0]. But now static and dynamic entities will deliver more than one item in this array, so I consider hardcoding it a bad habit.
Be careful! The array is unordered. Sometimes the dynamic entity comes first and sometimes the static entity. Since you will not be able to rely on the order in the resolutionsPerAuthority[0] array you’ll need to check the entity type of each object in the array:
Static:
amzn1.er-authority.echo-sdk.amzn1.ask.skill.<skill_id>.drinkType
Dynamic:
amzn1.er-authority.echo-sdk.dynamic.amzn1.ask.skill.<skill_id>.drinkType
Did you notice that they are exactly the same except the dynamic one contains the word “dynamic?” In code, to determine which object in resolutionsPerAuthority is dynamic, you can check if it contains “.er-authority.echo-sdk.dynamic.” Why not a simple check for contains “dynamic?” Let’s consider the case where you named your slot type dynamicType. In this case both the static and dynamic authority would contain dynamicType at the end of the string. Doing a simple contains check on either static or dynamic will return true, which isn’t what we want.
Let’s say our customer ordered matcha, which is a synonym for green tea. We’re in luck because we just dynamically updated our drinkType! Let’s zoom into the request and take a look at the OrderIntent. The resolutionsPerAuthority will contain two authorities.
...
{
"intent": {
"name": "OrderIntent",
"confirmationStatus": "NONE",
"slots": {
"drink": {
"name": "drink",
"value": "matcha",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.<skill_id>.drinkType",
"status": {
"code": "ER_SUCCESS_NO_MATCH"
}
},
{
"authority": "amzn1.er-authority.echo-sdk.dynamic.amzn1.ask.skill.<skill_id>.drinkType",
"status": {
"code": "ER_SUCCESS_MATCH"
},
"values": [
{
"value": {
"name": "green tea",
"id": "grnTea"
}
}
]
}
]
},
"confirmationStatus": "NONE",
"source": "USER"
}
}
}
}
...
At the top level (intent.slots.drink) the value is ‘matcha’, which means the skill captured our customer’s order. We can also see two resolutionsPerAuthority; in this case the first one is static and the second one is dynamic. Our statically defined drinkType does not include the value green tea and its synonym matcha so the status code is ER_SUCCES_NO_MATCH. The other dynamic one is ER_SUCCESS_MATCH and it contains the value green tea and the id grnTea. We’ve just updated our drink menu dynamically!
Let’s say we wanted to offer a limited-time green tea frappé drink promotion in our skill. We could add the drink entry to a database that the skill calls through a web service, so that when our skill opens we get an updated sale menu with the green tea frappé dynamically registered as a drinkType entity. Once the promotion ends we can remove that entry from the database. If a repeat customer attempts to order it won’t exist in either the static nor dynamic entities, and we can let the customer know that we no longer offer that item.
Now that we understand how to use dynamic entities let’s talk about limitations.
As you saw above, dynamic entities are very powerful, but there are a few limitations that you should be aware of:
This includes the combination of values and synonyms per slot type. If the total exceeds 100, you’ll receive a 403 error and your dynamic entities will not be registered, however, your static entities will continue to work.
You’re free to update your dynamic entities over and over again from any of your responses, however, the previous ones will be overwritten. You can’t use multiple responses to register 200 dynamic entities, however, you could load 100 entities based on the context your skill entered handling your customer’s response and then swap them out with a new set of 100 upon entering a different context
In order for your skill to return a directive, it must first recieve a request. This means that dynamic entities wont be registered until the skill has been opened. Ideally our customer will open the skill by saying, “Alexa, open coffee shop” which will trigger the LaunchRequest, where we can register your dynamic entities. If they were to say, “Alexa, tell coffee shop I want green tea”, the OrderIntent will be triggered before we are able to register our dynamic entities. In this case, the drink slot will resolve to green tea, but only the static entities will be available to our skill. If they ordered something from the promotional menu, we won’t be able to rely on the dynamic entities to check if it’s still on offer, so we’ll have to check manually.
Dynamic entities can make skills more engaging by personalizing interactions and by contextualizing slot types for improved accuracy.
When I walk into the coffee shop the barista and I both know I want a drink and that my drink is a green tea latte. The baristas can also make similar safe assumptions about other customers, so the ordering process is personalized and efficient which can make it more engaging.
Dynamic entities can mimic this behavior by dynamically mapping slot values based upon each customer’s past order history. Using dynamic entities, we can map the slot value my usual to green tea latte. When I interact with the skill, I can say, “I’ll have my usual”. The drink slot can be filled with “my usual” and resolved to green tea latte.
Skills that adapt to context can also be more engaging by being more accurate. You can set your dynamic entities in relation to current skill context, which makes your slots more contextually aware. For example, let’s say we have a skill that enables the customer to look up bus routes with their voice. Street and station names can be unconventional, with complicated spelling and hard-to-pronounce words. Using the device address API your skill could get the zip code of the customer’s echo device, use it to look up all the bus stops and cross streets within a specific distance radius, and set those street name values to your slot type using dynamic entities. Although the set of dynamic entities is much smaller, they are more highly relevant within the context of where your customer is interacting with your skill. As a result, your skill will be more accurate when interpreting the street names.
Our early testers have found that dynamic entities are powerful tools for driving engagement, helping them deliver personalized, higher-quality experiences in less time. James Dimmock of UK online supermarket Ocado says, “We offer over 100 types of milk with a lot of customers having a strong preference for a specific brand or type. With dynamic entities Ocado’s skill will enable customers to add their favourite to the basket faster and easier than ever before."
In addition, voice developers are using it to improve their business models. Joel Wilson, founder at US voice development agency Matchbox.io, found that the time savings from updating skills on the fly helps him operate faster. He says, “We will not have to have to change our language models and resubmit our skill every time our content changes.”
I hope this has inspired you to think about how you can put dynamic entities to use in your skills. If you do, I’d love to hear about it! Please reach out to me on Twitter SleepyDeveloper to let me know!