Sampling for Agents: Temperature, Top-p, Top-k — When Randomness Helps or Hurts
How LLMs turn logits into tokens — temperature, top_p, top_k, penalties, seeds — and why agent builders tune sampling differently for tool calls vs brainstorming.
Part 2 of the Building AI Agents series {Phần 2}. Previous {Trước}: Tokens & Context Windows · Next {Tiếp}: Prompt Engineering for Agents.
Every autoregressive LLM completes text one token at a time {Mỗi LLM autoregressive hoàn thành text từng token một}. At each step the model emits a logit vector over the full vocabulary — raw scores, not probabilities {Ở mỗi bước model phát ra vector logit trên toàn vocabulary — điểm thô, chưa phải xác suất}. Your sampling parameters decide how that vector becomes the next token {Các tham số sampling quyết định vector đó trở thành token tiếp theo như thế nào}. For agent builders this is not academic trivia: the same prompt with temperature=0.2 vs temperature=1.0 can mean reliable JSON tool calls vs creative hallucination {Với người xây agent đây không phải lý thuyết suông: cùng prompt với temperature=0.2 vs temperature=1.0 có thể là tool call JSON ổn định hoặc hallucination sáng tạo}.
This post covers the sampling pipeline you control at inference time {Bài này cover pipeline sampling bạn điều khiển lúc inference}. For tokenizer internals and a deeper math walkthrough, see Tokenization & Sampling Deep Dive {Để hiểu sâu tokenizer và math, xem Tokenization & Sampling Deep Dive}.
Open the full demo {Mở demo đầy đủ}: /tools/llm-sampling-demo/.
From logits to the next token {Từ logits đến token tiếp theo}
A transformer forward pass produces one logit per vocabulary entry {Một lần forward pass transformer sinh một logit cho mỗi entry trong vocabulary}. Logits are unbounded real numbers — higher means “more likely” in a relative sense, but they are not probabilities until you apply softmax {Logit là số thực không giới hạn — cao hơn nghĩa là “có khả năng hơn” theo nghĩa tương đối, nhưng chưa phải xác suất cho đến khi áp dụng softmax}.
PROMPT: "The weather today is"
│
▼
Transformer (one forward pass)
│
▼
LOGITS[ vocab_size ] e.g. " sunny" → 3.2, " cloudy" → 2.1, …
│
▼
Temperature scaling logits / T
│
▼
Softmax → probability distribution (sums to 1)
│
▼
Filters (top_k, top_p) → truncate + renormalize
│
▼
Sample or argmax → chosen token appended to context
│
▼
Repeat until stop condition
The loop runs until a stop token, max tokens, or custom stopping rule fires {Vòng lặp chạy đến khi stop token, max tokens, hoặc stopping rule tùy chỉnh kích hoạt}. Agents care about every iteration because tool arguments, JSON braces, and reasoning steps are all single-token decisions stacked together {Agent quan tâm mỗi vòng lặp vì argument tool, dấu ngoặc JSON, và bước reasoning đều là chuỗi quyết định từng token}.
Softmax and the baseline distribution {Softmax và phân phối cơ sở}
Given logits z over vocabulary indices i, softmax converts them to probabilities {Cho logits z trên các chỉ số vocabulary i, softmax chuyển thành xác suất}:
P(i) = exp(z_i) / Σ_j exp(z_j)
Numerically stable implementations subtract max(z) before exponentiating to avoid overflow {Implementation ổn định số học trừ max(z) trước khi lũy thừa để tránh overflow}. The raw softmax distribution reflects what the model “believes” before any sampling knobs {Phân phối softmax thô phản ánh model “tin” gì trước mọi nút sampling}. Often one token dominates — e.g. " sunny" at 40% while " foggy" sits at 0.3% {Thường một token chiếm ưu thế — vd " sunny" 40% trong khi " foggy" chỉ 0.3%}.
Callout: Logits are model outputs; probabilities are inference-time constructs {Callout: Logit là output của model; xác suất là cấu trúc lúc inference}. Changing
temperaturenever re-runs the transformer — it only reshapes the same logits {Đổitemperaturekhông chạy lại transformer — chỉ reshape cùng logits đó}.
Greedy decoding vs sampling {Greedy decoding vs sampling}
Greedy decoding picks argmax(P) — the single highest-probability token every step {Greedy decoding chọn argmax(P) — token xác suất cao nhất mỗi bước}. It is deterministic (given fixed logits) and often repetitive {Deterministic (với logits cố định) và hay lặp}. Many APIs approximate this with temperature=0, though providers may still apply subtle post-processing {Nhiều API xấp xỉ bằng temperature=0, dù provider vẫn có thể post-process tinh tế}.
Sampling draws from the probability distribution — like rolling a weighted die {Sampling rút từ phân phối xác suất — như tung xúc xắc có trọng số}. Low-probability tokens can win, which enables paraphrase, exploration, and diverse agent trajectories {Token xác suất thấp vẫn có thể thắng, giúp paraphrase, khám phá, và trajectory agent đa dạng}. The tradeoff is variance: two runs with identical prompts can diverge completely {Đánh đổi là phương sai: hai lần chạy cùng prompt có thể phân nhánh hoàn toàn}.
| Strategy | Mechanism | Typical use |
|---|---|---|
Greedy / T→0 | Always highest-probability token | Extraction, classification, strict formats |
| Low temperature (0.1–0.3) | Sharpened distribution, rare surprises | Tool calls, JSON, code, reasoning chains |
| Medium (0.5–0.8) | Balanced fluency and consistency | General chat, summarization |
| High (1.0–1.5+) | Flat distribution, high entropy | Brainstorming, creative writing, ideation |
Temperature — math and intuition {Temperature — công thức và trực giác}
Temperature T scales logits before softmax {Nhiệt độ T scale logits trước softmax}:
P(i | T) = exp(z_i / T) / Σ_j exp(z_j / T)
| T value | Effect on distribution | Intuition |
|---|---|---|
T → 0⁺ | Approaches one-hot on argmax | Nearly greedy; minor float noise aside |
T = 1 | Unmodified model distribution | Default “natural” shape |
T > 1 | Flatter — tail tokens gain mass | More random, exploratory |
T < 1 | Sharper — peak token dominates | Conservative, predictable |
import math
def softmax(logits):
m = max(logits)
exps = [math.exp(x - m) for x in logits]
s = sum(exps)
return [e / s for e in exps]
def sample_logits(logits, temperature=1.0):
scaled = [z / temperature for z in logits]
return softmax(scaled)
# Example logits for next word after "The weather today is"
logits = {" sunny": 3.2, " cloudy": 2.1, " rainy": 1.4, " foggy": -1.8}
tokens = list(logits.keys())
vals = list(logits.values())
for T in [0.2, 1.0, 1.8]:
probs = sample_logits(vals, T)
ranked = sorted(zip(tokens, probs), key=lambda x: -x[1])
print(f"T={T}:", ", ".join(f"{t.strip()} {p:.1%}" for t, p in ranked[:3]))
At T=0.2, " sunny" might jump to ~85%; at T=1.8, " rainy" and " cloudy" gain meaningful share {Ở T=0.2, " sunny" có thể lên ~85%; ở T=1.8, " rainy" và " cloudy" có phần đáng kể}. Use the demo above to drag the temperature slider and watch bars reshape live {Kéo slider temperature trên demo để thấy cột xác suất thay đổi trực tiếp}.
Callout: Temperature does not add “creativity” magically — it redistributes probability mass toward less likely tokens {Callout: Temperature không tạo “sáng tạo” một cách ma thuật — nó phân bổ lại xác suất sang token ít có khả năng hơn}. If the model assigns 0.01% to a nonsense token, even high T rarely picks it; garbage in logits, garbage in sampling {Nếu model gán 0.01% cho token vô nghĩa, dù T cao cũng hiếm khi chọn; logits tệ thì sampling tệ}.
Top-k — keep the k best, discard the rest {Top-k — giữ k token tốt nhất, bỏ phần còn lại}
Top-k sampling zeroes out every token outside the k highest probabilities, then renormalizes {Top-k sampling gán 0 mọi token ngoài k xác suất cao nhất, rồi chuẩn hóa lại}. With top_k=40 (a common default), the bottom 99.99% of a 100k vocabulary never gets sampled {Với top_k=40 (default phổ biến), 99.99% vocabulary phía đưới không bao giờ được sample}.
Raw probs: sunny 35% cloudy 22% rainy 15% … foggy 0.2% [50k more]
top_k = 3 → keep sunny, cloudy, rainy → renormalize to 100%
Pros: simple, fast, caps worst-case entropy {Ưu: đơn giản, nhanh, giới hạn entropy xấu nhất}. Cons: fixed k ignores context — when the model is confident, k=40 still leaves 39 distractors; when uncertain, k=5 may truncate valid options {Nhược: k cố định bỏ qua ngữ cảnh — model tự tin thì k=40 vẫn còn 39 nhiễu; không chắc thì k=5 có thể cắt mất lựa chọn hợp lệ}.
Top-p (nucleus) — adaptive truncation {Top-p (nucleus) — cắt thích ứng}
Nucleus sampling (Holtzman et al., 2019) keeps the smallest set of tokens whose cumulative probability ≥ p, then renormalizes {Nucleus sampling (Holtzman et al., 2019) giữ tập nhỏ nhất token có xác suất tích lũy ≥ p, rồi chuẩn hóa lại}. Unlike top-k, the candidate set grows and shrinks per step {Khác top-k, tập ứng viên co giãn theo từng bước}.
Sorted: sunny 35% → cum 35%
cloudy 22% → cum 57%
rainy 15% → cum 72%
cold 9% → cum 81%
warm 6% → cum 87% ← top_p=0.9 stops here (5 tokens)
Different step, flat distribution:
maybe 12% → cum 12%
perhaps 11% → cum 23%
… 20 tokens needed to reach p=0.9
| Parameter | Behavior when model is confident | Behavior when model is uncertain |
|---|---|---|
top_k=40 | Still 40 candidates | Still 40 candidates |
top_p=0.9 | Maybe 2–5 candidates | Maybe 30–80 candidates |
Callout: Most production stacks apply top_p after temperature and optionally top_k as a hard cap {Callout: Hầu hết stack production áp top_p sau temperature và tùy chọn top_k làm giới hạn cứng}. OpenAI, Anthropic, and vLLM all expose these knobs; exact ordering varies — check your provider docs {OpenAI, Anthropic, và vLLM đều expose các nút này; thứ tự chính xác khác nhau — xem docs provider}.
Why agents prefer top_p over top_k alone: tool-name tokens often spike one step (low entropy) while open-ended reasoning spreads mass (high entropy) {Vì sao agent thích top_p hơn top_k đơn lẻ: token tên tool thường spike một bước (entropy thấp) còn reasoning mở rộng phân tán (entropy cao)}. A fixed k cannot adapt to both in one run {k cố định không thích ứng cả hai trong một lần chạy}.
min_p — a brief note {min_p — ghi chú ngắn}
min_p (minimum probability threshold) drops any token with P(i) < min_p × max(P) after softmax {min_p (ngưỡng xác suất tối thiểu) loại token có P(i) < min_p × max(P) sau softmax}. It removes low-likelihood tail mass without a fixed k or p {Loại phần đuôi xác suất thấp mà không cần k hoặc p cố định}. Some local inference engines (llama.cpp, vLLM) expose it alongside top_p {Một số engine inference local (llama.cpp, vLLM) expose cùng top_p}. Useful when you want nucleus-like behavior with an absolute floor on relative likelihood {Hữu ích khi muốn hành vi kiểu nucleus với sàn tương đối trên likelihood}.
Repetition, frequency, and presence penalties {Penalty lặp, frequency, và presence}
Sampling parameters are not the only levers — logit processors adjust scores before softmax based on tokens already generated {Tham số sampling không phải lever duy nhất — logit processor điều chỉnh điểm trước softmax dựa trên token đã sinh}.
| Penalty | What it penalizes | Effect |
|---|---|---|
| Repetition | Tokens appearing in recent window | Reduces loops (“the the the”) |
| Frequency | Proportional to count in context | Stronger push against overused tokens |
| Presence | Binary: token appeared or not | Lighter nudge away from any repeat |
adjusted_logit(w) = logit(w) - penalty × f(w, context)
f = count(w) → frequency penalty
f = 1 if w seen else 0 → presence penalty
Agents hitting infinite tool-call loops or re-fetching the same URL often benefit from modest frequency_penalty (0.1–0.5) without lowering temperature {Agent rơi vào vòng lặp tool-call vô hạn hoặc fetch lại cùng URL thường được từ frequency_penalty (0.1–0.5) mà không cần hạ temperature}. Penalties interact with sampling — a penalized token may fall out of the top_p nucleus entirely {Penalty tương tác với sampling — token bị phạt có thể rơi khỏi nucleus top_p hoàn toàn}.
Seed and determinism — why temp 0 is not a guarantee {Seed và determinism — vì sao temp 0 không đảm bảo}
Passing a seed to the API requests reproducible sampling draws {Truyền seed cho API yêu cầu lần rút sampling tái lập được}. With temperature=0, most providers skip random sampling and take argmax — runs should match {Với temperature=0, hầu hết provider bỏ sampling ngẫu nhiên và lấy argmax — lần chạy nên khớp}. In practice, full determinism is elusive {Thực tế, determinism hoàn toàn khó nắm}:
- Floating-point non-associativity across GPU kernels and batch sizes {Tính không kết hợp của số thực trên GPU kernel và batch size}
- Different hardware / driver / cuDNN versions {Phần cứng / driver / cuDNN khác phiên bản}
- Provider-side routing (model shard, speculative decoding) {Routing phía provider (model shard, speculative decoding)}
- Concurrent requests and KV-cache layout in batched inference {Request đồng thời và layout KV-cache khi inference batch}
Callout: For agent evals, treat “same seed + temp 0” as highly correlated, not mathematically identical across environments {Callout: Với eval agent, coi “cùng seed + temp 0” là tương quan cao, không phải giống hệt toán học trên mọi môi trường}. Log tool-call schemas and hashes, not just final strings {Log schema tool-call và hash, không chỉ chuỗi cuối}.
Agent temperature playbook {Playbook nhiệt độ cho agent}
Different agent phases want different entropy {Các phase agent cần entropy khác nhau}.
| Agent task | Recommended T | top_p | Rationale |
|---|---|---|---|
| Function / tool selection | 0.0–0.2 | 0.1–0.5 | Schema token sequences are brittle |
| Structured JSON output | 0.0–0.3 | 0.1–0.6 | Braces, quotes, keys must be exact |
| Multi-step reasoning (CoT) | 0.2–0.5 | 0.8–0.95 | Some path diversity, mostly coherent |
| RAG answer synthesis | 0.3–0.7 | 0.9 | Natural prose, grounded in context |
| Brainstorming / ideation | 0.8–1.2 | 0.95–1.0 | Explore the tail of the distribution |
| Self-critique / reflection | 0.4–0.7 | 0.9 | Varied feedback without chaos |
Pattern: run a low-temperature planner (tool choice, routing) and optionally a higher-temperature writer for user-facing prose in a separate call {Pattern: chạy planner nhiệt độ thấp (chọn tool, routing) và tùy chọn writer nhiệt độ cao hơn cho prose hướng user ở call riêng}. Mixing both in one stream at T=1.0 is how you get valid reasoning followed by a hallucinated API path {Trộn cả hai trong một stream ở T=1.0 dễ có reasoning đúng rồi hallucinate API path}.
Interaction with structured and JSON output {Tương tác với structured và JSON output}
Modern APIs offer JSON mode, structured outputs, and grammar / constraint decoding — partially bypassing naive sampling {API hiện đại có JSON mode, structured outputs, và grammar / constraint decoding — bỏ qua một phần sampling thuần}. Under the hood, logits for illegal tokens may be masked to -∞ before softmax {Bên trong, logit token không hợp lệ có thể bị mask -∞ trước softmax}. That is stronger than low temperature alone {Mạnh hơn chỉ hạ temperature}.
Still, sampling params matter even with constraints {Dù vậy tham số sampling vẫn quan trọng khi có constraint}:
- Among legal tokens, temperature still affects which synonym, field ordering, or numeric literal appears {Giữa các token hợp lệ, temperature vẫn ảnh hưởng synonym, thứ tự field, hoặc literal số}
- Grammar masks do not fix wrong semantics —
"status": "succes"may be valid JSON with a typo field value {Grammar mask không sửa semantics sai —"status": "succes"vẫn có thể là JSON hợp lệ với giá trị sai chính tả} - Fallback: when constrained decoding is unavailable,
T=0+ strict prompt + regex validation remains the agent baseline {Fallback: khi không có constrained decoding,T=0+ prompt chặt + validate regex vẫn là baseline agent}
// Typical agent inference profile
const plannerCall = {
model: "gpt-4.1",
temperature: 0.1,
top_p: 0.3,
response_format: { type: "json_schema", json_schema: toolPlanSchema },
seed: 42,
};
const writerCall = {
model: "gpt-4.1",
temperature: 0.7,
top_p: 0.95,
// free-form markdown for the user
};
Putting the pipeline together {Gắn pipeline lại}
A mental model for debugging weird agent output {Mô hình tư duy debug output agent lạ}:
- Inspect logits shape (qualitatively): is the model confident or flat on this step? {Xem hình dạng logits (định tính): model tự tin hay phẳng ở bước này?}
- Check temperature: are you sampling when you meant to be greedy? {Kiểm tra temperature: bạn đang sample trong khi muốn greedy?}
- Check top_p / top_k: is the nucleus excluding the token you need (rare tool name)? {Kiểm tra top_p / top_k: nucleus có loại token bạn cần (tên tool hiếm)?}
- Check penalties: is frequency penalty killing a required repeated keyword? {Kiểm tra penalty: frequency penalty có giết keyword lặp bắt buộc?}
- Check constraints: does JSON mode cover this output path? {Kiểm tra constraint: JSON mode có cover path output này?}
DEBUG CHECKLIST
───────────────
□ temperature appropriate for phase (plan vs write)
□ top_p not too aggressive for rare tokens
□ penalties not fighting required repetition
□ seed logged for eval reproduction
□ structured output or post-validate for tool args
Key takeaways {Điểm chính}
- Logits → temperature-scaled softmax → optional top_k / top_p → sample or argmax is the core loop {Logits → softmax scale nhiệt độ → top_k / top_p tùy chọn → sample hoặc argmax là vòng lặp cốt lõi}.
- Greedy / low T for agents when correctness beats variety — tools, JSON, routing {Greedy / T thấp cho agent khi đúng quan trọng hơn đa dạng — tool, JSON, routing}.
- Higher T when you want diverse trajectories — brainstorming, alternative plans {T cao hơn khi cần trajectory đa dạng — brainstorm, kế hoạch thay thế}.
- top_p adapts to per-step uncertainty better than fixed top_k {top_p thích ứng với uncertainty từng bước tốt hơn top_k cố định}.
- Penalties, seeds, and constraints layer on top — sampling params alone do not make a reliable agent {Penalty, seed, và constraint xếp chồng lên — tham số sampling một mình không tạo agent đáng tin}.
Next up: how you steer what gets sampled via prompts, system messages, and few-shot exemplars — Prompt Engineering for Agents {Tiếp theo: cách điều hướng thứ được sample qua prompt, system message, và few-shot — Prompt Engineering for Agents}.
The Building AI Agents series {Loạt bài Building AI Agents}
- Tokens & Context Windows
- Sampling: temperature, top_p, top_k (current)
- Prompt Engineering for Agents
- Stopping Criteria & Output Control
- Context Engineering & Memory
- Fine-tuning vs Prompting vs RAG
- Evaluating LLMs & Agents
- Choosing a Model
- Function Calling & Tool Use
- Agent Patterns: ReAct, Reflection, Planning