Changing the answer instead of refusing
Refusing is not the only thing an output rail can do. It can replace the reply with a safer one and let the conversation carry on, by assigning to $bot_message.
Assigning to $bot_message
define flow mask staff codes
$leak = execute has_staff_code
if $leak
$bot_message = "Use the code on your receipt for a staff price."No bot statement and no stop: the flow changes the value the runtime is about to send. Lesson 20 named the other route, an action that returns RailOutcome.transform with TransformTarget.BOT_MESSAGE; assigning in the flow is the shorter of the two when the new text is fixed.
import pretend_nemo
from nemoguardrails import LLMRails, RailsConfig
from config_actions import has_staff_code
rails = LLMRails(RailsConfig.from_path("."))
rails.register_action(has_staff_code, "has_staff_code")
rails.llm.say('Bot message: "Use code STAFF20 for a staff price."', task="generate_bot_message")
result = rails.generate(messages=[{"role": "user", "content": "Any deals for staff?"}],
options={"log": {"activated_rails": True}})
print(result.response[0]["content"])
print([(rail.type, rail.name, rail.stop) for rail in result.log.activated_rails][-1])The user got the replacement sentence, and the output rail is in the log with stop set to False: the turn finished normally, with different words.
Choose between the two on what the user needs next. A refusal ends the exchange. A rewrite keeps it going, which suits a reply that was mostly right and had one thing in it that must not be sent.
- Build the rewritten sentence from part of the original
$bot_messageinstead of a fixed string. - Put
hide staff codesfrom lesson 22 aftermask staff codesin the list and predict which one wins. - Rewrite the action to return
RailOutcome.transformand read the reply the runtime sends.
Slow is fine. Stopping is the only problem.