NeMo Guardrailsnemoguardrails 0.24.0 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
20 small wins to finish your pathNext lesson

A stand-in model that decides

The echo model from lesson 4 says one sentence forever, so no rail built on top of it can be interesting. This lesson turns it into a stand-in that reads the question, looks the answer up, and knows which of the runtime's jobs it is doing at the time.

It is still not a language model. It is about forty lines of Python that implement the same interface, which is enough for the runtime to treat it as one. Writing it is the fastest way to learn what a real model is actually asked.

Words, not strings

python
import re

SKIP = {"the", "and", "for", "you", "your", "with", "what", "can", "how", "this",
        "that", "its", "from", "are", "was", "about", "tell", "give", "say"}


def words(text):
    """The words worth comparing, as a set."""
    return {w for w in re.findall(r"[a-z0-9]+", str(text).lower())
            if len(w) > 1 and w not in SKIP}

Comparing sets of words rather than whole strings is what lets the stand-in survive punctuation and word order. SKIP throws away the words that appear in every question and so carry no signal.

python
def handbook_answer(question):
    for word in words(question):
        if word in HANDBOOK:
            return HANDBOOK[word]
    return "I do not have that in the handbook."

The same three-line handbook from lesson 1, reached by word rather than by exact key. Ask about a refund in any phrasing and the refund line comes back.

Which question is this?

A guardrails runtime does not ask a model one kind of question. It asks several, and it names each one. The name is in a context variable the runtime sets before every call.

python
from nemoguardrails.context import llm_call_info_var


def task_name():
    """Which task the runtime is asking about, or None outside a task."""
    info = llm_call_info_var.get()
    return info.task if info else None

llm_call_info_var is a ContextVar. Read it inside generate_async and you know whether the runtime wants a canonical intent, a safety verdict or an answer for the user. The stand-in in this course branches on that name, and the branches arrive in lessons 10 and 13 as the tasks that need them are introduced.

Using it

Example
import pretend_nemo  # registers the engine named "pretend"
from nemoguardrails import LLMRails, RailsConfig

PRETEND_YML = """
models:
  - type: main
    engine: pretend
    model: pretend-1
"""
rails = LLMRails(RailsConfig.from_content(yaml_content=PRETEND_YML))
for ask in ["How long does a refund take?", "Is delivery free?", "Who won the cup?"]:
    print(rails.generate(messages=[{"role": "user", "content": ask}])["content"])

Three different answers, from a model that costs nothing and never leaves the process. pretend_nemo.py holds everything above plus the two branches still to come; importing it is what registers the engine.

It can also be told what to say

Example
rails = LLMRails(RailsConfig.from_content(yaml_content=PRETEND_YML))
rails.llm.say("Everything is on fire.")
print(rails.generate(messages=[{"role": "user", "content": "Is delivery free?"}])["content"])
print(rails.generate(messages=[{"role": "user", "content": "Is delivery free?"}])["content"])

say queues one exact answer, used once. That matters later: a lesson about output rails needs a specific sentence in front of the rail, and guessing at prompts until the model produces it is not a lesson. Everything else still comes from the rules above.

Worth remembering
  • A provider is any object with the five members from lesson 4.
  • llm_call_info_var tells the provider which task it is serving.
  • rails.llm.say(text) queues one exact answer for the next call.
Try it yourself
  • Add a fourth line to HANDBOOK in your own copy and ask about it.
  • Call say twice before one generate and work out which call gets which.
  • Remove "how" from SKIP and see whether any answer changes.

Every expert started right here.