Multimodal Data with NeMo Guardrails#
About Working with Multimodal Data#
NeMo Guardrails toolkit supports adding safety checks to multimodal content—images and text. The support is for input and output guardrails only. Depending on the image reasoning model, you can specify the image to check as a base64 encoded data or as a URL.
The safety check uses the image reasoning model as LLM as-a-judge to determine if the content is safe. The OpenAI, Llama Vision, and Llama Guard models can accept multimodal input and act as a judge model.
You must ensure the image size and prompt length do not exceed the maximum context length of the model.
Sample Configuration#
Create a directory, such as
configs/content_safety_vision
, and add aconfig.yml
file with the following content:models: - type: main engine: openai model: gpt-4o-mini - type: vision_rails engine: openai model: gpt-4o-mini rails: input: flows: - content safety check input $model=vision_rails dialog: single_call: enabled: False
Add a
configs/content_safety_vision/prompts.yml
file with the following content:prompts: - task: content_safety_check_input $model=vision_rails messages: - type: system content: | You are an AI assistant that evaluates if a user's message contains unsafe content. Carefully examine any text and images in the user's message. {%- if categories is not defined -%} {%- set categories = { "S1": "Violent Crimes.", "S2": "Non-Violent Crimes.", "S3": "Sex Crimes.", "S4": "Child Exploitation.", "S5": "Defamation.", "S6": "Specialized Advice.", "S7": "Privacy.", "S8": "Intellectual Property.", "S10": "Hate.", "S11": "Self-Harm.", "S12": "Sexual Content.", "S13": "Elections." } -%} {%- endif -%} Task: Check if there is unsafe content in "User" messages in conversations according to our safety policy with the below categories. <BEGIN UNSAFE CONTENT CATEGORIES> {%- for key, desc in categories.items() -%} {%- if key not in excluded_category_keys -%} {{ key }}: {{ desc }} {%- endif -%} {%- endfor -%} <END UNSAFE CONTENT CATEGORIES> IMPORTANT: Provide your safety assessment for the user message: - First line must read 'safe' or 'unsafe' and nothing more - If unsafe, a second line must include a comma-separated list of violated categories. - type: user content: "{{ user_input }}" stop: ["<|eot_id|>", "<|eom_id|>"] output_parser: is_content_safe max_tokens: 200
Example#
The following sample code uses the preceding configuration and sends requests to OpenAI endpoints. The sample image is a handgun.
Set the OpenAI environment variable with your token:
export OPENAI_API_KEY=<api-key>
Import required libraries:
import base64 import io import json import urllib.request import requests
Load the vision content safety configuration:
from nemoguardrails import RailsConfig from nemoguardrails.rails.llm.llmrails import LLMRails config = RailsConfig.from_path("./config/") rails = LLMRails(config, verbose=False)
Send an image reasoning request:
image_reasoning_message = [{ "role": "user", "content": [{ "type": "text", "text": "What is the surface color that the object is placed on?", }, { "type": "image_url", "image_url": { "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/SIG_Pro_by_Augustas_Didzgalvis.jpg/320px-SIG_Pro_by_Augustas_Didzgalvis.jpg" }, }], }] reasoning_response = rails.generate(messages=image_reasoning_message) print(f"Image Reasoning Response: {reasoning_response}") print(json.dumps(reasoning_response, indent=2))
Send a potentially unsafe request:
potentially_unsafe_message = [{ "role": "user", "content": [{ "type": "text", "text": "How can I use the item in the photo to get a higher salary without working hard?", }, { "type": "image_url", "image_url": { "url": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/SIG_Pro_by_Augustas_Didzgalvis.jpg/320px-SIG_Pro_by_Augustas_Didzgalvis.jpg" }, }], }] potentially_unsafe_response = rails.generate(messages=potentially_unsafe_message) print(f"Potentially Unsafe Response: {potentially_unsafe_response}") print(json.dumps(potentially_unsafe_response, indent=2))
Tips for Base 64 Encoded Images#
Some models, such as the Llama Vision models, do not read an image from a URL. For these models, encode the image in base 64 and provide the encoded image to the model.
The following code sample shows the common Python statements.
import base64
import json
from nemoguardrails import RailsConfig
from nemoguardrails.rails.llm.llmrails import LLMRails
config = RailsConfig.from_path("./content_safety_vision")
rails = LLMRails(config)
with open("<path-to-image>", "rb") as image_file:
base64_image = base64.b64encode(image_file.read()).decode()
messages = [{
"role": "user",
"content": [
{
"type": "text",
"text": "what is the surface color that the object is placed on?",
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
},
},
],
}]
response = rails.generate(messages=messages)
print(json.dumps(response, indent=2))