6.2.10 · D5AI Agents & Tool Use
Question bank — Guardrails and constrained generation
Before we start, a few plain-word anchors so nothing below uses an unearned symbol:


True or false — justify
TF1. "A guardrail and constrained generation can be swapped freely — they solve the same problem."
False. A guardrail acts around generation (filter the input or reject the output), while constrained generation acts inside the sampler at every step; you cannot force valid JSON by post-hoc filtering without wasteful rejection sampling.
TF2. "Constrained generation guarantees the output is safe."
False. It guarantees the output matches a formal grammar (e.g. valid JSON), but a valid JSON string can still contain toxic or false content — safety is a fuzzy property a grammar cannot express.
TF3. "Adding to an invalid token's logit gives it exactly zero probability."
Effectively true in floating point: underflows to , so after softmax its share is ; literal is avoided only because it produces NaN in the arithmetic.
TF4. "Multiplying a forbidden token's logit by removes it."
False. Logit becomes probability , so the token survives — and a token whose logit was negative is boosted up to , making it more likely.
TF5. "A regex constraint and an LM-as-judge guardrail are interchangeable ways to enforce a phone-number format."
False. The regex constraint proactively forbids off-pattern tokens during decoding so the format is always valid; an LM-judge only reviews finished text and may itself be wrong.
TF6. "Constrained decoding changes the model's weights."
False. It only edits the logits at sampling time via a mask; the trained parameters are untouched, which is why the same model can serve constrained and unconstrained requests.
TF7. "If every valid token has a very low logit, constrained decoding fails."
False. softmax renormalises over only the surviving (valid) tokens, so their probabilities are rescaled to sum to no matter how small the original logits were.
TF8. "Input guardrails are pointless if you have strong output guardrails."
False. Input guardrails stop prompt injection and jailbreaks that could corrupt tool calls or leak instructions before any output exists — see adversarial attacks on LLMs.
TF9. "Constrained generation always lowers output quality."
Not necessarily. It prunes only illegal tokens; if the model already wanted valid output, the distribution over legal tokens is unchanged, so fluent legal outputs stay just as likely.
TF10. "Regex-based content guardrails are as reliable as a trained classifier for detecting toxicity."
False. Regex catches only surface patterns; paraphrases like "I'll make sure you're compensated" slip past keyword filters, which is why fuzzy content needs a classifier or LM-judge.
Spot the error
SE1. "To mask, compute where mask is for valid and for invalid."
Wrong operation. Elementwise multiply leaves valid tokens with logit but sets invalid ones to logit (probability ), not zero probability. The fix is to add a bias before softmax (see the first figure's right panel).
SE2. "Since , we can safely write literal -inf into the logit tensor."
Risky. During the subtract-the-max stabilisation step (defined above), minus stays and its exponential is fine, but if is the max it poisons the shift and yields NaN; production code uses a large finite negative like .
SE3. "Apply the JSON schema constraint after the model finishes, by parsing and rejecting bad outputs."
That is rejection sampling, not constrained decoding. It can loop forever if the model rarely emits valid JSON; constrained decoding forbids the invalid token at the step it would be sampled.
SE4. "The mask for step is fixed once, computed from the prompt."
Wrong. The mask depends on the current prefix (the tokens decoded so far) — after
{ only " or } are legal, so the parser recomputes the legal set at every step as grows.SE5. "Use constrained generation to stop the bot promising refunds."
Wrong tool. 'Promising a refund' is a fuzzy content policy, not a formal grammar — that belongs to a guardrail (regex + LM-judge), as in the parent's customer-service example.
SE6. "Softmax over the constrained logits still divides by the sum over all tokens including the masked ones."
Wrong. The masked tokens contribute to the denominator , so the sum is effectively over valid tokens only — that is why renormalisation is automatic.
Why questions
WY1. "Why add the mask bias before softmax and not after? (feeds SE1, SE6, WY-chain root)"
Because softmax is what converts scores to probabilities; masking before it lets the exponential and normalisation do the zeroing cleanly (see figure 1). Masking after softmax would require you to re-normalise the remaining probabilities by hand — the exact bug SE6 exposes.
WY2. "Why does constrained generation save compute compared with a guardrail-and-retry loop? (mechanism behind TF1 and SE3)"
The constraint prunes illegal branches at each step, so the model never wastes a full generation on output it will discard; a reject-and-retry guardrail (SE3's rejection sampling) may burn several complete generations.
WY3. "Why can't constrained generation enforce 'never mention a competitor'? (the boundary TF2 and SE5 both hit)"
A competitor name can appear in infinitely many phrasings and contexts, which no finite-state grammar captures cleanly; content-level rules like this are better handled by a guardrail classifier — exactly why SE5's tool choice is wrong.
WY4. "Why does the parser need the whole prefix , not just the last token, to decide the legal set? (justifies SE4)"
Because grammars track state — whether you are inside a string, mid-number, or after a comma — and that state accumulates over the whole prefix , so nesting depth and open quotes matter; a single last token cannot reveal how deep you are.
WY5. "Why combine constrained generation with guardrails rather than pick one? (ties TF2 to the 'combine them' pattern)"
They cover complementary failure modes: the constraint guarantees format validity while the guardrail checks content safety; a valid-JSON toxic comment (the TF2 trap) needs both to be caught.
WY6. "Why is prompt-injection an input guardrail concern and not solvable by output masking? (deepens TF8)"
Injection corrupts the model's intent before it decodes, so a valid, well-formatted, on-schema output can still be doing exactly what the attacker wanted; you must inspect and sanitise the input. See function calling and tool use where injected text can trigger unintended tools.
WY7. "Why doesn't constrained decoding conflict with sampling strategies like temperature or top-p? (composes with TF6)"
The mask only zeroes illegal tokens; temperature and top-p from sampling strategies then reshape the distribution over the remaining legal tokens, so the two operate on disjoint concerns and compose. Because masking only edits logits (TF6), it never touches the sampler that runs afterwards.
Edge cases
EC1. "What if, given the prefix , no token is legal (a dead end in the grammar)?"
All logits become and softmax degenerates — a well-built constraint compiler prevents this by ensuring the grammar's state machine always has an exit (e.g. a closing brace path), or by allowing the end-of-sequence token.
EC2. "What if only one token is legal at a step?"
softmax over a single surviving logit returns probability for it regardless of its raw value, so decoding is forced — the model has no choice, which is exactly how required structural characters like closing quotes get emitted.
EC3. "What happens at the boundary where a schema field is 'integer, min 1, max 5'?"
The grammar is a state machine over characters, so it must forbid more than just the digit set: after
"rating": it disallows a leading - (no negatives), disallows a . (no decimals), and — because the value tops out at a single digit — after emitting one of 1–5 it forbids a second digit and forces a delimiter. For a wider range like min 1, max 250 the machine would instead permit one, two, or three digits and check the running value against the bound at each digit, blocking 9 after 25 because 259 > 250. Multi-digit, negative, and decimal handling is thus all encoded as extra states, not a flat digit whitelist.EC4. "Empty output: can constrained generation produce nothing?"
Only if the grammar's start state can legally reach end-of-sequence immediately; for a required-field JSON schema it cannot, so the opening
{ is forced and an empty string is impossible.EC5. "A guardrail's toxicity classifier scores exactly at the threshold — block or pass?"
The behaviour is a design choice, but a boundary score signals an ambiguous case; robust systems either escalate to an LM-judge or apply a conservative 'block on tie' policy rather than leaving it undefined.
EC6. "The RLHF-aligned model already refuses harmful requests — are guardrails redundant?"
No. Alignment from RLHF and preference learning shifts the model's tendencies but gives no hard guarantee; guardrails add an independent, auditable layer that fails safe even when alignment is bypassed.
EC7. "In a multi-agent pipeline, where should guardrails live?"
At every trust boundary — one agent's output is another's input, so both output guardrails (before hand-off) and input guardrails (on receipt) are needed, as discussed in multi-agent systems.
Recall Quick self-test
The single most common masking bug is ::: multiplying logits by (or a mask) instead of adding a bias before softmax. Constraints guarantee ::: format/grammar validity, never content safety. The mask at step depends on ::: the full current prefix (all tokens decoded so far), recomputed every step.