Steering Output with Logit Bias

AILLMMachine LearningBackend
Share on LinkedIn

You need the model to respond with exactly "positive", "negative", or "neutral" — not "The sentiment is positive" or "Positive!". Prompting helps; logit bias guarantees the first token comes from your allowed set. Logit bias operates below the prompt layer, adjusting token probabilities at each generation step. It's a scalpel most teams don't know exists, useful for classification endpoints, format enforcement, and blocking specific outputs.

How logit bias works

During generation, the model computes logits (raw scores) for each token in the vocabulary. Logit bias adds a value before softmax sampling:

adjusted_logit[token_id] = original_logit[token_id] + bias_value
# Force response to start with valid JSON open brace
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Extract name and age as JSON"}],
    logit_bias={
        token_id("{"): 5,       # encourage
        token_id("```"): -100,  # ban markdown fences
    },
    max_tokens=100,
)

Bias -100 makes a token effectively impossible. Bias +5 to +20 nudges without forcing.

Getting token IDs

You need the tokenizer mapping:

import tiktoken

enc = tiktoken.encoding_for_model("gpt-4o")
token_ids = {enc.encode(word)[0]: bias for word, bias in [
    ("positive", 10),
    ("negative", 10),
    ("neutral", 10),
    ("The", -100),
    ("I", -100),
]}

For multi-token words, bias each token ID individually. Single-token words in the vocabulary work most reliably.

Classification forcing

Restrict output to label vocabulary:

def classification_bias(labels: list[str], model: str) -> dict[int, float]:
    enc = tiktoken.encoding_for_model(model)
    bias = {}
    # Boost label tokens
    for label in labels:
        for token_id in enc.encode(label):
            bias[token_id] = 10
    # Suppress common preamble tokens
    for word in ["The", "Based", "I", "This", "It"]:
        for token_id in enc.encode(word):
            bias[token_id] = -50
    return bias

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": f"Classify: {text}"}],
    logit_bias=classification_bias(["billing", "technical", "other"], "gpt-4o-mini"),
    max_tokens=5,
    temperature=0,
)

Combine with temperature=0 for maximum determinism.

JSON key enforcement

Ensure specific keys appear:

JSON_KEYS = ['"name"', '"email"', '"phone"']
bias = {}
for key in JSON_KEYS:
    for tid in enc.encode(key):
        bias[tid] = 5
# Ban markdown
for tid in enc.encode("```"):
    bias[tid] = -100

Less reliable than constrained decoding for full schema compliance, but works on any model with logit_bias support.

Preventing unwanted patterns

Block specific outputs:

BLOCKED = ["As an AI", "I cannot", "I'm sorry"]
bias = {}
for phrase in BLOCKED:
    for tid in enc.encode(phrase):
        bias[tid] = -80

Heavy-handed — can cause unnatural phrasing. Prefer output filtering for safety; logit bias for format.

Limitations

For schema compliance, prefer structured outputs or constrained decoding. Use logit bias for simple, token-level steering.

Self-hosted logits processors

vLLM supports custom logits processors:

def allowed_token_processor(allowed_ids: set[int]):
    def processor(token_ids, logits):
        mask = torch.full_like(logits, float('-inf'))
        mask[allowed_ids] = 0
        return logits + mask
    return processor

Equivalent to logit bias with hard masking — useful for open-source deployment.

Token ID lookup workflow

Logit bias requires numeric token IDs, not strings:

import tiktoken

enc = tiktoken.encoding_for_model("gpt-4o")
token_id = enc.encode("€")[0]  # get ID for euro symbol
print(f"Token ID for €: {token_id}")

# Build bias dict
logit_bias = {token_id: 100}  # strongly prefer €

Always verify token IDs match your deployment model — GPT-4 and GPT-4o may tokenize differently. Test bias effect on a sample prompt before production deployment.

Combining logit bias with temperature

High temperature randomizes token selection — logit bias becomes less effective:

# Weak steering: high temperature dilutes bias
response = client.chat.completions.create(
    model="gpt-4o",
    temperature=0.9,
    logit_bias={euro_token_id: 50},
    ...
)

# Strong steering: low temperature + high bias
response = client.chat.completions.create(
    model="gpt-4o",
    temperature=0.0,
    logit_bias={euro_token_id: 100},
    ...
)

For format enforcement (JSON braces, specific keywords), use temperature=0.0 with targeted bias. For soft nudges (prefer formal tone), temperature=0.3–0.5 with moderate bias (+20 to +50).

When to use logit bias vs alternatives

Goal Best approach
Force JSON output Structured outputs / constrained decoding
Block specific words Logit bias (-100) or output filter
Prefer currency symbol Logit bias (+50 to +100)
Enforce schema fields Pydantic + Instructor retry
Control response length max_tokens + stop sequences

Logit bias is a scalpel for token-level nudges — not a replacement for structured outputs or prompt engineering.

Failure modes

Production checklist

Common production mistakes

Teams get logit bias steering wrong in predictable ways:

LLM features around logit bias steering break in production when prompts assume deterministic output, context windows are sized for dev datasets, or token costs are never budgeted per user session. Always log prompt hash, model version, and latency—not raw prompts with PII.

Resources

Frequently asked questions

What is logit bias in LLM APIs?

Logit bias adjusts the probability of specific tokens appearing in the output by adding a bias value (-100 to +100) to their logits before sampling. Positive bias makes tokens more likely; -100 effectively bans a token. It's applied at each generation step, affecting only the tokens you specify.

When should I use logit bias vs prompt engineering?

Logit bias for hard constraints: forcing JSON keys, restricting output to a vocabulary (yes/no, enum labels), preventing specific tokens (profanity, markdown fences). Prompt engineering for semantic guidance. Logit bias is deterministic control; prompts are probabilistic suggestions.

Does logit bias work with all models and providers?

OpenAI supports logit_bias on completions and chat endpoints. Anthropic doesn't expose logit bias directly — use tool use or constrained decoding instead. Self-hosted models via vLLM support logits processors for equivalent control. Check provider docs — support varies.

Hiring a senior Android / Flutter engineer?

I architect and ship production mobile software — Kotlin, Jetpack Compose, Flutter — for robotics, EV infrastructure, fintech, and real-time systems. Open to remote roles in Europe and the US.

Get in touch →