RailOutcome: allow, block, transform
Lesson 18 used two of the three decisions a rail can return. This lesson looks at the object itself, at the third decision, and at the older style it replaced, which still appears in most material you will find online.
Three decisions
from nemoguardrails.actions.rail_outcome import RailOutcome, TransformTarget
print(RailOutcome.allow().decision, RailOutcome.allow().is_blocked)
print(RailOutcome.block(reason="policy").decision, RailOutcome.block().is_blocked)
rewrite = RailOutcome.transform([(TransformTarget.BOT_MESSAGE, "redacted")])
print(rewrite.decision, rewrite.transforms[0].text)allow lets the content through unchanged. block stops it, and the runtime decides how to present that; the outcome itself carries no refusal wording. transform replaces a conversation value, and the three it can replace are the user message, the bot message and the retrieved chunks.
reason and metadata are there for logs and for whatever reads them downstream. The documentation is explicit that metadata must not be load-bearing: code deciding what to do should read decision or is_blocked.
What it replaced
from nemoguardrails.actions import action
try:
@action(output_mapping=lambda value: not value)
async def old_style():
return True
except TypeError as error:
print("TypeError:", error)Older versions let an action return a boolean or a number and told the runtime how to read it with output_mapping. That argument is gone and passing it raises. The runtime no longer guesses a rail decision from a plain value at all.
An action reached through the library's own rail machinery must return a RailOutcome. An ordinary action whose result a flow reads itself, like check_length in lesson 16, may still return anything, because the if in the flow is doing the interpreting.
Which to use
| Your action is | Return |
|---|---|
Read by an if in your own flow | Whatever is convenient: a bool, a string, a number |
| Standing in for a library rail | RailOutcome |
| Rewriting the message rather than refusing it | RailOutcome.transform, or assign in the flow |
Assigning in the flow is the simpler of the two rewrite routes and it is what lesson 22 uses.
allow,blockandtransformare the three decisions.is_blockedis the field a flow reads.output_mappingis removed and raisesTypeError.
- Call
RailOutcome.transform([])and read the error about transforms being non-empty. - Build a block outcome with
metadata={"score": 0.91}and print it.
This is what real progress feels like.