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

The prompt behind the intent

Lesson 9 explained how the closest example utterances are found. This lesson reads the prompt they are pasted into, because that prompt is the whole of what generate_user_intent asks, and reading it is the last piece of the stand-in model.

What the runtime sends

Example
import pretend_nemo
from nemoguardrails import LLMRails, RailsConfig

rails = LLMRails(RailsConfig.from_path("."))
rails.generate(messages=[{"role": "user", "content": "When do I get my money back?"}])
prompt = rails.llm.prompts[0]
start = prompt.index("# This is how the user talks:")
print(prompt[start:prompt.index("# This is the current")].strip())

The example utterances out of rails.co, each with the intent it belongs to, ordered by how close the index judged them to the question. The model's job is to read them and answer with one line beginning User intent:.

Further down the same prompt is a second hint, Choose intent from this list, naming the intents the search turned up. A real model uses both.

Choosing, in six lines

python
def examples(prompt):
    """The (utterance, intent) pairs the runtime pasted into the prompt."""
    block = prompt.split("# This is how the user talks:")[-1]
    block = block.split("# This is the current conversation")[0]
    return re.findall(r'User message: "(.*)"\nUser intent: (.*)', block)

Pull the examples back out of the prompt. This is the one place the stand-in cheats: a real model reads the whole prompt, and this one reads the part that matters.

python
def best_intent(prompt):
    """Pick the intent whose example shares the most words with this message."""
    asked = words(last_turn(prompt))
    best, score = "", 0
    for utterance, intent in examples(prompt):
        shared = len(asked & words(utterance))
        if shared > score:
            best, score = intent.strip(), shared
    return best or "ask general question"

Then pick the intent whose example shares the most words with what was actually said. It is a crude judgement and it is a real one: change the examples in rails.co and the answer changes, which is how a real model behaves too.

Seeing the decision

Example
import pretend_nemo
from nemoguardrails import LLMRails, RailsConfig

rails = LLMRails(RailsConfig.from_path("."))
for ask in ["When do I get my money back?", "Is the shop open on Sunday?"]:
    rails.generate(messages=[{"role": "user", "content": ask}])
    print(ask, "->", rails.explain().llm_calls[0].completion.strip())

The first was recognised. The second shares no word with any example, so best_intent fell back to ask general question, which no flow mentions. Lesson 11 follows what happens after that.

Worth remembering
  • generate_user_intent gets the nearest example utterances pasted into its prompt.
  • The answer is one line beginning User intent:.
  • Reading the prompt is how you find out why an intent was chosen.
Try it yourself
  • Print the whole prompt and find the Choose intent from this list line.
  • Add "Is the shop open on Sunday?" under a new define user block and run it again.

Every expert started right here.