IBM Cloud Docs
Conversation building tips

Conversation building tips

Get tips about ways to address common tasks.

Adding nodes

  • Add a node name that describes the purpose of the node.

    Today, you know what the node does, but months from now you might not remember. And the node name is displayed in the log, which can help you debug a conversation later.

  • To gather the information that is required to complete a task, use a node with slots instead of a bunch of separate nodes to elicit information from users. See Gathering information with slots.

  • For a complex process flow, tell users about any information they need to provide at the start of the process.

  • Understand how your assistant travels through the dialog tree and the impact that folders, branches, jump-tos, and digressions have on the route. See Dialog flow.

  • Do not add jump-tos everywhere. They increase the complexity of the dialog flow, and make it harder to debug the dialog later.

  • To jump to a node in the same branch as the current node, use Skip user input instead of a Jump-to.

    This choice prevents you from having to edit the current node's settings when you remove or reorder the child nodes that are jumped to. See Defining what to do next.

  • Before you enable digressions away from a node, test the most common user scenarios. And be sure that likely digressed-to nodes are configured to return. See Digressions.

Adding responses

  • Keep answers short and useful.

  • Reflect the user's intent in the response.

    Doing so assures users that the bot is understanding them, or if it is not, gives users a chance to correct a misunderstanding immediately.

  • Include links to external sites in responses if the answer depends on data that changes frequently.

  • Avoid overusing buttons. Encouraging users to pick predefined options from a set of buttons is less like a real conversation, and decreases your ability to learn what users really want to do. When you let real users ask for things in their own words, you can use the input to train the system and derive better intents.

  • Avoid using a bunch of nodes when one node is sufficient. For example, add multiple conditional responses to a single node to return different responses depending on details provided by the user. See Conditional responses.

  • Word your responses carefully. You can change how someone reacts to your system based simply on how you phrase a response. Changing one line of text can prevent you from having to write multiple lines of code to implement a complex programmatic solution.

Tips for capturing information from user input

It can be difficult to know the syntax to use in your dialog node to accurately capture the information you want to find in the user input. Here are some approaches that you can use to address common goals.

  • Returning the user's input: You can capture the exact text uttered by the user and return it in your response. Use the following SpEL expression in a response to repeat the text that the user specified back in the response:

    You said: <? input.text ?>.

    If autocorrection is on, and you want to return the user's original input before it was corrected, you can use <? input.original_text ?>. But, be sure to use a response condition that checks whether the original_text field exists first.

  • Determining the number of words in user input: You can perform any of the supported String methods on the input.text object. For example, you can find out how many words there are in a user utterance by using the following SpEL expression:

    input.text.split(' ').size()

  • Dealing with multiple intents: A user enters input that expresses two separate tasks. I want to open a savings account and apply for a credit card. How does the dialog recognize and address both of them? See the Compound questions blog entry.

  • Dealing with ambiguous intents: A user enters input that is ambiguous enough that your assistant finds two or more nodes with intents that might potentially address it. How does the dialog know which dialog branch to follow? If you enable disambiguation, it can show users their options and ask the user to pick the correct one. See Disambiguation for more details.

  • Handling multiple entities in input: If you want to evaluate only the value of the first detected instance of an entity type, you can use the syntax @entity == 'specific-value' instead of the @entity:(specific-value) format.

    For example, when you use @appliance == 'air conditioner', you are evaluating only the value of the first detected @appliance entity. But, using @appliance:(air conditioner) gets expanded to entity['appliance'].contains('air conditioner'), which matches whenever there is at least one @appliance entity of value 'air conditioner' detected in the user input.

  • Hiding data from the log: You can prevent information from being stored in logs by storing it in a context variable and nesting the context variable within the $private section of the message context. For example, $private.my_info. Storing data in the private object hides it from the logs only. The information is still stored in the underlying JSON object. Do not allow this information to be exposed to the client application.

  • Checking for personal information: If you want to check for and prevent a user from submitting personally identifiable information (PII) to some later process, you can add a dialog node that conditions on a pattern entity. Place the node at the beginning of the dialog tree to ensure that it checks the input first. For example, the entity might check for US Social Security number patterns or email address patterns. It can then respond with something like, Please do not submit personally identifiable information. Can you reenter your request? You can optionally reset the context to ensure that the user-submitted information with PII is not retained.

Condition usage tips

  • Checking for values with special characters: If you want to check whether an entity or context variable contains a value, and the value includes a special character, such as an apostrophe ('), then you must surround the value that you want to check with parentheses. For example, to check if an entity or context variable contains the name O'Reilly, you must surround the name with parentheses.

    @person:(O'Reilly) and $person:(O'Reilly)

    Your assistant converts these shorthand references into these full SpEL expressions:

    entities['person']?.contains('O''Reilly') and context['person'] == 'O''Reilly'

    SpEL uses a second apostrophe to escape the single apostrophe in the name.

  • Checking for multiple values: If you want to check for more than one value, you can create a condition that uses OR operators (||) to list multiple values in the condition. For example, to define a condition that is true if the context variable $state contains the abbreviations for Massachusetts, Maine, or New Hampshire, you can use this expression:

    $state:MA || $state:ME || $state:NH

  • Checking for number values: When you compare numbers, first make sure the entity or variable that you are checking has a value. If the entity or variable does not have a number value, it is treated as having a null value (0) in a number comparison.

    For example, you want to check whether a dollar value included in user input is less than 100. If you use the condition @price < 100, and the @price entity is null, then the condition is evaluated as true because 0 is less than 100, even though the price was never set. To prevent this type of inaccurate result, use a condition such as @price AND @price < 100. If @price has no value, then this condition correctly returns false.

  • Checking for intents with a specific intent name pattern: You can use a condition that looks for intents that match a pattern. For example, to find any detected intents with intent names that start with 'User_', you can use a syntax like this in the condition:

    intents[0].intent.startsWith("User_")

    However, when you do so, all of the detected intents are considered, even those with a confidence lower than 0.2. Also, check that intents that are considered irrelevant based on their confidence score are not returned. To do so, change the condition as follows:

    !irrelevant && intents[0].intent.startsWith("User_")

  • How fuzzy matching impacts entity recognition: If you use an entity as the condition and fuzzy matching is enabled, then @entity_name evaluates to true only if the confidence of the match is greater than 30%. That is, only if @entity_name.confidence > .3.

Storing and recognizing entity pattern groups in input

To store the value of a pattern entity in a context variable, append .literal to the entity name. Using this syntax ensures that the exact span of text from user input that matched the specified pattern is stored in the variable.

Append .literal
Variable Value
email <? @email.literal ?>

To store the text from a single group in a pattern entity with groups defined, specify the array number of the group that you want to store. For example, assume that the entity pattern is defined as follows for the @phone_number entity. (Remember, the parentheses denote pattern groups):

\b((958)|(555))-(\d{3})-(\d{4})\b

To store only the area code from the phone number that is specified in user input, you can use the following syntax:

Area code only
Variable Value
area_code <? @phone_number.groups[1] ?>

The groups are delimited by the regular expression that is used to define the group pattern. For example, if the user input that matches the pattern that is defined in the entity @phone_number is: 958-234-3456, then the following groups are created:

Group details
Group number Regex engine value Dialog value Explanation
groups[0] 958-234-3456 958-234-3456 The first group is always the full matching string.
groups[1] ((958)l(555)) 958 String that matches the regex for the first defined group, which is ((958)l(555)).
groups[2] (958) 958 Match against the group that is included as the first operand in the OR expression ((958)l(555))
groups[3] (555) null No match against the group that is included as the second operand in the OR expression ((958)l(555))
groups[4] (\d{3}) 234 String that matches the regular expression that is defined for the group.
groups[5] (\d{4}) 3456 String that matches the regular expression that is defined for the group.

To help you decipher which group number to use to capture the section of input you are interested in, you can extract information about all the groups at once. Use the following syntax to create a context variable that returns an array of all the grouped pattern entity matches:

Array of matched groups
Variable Value
array_of_matched_groups <? @phone_number.groups ?>

Use the "Try it out" pane to enter some test phone number values. For the input 958-123-2345, this expression sets $array_of_matched_groups to ["958-123-2345","958","958",null,"123","2345"].

You can then count each value in the array starting with 0 to get the group number for it.

Array elements
Array element value Array element number
"958-123-2345" 0
"958" 1
"958" 2
null 3
"123" 4
"2345" 5

From the result, you can determine that to capture the last four digits of the phone number, you need group #5, for example.

To return the JSONArray structure that is created to represent the grouped pattern entity, use the following syntax:

JSON of matched groups
Variable Value
json_matched_groups <? @phone_number.groups_json ?>

This expression sets $json_matched_groups to the following JSON array:

[
  {"group": "group_0","location": [0, 12]},
  {"group": "group_1","location": [0, 3]},
  {"group": "group_2","location": [0, 3]},
  {"group": "group_3"},
  {"group": "group_4","location": [4, 7]},
  {"group": "group_5","location": [8, 12]}
]

location is a property of an entity that uses a zero-based character offset to indicate where the detected entity value begins and ends in the input text.

If you expect two phone numbers to be supplied in the input, then you can check for two phone numbers. If present, use the following syntax to capture the area code of the second number, for example.

JSON of matched groups
Variable Value
second_areacode <? entities['phone_number'][1].groups[1] ?>

If the input is I want to change my phone number from 958-234-3456 to 555-456-5678, then $second_areacode equals 555.