refrain and filter
Lesson 10's fix assumes a wrong answer can be made right. Sometimes the right move is to send nothing, and Guardrails has two actions for that.
from guardrails import Guard
from guardrails_ai.valid_length import ValidLength
for action in ["noop", "refrain", "filter"]:
desk = Guard().use(ValidLength(min=1, max=20, on_fail=action))
outcome = desk.validate("Order 8821 is running late and arrives Friday.")
print(action, "->", repr(outcome.validated_output))refrain means the answer is not safe to show, so no answer is shown. On a plain string filter does the same thing, which the documentation warns about: filtering is meant for structured output, where it removes only the field that failed. Lesson 18 has an object with fields and picks that up.
Why it is None and not an empty string
The value Guardrails kept internally is not None.
desk = Guard().use(ValidLength(min=1, max=20, on_fail="refrain"))
outcome = desk.validate("Order 8821 is running late and arrives Friday.")
print(repr(outcome.validated_output))
print(repr(desk.history.last.iterations.last.guarded_output))
print(desk.history.last.status)The iteration holds an empty string, which is what refraining produces for a text output. The outcome holds None, because Call.guarded_output returns a value only when the Guard passed or every failure was a noop, and this one was neither.
That rule is worth keeping in mind for the rest of the course. validated_output being None does not tell you what happened; it tells you the Guard is not willing to vouch for anything. The history says which of the reasons applied.
Which one to reach for
- refrain when showing a wrong answer is worse than showing none. A refund promise, a made-up delivery date, a leaked address.
- filter when the answer has parts and only one part is bad. That needs structured output, so it waits for lesson 18.
- exception when your own code should decide. Refraining returns a quiet
Nonethat is easy to pass along by accident.
- Swap
refrainforexceptionand decide which one your support desk should use. Write down why. - Run the loop again with a value that passes and print
validated_outputfor all three actions. - Print
outcome.errorafter a refrain. It isNone, because refusing to answer is not an error.
Little by little, you're building something great.