guardrails — Guardrail, GuardrailLibrary, GuardrailEngine
On this page
Injects explicit safety, grounding, and output-quality instructions directly into the prompt. The module's design principle, stated in its docstring: guardrails are prompt instructions that steer generation before it happens, not post-hoc output filters.
Table of contents
Guardrail
@dataclass
class Guardrail:
name: str
instruction: str
priority: int = 50 # higher = injected first
A single named, prioritized instruction string. priority determines render order (descending) when multiple guardrails are combined.
GuardrailLibrary
A namespace class (not instantiated) holding every built-in Guardrail as a class attribute.
SAFE_OUTPUT (110) is the highest-priority guardrail; NO_MARKDOWN_LEAKAGE (30) is the lowest.
GuardrailEngine
GuardrailEngine(extra_guardrails: Optional[List[Guardrail]] = None) -> None
build()
def build(self, request: PromptRequest) -> tuple[str, List[str]]
Selects applicable guardrails, sorts them, deduplicates by name, renders the final instruction block, and returns (block, applied_names).
Internal workflow
_select(request)→ candidateGuardraillist (see Selection logic).- Append
self._extra(constructor-supplied guardrails) — these are always appended regardless ofrequest.enable_guardrails. - Sort descending by
.priority. - Deduplicate by
.name, keeping the first occurrence encountered after sorting (i.e. if a name appears twice with different priorities, the higher-priority instance's position is kept but ties/order among equal-name duplicates follow Python's stable-sort behavior on the pre-sort list order). _render(unique, request)→ the final block string.- Return
(block, [g.name for g in unique]).
_select (internal)
def _select(self, req: PromptRequest) -> List[Guardrail]
Selection rules, in order:
- Always-on (regardless of
enable_guardrails):SAFE_OUTPUT,CONCISE. - If
req.enable_guardrails:req.documentsnon-empty → addGROUNDING,NO_FABRICATIONreq.enable_uncertainty→ addUNCERTAINTYreq.enable_citationsandreq.documentsnon-empty → addCITE_SOURCESreq.prompt_typenot in{AGENT, TOOL_USE}→ addSTAY_ON_TOPIC- always (within this branch) → add
PII_PROTECTION
- Strategy-driven (independent of
enable_guardrails):req.strategyin{CHAIN_OF_THOUGHT, MULTI_HOP, LEAST_TO_MOST}→ addSHOW_REASONING. - Complexity-driven (independent of
enable_guardrails):req.complexityin{COMPLEX, EXPERT}→ addSELF_CHECK.
[!NOTE] Strategy/complexity guardrails apply even with
enable_guardrails=FalseSHOW_REASONINGandSELF_CHECKare added outside theif req.enable_guardrails:block, so settingenable_guardrails=Falsedoes not suppress them — onlyGROUNDING,NO_FABRICATION,UNCERTAINTY,CITE_SOURCES,STAY_ON_TOPIC, andPII_PROTECTIONare gated by that flag.SAFE_OUTPUTandCONCISEare unconditionally always-on.
_render (internal)
def _render(self, guardrails: List[Guardrail], req: PromptRequest) -> str
- Resolves
lang = resolve_lang(req.language)(see templates). - If any guardrails are selected: appends the localized header (
guardrail_header(lang)) then a numbered list, where each guardrail's text is looked up viaguardrail_text(g.name, lang, fallback=g.instruction)— i.e. it prefers a natively-authored bilingual instruction fromtemplatesand falls back to the guardrail's own.instructionstring if no localized version exists for that name/language. - Appends the output-format instruction: first tries
format_instruction_text(req.output_format, lang)(bilingual, fromtemplates.py); if that returnsNone, falls back toself._FORMAT_INSTRUCTIONS.get(req.output_format)(English-only, defined on this class). - If
req.output_schemais set andreq.output_format == OutputFormat.STRUCTURED, appends a JSON-formatted schema block to the format instruction.
_FORMAT_INSTRUCTIONS (English fallback, class attribute):
Parameters
Returns
(instruction_block: str, applied_guardrail_names: List[str]).
Raises
No exceptions raised under normal use.
Side effects
One logger.debug call listing applied guardrail names.
Thread safety
Stateless with respect to self beyond the constructor-fixed _extra list; safe for concurrent read-only use across threads (not explicitly tested).
Examples
1. Basic
from zerda.prompt.guardrails import GuardrailEngine
from zerda.prompt.types import PromptRequest
engine = GuardrailEngine()
block, applied = engine.build(PromptRequest(query="What is RAG?"))
print(applied) # ['safe_output', 'concise'] (no docs -> no grounding-related guardrails)
2. Intermediate — with documents and citations
req = PromptRequest(query="...", documents=[doc1, doc2], enable_citations=True)
block, applied = engine.build(req)
# applied includes 'grounding', 'no_fabrication', 'cite_sources', 'pii_protection', 'stay_on_topic'
3. Advanced — custom extra guardrail
from zerda.prompt.guardrails import Guardrail, GuardrailEngine
no_legal_advice = Guardrail(
name="no_legal_advice",
instruction="Do not provide legal advice; recommend consulting a licensed attorney.",
priority=85,
)
engine = GuardrailEngine(extra_guardrails=[no_legal_advice])
4. Error handling — there is little to fail here
# GuardrailEngine.build() does not raise for missing/None fields on a well-formed PromptRequest;
# malformed enum values would already have raised earlier, in PromptEngine.build().
5. Production — structured output with schema
req = PromptRequest(
query="Extract line items from this invoice.",
documents=[invoice_doc],
output_format=OutputFormat.STRUCTURED,
output_schema={"type": "object", "properties": {"line_items": {"type": "array"}}},
)
block, applied = engine.build(req)
assert "Schema:" in block
Best practices
- If you need a guardrail suppressed entirely regardless of settings, you cannot do so through
PromptRequestflags forSAFE_OUTPUT/CONCISE(always-on) or forSHOW_REASONING/SELF_CHECK(strategy/complexity-driven) — you would need to subclass or bypassGuardrailEngine. - Prefer
extra_guardrailsover monkey-patchingGuardrailLibraryfor custom policies.
Common mistakes
- Assuming
enable_guardrails=Falseproduces a guardrail-free prompt. It doesn't —SAFE_OUTPUT,CONCISE, and (conditionally)SHOW_REASONING/SELF_CHECKstill apply. - Expecting a format instruction line for
OutputFormat.TEXT— none exists in either the bilingual table or the English fallback dict.