Best practices for building bots with Composer

APPLIES TO: Composer v1.x and v2.x

Bot Framework Composer is a visual authoring tool for building conversational AI software. By learning the concepts described in this section, you'll become equipped to design and build a bot using Composer that aligns with the best practices. Before reading this article, you should read the introduction to Bot Framework Composer article for an overview of what you can do with Composer.

Use the basic authoring process to build your bots:

The following list includes the recommended best practices and things to avoid for building bots with Composer:

Recommended Not recommended
Plan your bot -------
Give your bot a bit of personality Make your bot talk too much
Consider when to use dialogs Nest more than two deep conditionals
Consider the non-happy path -------
Name dialogs clearly -------
Keep dialogs short -------
Create a dialog for help/cancel -------
Keep a root menu -------
Keep state properties consistent -------
Define LG templates and reuse them consistently -------
Parameterize reusable LG templates -------
Add variations for bot responses -------
Make your prompt text clear -------
Prepare for ambiguity in the responses -------
Add prompt properties -------
Use LUIS prebuilt entities ------
Use LUIS entities to support synonyms in a multi-choice prompt ------

Design bots

Plan your bot

Before building your bot application, make a plan of the bot you want to create. Ensuring a great Conversational User Experience (CUX) should be your number one priority when designing a bot. Consider the following questions:

  • What your bot is used for? Determine the kind of bot you plan to build. This will help to define the functionalities you want to implement in the bot.
  • What problems does your bot intend to solve? Be clear about the problems your bot intends to solve. Solving problems for customers is the top factor you should consider when building bots. You should also consider things such as how to solve the user's problem better/easier/faster than any of the alternative experiences.
  • Who will use your bot? If you are designing a bot, it's safe to assume that you are expecting users to use it. Different customers will expect different user experiences. This will also determine the complexity you should consider in your bot design. Consider what languages to implement for the bot.
  • Where will your bot run? You should decide the platforms your bot will run on. For example, a bot designed to run on a mobile device will have more features like sending SMS to implement.

Tip

Most successful bots have at least one thing in common: great CUX. The CUX guide, contains guidance on designing a bot. This guidance aligns with best practices and capitalizes on lessons learned.

Give your bot personality

Adding personality to your bot makes it more conversational and engaging. Here are some tips to give your bot a bit of personality:

  • Use language generation to create multiple variations of messages. A little bit of personality goes a long way, don't over use it.
  • Consider the context where your bot will be used. Bots used in private scenarios can turn out to be more conversational than bots in public. A bot will be more descriptive to a new user than to a returning user.
  • Define language generation templates and reuse them across the bot consistently. This will make your bot's personality consistent.
  • Use cards to give your bots visual branding and personality if your platform supports UI cards.

Provide answers to user queries

A great conversational bot does not require users to type too much, talk too much, repeat themselves several times, or explain things that the bot should automatically know and remember. Being concise and clear in messages is highly recommended in your design. Make the messages your bot sends relevant and information-dense. Don't say less or more than the conversation requires.

Design dialogs

When to use dialogs

Think of dialogs as modular pieces with specific functionalities. Each dialog contains instructions for how the bot will react to the input. Dialogs allow you more granular control of where you start and restart, and they allow you to hide details of the "building blocks" that people do not need to know.

Consider using dialogs when you want to:

  • Reuse things.
  • Have interruptions that are local to that flow (for example, contextual help inside a date collection flow).
  • Have a place in your conversation that you need to jump to easily from other places.
  • Nest more than two deep conditionals within a dialog.

The following example shows a bot which nests two switch statements. This is inefficient and hard to read.

nested switch statements

Instead of using nested switch statements, you can use dialogs to encapsulate the functionalities.

use dialogs for encapsulation

Consider the unhappy path

When designing dialogs, you should consider asking follow-up questions, clarifications, and whether you want to use local interruption which only happens within the context of a child dialog.

  • Prepare for unexpected responses. When your bot asks questions such as "What's your name?", get your bot prepared for answers such as "Why?" and "No". You can make use of prompt capabilities such as using Unrecognized prompt and Invalid prompt properties. Read how to make use of them in the add prompt properties section.

  • Use interruptions. Consider using the Allow Interruptions property to either handle a global interruption or a local interruption within the context of the dialog.

Tip

For any prompt action, The Allow Interruptions property is located in the properties pane on the Other tab, under Prompt Configurations. You can set the value to be true or false.

Name dialogs clearly

You should name your dialogs clearly when you create them as you cannot change the name of your dialog once created. You should use a naming scheme early as you might end up with a lot of dialogs.

Some commonly used naming schemes include but are not limited to the following:

  • Camel case: myDialog
  • Pascal case: MyDialog
  • Snake case: my_dialog
  • Kebab Case: my-dialog

Note

Don't use spaces and special characters in dialog names.

Keep dialogs short

It's easy for you to view shorter dialogs in the authoring canvas and see all the "hidden details" in a dialog when you want to. You should also try to limit the complexity of your dialog system. See some examples in the AskingQuestionsSample. You can click through and see the dialogs.

Create a dialog for help/cancel

It is a good practice to create a dialog for help/cancel, either locally or globally. By creating global help/cancel dialog, you can let users exit out of any process at any time and get back to the main dialog flow. Local help/cancel dialog will be very helpful to handle interruptions within the context of a dialog.

You can read more in the weather bot tutorial- adding help and cancel functionality to your bot article to see how to create a dialog for help/cancel functionalities.

Design conversation flows

Keep a root menu

It is a good practice to present a root menu with some common choices like at the beginning of the interaction. That menu should come back into play when the user completes a task. Think of this root menu is like an app's home screen. You begin your interaction with the app from the home screen and end with the home screen. Then you can take your next action.

Keep state properties consistent

It's useful to establish conventions for your state properties across conversation, user, and dialog state for consistency and to prepare for context sharing scenarios.

When creating a property, think about the lifetime of that property. Do not hesitate to use turn memory scope to capture volatile information. There is no point using dialog.confirmation.outcome when you are asking a confirmation prompt because the lifetime of that confirmation is only for that particular turn of the conversation. You should not feel bad about using that turn memory scope. The memory concept article contains basic concepts of memory scopes used in Composer.

Don't nest more than two deep conditionals

When you nest more than two deep conditionals (loops or switch statements) in a single dialog, you should consider building child dialogs to encapsulate them. Making use of child dialogs to encapsulate bots functionalities is highly recommended for maintaining conversation flows.

Design bot responses

Define bot response templates and reuse them consistently

Reusing LG templates helps to keep consistency across the bot. You can define LG templates in advance in the common.lg file and use them in different dialogs when necessary. In Composer, you can select Bot Responses and then select Common in the bot explorer to see the templates defined and shared by all the dialogs.

To import the common templates into another LG file, add the line [import](common.lg) at the top.

It is a good practice to build templates for reusable components and use them consistently. For example, things like acknowledgment phrases and apology phrases will be used by a bot in several different places, like every time you have an invalid prompt or unrecognized intent.

Here is an example of an acknowledgePhrase template with three variations:

#acknowledgePhrase
- I'm sorry you are having this problem. Let's see if there is anything we can do.
- I know it is frustrating – let's see how we can help…
- I completely understand your situation. Let me try my best to help.

Parameterize reusable language generation templates

For things like prompts, for texts in send activity, composition is one of the key things in LG, which enables reusability but also enables parameterization. You can have some lowest unit of composition.

When defining reusable templates, parameterize them so they can be used in different scenarios by passing in the appropriate options for expansion or evaluation.

  • You can set up templates with parameters that take properties as parameters, so you can do things like date formatters or card builders.
  • When you set up a template, instead of referring directly to a specific property Dialog.foo, use a parameter name instead. For example, in the code below, specify name as a parameter instead of referring to a property.
  • Set up cards in parts and compose them into bigger cards.

For example:

# welcomeUser(name)
- ${greeting()}, ${ personalize(name)}

# greeting
- Hello
- Howdy
- Hi

# personalize(name)
- IF: ${name != ''}
- ${ name }
- ELSE:
- HUMAN

Having set up these templates, you can now use them in a variety of situations. For example:

> Greet a user whose name is stored in `user.name`
- ${ welcomeUser(user.name) }

> Greet a user whose name you don't know:
- ${ welcomeUser() }

> Use personalization in another message:
- That's ok, ${ personalize(user.name) } , we can try again!

Tip

Read more in the .lg file format and structured response template articles.

Add variations to bot responses

Language generation lets you define multiple variations of a phrase to make bots replies less robotic. For example, in the weather bot tutorial - adding language generation article, you can define multiple variations of a greeting message to make the conversation more natural. However, this does not mean you should add as many variations as possible, it depends on how you want your bot to respond and in what tone and voice.

Design inputs

Make your prompt clear

Make sure your prompt texts are clear and unambiguous. Ambiguity is a problem in languages and it is something we should avoid when we phrase the text of a prompt.

Consider giving your user input hints including using suggested responses. This will help make your prompt clear and avoid ambiguity. For example, instead of saying "What is your birthday", you can say "What is your birthday? Please include the day month and year in the form of DD/MM/YYYY".

Prepare for ambiguous requests

While ambiguity is something you try to avoid in outgoing messages, you should also be prepared for ambiguity in the incoming responses from users. This helps to make your bot perform better but also prepares you for platforms like voice where users more commonly add words.

People tend to type differently than they speak. For example, they might enter, "my birthday is 1/25/78", in a text input field, but instead say, "my birthday is in January, it's the 25th", in response to a verbal prompt.

Sometimes when people make their bots personality rich they introduce language ambiguity. For example, be cautious when you use greeting messages such as "What's up?", which is a question that users will try to answer. If you don't prepare your bot to responses like "Nothing", it will end up confusion.

Add prompt properties

Make use of the prompt features such as Unrecognized prompt and Invalid prompt. These are powerful properties that give you a lot of control over how your bot responds to unrecognized and invalid answers. Access these properties under the Other tab of any type of input (Ask a question) action.

Add guidance along the prompts for re-prompting, otherwise the bot will keep asking the same question without telling the users why it is asking again.

Use validations when possible. The Invalid prompt fires when the input does not pass the defined validation rules. Here are two examples of how to phrase in the Unrecognized prompt and Invalid prompt fields.

  • Unrecognized prompt

    - Sorry, I do not understand '${this.value}'. Please enter a ZIP code in the form of 12345.
    
  • Invalid prompt

    - Sorry, '${this.value}' is not valid. I'm looking for a 5-digit number as ZIP code. Please specify a ZIP code in the form 12345.
    

Design recognizers

Use LUIS prebuilt entities

LUIS provides a list of prebuilt entities which are very handy to use. When you think of defining entities, check the list of LUIS prebuilt entities first instead of reinventing your own wheels. Some commonly-used prebuilt entities include: time, date and Number.

For the best practices of building LUIS models, you should read the best practices for building a language understanding (LUIS) app article.

Use LUIS entities to support synonyms in a multi-choice prompt

It is possible to use LUIS entities as part of a multi-choice prompt so that the bot can understand a wider set of replies. This can be achieved using the LUIS list entity, which you can define Expected responses in the User Input section of a multi-choice prompt's properties panel. For example:

- American food
- Mexican food
- Asian food

@ list  foodType =
  - American food:
    - burger
    - pizza
    - hot dog

  - Mexican food:
    - taco
    - torta
    - posole

    - Asian food:
    - pho
    - noodle
    - dim sum

The following image demonstrates how this appears in the Authoring canvas and Properties pane in Composer:

Main and child dialog

In the example above, burger, pizza, and hot dog will be recognized as the same entity as American food; taco, torta, and posole will be recognized as the same entity as Mexican food; and pho, noodles, and dim sum will be recognized as the same entity of Asian food.

You can also see a good implementation of this in the ToDoWithLuisSample. Do the following to get the To Do with LUIS example running in Composer:

  1. Clone the Bot Builder samples github repo onto your machine.

  2. Within the composer-samples folder you'll find C# and JavaScript projects, choose a language and navigate into the projects subfolder.

  3. In this folder you'll find a ToDoWithLuisSample project which you can open in Composer.

Now that you have it loaded in Composer, you can select the additem dialog from the bot explorer. Then, in the BeginDialog trigger select the multi-choice prompt as follows:

multiple choice prompt

Additional information