ai Conversational Apps NeMo nvidia

How To Build Better Conversational Apps with NeMo Guardrails

While current Large Language Models (LLMs) like those powering OpenAI’s ChatGPT are impressive, they have limitations in generating accurate and reliable text. Consequently, integrating a generic chatbot into your website to assist clients might give you pause. We recently discovered Nvidia’s NeMo Guardrails, a toolkit to help tackle these issues. With it, we can now further tailor our conversational apps to selectively include or exclude specific domain knowledge and mitigate the risks associated with misinformation or offensive content, instilling confidence in both ourselves and our users. It gets us a step closer to creating conversational experiences that are not only intelligent and user-friendly but also ethical and trustworthy.

Like the name suggests, the toolkit helps your team set up guardrails for your LLM to steer conversations in certain directions (topics, perhaps) or keep them from veering off track altogether. They aim to support three categories of guardrails: topical, safety, and security. It is supported by popular frameworks like LangChain and works with all kinds of LLMs, like those behind ChatGPT.1

We chose to start simple to get a feel for what is involved. We explored the guardrails on two chatbots: the first is restricted to a specific topic, and the second has no topical restrictions but is set to fact-check itself and confess if it is generating a hallucination for safer interaction. We have yet to look into the guardrails with regards to security.

Set Up

NeMo Guardrails is written in Python, so we chose to use pip to install the toolkits and kept our sandbox in a virtual environment (ve) using venv (If you prefer to use a container or anything else, then set that up and skip the instructions for creating a ve). After creating a directory for your project, create the ve there and install all necessary packages. We will be using OpenAI’s text-davinci-003 as our LLM for both examples, so we also installed the openai package. If you choose to use OpenAI’s models, you will need an API key. It is pretty simple to do so.

Getting an OpenAI API Key
  • Go to platform.openai.com and sign in to your account.
  • In your profile dropdown menu, click on ‘View API Keys’.
  • Click on ‘API Keys’, then on ‘Create New Secret Key’.
  • Name and save your key, then exit.
Installing Packages in a Virtual Environment
mkdir my_projectcd my_project

python -m venv venv
source venv/bin/activate

pip install nemoguardrails
pip install openai
export OPENAI_API_KEY=<paste your key here>

Now, if all went well, the guardrails CLI should be ready to use. To test this out:

nemoguardrails --help

You should see something like this:

Nvidia did a nice job with their introductory documentation. If you’d like to start out with the basics, they have a hello-world example that is pretty straight forward to implement and a good way to find out if you set things up correctly, before you move to more advanced applications.

About Colang

For our examples we will be creating YAML configuration files and Colang guardrail files. Colang is a modeling language and runtime developed by NVIDIA for conversational AI. It is meant to be similar to Python for easy adoption.

For the purpose of this blog we’ll need to know about message and flow blocks of Colang code. Message blocks are used to define user and bot message types. The flow blocks define how the chat should develop. It will contain the order of user and bot message types, as well as other logic. We’ll go through the guardrails in more detail in the next sections. Here are some handy links for more detailed documentation on Colang and the config file guide:

Restricted Topics Chatbot

One of the most common types of virtual assistants these days is the chatbot that pops up eager to answer any product related questions a user/client may have. These bots are expected to have a specific knowledge base. We will create a chatbot that is programmed to provide information only about one subject, in this case, about the 2022 American Time Use Survey, provided by the Bureau of Labor Statistics. We used Nvidia’s topical_rail example as a guide.

Configurations

We begin by creating a config.yml file. It includes basic instructions, a sample conversation, and model information.

instructions:
  - type: general
    content: |
      The following dialogue features a discussion between a user and a bot
      regarding the American Time Use Survey or 2022. 
      The bot provides accurate and brief information. 
      Whenever the bot is unfamiliar with an answer, it honestly states that
      it doesn't know.
sample_conversation: |
  user "Hello"
    express greeting
  bot express greeting
    "Hi there! How may I help you today?"
  user "What can you do for me?"
    ask about capabilities
  bot respond about capabilities
    "I can answer questions based on the topic 'American Time Use Survey
    (ATUS) of 2022' gathered and published by the US Bureau of Labor
    Statistics."
  user "Can you give me a summary about ATUS?"
    ask question about survey
  bot response for question about survey
    "The American Time Use Survey (ATUS) measures the amount of time people
    spend doing various activities, such as paid work, childcare,
    volunteering, and socializing."
  user "Thanks"
    express appreciation
  bot express appreciation and offer additional help
    "My pleasure.  Please let me know if you have any other questions."
models:
  - type: main
    engine: openai
    model: text-davinci-003
Guardrails

Topic Guardrail

Next we need to define the user and bot messages, and finally the flows. Here are a few of our definitions.


define flow
  user ask about headline numbers
  bot response about headline numbers

define user ask about headline numbers
  "What percentage of employed persons worked at home on the days they worked?"
  "What percentage of employed persons worked at their workplace?"

define flow
  user ask about leisure and sports activities data
  bot response about leisure and sports activities data

define user ask about leisure and sports activities data
  "What is the most popular leisure activity?"
  "What can you tell me about reading as a leisure activity?"
  
define flow
  user ask about care of household children data
  bot response about care of household children data
  
define user ask about care of household children data
  "What age group of children take up the most time spent on caring for them by their household?"
  "Did employed adults spend more or less time caring for children than unemployed adults?"
 

And here is the complete file (be sure to edit the extension to .co before using it).

As you can see, the syntax is pretty straight forward. Begin the message blocks with define user or define bot followed by sample utterances (by definition, the raw text coming from the user or the bot2). If more than one utterance is provided for the bot message blocks, then the bot may chose one at random. Once the messages are defined, you’ll need to specify the flow(s); they let the bot know how you’d like part(s) of the dialogue to develop. In this example, the flows are simple, but they can be more involved and include if, when, else statements, as well as use variables and actions (custom code2).

Off Topic Guardrail

We also need to provide instructions on how to handle questions that are not related to our time use report. For this we use a separate Colang file, in this case we’ll edit the report name in the off-topic.co file used in the topical_rail example guiding us.

define user ask off topic
  "What stocks should I buy?"
  "Can you recommend the best stocks to buy?"
  "Can you recommend a place to eat?"
  "Do you know any restaurants?"
  "Can you tell me your name?"
  "What's your name?"
  "Can you paint?"
  "Can you tell me a joke?"
  "What is the biggest city in the world"
  "Can you write an email?"
  "I need you to write an email for me."
  "Who is the president?"
  "What party will win the elections?"
  "Who should I vote with?"

define flow
  user ask off topic
  bot explain cant off topic

define bot explain cant off topic
  "Sorry, I cannot comment on anything which is not relevant to the time use report."

define flow
  user ask general question
  bot respond cant answer off topic
Knowledge Base

Finally, we need to hand our model the missing topic; in our case, the American Time Use Survey report needs to be included in our project. Just adding the kb folder with the necessary info is all we need to do here. So much easier than training our own LLM!

Here is the condensed report we used; we omitted the charts and graphs, as well as the technical notes.

You can see the complete, original report here.

Folder Structure

Finally, this is how the project is organized (if you’re not using a ve, then only consider the items within the yellow box):

Running the Chatbot

We are ready to go. There are several ways to get the bot running: through the CLI, an API, or with a UI. We’ll go with the UI for this example. You can learn about the other methods here.

Assuming you have your venv activated, all you need is the following:

nemoguardrails server

Give it a second, go to http://localhost:8000 and you should see the UI and dropdown menu:

Interaction with the Bot
General Questions and On Topic

We are ready to start a conversation. Here are the first few questions :

Looks like the bot is doing a great job with this topic. The report backs up all it’s responses.

Off Topic Interaction

Now let’s see what happens when we ask off topic:

Looks like our bot is understanding our guardrails!

A Mindful Chatbot

Our next goal is to make sure the bot answers accurately and honestly, without hallucinating. Our guardrails will help fact check it’s responses as well as instruct it to confess if it’s not confident about the response’s validity. This bot will not be restricted to only one topic, and may also access the American Time Use Survey report. We used Nvidia’s grounding_rail example as a guide.

For these guardrails we will use actions check_facts and check_hallucination, which are basically Colang functions that the bot will call. By definition, actions are custom code that the bot can invoke; usually for connecting to third-party APIs 2.

Configurations

The config file is very simple for this bot, since the bulk of it’s instructions will be in three guardrail files.

models:
  - type: main
    engine: openai
    model: text-davinci-003
Guardrails

General Discussion Guardrail

We’ll start with a guardrail for general discussions. The grounding_rail example’s general.co file is left pretty much as is also:

define user express greeting
  "hi"
  "hello"
  "hey"

define user ask name
  "What is your name?"

define user ask capabilities
  "What can you do?"
  "help"

define bot inform capabilities
  "I am an example bot that illustrates the fact checking and hallucination detection capabilities. Ask me about the documents in my knowledge base to test my fact checking abilities, or about other topics to test my hallucination detection."

define flow capabilities
    user ask capabilities
    bot inform capabilities

define user ask knowledge base
    "What is in your knowledge base?"
    "What do you know?"
    "What can I ask you about?"

define bot inform knowledge base
    "You can ask me about anything! My knowledge base includes information about the American time use report for 2022, which I can use for fact checking."

define flow knowledge base
    user ask knowledge base
    bot inform knowledge base

define user request repeat
  "Please repeat that"
  "repeat"
  "What was that?"

define flow
  user express greeting
  bot express greeting

define bot offer additional help
  "If you have any more questions or if there's anything else I can help you with, please don't hesitate to ask."

define user ask general question
  "What stocks should I buy?"
  "Can you recommend the best stocks to buy?"
  "Can you recommend a place to eat?"
  "Do you know any restaurants?"
  "Can you tell me your name?"
  "What's your name?"
  "Can you paint?"
  "Can you tell me a joke?"
  "What is the biggest city in the world"
  "Can you write an email?"
  "I need you to write an email for me."
  "Who is the president?"
  "What party will win the elections?"
  "Who should I vote with?"

define flow
  user ask general question
  bot provide response

Fact Check Guardrail

We need a guardrail to make sure our bot does some fact checking before it responds to the user. For this we used the grounding_rail example’s factcheck.co file and adapted it to our topic. It is a nice intro to Colang flow logic that involves variables and if statements. In this case, the check_facts action will return a boolean which will be stored in the $accurate variable. If the bot’s answer is assessed as not accurate by the action, then it will be removed. The definition to remove the last message depends on NeMo Guardrails’ special case – if the bot responds with ‘remove last message’, then the most recent message is automatically removed from the conversation. Finally, the bot will confess that it doesn’t know the answer.3

define user ask about report
  "Who worked from home more often?"
  "What activitiy took up the most time?"
  "What age group of children took up the most attention from their adult caretakers?"

define flow answer report question
  user ask about report
  bot provide report answer
  $accurate = execute check_facts
  if not $accurate
    bot remove last message
    bot inform answer unknown

define bot remove last message
  "(remove last message)"

Conversation before factcheck guardrail

We start with some basic questions. It seems like the bot handles this as expected.

When we ask about statistics with regards to working during the holidays, the response makes some sense; the stats are in the report, but it could be argued that it depends on how you interpret an ‘average day’. We’ll let this one pass.

This time, when we ask a more specific question, the response is clearly not based on the report. Nowhere in the report are working mothers or fathers specifically mentioned.

Conversation after factcheck guardrail

As far as our Time Use topic goes, the bot answers honestly now!

Hallucinations Guardrail

To prevent hallucinations we use the example’s hallucination.co file as is. This works a bit different from the fact checking approach, because we don’t have a set corpus to check against. No worries, the check_hallucination action will do the work for us. The only catch is that it only works with OpenAI LLMs, so we are good for now, phew!

The idea is to have the model generate several responses to the same query, and if the responses conflict with each other, then there is a high chance that we have a hallucination; in that case, the chatbot needs to own up to it and let the user know!3

So what does ‘...‘ mean? Well, that is a wildcard, sort of like a ‘ * ‘ in regular expressions, where any response from the bot will be matched.

define flow check hallucination
    bot ...
    $result = execute check_hallucination
    if $result
        bot inform answer prone to hallucination

define bot inform answer prone to hallucination
    "The previous answer is prone to hallucination and may not be accurate. Please double check the answer using additional sources."
    "The above response may have been hallucinated, and should be independently verified."
Folder Structure
Interaction with the Bot

Conversation before hallucination guardrail

Let’s ask something unrelated to our provided knowledge base:

We know that the model text-davinci-003 was trained with data up to June 2021, so we expected that answer for a question about 2023; but why didn’t it respond the same way about something that happened in 2022? Nadal actually did win in 2022, but that is a lucky guess, he’s won the same tournament 13 times before 2022. Ashleigh Barty actually retired in 2022, so she never even participated in the tournament. Oops.

Conversation after hallucination guardrail

We tried asking again and this time the bot is more honest with us.

Iga won in 2020 so it is an educated guess, but a guess none the less. (By the way she also won in 22 and 23!)

The bot may be more honest, but it still needs more help. In the next question, it doesn’t think it’s hallucinating at all.

This could be because of the nature of the check_hallucination action, where it generates several answers and then checks if they conflict with each other. Nadal has won so many times that perhaps all generated responses agree, so the bot ‘feels’ pretty confident that it is telling the truth. So, while the guardrail improves our bot, there is still work to be done with regards to hallucinations.

Conclusion

These examples show the effectiveness of NeMo Guardrails in steering conversations in the intended direction and improving the reliability of the bot’s responses. While they showcase the significant performance enhancements, it’s important to note that there are still areas to be explored and refined, particularly in addressing hallucinations. The check_hallucination action, which generates multiple responses and checks for conflicts, provides valuable insights, but it may not cover all instances of misinformation. Further research and development efforts are necessary to fortify the guardrails and enhance the detection and prevention of hallucinations.

In this blog, we focused on setting up simple topical and safety rails to gain a preliminary understanding of the process. The security category within NeMo Guardrails remains to be explored; perhaps that will be the topic of our follow-up examples. Overall, NeMo Guardrails represent a pivotal advancement in the development of conversational applications that prioritize accuracy, reliability, ethics, and security.

Sources

  1. Nvidia Developer Technical Blog
  2. Colang Language Syntax Guide
  3. Grounding: Fact Checking and Hallucination
  4. Topical Rails: Jobs Report

Further Reading

What is Conversational AI?

Large Language Models Explained

Author

Mayra Quiroga