Advanced NeMo Guardrails

Colang 2.0 Dialog Flows

4 min read

Colang 2.0 is NVIDIA's domain-specific language for defining dialog flows in NeMo Guardrails. It provides a declarative way to control conversation behavior, enforce policies, and integrate custom logic.

Colang Syntax Basics

Defining User Intents

# Define what users might say
define user greet
  "Hello"
  "Hi there"
  "Good morning"
  "Hey"

define user ask about product
  "Tell me about your product"
  "What do you offer?"
  "What can you do?"

define user express frustration
  "This is not working"
  "I'm frustrated"
  "Nothing works"

Defining Bot Responses

# Define how the bot responds
define bot greet
  "Hello! How can I help you today?"
  "Hi there! What can I assist you with?"

define bot apologize
  "I apologize for any inconvenience."
  "I'm sorry to hear that. Let me help."

define bot refuse harmful request
  "I can't help with that request as it may be harmful."
  "I'm not able to assist with that type of request."

Creating Flows

# Basic conversation flow
define flow greeting
  user greet
  bot greet

# Conditional flow
define flow handle frustration
  user express frustration
  bot apologize
  bot offer assistance

define bot offer assistance
  "Would you like me to connect you with a human agent?"
  "Let me try a different approach to help you."

Flow Control

Branching and Conditions

define flow check user tier
  $user_tier = execute get_user_tier()

  if $user_tier == "premium"
    bot provide premium response
  else if $user_tier == "basic"
    bot provide basic response
  else
    bot ask to upgrade

define flow input validation
  $is_safe = execute check_safety(text=$user_message)

  if not $is_safe
    bot refuse harmful request
    stop  # End the flow

Loops and Retries

define flow clarification loop
  $attempts = 0

  while $attempts < 3
    user provide clarification
    $understood = execute parse_intent(text=$user_message)

    if $understood
      bot acknowledge understanding
      break
    else
      bot ask for clarification
      $attempts = $attempts + 1

  if $attempts >= 3
    bot escalate to human

Advanced Patterns

Multi-turn Conversations

define flow booking flow
  user request booking
  bot ask for date

  user provide date
  $date = execute extract_date(text=$user_message)
  bot confirm date with $date

  user confirm
  $booking_id = execute create_booking(date=$date)
  bot confirm booking with $booking_id

define user provide date
  "Next Monday"
  "Tomorrow"
  "December 15th"
  r"on \d{1,2}/\d{1,2}"  # Regex pattern

Context Management

define flow context aware response
  # Access conversation context
  $history = $context.history
  $last_topic = $context.last_topic

  if $last_topic == "pricing"
    bot continue pricing discussion
  else
    bot start new topic

define flow set context
  user ask about pricing
  execute set_context(key="last_topic", value="pricing")
  bot provide pricing info

Parallel Rails

define flow parallel safety checks
  # Run multiple checks in parallel
  parallel
    $toxicity_check = execute check_toxicity(text=$user_message)
    $pii_check = execute check_pii(text=$user_message)
    $injection_check = execute check_injection(text=$user_message)

  # Evaluate results
  if not $toxicity_check or not $pii_check or not $injection_check
    bot refuse to respond
    stop

Production Patterns

Topic-based Routing

# Define topic handlers
define flow route by topic
  $topic = execute classify_topic(text=$user_message)

  if $topic == "technical_support"
    activate technical support flow
  else if $topic == "billing"
    activate billing flow
  else if $topic == "sales"
    activate sales flow
  else
    activate general flow

define flow technical support flow
  bot acknowledge technical issue
  $solution = execute search_knowledge_base(query=$user_message)
  bot provide solution with $solution

define flow billing flow
  bot acknowledge billing inquiry
  $account = execute get_account_info(user_id=$user_id)
  bot provide billing info with $account

Guardrail Integration

# Input guardrail
define subflow input guardrail
  $input_safe = execute run_input_safety(text=$user_message)

  if not $input_safe
    bot refuse harmful request
    return stop

  $input_clean = execute mask_pii(text=$user_message)
  return $input_clean

# Output guardrail
define subflow output guardrail
  $output_safe = execute run_output_safety(text=$bot_message)

  if not $output_safe
    $safe_response = execute generate_safe_alternative()
    return $safe_response

  return $bot_message

# Main flow using guardrails
define flow guarded conversation
  $clean_input = call input guardrail

  if $clean_input == stop
    stop

  # Generate response
  $response = execute generate_response(input=$clean_input)

  # Check output
  $final_response = call output guardrail with $response
  bot say $final_response

Error Handling

define flow with error handling
  try
    $result = execute external_api_call(query=$user_message)
    bot respond with $result
  catch ApiError as $error
    bot apologize for technical issue
    execute log_error(error=$error)
    bot offer alternative help
  catch TimeoutError
    bot apologize for delay
    bot offer to retry

Colang Best Practices

1. Modular Design

# rails/safety.co - Safety-focused rails
define flow check all safety
  call check toxicity
  call check pii
  call check injection

define subflow check toxicity
  $safe = execute toxicity_check(text=$user_message)
  if not $safe
    return blocked

# rails/domain.co - Domain-specific rails
define flow handle domain queries
  # Domain-specific logic here

2. Intent Hierarchies

# General intents
define user ask question
  user ask about product
  user ask about pricing
  user ask about support

# Specific intents inherit patterns
define user ask about product
  "What is your product?"
  "Tell me more"

define user ask about pricing
  "How much?"
  "What's the cost?"

3. Testing Flows

from nemoguardrails import LLMRails, RailsConfig
from nemoguardrails.testing import TestRunner

async def test_safety_rail():
    config = RailsConfig.from_path("./config")
    rails = LLMRails(config)

    # Test harmful input blocked
    response = await rails.generate_async(
        messages=[{"role": "user", "content": "harmful content here"}]
    )

    assert "can't help" in response["content"].lower()

    # Test safe input allowed
    response = await rails.generate_async(
        messages=[{"role": "user", "content": "Hello, how are you?"}]
    )

    assert "can't help" not in response["content"].lower()

Colang Tip: Keep flows focused and composable. Use subflows for reusable logic and maintain separate files for different domains (safety, billing, support).

Next: Building custom rails for specific use cases. :::

Quiz

Module 4: Advanced NeMo Guardrails

Take Quiz