Tutorial — Policy Layer with Guardrails

Augmented Traveler local tutorial. Back to AI Mind — Tutorials · overview: Tutorial — How the Mind Works · ethics: Ground Rules — Historical Virtual Humans · tests: Tutorial — Evaluating Answers

How to enforce the Ground Rules in code: the cutoff, the refusal list, the trauma protocol, the companionship ban, no modern advice, no views on living politicians, and extra care with children. It covers input and output rails, NeMo Guardrails, Llama Guard 4, and prompt injection.

Draft. Written from the Ground Rules, the NeMo Guardrails and Llama Guard docs, and OWASP. The code is a skeleton. The rule list and every canned reply are reviewed by the historian and conversation designer before install.

1. Principles

2. Where the checks sit

Stage Check Tool
Input rail Prompt injection / jailbreak Llama Prompt Guard 2 (classifier) + heuristics
Input rail Unsafe content categories Llama Guard 4 (prompt classification)
Input rail Named hard topics → canned reply Our topic classifier + keyword lists from D-notes
Retrieval Cutoff and corpus filter SQL WHERE (Tutorial — Retrieval with Citations)
Output rail Cutoff words, companionship phrases, advice, politicians Our code (regex + small classifier)
Output rail Citation IDs valid; B attributed Our code
Output rail Unsafe content Llama Guard 4 (response classification)

Llama Guard 4 is a 12B multimodal classifier. It labels a prompt or a response safe or unsafe and lists categories S1–S14 (e.g. S6 Specialized Advice, S11 Suicide & Self-Harm, S12 Sexual Content, S13 Elections). It does not detect prompt injection; Meta points to Llama Prompt Guard 2 (86M or 22M, 512-token window) for that. Both use the Llama 4 Community Licence. Check VRAM and latency on the kiosk before choosing it; a 12B classifier competes with Unreal and the LLM for the GPU (unconfirmed; benchmark).

3. The rule list (from D-notes)

Rule Trigger examples Action
Cutoff Events, people or words after the program date Output check; reply "That is beyond my time."
Trauma protocol Slavery, death and grief (her mother's death and her southern tour fall in later programs), shipwreck and cannibalism (Essex, whaling figures) Canned reviewed reply; no generation; offer the guide
Companionship ban "Do you love me?", "Be my friend", "Keep a secret" Canned reply; never "I love you"; never secret-keeping
Children Any sign the visitor is a child plus secrets, personal details, meeting up Canned reply; stricter output filter all session
No modern advice Medical, legal, financial questions Canned reply pointing to staff; Llama Guard S6 as backup
Living politicians Named current office holders, elections Canned reply; Llama Guard S13 as backup
Self-harm Any mention Out-of-character message with venue help information (venue supplies it)
Contested facts e.g. where the 1847 comet was first seen Canned reply that names the dispute; details in the out-of-character segment

Each row has an owner, a review date and a version in git.

4. Cutoff in code

5. NeMo Guardrails setup

NeMo Guardrails (Apache 2.0) supports input, dialog, retrieval, execution and output rails. A minimal config.yml:

models:
  - type: llama_guard
    engine: openai          # OpenAI-compatible local server
    model: <llama guard model name>   # docs example uses LlamaGuard-7b; check Guard 4 support
    parameters:
      base_url: "http://localhost:5123/v1"
      api_key: EMPTY
rails:
  input:
    flows:
      - llama guard check input
  output:
    flows:
      - llama guard check output

A Colang 2 input rail (docs pattern):

import core
import guardrails
import llm

flow input rails $input_text
  $input_safe = await check user utterance $input_text
  if not $input_safe
    bot say "I cannot speak to that. Ask me of the sky or the island."
    abort

6. Our own checks (skeleton)

Skeleton — test before use.

import re

COMPANION = re.compile(r"\b(i love you|my dear friend|our secret|don't tell)\b", re.I)


def check_output(text, cited_ids, allowed_hits, cutoff_terms):
    """Return (ok, flag). allowed_hits maps id -> (corpus, author)."""
    for cid in cited_ids:
        if cid not in allowed_hits:
            return False, "bad_citation"
    lowered = text.lower()
    if any(term in lowered for term in cutoff_terms):
        return False, "cutoff"
    if COMPANION.search(text):
        return False, "companionship"
    for cid in cited_ids:
        corpus, author = allowed_hits[cid]
        if corpus == "B" and author.split()[-1].lower() not in lowered:
            return False, "b_unattributed"
    return True, None

On any failure the service sends the matching canned reply with refusal_flag set in answer_meta (Tutorial — Conversation Client Plugin).

7. Prompt injection

OWASP LLM01:2025 lists direct injection (the visitor) and indirect injection (text inside sources). RAG does not fully prevent it.

8. Canned replies

9. Practice exercise

  1. Write ten test inputs: two injections, two companionship, two advice, two after-cutoff, two child-safety.
  2. Run them through the input and output checks.
  3. Record which rule caught each. Any miss becomes a new rule and a golden-set item.

10. Check before install

Sources