So you just saw how you can build a guardrail to prevent a very simple problem, which is the mention of a forbidden word. Now let's extend that and build a much more sophisticated Guardrail that tackles one of the biggest problems of modern generative AI systems, which is hallucinations. In your pizza shop chatbot now, let's start by building the validator that actually detects these hallucinations in responses to customer questions. We've seen a lot of examples and use headlines of how hallucinations really harm the safety and effective use of generative AI. So, for example, some issues here with, you know, the ChatGPT lawyer that was very famous, lawsuits from various politicians. Fines to large enterprises, etc. And in this lesson, we're going to go back to that example of our chatbot failing on a hallucination. So you saw this in our first lesson. But I'm just going to recap your memory where we have the exact same system message vector database and unguarded client and we use all of this to set up our RAG chat widget. Let's look at how his chatbot does. When I ask a question about, you know, how I reproduce a recipe and then we saw that it hallucinated a recipe that just didn't exist in our shared data drive. Okay, so now let's see how we can build a validator that helps mitigate hallucinations. When we talk about hallucinations and mitigating hallucinations, we mean hallucinations specifically in the context of groundedness, which is when you have some sources that you, as an organization or as a developer can trust are, you know, truthful. And you can use them to truthfully respond to any questions that come in. And once you have these sources, how, faithful is your LLM within your RAG chatbot being to these sources that you talked about? NLI models are essentially checks of how faithful some text is given some higher-level context. So the core idea with NLI entailment is, you know, the premise and hypothesis. Premise as it sounds like some context you can really trust. And hypotheses, are some statements that might be related to the premise. Both of these act as inputs to the NLI model and the NLI model is basically a classifier that predicts that, given the premise to be true. How likely is it that the hypothesis is entailed? That is, the hypothesis is truthful or faithful to the premise? How likely is it that the hypothesis is contradictory or is not entailed from the premise? And how likely is it that the hypothesis is neutral? So that is the core idea behind NLI entailment, and we are going to use this to detect if our language model is being truthful to the sources in our vector database. So, to carry out natural language inference, you're going to import some additional machine learning libraries. Nltk which includes tools for natural language processing, the sentence transformer embedding model and the pipeline from HuggingFace transformers. Additionally, you'll import the various guardrails, classes, and functions that you saw in the previous lesson to allow you to build a guardrail that uses that NLI model. So let's set up our NLI model, and you're going to be using HuggingFace to do this. The NLI model you'll be using is the fine-tuned NLI provenance model, which is uploaded to the Guardrails AI HuggingFace organization. And then we're going to create a HuggingFace pipeline out of this model. So all this model does is set up some much-needed boilerplate to be able to use this model really easily. When you run this in the notebook, it will take a few seconds to download and set up the model weights. So you may want to pause the video here. Now we have our local NLI model set up within a pipeline. We can take this pipeline out for a little spin and see how it performs. So let's try it on a sentence that should be entailed. So I am going to paste in for my first example here the premise "sun rises in the East sets in the west." And then a hypothesis that is entailed from this premise, which is, you know, "the sunrise in the East." And now let's see what my NLI pipeline has to say for this. And I'm just going to add pretty print here. So let me try running this on my pipeline. Awesome. This was my premise, my hypothesis. And the result is entailment with a very high score of 0.869. Now let's look at a contradictory sentence. So the only difference between these, is in the hypothesis, where the hypothesis is now from the same premise "is the sun rises in the west." Let's look at what our NLI pipeline has to say about this. And running our model in the background, we get contradiction as our label once again with a very high score of 0.864. And so we're getting the hang of how our NLI pipeline works. And what we can do here is use this as the building block of our hallucination detection validator. So what do we need to do first is actually situate this NLI model within a broader system, where that system makes sure that our LLM output as well as the sources within our vector database, are in the right format so that they can be consumed by this NLI model. So what I have here is of high level description of how this NLI is going to work. I'm going to go into this in much more detail step by step. But on a very high level, what we're doing is like chunking and splitting up the sources of information that we get both in our LLM output as well as in our vector database, and then passing those pairwise chunks to our NLI model, where if we get entail, then the LLM. output isn't hallucinated. And if it's contradictory, then it negates whatever information is present in our sources and therefore is hallucinated. All right. So with that out of the way, let's start building our hallucination validator. This is a very complex validator with, you know, many moving pieces as we. Saw in the diagram. So what we're going to end up doing. Is like build this step by step. All we've done is set up the validate class same as we did for our previous example. And both of these are just stubs right now. The second thing we need to do is implement sentence chunking. When we get our LLM output, which is composed of many sentences and might even be many paragraphs when we're validating it for groundedness, we validate it on a sentence-by-sentence level. And so what we need to do is split up our LLM output into individual components sentences as we see here. So what I'm going to do is I'm just going to copy-paste this here. In our next cell and then add this additional function which I'm going to call sentence splitter. This function basically takes in some text and uses the NLTK sentence tokenizer to return a list of strings. And then my validate Function is the main function where I implement the logic of my validator. So all I'm doing within my validate function is splitting the text into sentences as I see here. And then passing. Okay, so now that I have each individual sentence available to me, what I want to do next is see if that sentence is grounded in the sources that are relevant to that sentence. And for that, the first thing I want to do is find what my relevant sources are. So as part of that, I am going to add in this additional function to this class, which I am going to call find relevant sources. And what this function does is it embeds both our source sentences as well as our LLM generated sentences. I use the same embedding model. This is key that we use the exact same embedding model to embed both my document sources as well as my LLM generated sentences. And then I iterate over each sentence, compute the cosine similarity between my sentence embedding and all of my source embeddings. I sort my cosine similarities. And then I pick my top five. And then once I have that, I then keep track of what are the five most relevant sources for each sentence. Once I've implemented this function, we go back to our validate function and I am going to add in a call to our find relevant sources function in our validator. Where I pass in the sentences that we split in our last step, the sources that are relevant for those sentences. And then move on to the next step. Our final step in building our validator is to figure out if the five most relevant sources for each sentence do in fact, entail. Or prove whatever is stated in the sentence. What we're going to end up doing here is to take our relevant sources as the premise. We take each sentence as our hypotheses, which may be entailed or contradictory from our relevant sources. And we use our NLI model to make a determination of groundedness or not. And since we'd already set up our pipeline earlier, this is actually going to be a pretty straightforward function, which we're going to call check entailment. So this function basically takes in one sentence. This is the LLM output sentence. And it takes a list of sources that are relevant for that sentence. And this function returns a boolean. Where it's basically true if the NLI pipeline predicts a true label. Or entailed label, and false if the NLI pipeline predicts either contradictory or neutral. Now that we have our check entailment function, let us go back to our validate logic and validate function. And the last thing we did here was find a set of relevant sources per sentence. Now what we end up doing, is iterate over each sentence that we have and see if it is entailed, right? So we pass in each sentence, as well as a list of relevant sources into the check entailment function that we just implemented. If we get a false value back, then we add this specific sentence to our list of hallucinated sentences. Otherwise, we add the sentence to our list of entailed sentences. Before we can stop here, we add our final logic check to our validator, where if we have any hallucinated sentences, we return a fail result. As we've seen in our last example. Otherwise, we return a pass result. The final thing we need to do before we can use this validator, is to make sure that all of the sources, the embedding model, and the entailment model that we're using is all accessible within our class. So this is really, really straightforward. We first update the arguments that the init function can take. Where we make some space here for the embedding model. The sources. And the entailment model. And then, we're going to make sure that all of these three arguments that we've passed in are accessible to all functions of our class. By making them class variables. So what this looks like is making a self dot embedding model. That is basically a sentence transformers initialized model using the model called All-MiniLM-L6-V2. This is a very small but very mighty embedding model that does really well on a bunch of leaderboards. Self dot sources equals sources, and then self dot NLI pipeline, which is our initialize pipeline, basically initialized from the entailment model that we passed in. Okay so you built up this really great validator. How can you check that it's actually working? You can try out the validator by instantiating the hallucination validator class and passing in some source text as you see in this line of code. Then, you can pass the hallucination validator some text that you validate. The same as what we saw above, and then capture and print the result. As you can see, the validator returns a failure here because the text isn't entailed. Great. So the validator is working. Now let's go on to the next lesson to see how to wrap it in a guard. And then use it to test for hallucinations within the chatbot.