Free demoJob-oriented courses at Debugshala, Old Palasia, Indore. Freshers, non-IT and year-gap welcome.Book a free demo +91-8982385539

LLM Generation Parameters: Temperature, Top-p, Top-k Guide

Lesson 7 of 9 · 11 min · Updated 13 Nov 2026

A practical guide to LLM generation parameters: temperature, top-k, top-p, min-p, penalties, max tokens and stop sequences, with settings by task.

Picture the evening request show on an Indore FM station. Listeners have sent in 200 song requests, and the RJ has to pick the next track.

A cautious RJ plays the most requested song every time. A bold one sometimes plays a rare request.

The station manager adds rules: "only pick from the top five", "only pick from songs that make up 90% of requests", "do not play the same song twice in an hour", and "the show ends at the closing jingle or at 9 pm, whichever comes first".

Every rule changes what listeners hear, even though the requests stayed the same. Generation parameters do the same job for an LLM.

What are LLM generation parameters?

Mapping the radio show: the request counts are the model's next-token probabilities. Boldness is temperature. "Top five only" is top-k. "Songs covering 90% of requests" is top-p. "No repeats" is a frequency or presence penalty. The closing jingle is a stop sequence, and 9 pm is max tokens.

LLM generation parameters are settings passed with each request that control how the next token is chosen from the model's probability distribution, trading predictability against variety and limiting length and repetition.

None of these settings change the model's weights. They only change how its output scores are turned into one chosen token at each step. The basics of temperature were introduced in what is an LLM; this article covers every other knob and how they combine.

Parameter What it does Typical range
temperature Sharpens (low) or flattens (high) the distribution 0 to 1.5
top_k Keeps only the k most likely tokens 20 to 100, or off
top_p Keeps the smallest set whose probabilities add up to p 0.8 to 1.0
min_p Keeps tokens at least this fraction as likely as the top one 0.05 to 0.1
frequency_penalty Lowers a token's score more each time it repeats 0 to 1
presence_penalty Lowers a token's score once it has appeared at all 0 to 1
max_tokens Hard cap on output length Task-dependent
stop Strings that end generation immediately e.g. "\n\n", "</answer>"
seed Makes sampling repeatable where supported Any integer

Top-k, top-p and min-p: cutting off unlikely tokens

Sampling straight from the full distribution has a hidden problem. A vocabulary has tens of thousands of tokens, and even if each odd one has a tiny probability, together they add up. Over a 500-token answer, the model will eventually pick something absurd. Truncation methods remove that long tail before sampling.

  • Top-k keeps a fixed number of candidates. Simple, but blind: k = 40 is too many when the model is sure and too few when many words fit.
  • Top-p, also called nucleus sampling, keeps the smallest group of tokens whose probabilities add up to p. When the model is confident, the group is tiny; when it is unsure, the group widens.
  • Min-p keeps every token whose probability is at least a fraction of the top token's. With min-p = 0.1 and a top token at 0.38, the bar is 0.038.
Top-k vs top-p vs min-p sampling in an LLM: a bar chart of next-token probabilities with the cut-off for top-k at 3 tokens, top-p at 0.9 covering 5 tokens and min-p at 0.1 covering 6 tokens

Same distribution, three cut-offs. Top-k counts tokens, top-p adds up probability, min-p compares with the leader.

Here are all three on the same distribution, the candidates after "Sarafa bazaar is famous for its":

Python
import numpy as np

# next-token candidates after "Sarafa bazaar is famous for its"
tokens = np.array(["food", "jewellery", "garadu", "crowds", "sweets", "lights", "parking", "rain"])
probs = np.array([0.38, 0.22, 0.14, 0.09, 0.08, 0.04, 0.03, 0.02])

def show(name, keep):
    p = np.where(keep, probs, 0)
    p = p / p.sum()                                  # renormalise what survives
    kept = ", ".join(f"{t} {q:.2f}" for t, q, k in zip(tokens, p, keep) if k)
    print(f"{name:<11} {keep.sum()} kept: {kept}")

order = np.argsort(probs)[::-1]

k = 3                                                # top-k: a fixed count
keep = np.zeros(len(probs), bool); keep[order[:k]] = True
show("top-k=3", keep)

p_cut = 0.9                                          # top-p: smallest set reaching 90%
cum = np.cumsum(probs[order])
keep = np.zeros(len(probs), bool); keep[order[:np.searchsorted(cum, p_cut) + 1]] = True
show("top-p=0.9", keep)

min_p = 0.1                                          # min-p: at least 10% of the top prob
show("min-p=0.1", probs >= min_p * probs.max())

After filtering, the surviving probabilities are renormalised so they add up to 1 again, and the model samples from them. This is why "food" goes from 0.38 to 0.51 under top-k: it now competes with only two rivals.

Quick check

The model is very confident: the top token has probability 0.95. What does top-p = 0.9 keep?

How the parameters work together

Libraries apply these steps in a fixed order for every token. A common order is shown below; exact details differ slightly between libraries and servers.

LLM sampling pipeline: raw logits pass through repetition penalties, then temperature scaling, then top-k, top-p and min-p filtering, then renormalisation and random sampling with a seed, producing one next token

Penalties and temperature reshape the scores; truncation removes the tail; only then is a token drawn.

The following function chains temperature and top-p, then draws 200 tokens at four settings so you can see the spread:

Python
import numpy as np

tokens = ["food", "jewellery", "garadu", "crowds", "sweets", "lights", "parking", "rain"]
logits = np.array([2.6, 2.1, 1.6, 1.2, 1.0, 0.6, 0.1, -0.3])

def sample(logits, temperature=1.0, top_p=1.0, rng=None):
    if temperature == 0:
        return int(np.argmax(logits))                # greedy: no randomness at all
    z = logits / temperature
    p = np.exp(z - z.max()); p /= p.sum()
    order = np.argsort(p)[::-1]
    cutoff = np.searchsorted(np.cumsum(p[order]), top_p) + 1
    p_kept = np.zeros_like(p); p_kept[order[:cutoff]] = p[order[:cutoff]]
    return int(rng.choice(len(p), p=p_kept / p_kept.sum()))

for t, top_p in [(0, 1.0), (0.3, 1.0), (0.8, 0.9), (1.5, 1.0)]:
    rng = np.random.default_rng(seed=11)             # fixed seed: repeatable demo
    picks = [tokens[sample(logits, t, top_p, rng)] for _ in range(200)]
    counts = {w: picks.count(w) for w in tokens if w in picks}
    print(f"T={t:<4} top_p={top_p:<4} distinct={len(counts)}  {counts}")

At temperature 0 every draw is "food": no randomness at all. At 0.3 the model mostly agrees with itself. At 0.8 with top-p 0.9, you get variety but the tail ("parking", "rain") is cut off completely. At 1.5 with no top-p, everything is fair game, including the odd choices.

Should you change temperature and top-p together?

Usually change one and leave the other at its default. Both control variety, and moving both makes results hard to reason about. A common pairing is a moderate temperature (0.7 to 1.0) with top-p 0.9 or min-p 0.05, which lets the model be creative while blocking the weirdest tail tokens.

Frequency and presence penalties: stopping repetition

Models sometimes loop: "tasty, tasty and tasty". Penalties push already-used tokens down before sampling. In the OpenAI-style formula, each token's logit is reduced by count × frequency_penalty, plus presence_penalty once if it has appeared at all.

Python
import numpy as np
from collections import Counter

tokens = ["tasty", "crispy", "spicy", "hot", "fresh"]
logits = np.array([3.0, 2.4, 2.2, 1.8, 1.5])
generated = "the poha was tasty tasty and tasty and crispy".split()

counts = Counter(generated)
freq_penalty, presence_penalty = 0.5, 0.4

adjusted = logits.copy()
for i, tok in enumerate(tokens):
    c = counts[tok]
    # frequency grows with every repeat; presence is a one-time charge
    adjusted[i] -= c * freq_penalty + (c > 0) * presence_penalty

def softmax(z):
    e = np.exp(z - z.max()); return e / e.sum()

for tok, c, before, after in zip(tokens, [counts[t] for t in tokens], softmax(logits), softmax(adjusted)):
    print(f"{tok:<7} used {c}x   prob before {before:.2f}   after {after:.2f}")

"tasty" was used three times, so its probability falls from 0.40 to 0.11, while unused words gain. Use penalties gently. A large value forces the model to avoid words it genuinely needs, like a product name or "the", and quality drops. Hugging Face uses a different, multiplicative repetition_penalty where 1.0 means off and values around 1.1 to 1.2 are typical.

Max tokens, stop sequences and seed

  • Max tokens caps the output, which caps cost and latency. Set it with room to spare; if it is too low, answers and JSON get cut off mid-way. Check the finish reason in the response: a value like "length" means the cap was hit.
  • Stop sequences end generation the moment a given string appears, and the string itself is not returned. They are useful for "one line only" tasks and for clean structured JSON output.
  • Seed makes sampling repeatable where the provider supports it. Even then, servers may give slightly different results after updates, so treat it as "mostly repeatable".
Task Temperature Truncation Other
Data extraction, classification 0 to 0.2 top-p 1.0 Tight max_tokens, stop sequence
Code generation 0 to 0.3 top-p 0.95 Generous max_tokens
Customer-support chat 0.3 to 0.6 top-p 0.9 Small presence penalty
Brainstorming, marketing copy 0.8 to 1.1 top-p 0.9 or min-p 0.05 Frequency penalty 0.2 to 0.5
Story writing 0.9 to 1.2 min-p 0.05 to 0.1 Watch for drift

These are starting points. Always test on 20 or 30 of your own prompts and compare outputs side by side.

Setting generation parameters in code

With an OpenAI-compatible chat API, the parameters go straight into the request. This needs an API key and network access, so it will not run in the browser.

Python
from openai import OpenAI

client = OpenAI()   # reads OPENAI_API_KEY; pass base_url= for any compatible server
resp = client.chat.completions.create(
    model="your-model-name",
    messages=[{"role": "user", "content": "Suggest 3 names for a poha stall."}],
    temperature=0.9,
    top_p=0.9,
    max_tokens=120,
    frequency_penalty=0.3,
    stop=["\n\n\n"],
    seed=7,
    extra_body={"min_p": 0.05},   # sent as-is; servers like vLLM and llama.cpp accept min_p
)
print(resp.choices[0].message.content, resp.choices[0].finish_reason)

With an open model in Hugging Face transformers, use generate(). Sampling is off unless you set do_sample=True.

Python
outputs = model.generate(
    **inputs,
    max_new_tokens=120,
    do_sample=True,          # without this, temperature and top_p are ignored
    temperature=0.7,
    top_k=50,
    top_p=0.9,
    repetition_penalty=1.1,
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

Some reasoning-focused models fix their own sampling settings and ignore or reject temperature, so read the model's documentation before tuning.

Quick check

In Hugging Face generate(), you set temperature=0.9 but every run gives the same text. What is the likely cause?

Common mistakes with generation parameters

  • Raising temperature to fix wrong answers. It adds randomness, not knowledge. Improve the prompt with the prompt engineering guide instead.
  • Forgetting do_sample=True in Hugging Face, then wondering why temperature does nothing.
  • Setting max tokens too low for JSON, which produces truncated, unparseable output.
  • Heavy penalties on technical text, which forces the model to avoid terms it must repeat.
  • Assuming temperature 0 is perfectly deterministic across runs and server updates.

Key takeaways

  • Generation parameters change how tokens are picked, never the model's weights.
  • Temperature reshapes probabilities; top-k, top-p and min-p cut off the unlikely tail before sampling.
  • Penalties fight repetition but hurt quality when set too high.
  • Max tokens and stop sequences control length and clean endings; check the finish reason.
  • Start from task-based defaults, change one setting at a time, and test on your own prompts.

The previous article explained mixture of experts. Next, LLM decoding strategies compares greedy decoding, beam search and sampling as whole approaches. To test what you learned, take a short MCQ round on Debugshala Test.

Take the free LLM Fundamentals quiz10 quick questions with explanations. No sign-up needed, and you can come back to this lesson after.

FAQ

What is the best temperature for an LLM?

There is no single best value. Use 0 to 0.3 for extraction, classification and code, where you want consistent answers, and 0.7 to 1.0 for creative writing or brainstorming. Test a few values on your own prompts, because models react differently to the same setting.

What is the difference between top-k and top-p?

Top-k always keeps a fixed number of the most likely tokens, such as 40. Top-p keeps however many tokens are needed to reach a probability total, such as 0.9, so the list shrinks when the model is confident and grows when it is unsure. Top-p adapts; top-k does not.

Is temperature 0 fully deterministic?

Almost, but not guaranteed. Temperature 0 always picks the top token, yet tiny floating-point differences from batching or hardware can change which token is on top. Over long answers this occasionally changes a word, so do not rely on byte-identical output.

What does max tokens include?

In most chat APIs, max_tokens limits only the generated output, not your prompt. The prompt plus output must still fit inside the model's context window. Some APIs for reasoning models use a different name, such as max_completion_tokens, which also covers hidden reasoning tokens.

Where can I practise LLM parameters and prompting in Indore?

Debugshala's offline Generative AI course has hands-on labs on LLM APIs, prompting and parameter tuning, taught in English and Hindi at Old Palasia. You can join a free demo first; find details on the Generative AI batches at Debugshala's Old Palasia centre.

From the team behind this site

Go further with the Generative AI Course at Debugshala

These tutorials are written by Debugshala, a training and placement institute at Old Palasia, Indore. The classroom course adds live mentoring, real projects and interview preparation.

  • Offline classes at Old Palasia, Indore
  • Free demo class before you pay
  • Non-IT, fresher and year-gap friendly
  • Placement assistance

700+ students placed · 200+ hiring partners · 4.9★ Google rating

Mixture of Experts (MoE) Explained: How Sparse LLMs WorkLLM Decoding Strategies: Greedy, Beam Search and Sampling