Skip to main content

Sampling

Controlling how the model picks tokens and constraining output format.


The model does not produce tokens directly but rather a probability distribution over all possible tokens. We must then choose how to pick the next token from the distribution. This is the job of a sampler, which using NobodyWho you can freely modify to achieve better quality outputs or constrain the outputs to some known format (e.g. JSON).

Sampler Presets

NobodyWho offers several built-in presets you can apply to your NobodyWhoChat node:

JSON Output

Force the model to always produce valid JSON:

chat.set_sampler_preset_json()
chat.system_prompt = "Generate a character with name, weapon, and armor properties."
chat.ask("Create a fantasy character")
# Output will always be valid JSON, e.g.:
# {"name": "Eldara", "weapon": "enchanted bow", "armor": "leather vest"}

Temperature

Control the "creativity" of the model. Lower values make the model more deterministic:

chat.set_sampler_preset_temperature(0.2) # More focused/deterministic
chat.set_sampler_preset_temperature(1.5) # More creative/random

Greedy

Always pick the most probable token:

chat.set_sampler_preset_greedy()

Structured Output

One of the most powerful features is constraining the model to produce output in a specific format. This gives you a hard guarantee that the output matches your format, rather than relying on the model to get it right on its own.

Grammar Constraints

You can constrain the model's output using a GBNF grammar:

var grammar = """
root ::= greeting " " name
greeting ::= "Hello" | "Hi" | "Hey"
name ::= "World" | "Friend" | "There"
"""
chat.set_sampler_preset_constrain_with_grammar(grammar)

This makes it impossible for the model to generate anything outside your defined format.

For a comprehensive tutorial on writing GBNF grammars, including JSON generation, compact formats, and practical game examples, see the Structured Output guide.

JSON Schema Constraints

Force the model to produce JSON matching a specific schema:

var schema = JSON.stringify({
"type": "object",
"properties": {
"name": {"type": "string"},
"level": {"type": "integer"},
"class": {"type": "string", "enum": ["Warrior", "Mage", "Rogue"]}
},
"required": ["name", "level", "class"]
})
chat.set_sampler_preset_constrain_with_json_schema(schema)

Regex Constraints

For simpler patterns, constrain the output with a regular expression:

# Force the model to answer with exactly "yes" or "no"
chat.set_sampler_preset_constrain_with_regex("yes|no")

Changing Samplers Mid-Conversation

You can change the sampler at any point during a conversation. The new sampler will take effect on the next ask() call:

# Start with free-form chat
chat.ask("Tell me about yourself")
var response = await chat.response_finished

# Switch to structured output for the next question
chat.set_sampler_preset_json()
chat.ask("Now describe your stats as JSON")
var json_response = await chat.response_finished