Top-p Nucleus Sampling
How top-p restricts sampling to the most probable token set.
Top-p Nucleus Sampling is a free AI Prompt Engineering lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the AI Prompt Engineering learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is Top-p Sampling?
Top-p sampling (also called nucleus sampling) is a technique that restricts sampling to a dynamic subset of the vocabulary. Instead of sampling from all tokens, the model considers only the smallest set of tokens whose cumulative probability is at least p.
Proposed in the paper 'The Curious Case of Neural Text Degeneration' (Holtzman et al., 2019), it outperforms simple temperature scaling for diverse yet coherent generation.
How Top-p Works Step by Step
Algorithm:
- Compute softmax probabilities over the full vocabulary
- Sort tokens by probability (highest first)
- Walk down the sorted list, accumulating probability, until the cumulative sum reaches p
- This set of tokens is the nucleus
- Sample from the nucleus only (renormalize probabilities to sum to 1)
import numpy as np
def top_p_sample(logits, p=0.9):
probs = softmax(logits, temperature=1.0)
# Sort by probability descending
sorted_indices = np.argsort(probs)[::-1]
sorted_probs = probs[sorted_indices]
# Find nucleus: smallest set with cumulative prob >= p
cumulative = np.cumsum(sorted_probs)
nucleus_size = np.searchsorted(cumulative, p) + 1
nucleus_indices = sorted_indices[:nucleus_size]
nucleus_probs = sorted_probs[:nucleus_size]
# Renormalize
nucleus_probs = nucleus_probs / nucleus_probs.sum()
# Sample
chosen = np.random.choice(nucleus_indices, p=nucleus_probs)
return chosen
token = top_p_sample(logits, p=0.9)The Dynamic Nucleus
The key insight of top-p: the nucleus size is dynamic. When the model is very confident (one token dominates with probability 0.95), the nucleus contains just 1 token. When the model is uncertain (many tokens have similar probability), the nucleus expands to include more tokens.
This self-adapts to the model's confidence — high confidence → low vocabulary size → focused output. Low confidence → larger vocabulary → more exploration.
# High-confidence situation: model strongly prefers 'the'
high_confidence_logits = np.array([5.0, 1.0, 0.5, 0.1, -0.5])
hc_probs = softmax(high_confidence_logits)
print('High confidence probs:', np.round(hc_probs, 3))
# [0.974, 0.018, 0.011, 0.007, 0.004]
# Top-p=0.9 nucleus: just 1 token (cumulative after token 0 = 97.4% > 90%)
# Low-confidence situation: model unsure
low_confidence_logits = np.array([1.1, 1.0, 0.9, 0.8, 0.7])
lc_probs = softmax(low_confidence_logits)
print('Low confidence probs:', np.round(lc_probs, 3))
# [0.218, 0.208, 0.199, 0.190, 0.181]
# Top-p=0.9 nucleus: all 5 tokens (need all to reach 90%)Top-p in the OpenAI API
Set top_p in your API call. The valid range is 0.0–1.0. The default is 1.0 (full vocabulary, no nucleus restriction).
OpenAI recommends: if you change top_p, leave temperature at 1.0, and vice versa. Adjusting both simultaneously makes the effective sampling behavior hard to predict.
import openai
client = openai.OpenAI(api_key='sk-...')
# Nucleus sampling: top 90% of probability mass
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': 'Tell me an interesting fact about the ocean.'}],
temperature=1.0, # leave temperature at default
top_p=0.9 # sample from top 90% nucleus
)
print(resp.choices[0].message.content)p=1.0: Unrestricted Sampling
When top_p=1.0, the nucleus includes all tokens — the full vocabulary. This is equivalent to pure temperature sampling with no top-p restriction. Every token, no matter how improbable, has a non-zero chance of being selected.
Use p=1.0 when you want maximum diversity. At p=1.0, only temperature controls the shape of the distribution.
# p=1.0: all tokens in nucleus
resp_full = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': 'Generate a creative story opening.'}],
temperature=1.0,
top_p=1.0 # no nucleus restriction
)
# p=0.5: very focused nucleus
resp_focused = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': 'Generate a creative story opening.'}],
temperature=1.0,
top_p=0.5 # only top 50% probability mass
)Trade-off: Top-p vs Temperature
Both parameters control output diversity, but differently:
- Temperature reshapes the entire distribution — a token's relative probability vs all others changes
- Top-p truncates the distribution — a token is simply excluded if it is outside the nucleus, regardless of its relative probability
Top-p prevents the 'tail sampling' problem: with high temperature, extremely improbable tokens (gibberish, unrelated words) occasionally get sampled. Top-p removes these tokens from consideration entirely.
# The tail problem with temperature alone
high_temp_logits = np.array([3.0, 2.0, 1.0, 0.0, -1.0, -5.0, -10.0])
probs_high_temp = softmax(high_temp_logits, temperature=2.0)
print('High temp probs:', np.round(probs_high_temp, 4))
# The last token (logit=-10) still has a small probability
# With many tokens in a real vocab, these rare tokens accumulate
# and occasionally get sampled, producing incoherent output
# Top-p=0.9 cuts these off entirely
# ensuring only tokens contributing to the top 90% are consideredCombining Temperature and Top-p
When combining both parameters, temperature is applied first (reshaping the distribution), then top-p is applied to the resulting probabilities (truncating to the nucleus).
Common production configurations:
- Creative writing: temp=1.0, top_p=0.95
- Chat: temp=0.8, top_p=0.9
- Code: temp=0.2, top_p=1.0 (top-p not restrictive at low temp)
def combined_sample(logits, temperature=1.0, top_p=0.9):
# Step 1: apply temperature
probs = softmax(logits, temperature=temperature)
# Step 2: apply top-p nucleus
sorted_idx = np.argsort(probs)[::-1]
sorted_probs = probs[sorted_idx]
cumulative = np.cumsum(sorted_probs)
nucleus_size = np.searchsorted(cumulative, top_p) + 1
nucleus_idx = sorted_idx[:nucleus_size]
nucleus_probs = probs[nucleus_idx]
nucleus_probs = nucleus_probs / nucleus_probs.sum()
return np.random.choice(nucleus_idx, p=nucleus_probs)Top-p and Repetition
Low top-p values can cause repetition. When the nucleus is very small (e.g., p=0.5), the model repeatedly samples from a tiny set of tokens. The output becomes repetitive and predictable — the opposite of the intended creative effect.
Watch for repetition as a signal that top-p is set too low for the task. A useful diagnostic: if the model loops on the same phrases, increase top-p or temperature.
def detect_repetition(text, window=20):
words = text.split()
if len(words) < window * 2:
return False
# Check if any window of words repeats within the text
for i in range(len(words) - window):
phrase = ' '.join(words[i:i + window])
rest = ' '.join(words[i + window:])
if phrase in rest:
return True
return False
response = call_llm(prompt)
if detect_repetition(response):
print('Warning: repetition detected — consider increasing top_p or temperature')Top-p vs Top-k: A Preview
Top-p and top-k both truncate the vocabulary before sampling, but differently:
- Top-p: dynamic nucleus size — expands when model is uncertain, shrinks when confident
- Top-k: fixed nucleus size — always consider exactly k tokens regardless of confidence
Top-p is generally preferred because it adapts to the model's confidence. Top-k is covered in detail in the next lesson.
# Top-k equivalent for comparison
def top_k_sample(logits, k=50):
probs = softmax(logits)
# Keep only top-k tokens
top_k_indices = np.argsort(probs)[::-1][:k]
top_k_probs = probs[top_k_indices]
top_k_probs = top_k_probs / top_k_probs.sum()
return np.random.choice(top_k_indices, p=top_k_probs)
# Key difference: k is always 50, regardless of model confidence
# Top-p nucleus size varies from 1 to thousands depending on confidenceDefault Values and When to Change Them
API default values: top_p = 1.0 (no nucleus restriction). When should you change it?
- Lower top_p (0.7–0.9): when outputs feel incoherent or contain nonsensical words — too much tail sampling
- Keep at 1.0: when temperature is already low — at low temperature, the distribution is already sharp and top-p is not restrictive anyway
- Do not lower below 0.5: causes repetition and loss of diversity
# Guidance: what to adjust based on symptoms
TROUBLESHOOTING = {
'output is incoherent or contains random words': {
'fix': 'lower top_p to 0.9 or 0.85',
'or': 'lower temperature'
},
'output is repetitive and looping': {
'fix': 'increase top_p or temperature',
'also': 'try adding frequency_penalty or presence_penalty'
},
'output is too predictable and boring': {
'fix': 'increase temperature to 0.9-1.2',
'keep': 'top_p at 0.95'
},
'output needs to be deterministic': {
'fix': 'set temperature=0, top_p=1.0'
}
}Top-p in Anthropic Claude
Anthropic's Claude API also exposes top_p as a parameter. The behavior is identical: the model builds a nucleus of the smallest set of tokens whose cumulative probability meets the threshold p, then samples from that nucleus.
Combine with temperature for fine control: use temperature to shape the distribution, and top_p to cap which tokens can be selected from that distribution.
import anthropic
claude = anthropic.Anthropic(api_key='sk-ant-...')
# Creative writing with nucleus sampling
message = claude.messages.create(
model='claude-opus-4-5',
max_tokens=256,
temperature=1.0,
top_p=0.95,
messages=[{
'role': 'user',
'content': 'Write a short poem about the ocean.'
}]
)
print(message.content[0].text)Knowledge Check
What is the key advantage of top-p (nucleus) sampling over top-k sampling?
Recap: Top-p Nucleus Sampling
Top-p sampling builds a dynamic nucleus — the smallest set of tokens covering at least p of the total probability:
- p=1.0: full vocabulary, no restriction
- p=0.9: top 90% probability mass — typical creative setting
- p=0.5: very focused — risk of repetition
The nucleus expands when the model is uncertain and contracts when confident. This prevents tail sampling (gibberish from improbable tokens) while preserving diversity. Next lesson: top-k sampling and how it differs from top-p.
Frequently asked questions
Is the “Top-p Nucleus Sampling” lesson free?
Yes — the full text of “Top-p Nucleus Sampling” is free to read here on the web, and the AI Prompt Engineering course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the AI Prompt Engineering course, upgrade to CoddyKit PRO.
What will I learn in “Top-p Nucleus Sampling”?
How top-p restricts sampling to the most probable token set. You practise AI Prompt Engineering with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start AI Prompt Engineering?
No prior experience is required. AI Prompt Engineering on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Top-p Nucleus Sampling” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this AI Prompt Engineering lesson?
Yes. Every AI Prompt Engineering lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- What Is Temperature in LLMs?
- Top-p Nucleus Sampling
- Top-k Sampling
- Choosing Parameters for Your Use Case