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 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)

For detailed usage, method signatures, 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 print(f"Response: {response['content']}")
55
56 # Print what happened
57 if hasattr(response, 'log'):
58 response.log.print_summary()
59
60asyncio.run(main())