jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

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 temperature never re-runs the transformer — it only reshapes the same logits {Đổi temperature khô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}.

StrategyMechanismTypical use
Greedy / T→0Always highest-probability tokenExtraction, classification, strict formats
Low temperature (0.1–0.3)Sharpened distribution, rare surprisesTool calls, JSON, code, reasoning chains
Medium (0.5–0.8)Balanced fluency and consistencyGeneral chat, summarization
High (1.0–1.5+)Flat distribution, high entropyBrainstorming, 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 valueEffect on distributionIntuition
T → 0⁺Approaches one-hot on argmaxNearly greedy; minor float noise aside
T = 1Unmodified model distributionDefault “natural” shape
T > 1Flatter — tail tokens gain massMore random, exploratory
T < 1Sharper — peak token dominatesConservative, 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"" 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
ParameterBehavior when model is confidentBehavior when model is uncertain
top_k=40Still 40 candidatesStill 40 candidates
top_p=0.9Maybe 2–5 candidatesMaybe 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}.

PenaltyWhat it penalizesEffect
RepetitionTokens appearing in recent windowReduces loops (“the the the”)
FrequencyProportional to count in contextStronger push against overused tokens
PresenceBinary: token appeared or notLighter 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 taskRecommended Ttop_pRationale
Function / tool selection0.0–0.20.1–0.5Schema token sequences are brittle
Structured JSON output0.0–0.30.1–0.6Braces, quotes, keys must be exact
Multi-step reasoning (CoT)0.2–0.50.8–0.95Some path diversity, mostly coherent
RAG answer synthesis0.3–0.70.9Natural prose, grounded in context
Brainstorming / ideation0.8–1.20.95–1.0Explore the tail of the distribution
Self-critique / reflection0.4–0.70.9Varied 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ạ}:

  1. 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?}
  2. Check temperature: are you sampling when you meant to be greedy? {Kiểm tra temperature: bạn đang sample trong khi muốn greedy?}
  3. 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)?}
  4. 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?}
  5. 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}

  1. Tokens & Context Windows
  2. Sampling: temperature, top_p, top_k (current)
  3. Prompt Engineering for Agents
  4. Stopping Criteria & Output Control
  5. Context Engineering & Memory
  6. Fine-tuning vs Prompting vs RAG
  7. Evaluating LLMs & Agents
  8. Choosing a Model
  9. Function Calling & Tool Use
  10. Agent Patterns: ReAct, Reflection, Planning