Core Classes Reference

View as Markdown

This guide covers the two fundamental classes in the NeMo Guardrails library: RailsConfig for loading configurations and LLMRails for generating responses with guardrails.

RailsConfig

The RailsConfig class represents a complete guardrails configuration, including models, rails, flows, prompts, and other settings. This class requires to load the configuration from a directory or a single file you created in the previous chapter About Configuring Guardrails.

Loading Configuration from a Directory

The most common way to load a configuration is from a directory containing config.yml and Colang files:

1from nemoguardrails import RailsConfig
2
3config = RailsConfig.from_path("path/to/config")

Expected directory structure:

config/
├── config.yml # Main configuration file
├── rails/ # Colang flow files
│ ├── input.co
│ ├── output.co
│ └── ...
├── kb/ # Knowledge base documents (optional)
│ └── docs.md
├── actions.py # Custom actions (optional)
└── config.py # Custom initialization (optional)

Loading from a Single File

You can also load from a single YAML file:

1config = RailsConfig.from_path("path/to/config.yml")

Loading from Content

For dynamic configurations or testing, load directly from strings:

1from nemoguardrails import RailsConfig
2
3yaml_content = """
4models:
5 - type: main
6 engine: openai
7 model: gpt-4
8
9instructions:
10 - type: general
11 content: |
12 You are a helpful assistant.
13"""
14
15colang_content = """
16define user express greeting
17 "hello"
18 "hi"
19
20define flow
21 user express greeting
22 bot express greeting
23"""
24
25config = RailsConfig.from_content(
26 yaml_content=yaml_content,
27 colang_content=colang_content
28)

Loading from a Dictionary

You can also provide configuration as a Python dictionary:

1config = RailsConfig.from_content(
2 config={
3 "models": [
4 {"type": "main", "engine": "openai", "model": "gpt-4"}
5 ],
6 "instructions": [
7 {"type": "general", "content": "You are a helpful assistant."}
8 ]
9 }
10)

Combining Configurations

Configurations can be combined using the + operator:

1base_config = RailsConfig.from_path("path/to/base")
2additional_config = RailsConfig.from_path("path/to/additional")
3
4combined_config = base_config + additional_config

This is useful for:

  • Adding rails to a base configuration.
  • Layering environment-specific settings.
  • Combining shared and application-specific configurations.

Key Configuration Properties

PropertyTypeDescription
modelsList[Model]LLM models configuration
instructionsList[Instruction]System instructions for the LLM
sample_conversationstrExample conversation for prompts
railsRailsRails configuration (input, output, dialog, etc.)
flowsList[Dict]Colang flow definitions
promptsList[TaskPrompt]Custom prompts for various tasks
colang_versionstrColang version (“1.0” or “2.x”)

LLMRails

The LLMRails class is the main interface for generating responses with guardrails applied.

Initialization

1from nemoguardrails import LLMRails, RailsConfig
2
3config = RailsConfig.from_path("path/to/config")
4rails = LLMRails(config)

Constructor parameters:

ParameterTypeDescription
configRailsConfigThe rails configuration
llmBaseLLM | BaseChatModelOptional pre-configured LLM (overrides config)
verboseboolEnable verbose logging

Using a Custom LLM

You can provide your own LLM instance:

1from langchain_openai import ChatOpenAI
2from nemoguardrails import LLMRails, RailsConfig
3
4config = RailsConfig.from_path("path/to/config")
5llm = ChatOpenAI(model="gpt-4", temperature=0.7)
6
7rails = LLMRails(config, llm=llm)

When providing an LLM via the constructor, it takes precedence over any main LLM specified in the configuration.

Generating Responses

Using Messages (Chat Format)

1response = rails.generate(messages=[
2 {"role": "user", "content": "Hello! How are you?"}
3])
4print(response["content"])

Using a Prompt (Completion Format)

1response = rails.generate(prompt="Complete this sentence: The sky is")
2print(response)

With Conversation History

1messages = [
2 {"role": "user", "content": "My name is John."},
3 {"role": "assistant", "content": "Hello John! How can I help you?"},
4 {"role": "user", "content": "What's my name?"}
5]
6
7response = rails.generate(messages=messages)
8print(response["content"]) # Should remember the name

Passing Context

You can pass additional context using the context role:

1response = rails.generate(messages=[
2 {
3 "role": "context",
4 "content": {
5 "user_name": "Alice",
6 "user_role": "admin"
7 }
8 },
9 {"role": "user", "content": "What permissions do I have?"}
10])

You can access context variables in Colang flows using $variable_name syntax:

define bot explain permissions
"Hello {$user_name}! As an {$user_role}, you have full system access."

Alternatively, you can access context variables through the context parameter. For example, you can set up an action function that uses a variable extracted from the context parameter as follows:

1@action()
2async def check_permissions(context: Optional[dict] = None):
3 user_role = context.get("user_role")
4 return user_role == "admin"

For detailed information about context variables, see Action Parameters: The Context Parameter and Colang 1.0 Language Syntax: Variables.

Asynchronous Generation

For async contexts, use generate_async:

1import asyncio
2from nemoguardrails import LLMRails, RailsConfig
3
4async def main():
5 config = RailsConfig.from_path("path/to/config")
6 rails = LLMRails(config)
7
8 response = await rails.generate_async(messages=[
9 {"role": "user", "content": "Hello!"}
10 ])
11 print(response["content"])
12
13asyncio.run(main())

Streaming Responses

For real-time token streaming:

1async def stream_response():
2 config = RailsConfig.from_path("path/to/config")
3 rails = LLMRails(config)
4
5 async for chunk in rails.stream_async(messages=[
6 {"role": "user", "content": "Tell me a story."}
7 ]):
8 print(chunk, end="", flush=True)

For detailed streaming configuration, refer to Streaming.

Event-based Generation

For low-level control using events:

1events = rails.generate_events(events=[
2 {
3 "type": "UtteranceUserActionFinished",
4 "final_transcript": "Hello!"
5 }
6])
7
8for event in events:
9 if event["type"] == "StartUtteranceBotAction":
10 print(f"Bot says: {event['script']}")

For detailed event-based API usage, refer to Event-Based API.

Generation Options

Fine-tune generation behavior using the options parameter:

1response = rails.generate(
2 messages=[{"role": "user", "content": "Hello!"}],
3 options={
4 "rails": ["input", "output"], # Only apply these rails
5 "output_vars": ["user_message"], # Return context variables
6 "log": {
7 "activated_rails": True,
8 "llm_calls": True
9 }
10 }
11)

For the message-based call shown above, passing options changes the return type. Without options, generate() returns an OpenAI-style message dictionary that you index with response["content"]. With options, it returns a GenerationResponse object whose message list you read with response.response[0]["content"]. For a prompt-based LLMRails call, the optionless return and GenerationResponse.response are strings instead.

The IORails engine also returns a GenerationResponse when you pass options, but fields that depend on the Colang runtime remain unavailable. output_vars and state raise ValueError. The log.internal_events and log.colang_history options raise NotImplementedError.

For detailed options, refer to Generation Options.


Checking Messages Against Rails

The check_async() and check() methods validate messages against input and output rails without triggering full LLM generation:

1from nemoguardrails.rails.llm.options import RailStatus
2
3result = await rails.check_async([
4 {"role": "user", "content": "Hello! How can I hack into a system?"}
5])
6
7if result.status == RailStatus.BLOCKED:
8 print(f"Input blocked by rail: {result.rail}")

By default, the methods automatically detect which rails to run based on message roles. You can override this with the rail_types parameter:

1from nemoguardrails.rails.llm.options import RailType
2
3result = await rails.check_async(
4 [{"role": "user", "content": "Hello!"}],
5 rail_types=[RailType.INPUT]
6)

The LLMRails and IORails engines both implement these methods, and the Guardrails facade forwards the call to the engine it selected.

For detailed usage, method signatures, engine differences, and examples, refer to Check Messages.


Registering Custom Actions

You can register custom Python functions as actions:

1from nemoguardrails import LLMRails, RailsConfig
2
3async def get_weather(city: str) -> str:
4 """Get weather for a city."""
5 return f"Weather in {city}: Sunny, 22°C"
6
7config = RailsConfig.from_path("path/to/config")
8rails = LLMRails(config)
9
10# Register the action
11rails.register_action(get_weather, name="get_weather")

For detailed action registration, refer to Custom Actions.


Registering Embedding Search Providers

For custom knowledge base search:

1from nemoguardrails import LLMRails, RailsConfig
2from nemoguardrails.embeddings.index import EmbeddingsIndex
3
4class CustomSearchProvider(EmbeddingsIndex):
5 async def search(self, text: str, max_results: int):
6 # Custom search logic
7 pass
8
9config = RailsConfig.from_path("path/to/config")
10rails = LLMRails(config)
11
12# Register the provider
13rails.register_embedding_search_provider("custom", CustomSearchProvider)

Complete Example

1import asyncio
2from nemoguardrails import LLMRails, RailsConfig
3
4async def main():
5 # Load configuration
6 config = RailsConfig.from_content(
7 yaml_content="""
8models:
9 - type: main
10 engine: openai
11 model: gpt-4
12
13rails:
14 input:
15 flows:
16 - self check input
17 output:
18 flows:
19 - self check output
20
21prompts:
22 - task: self_check_input
23 content: |
24 Check if the following is safe: {{ user_input }}
25 Answer (Yes/No):
26 - task: self_check_output
27 content: |
28 Check if the following is safe: {{ bot_response }}
29 Answer (Yes/No):
30""",
31 colang_content="""
32define user express greeting
33 "hello"
34 "hi"
35
36define bot express greeting
37 "Hello! How can I help you today?"
38
39define flow
40 user express greeting
41 bot express greeting
42"""
43 )
44
45 # Create rails instance
46 rails = LLMRails(config, verbose=True)
47
48 # Generate response
49 response = await rails.generate_async(
50 messages=[{"role": "user", "content": "Hello!"}],
51 options={"log": {"activated_rails": True}}
52 )
53
54 # `options` was passed, so `response` is a GenerationResponse
55 print(f"Response: {response.response[0]['content']}")
56
57 # Print what happened
58 if response.log:
59 response.log.print_summary()
60
61asyncio.run(main())