What's in a name? Detecting names using LUIS
A lot of our early work with LUIS involved trying to extract names from utterances. For example, a user asks the bot “where can I find John’s details?”, and the bot needs to know to search for “John”.
We’ve needed this for several projects now, and found several useful ways to improve name detection in LUIS.
What should an ideal name detector be able to do?
An ideal name detector should be able to deal with all possible names a user can give it, and in all possible forms. This includes:
- Names of any length (for example, someone with two middle names)
- Names in other languages
- Names which contain punctuation (for example, the surname “Smith-O’Reily”)
- Nicknames, or shortenings of existing names
- Recently created names (such as Abcde or Khaleesi)
- Names used in the context of possession (so John should be detected in both “John’s” and “Johns”)
One of the problems which is easiest to overlook is when users make errors. An important part of bot design is making sure your bot portrays an approachable and pleasant demeanor. One of the easiest ways to fail to do this is if your bot is seen to be mocking the user’s mis-use of apostrophes.
The personName entity
LUIS comes with a built-in entity called ‘personName’. If included in a LUIS app, it will automatically identify any name from a large list in any utterances sent to the app.
Generally speaking, the LUIS pre-built entites are pretty good. In particular, the dateTimeV2 entity is impressive- it detected a far larger range of dates and times than we expected. Naïvely, I’d expected it to required an exact date string, but it was equally happy with requests such as ‘next Wednesday’.
Using personName, we initally had good results using this entity, but hit a number of problems in testing.
- A number of common shortenings of names were not being detected correctly. Users with nicknames or uncommon names were also undetected. As the entity is pre-built, there was no way to extend or train the entity to detect these.
- The entity would successfully detect that “John” was a name when asked for “John’s details”, but was unable to extract it from “Johns details”.
Ultimately, because we couldn’t improve this entity to meet our needs, we had to find a better solution.
Custom built entities
A better way to detect names is using a custom entity. Often, when defining an entity, you will have a fixed set of possible values it can take. With names, this is not the case - new names and nicknames are constantly being created, so the entity should ideally accept any random string as a potential name. A custom entity can be trained to do this.
When training LUIS to do this, some care is needed. In our initial attempts, we just used a variety of common English names in our example utterances. This led to the bot recognising a very narrow range of names. The bot was much more successful at detecting any string when context was ignored entirely in the entities provided in the utterances. Instead of training LUIS to understand “look up details for John”, we instead trained with “look up details for xdfhawnw”. Once it understood “xdfhawnw” as a name, it was fairly happy to accept anything.
Just using random strings instead of names isn’t enough, however. The actual words being detected should be context free, but just using random strings resulted in the bot being unable to accept a two or three part name. For the best results, we used random strings, which were approximately the right length/form or a name, such as ‘Wxgayst Degzdsfgd-Stsdts’.
The main drawback of using this approach is when handling possession. With personName, it would automatically extract “John” if the user asked for “John’s details”- with a custom entity, LUIS returns “John’s”. The bot does need to do some manual handling of the string, depending on the context of the intent.
A combined approach
Each of the above approaches has advantages and disadvantages. The personName entity works reliably for a limited set of common names, whereas a custom entity detects a wider range of names, but can hit unforeseen problems.
The best solution we’ve found so far is to check for both entities. If no personName is detected, then fall back onto a custom entity. While not a perfect solution, it’s given a consistently high success rate in our development.