Structured JSON Output, guaranteed by construction
Token-level constraint enforcement: JSON Schema, choice lists, regex patterns, and Lark grammars. The model literally cannot produce output that doesn't parse.
The Problem
LLMs produce free-form text. Game code needs structured data. The standard approach (generate text, parse it, hope it's valid JSON, handle parse errors, retry on failure) is fragile, slow, and adds complexity to every integration point.
Four Constraint Types
Four ways to lock the output shape, all enforced during generation rather than after. Every token the model emits is masked against the constraint, so the output is guaranteed to be valid: no retries, no error handling, no fallback parsers.
- JSON Schema: full Draft-7 support including nested objects, arrays, enums, numeric ranges, string patterns, and required/optional fields. Use it for inventory items, quests, NPC stat blocks, dialogue trees.
- Choice (enum): force the model to pick from a fixed list of strings. Compiled to a regex internally and enforced at the token level. Ideal for picking emotions, actions, faction names, branch labels.
- Regex: constrain to any regular expression. Use
it for IDs, timestamps, dice notation (
\d+d\d+), version strings, hex colours, anything with a fixed lexical shape. - Lark grammar: define a context-free grammar (Lark / EBNF style) and the model is constrained to produce a parseable derivation. Use it for domain-specific command languages, query DSLs, deterministic dialogue scripts, or any structure JSON Schema can't express.
Auto Schema Injection
By default the engine prepends a concise description of the active
constraint to the system message, so the model knows the target
shape ahead of time and the constraint engine has less work to do
during sampling. Configurable via the schema_injection
setting (none / light / concise /
full). Constraint trees are also cached across requests
with the same shape so the per-call overhead drops to near-zero.
Example: JSON Schema
// Define the schema for a generated item
let schema = json!({
"type": "object",
"properties": {
"name": { "type": "string" },
"rarity": {
"type": "string",
"enum": ["common", "uncommon", "rare", "legendary"]
},
"damage": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"description": { "type": "string" }
},
"required": ["name", "rarity", "damage", "description"]
});
// Generate: output is guaranteed to match the schema
let item = engine.llm().generate_structured(
"Create a fire-enchanted sword for a level 20 warrior",
&schema
).await?;The result:
{
"name": "Embercleaver",
"rarity": "rare",
"damage": 47,
"description": "A longsword wreathed in smoldering flame, forged in the heart of Mount Valdris."
}Use Cases
- Inventory items, generate weapons, armor, potions with typed stats
- Quest data, produce quest objectives, rewards, and branching conditions
- NPC stats, generate character sheets, skill distributions, personality traits
- Dialogue choices, return an array of player response options with mood tags
- World events, produce structured event descriptions with triggers and consequences
How It Works
Each constraint compiles to a finite-state machine (or pushdown automaton, for Lark grammars). At every sampling step, the engine asks the FSM which next tokens are legal and zeroes out the logits of the rest, then samples normally from what remains. Invalid output is impossible (not unlikely, impossible). Constraint compilation is cached across requests, so the second call with the same schema pays only the per-token mask cost.