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

define user and define bot

define user names a user intent and lists example messages for it, and define bot names a bot intent and gives the exact words the bot says for it; both live in a Colang .co file.

Last updated: 30 Sep, 2026 · NeMo Guardrails 0.24.1

The model answered everything its instructions allowed, and rails.explain() showed a single general call. Colang is how you tell NeMo what users say and what the bot says back.

Colang: define user and define bot · from The Complete AI Security Course In 8 Hours · 39:17 to 43:53

The clip calls Colang an expression language that sits between natural language and a programming language. A Colang file uses a few keywords: define, user, bot and flow. The video defines a user who goes off topic, with examples such as how to make a coffee and tell me a joke, and a bot that refuses off topic. The words after define user and define bot are names you choose.

Syntax:

text
define user ask off topic       # a user intent: a name you choose
  "tell me a joke"              # example messages, one per line
  "write me a poem"

define bot refuse off topic     # a bot intent
  "I'm an Enterprise IT ..."    # the exact words the bot says

The user intent from the video

Eight examples of going off topic, from the video's demo app, as they appear on screen in the clip.

text
define user ask off topic
  "tell me a joke"
  "what is the capital of france"
  "write me a poem"
  "what is 2 plus 2"
  "what should I eat for dinner"
  "who won the game yesterday"
  "recommend a movie"
  "what is the weather like"

The bot intent

text
define bot refuse off topic
  "I'm an Enterprise IT Assistant focused on Kubernetes, Intel hardware, and networking. I can't help with that — but ask me anything technical!"

Two files the Colang lessons need

From here on, the folder has two more files. Both exist because of how this course runs NeMo, and each has a lesson of its own.

config.py: the example search

NeMo compares every message with your examples. By default it does that with a local embedding model that it downloads on first use. This config.py registers a search that hands the model every example instead, so nothing is downloaded. The Embedding model lesson explains it.

python
from nemoguardrails.embeddings.index import EmbeddingsIndex


class EveryExample(EmbeddingsIndex):
    """Hands the model every example instead of the closest few."""

    def __init__(self, **kwargs):
        self.items = []

    async def add_items(self, items):
        self.items.extend(items)

    async def build(self):
        pass

    async def search(self, text, max_results=5, threshold=None):
        return self.items


def init(app):
    app.register_embedding_search_provider("every_example", EveryExample)
yaml
core:
  embedding_search_provider:
    name: every_example

prompts.yml: the intent prompt

NeMo asks the model which intent a message has. gpt-oss-120b needs one extra line in that prompt, or it answers the user instead of naming the intent. The The prompt behind the intent lesson shows the bug and the fix.

yaml
prompts:
  - task: generate_user_intent
    content: |-
      """
      {{ general_instructions }}
      """

      # This is how a conversation between a user and the bot can go:
      {{ sample_conversation | verbose_v1 }}

      # This is how the user talks:
      {{ examples | verbose_v1 }}

      # This is the current conversation between the user and the bot:
      {{ sample_conversation | first_turns(2) | verbose_v1 }}
      {{ history | colang | verbose_v1 }}

      Do not answer the user. Reply with one line: the user intent of the last message.
      Use an intent from the examples when one fits, otherwise write a new short intent.
    output_parser: verbose_v1
Project files used on this pageThis lesson builds on a project from earlier lessons. The code below imports this file. Click a file to see its code, or follow the link to the lesson that wrote it. To run the code yourself, keep it in the same folder.
View the code here
config.yml
models:
  - type: main
    engine: openai
    model: openai/gpt-oss-120b
    api_key_env_var: GROQ_API_KEY
    parameters:
      base_url: https://api.groq.com/openai/v1
      temperature: 0

instructions:
  - type: general
    content: |
      You are an Enterprise IT Assistant specialising in Kubernetes,
      Intel hardware, and enterprise networking.
      Only answer questions about these topics.
      Answer in one or two short sentences.

core:
  embedding_search_provider:
    name: every_example

Sending an off-topic message

ExampleAPI key
from nemoguardrails import LLMRails, RailsConfig

rails = LLMRails(RailsConfig.from_path("."))


def chat(message):
    reply = rails.generate(messages=[{"role": "user", "content": message}])
    print("User:", message)
    print("Bot :", reply["content"])

chat("Tell me a funny joke!")
print(rails.explain().colang_history)

What the two definitions did

  • The intent was recognised: the history shows ask off topic under the user's message.
  • The bot intent was not used. The next line is bot general response: nothing says that refuse off topic follows ask off topic, so the model wrote a reply itself, borrowing the words it had seen.
  • What joins them is a flow, the next lesson.

define user vs define bot

define userdefine bot
NamesWhat the user meansWhat the bot says
Lines under itExamples, matched by meaningThe exact reply, sent word for word
Used byIntent detectionFlows

Where you write these

  • Every topic you want to refuse, every jailbreak pattern, every greeting: the video writes one pair for each.
  • Questions your team answers the same way every time.
Watch out. Indentation matters. The example lines under define user are indented by two spaces; without the indent they are read as new statements and the file fails to load.
Try it yourself
  • Add "how to make a coffee", the video's first example, to ask off topic.
  • Remove the two-space indent from one example and read the load error.

Slow is fine. Stopping is the only problem.