rails.output.flows
An input rail checks the message on the way in. An output rail checks the reply after it has been written and before it reaches the user, which is the last chance to stop something going out.
self check output
rails:
output:
flows:
- self check output
prompts:
- task: self_check_output
content: |
Blocked topics: staff20
Message: "{{ bot_response }}"
Answer Yes if the message is about a blocked topic, No otherwise.The same shape as self check input in lesson 13, one key over. rails.output.flows lists the flows to run on every reply, and the self_check_output task gets the reply as {{ bot_response }} instead of the user's message. The flow reads the model's answer with the rule from lesson 14: Yes blocks, No allows.
A reply that is stopped
import pretend_nemo
from nemoguardrails import LLMRails, RailsConfig
rails = LLMRails(RailsConfig.from_path("."))
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, "llm_calls": True}})
print(result.response[0]["content"])
for rail in result.log.activated_rails:
print(rail.type, "|", rail.name, "| stop:", rail.stop)say made the model write a reply that gives away a staff code. The runtime produced that reply through the three dialog steps from lesson 12, then ran the output rail on it, and the rail stopped the turn. The user saw the refusal, not the code.
What an output rail costs
import pretend_nemo
from nemoguardrails import LLMRails, RailsConfig
rails = LLMRails(RailsConfig.from_path("."))
rails.llm.say('Bot message: "Paris is the capital of France."', task="generate_bot_message")
result = rails.generate(messages=[{"role": "user", "content": "What is the capital of France?"}], options={"log": {"activated_rails": True, "llm_calls": True}})
print(result.response[0]["content"])
print([call.task for call in result.log.llm_calls])A harmless reply goes through, and the log shows why it costs more than it did: a fourth model call, self_check_output, after the three that wrote the reply. Every reply checked this way is one more request to the model.
- Change the
saysentence so it mentionsstaff20in lower case and run the first example again. - Put
self check inputfrom lesson 13 in the same config and count the model calls for one message. - Print
rails.llm.prompts[-1]and find where the reply was pasted into the prompt.
Little by little, you're building something great.