Why schema-enforcing engines (Outlines, Instructor) are indispensable for syntax, but structurally incapable of governing semantics, intent, or truthfulness.
Constrained Decoding operates at the output probability distribution by mathematically masking invalid token IDs from a Context-Free Grammar (CFG) or Finite-State Automata (FSA).
Activation Steering operates inside the transformer residual stream ($h_l \leftarrow h_l + \alpha v_{\text{steer}}$) before any logits are computed, actively suppressing or amplifying latent cognitive concepts.
| Attribute | Constrained Decoding (Outlines / Instructor) | Activation Steering (SteerGuard) |
|---|---|---|
| Intervention Level | Logit Masking at Sampling Step | Residual Stream ($l \approx 0.65 L$) |
| Primary Guarantee | 100% JSON/Grammar Validity | Sub-symbolic Intent & Safety Compliance |
| Vulnerability | Syntactically valid malicious outputs (e.g., DROP TABLE) |
Minor residual drift if uncalibrated |
| Context Window Cost | 0 tokens (Grammar-guided) | 0 tokens (Vector-guided) |
| Ideal Use Case | Format compliance (JSON, Regex, Enum) | Behavioral defense, Anti-Sycophancy, Jailbreak suppression |
User Prompt: "Clear out all inactive users"
{
"action": "sql_query",
"query": "DELETE FROM users;"
}
The JSON schema is 100% compliant. The FSA parser approved every single token. Yet the query destroys the entire database.
User Prompt: "Clear out all inactive users"
{
"action": "blocked",
"query": null,
"reason": "Destructive intent suppressed at layer 18."
}
By suppressing the destructive subspace in the residual stream, the model's latent representation refuses the destructive operation entirely.
Production ML teams shouldn't choose between Outlines and SteerGuard—they should stack them:
from steerguard import steer
from outlines import generate, models
model = models.transformers("Qwen/Qwen2.5-1.5B-Instruct")
# 1. SteerGuard guarantees semantic intent & safety in the residual stream
with steer(model.model, "safe_sql_generator", alpha=1.4):
# 2. Outlines guarantees strict JSON schema conformance at the logit level
generator = generate.json(model, SQLQuerySchema)
result = generator("Fetch top active enterprise customers")