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.
Mỗi LLM autoregressive hoàn thành text từng token một. Ở 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. Các tham số sampling quyết định vector đó trở thành token tiếp theo như thế nào. 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.
Bài này cover pipeline sampling bạn điều khiển lúc inference. Để hiểu sâu tokenizer và math, xem Tokenization & Sampling Deep Dive.
Mở demo đầy đủ:
Từ logits đến token tiếp theo
Một lần forward pass transformer sinh một logit cho mỗi entry trong vocabulary. 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
Vòng lặp chạy đến khi stop token, max tokens, hoặc stopping rule tùy chỉnh kích hoạt. 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 và phân phối cơ sở
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)
Implementation ổn định số học trừ max(z) trước khi lũy thừa để tránh overflow. Phân phối softmax thô phản ánh model “tin” gì trước mọi nút sampling. Thường một token chiếm ưu thế — vd " sunny" 40% trong khi " foggy" chỉ 0.3%.
Callout: Logit là output của model; xác suất là cấu trúc lúc inference. Đổi
temperaturekhông chạy lại transformer — chỉ reshape cùng logits đó.
Greedy decoding vs sampling
Greedy decoding chọn argmax(P) — token xác suất cao nhất mỗi bước. Deterministic (với logits cố định) và hay lặp. Nhiều API xấp xỉ bằng temperature=0, dù provider vẫn có thể post-process tinh tế.
Sampling rút từ phân phối xác suất — như tung xúc xắc có trọng số. 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. Đá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 — công thức và trực giác
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]))
Ở T=0.2, " sunny" có thể lên ~85%; ở T=1.8, " rainy" và " cloudy" có phần đáng kể. Kéo slider temperature trên demo để thấy cột xác suất thay đổi trực tiếp.
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. 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 — giữ k token tốt nhất, bỏ phần còn lại
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. 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%
Ưu: đơn giản, nhanh, giới hạn entropy xấu nhất. 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) — cắt thích ứng
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. 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: 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, và vLLM đều expose các nút này; thứ tự chính xác khác nhau — xem docs provider.
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). k cố định không thích ứng cả hai trong một lần chạy.
min_p — ghi chú ngắn
min_p (ngưỡng xác suất tối thiểu) loại token có P(i) < min_p × max(P) sau softmax. Loại phần đuôi xác suất thấp mà không cần k hoặc p cố định. Một số engine inference local (llama.cpp, vLLM) expose cùng top_p. Hữu ích khi muốn hành vi kiểu nucleus với sàn tương đối trên likelihood.
Penalty lặp, frequency, và presence
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
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. 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 và determinism — vì sao temp 0 không đảm bảo
Truyền seed cho API yêu cầu lần rút sampling tái lập được. 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. Thực tế, determinism hoàn toàn khó nắm:
- Tính không kết hợp của số thực trên GPU kernel và batch size
- Phần cứng / driver / cuDNN khác phiên bản
- Routing phía provider (model shard, speculative decoding)
- Request đồng thời và layout KV-cache khi inference batch
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 schema tool-call và hash, không chỉ chuỗi cuối.
Playbook nhiệt độ cho agent
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: 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. Trộn cả hai trong một stream ở T=1.0 dễ có reasoning đúng rồi hallucinate API path.
Tương tác với structured và JSON output
API hiện đại có JSON mode, structured outputs, và grammar / constraint decoding — bỏ qua một phần sampling thuần. Bên trong, logit token không hợp lệ có thể bị mask -∞ trước softmax. Mạnh hơn chỉ hạ temperature.
Dù vậy tham số sampling vẫn quan trọng khi có constraint:
- Giữa các token hợp lệ, temperature vẫn ảnh hưởng synonym, thứ tự field, hoặc literal số
- 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: 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
};
Gắn pipeline lại
Mô hình tư duy debug output agent lạ:
- Xem hình dạng logits (định tính): model tự tin hay phẳng ở bước này?
- Kiểm tra temperature: bạn đang sample trong khi muốn greedy?
- Kiểm tra top_p / top_k: nucleus có loại token bạn cần (tên tool hiếm)?
- Kiểm tra penalty: frequency penalty có giết keyword lặp bắt buộc?
- 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
Điểm chính
- 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 / T thấp cho agent khi đúng quan trọng hơn đa dạng — tool, JSON, routing.
- T cao hơn khi cần trajectory đa dạng — brainstorm, kế hoạch thay thế.
- top_p thích ứng với uncertainty từng bước tốt hơn top_k cố định.
- Penalty, seed, và constraint xếp chồng lên — tham số sampling một mình không tạo agent đáng tin.
Tiếp theo: cách điều hướng thứ được sample qua prompt, system message, và few-shot — Prompt Engineering for Agents.
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