Bandits, exploration, and sampling

Strip an MDP down to a single state and you get a bandit: no transitions to reason about, no discounting, just the purest form of the one dilemma that never goes away in reinforcement learning. Do I take the action that looks best right now, or do I try something else to learn whether "best" is really best? That is exploration versus exploitation, and it is not a footnote. It is the reason temperature exists as a decoding knob, it is the reason RL fine-tuning can quietly strangle itself through "entropy collapse," and it is why every serious RLVR recipe carries some term whose only job is to keep the policy from getting too sure of itself too soon. This chapter derives the bandit machinery lightly and spends most of its energy on the LLM translation, because the translation is where the money is.

Theory

The -armed bandit

You face actions (arms). Each time you pull arm you receive a reward drawn from a fixed but unknown distribution with mean

This is the action value from Chapter 5.2, collapsed to a single state so I can drop the state argument. If you knew every you would pull forever and be done. You do not, so you estimate. Let be your estimate of at time . The natural estimator is the sample average of the rewards seen so far from arm :

By the law of large numbers as the count of pulls of grows, but only if you keep pulling . That "if" is the whole problem.

Incremental mean: why you never store the history

Storing every past reward to recompute (2) is wasteful. Let be the estimate after rewards and the -th reward for a given arm. Then

Split the last expression and simplify:

This is the archetypal RL update: new estimate = old estimate + step size × (target − old estimate). The term is a prediction error, and is a step size that shrinks over time. Replace with a constant and you get an exponentially-weighted recency-biased average, which is what you want in a nonstationary problem where drifts. RL fine-tuning of an LLM is emphatically nonstationary, because the policy you are learning changes the distribution of states you visit, so constant step sizes are the norm there.

The exploration-exploitation dilemma and three ways to handle it

If you always pull (pure greedy), you can lock onto an arm that got lucky early and never discover a better one whose first few pulls were unlucky. You need to explore. Three classic mechanisms, in rising order of sophistication:

-greedy. With probability exploit (pull the greedy arm), with probability explore (pull a uniformly random arm). Dead simple, and it works, but it explores indiscriminately: a clearly terrible arm gets pulled as often as a promising-but-uncertain one.

Upper confidence bound (UCB). Explore in proportion to how uncertain you are, not uniformly. Pick

where is the number of pulls of so far and tunes the exploration bonus. Arms pulled rarely have a large bonus and get tried; arms pulled often have a small bonus and are trusted. This "optimism in the face of uncertainty" is provably near-optimal for stationary bandits.

Boltzmann / softmax. Convert estimated values into a probability distribution and sample. This is the one that matters for LLMs, so it gets its own equation:

The parameter is a temperature. As the softmax concentrates all mass on the greedy arm (pure exploitation); as it flattens to uniform (pure exploration). Look at (5) and then look at how a language model picks its next token, and you should feel a jolt of recognition, because they are the same equation.

Regret, lightly

How do you score an exploration strategy? By regret: the cumulative gap between the reward you got and the reward the best arm would have given.

Pure greedy can suffer linear regret: if it locks onto a suboptimal arm, the per-step gap never closes and grows like . Good strategies achieve logarithmic regret, , and the Lai-Robbins result says you cannot do better than logarithmic in general. I will not prove that bound (it is a KL-divergence argument on how many pulls it takes to distinguish two reward distributions), but the intuition is worth stating plainly.

Why regret is at least logarithmic (intuition, not a proof)

To be confident that a suboptimal arm is really worse than the best arm , you have to pull enough times that its sample-average reward separates from 's by more than the noise. If the reward noise has scale and the value gap is , the standard error of after pulls is , so you need roughly

pulls to be sure. Each of those pulls costs you in regret, contributing to for that arm. The appears once you demand the confidence grow with the horizon (you must keep re-checking as grows), which multiplies the pull count by a factor. The takeaway for LLM training: exploration is not free, but the cost of confirming an arm is bad is bounded, so a little exploration buys a lot of insurance. Refuse to explore and you risk linear regret, which in fine-tuning shows up as a policy that commits early to a mediocre reasoning style and never escapes it.

Temperature as the LLM's exploration knob

A language model produces a vector of logits over the vocabulary at each step. The sampling distribution is a tempered softmax, exactly (5) with the logits playing the role of the value estimates:

So temperature is literally Boltzmann exploration bolted onto next-token prediction. At (greedy decoding, argmax) the model exploits: it always emits its single most likely token, deterministic and safe and often bland. Crank up and the model explores, sampling rarer tokens, which is what you want during RL rollouts because you cannot learn from an answer you never generate. If your rollout temperature is too low, every completion for a given prompt is nearly identical, the reward signal has no variation to learn from, and gradient estimates collapse toward zero. If it is too high, completions are gibberish and rewards are uniformly low for the wrong reason. Choosing rollout temperature is choosing an exploration rate, and it is one of the few genuinely load-bearing hyperparameters in RLVR.

There is a clean derivative fact that makes the knob's behavior precise: temperature is a smooth interpolation between the uniform distribution and the point mass on the argmax.

Temperature interpolates uniform and greedy

Consider two tokens with logit gap . Their probability ratio under (7) is

As , the exponent , so the ratio blows up and token 1 takes essentially all the mass: the distribution collapses to the argmax. As , the exponent , so the ratio and the two tokens become equally likely: the distribution flattens toward uniform over the whole vocabulary. Because this holds for every pair of tokens, the entire distribution slides monotonically from a point mass () to uniform () as increases. Temperature is a single dial spanning pure exploitation to pure exploration, which is exactly the bandit tradeoff of (5).

Top-k and top-p: truncation is exploration control too

Temperature is the smooth exploration dial, but in practice LLM decoding usually stacks a second, sharper control on top of it: truncated sampling. Top-k keeps only the highest-probability tokens and renormalizes the softmax over just those, zeroing the rest. Top-p (nucleus) sampling keeps the smallest set of tokens whose cumulative probability first exceeds , so the number of candidates flexes with how peaked the distribution is. Both are, in the bandit language, hard restrictions of the action set before sampling: they forbid the long tail of low-value arms entirely rather than merely making them unlikely.

This matters for RL rollouts in a way that is easy to get wrong. Truncation removes exploration in the tail. If you generate RLVR rollouts with an aggressive top-k of, say, , you have made decoding greedy no matter what temperature says, and every completion for a prompt will be identical, giving you zero learnable variation. Conversely, leaving the full tail open at high temperature can let the policy wander into token sequences it will never actually deploy at inference time, creating a train-inference mismatch. The practical rule I follow is to make rollout sampling match, or be slightly more exploratory than, the decoding settings you will evaluate under, so that the reward signal reflects behavior you actually intend to keep. Truncation is not a rounding detail; it is a second exploration knob sitting in series with temperature.

Contextual bandits: the bridge to full RL

The pure -armed bandit has one state, which is why it is the cleanest place to study exploration. A contextual bandit adds a state that you observe before choosing, but still with no transitions: each round you see a context , pick an action, get a reward, and the context for the next round is drawn independently. Action values become context-dependent, , and the policy becomes a conditional distribution . This is exactly the sequence-level view of LLM generation from Chapter 5.1: the prompt is the context, the whole completion is the single action, the verifier is the reward, and there is no transition to a "next prompt" that your action influenced. GRPO, at its core, treats reasoning-model training as a contextual bandit, which is why the exploration machinery of this chapter, temperature and entropy, is the machinery that actually governs it, and why the value-function and multi-step credit-assignment apparatus of Chapter 5.2 can be sidestepped. The lab in Chapter 5.5 is literally a contextual bandit for that reason.

Entropy, and how RL fine-tuning collapses it

The right way to measure how much a policy explores is its entropy. For the next-token distribution,

Entropy is maximized ( nats) by the uniform distribution and is zero for a deterministic policy. Here is the failure mode that bites RL fine-tuning, and it is worth taking seriously because it is not hypothetical, it is the default trajectory of a naive run.

Policy-gradient training pushes probability mass toward actions that earned high reward. That is the whole idea. But nothing in the bare objective pushes back, so the policy keeps sharpening: the entropy (8) falls, the rollouts for a given prompt become more and more alike, exploration dies, and the model converges prematurely onto whatever reasoning pattern happened to work early. This is entropy collapse. Once entropy is near zero the gradient signal starves, because with no variation among sampled completions there is no advantage to learn from (Chapter 5.5 makes "advantage needs variation" precise). The model gets stuck, sometimes at a genuinely mediocre policy, and no amount of further training rescues it because it can no longer generate the alternatives it would need to discover something better.

Entropy collapse is a silent killer, so instrument it

The reason entropy collapse is dangerous is that the reward curve can look fine while it happens. Reward climbs, then plateaus, and you shrug and call it converged, when actually the policy has gone deterministic and simply cannot improve. Always log the mean per-token entropy (8) of your rollouts as a first-class metric next to reward. Two standard countermeasures, both of which you will meet again in the GRPO and PPO chapters:

  • Entropy bonus. Add to the objective so the optimizer is paid to stay uncertain. This is the softmax-policy analogue of -greedy: a direct incentive to keep exploring.
  • KL penalty to a reference policy. Add to anchor the trained policy near the original model, which was high-entropy and fluent. This both prevents collapse and stops the policy from drifting into degenerate reward-hacking text.

On the baseline machine, entropy and KL are cheap scalars to compute from logits you already have, so there is no excuse not to log them (record the actual entropy trajectory of your first GRPO run: measured on the baseline machine — record value, date, driver).

Read-along: Sutton & Barto Chapter 2; Grokking AI Chapter 10

[S&B] Chapter 2 is the canonical bandit chapter. Section 2.2 is the -greedy setup, Section 2.4 derives the incremental mean, my (3); Section 2.6 covers nonstationarity and constant step sizes; Section 2.7 is UCB, my (4); Section 2.8 is the gradient-bandit / softmax view that anticipates (5) and the whole policy-gradient story of Chapter 5.4. Read Section 2.3 on the ten-armed testbed alongside the lab below, which is a miniature of it. For a gentler on-ramp, [GAIA] Chapter 10 walks through reinforcement learning with a slot-machine framing and Q-learning intuition and almost no calculus, which is a nice way to build the exploration-exploitation feel before returning to Sutton and Barto's formal treatment.

Tooling

The tool is the simulator: a ten-armed testbed you can run in a second to feel the difference between exploiting and exploring, and a temperature sweep that connects the bandit softmax directly to LLM decoding. Reuse the uv project from Chapter 5.1 (uv add numpy matplotlib if you have not already).

Lab

Two artifacts. First, an -greedy vs greedy comparison on a ten-armed bandit that prints how often pure greedy locks onto the wrong arm. Second, a temperature sweep over a fixed logit vector that prints entropy as a function of , making (7) and (8) concrete and previewing entropy collapse.

"""Two demos in one file.

(A) 10-armed bandit: greedy vs epsilon-greedy, averaged over runs.
    Shows that refusing to explore can lock onto a suboptimal arm.
(B) Temperature sweep: entropy of a tempered softmax vs tau, the
    exploration knob an LLM exposes as its sampling temperature.

Run:  uv run python labs/bandit_and_temperature.py
"""
from __future__ import annotations
import numpy as np


# ---------- (A) ten-armed testbed ----------
def run_bandit(epsilon: float, steps: int, rng: np.random.Generator):
    k = 10
    q_star = rng.normal(0.0, 1.0, size=k)      # true means
    best = int(np.argmax(q_star))
    Q = np.zeros(k)                            # estimates
    N = np.zeros(k)                            # pull counts
    optimal_pulls = 0
    for t in range(steps):
        if rng.random() < epsilon:
            a = rng.integers(k)                # explore
        else:
            a = int(np.argmax(Q))              # exploit
        reward = rng.normal(q_star[a], 1.0)    # noisy reward
        N[a] += 1
        Q[a] += (reward - Q[a]) / N[a]         # incremental mean, eq (3)
        optimal_pulls += (a == best)
    return optimal_pulls / steps


def bandit_demo(runs=500, steps=1000):
    rng = np.random.default_rng(1)
    for eps in (0.0, 0.01, 0.1):
        rate = np.mean([run_bandit(eps, steps, rng) for _ in range(runs)])
        label = "greedy" if eps == 0 else f"eps-greedy(e={eps})"
        print(f"{label:<22} optimal-arm rate over {steps} steps: {rate:.3f}")


# ---------- (B) temperature = LLM exploration knob ----------
def softmax(z, tau):
    z = z / tau
    z = z - z.max()                            # numerical stability
    e = np.exp(z)
    return e / e.sum()


def entropy(p):
    p = p[p > 0]
    return float(-(p * np.log(p)).sum())       # nats, eq (8)


def temperature_demo():
    # A plausible next-token logit vector: one clear favorite, a few
    # contenders, a long tail. Same shape an LLM produces per step.
    logits = np.array([6.0, 5.2, 4.8, 3.0, 2.5, 1.0, 0.5, 0.0, -1.0, -2.0])
    h_max = np.log(len(logits))
    print(f"\nmax possible entropy (uniform): {h_max:.3f} nats")
    for tau in (0.1, 0.5, 0.7, 1.0, 1.5, 2.0, 5.0):
        p = softmax(logits, tau)
        top = p.max()
        print(f"tau={tau:<4} entropy={entropy(p):.3f} nats   "
              f"P(argmax)={top:.3f}")


if __name__ == "__main__":
    print("=== (A) exploration on a 10-armed bandit ===")
    bandit_demo()
    print("\n=== (B) temperature sweep (LLM decoding knob) ===")
    temperature_demo()

What you should see. In part (A), pure greedy () lands on the optimal arm markedly less often than over 1000 steps, typically well under it, because greedy sometimes commits to an arm that got a lucky first pull and never re-checks, the linear-regret trap made visible. In part (B), entropy is tiny at with near 1 (this is what a collapsed policy looks like) and climbs steadily toward the uniform ceiling of nats as grows, with falling toward . That single monotone column of entropies is exactly the dial you turn when you set rollout temperature for RL fine-tuning: too low and you have preemptively collapsed, too high and you are sampling noise. Keeping that dial in the productive middle, and logging entropy so you notice when training pushes it down on its own, is most of what "exploration" means in practice for a reasoning model.

Note

Post angle: "The one knob that decides whether your AI keeps learning or gives up." Temperature is usually explained as a creativity slider for chatbots, but the deeper story is that it is a fifty-year-old idea from slot-machine math, the explore-versus-exploit dilemma, wearing a modern coat. When you train a reasoning model, the model is constantly tempted to become a know-it-all that always gives the same answer, and the moment it does, it stops being able to learn, because it can no longer surprise itself into finding a better answer. The essay connects casino odds to why a training run can look healthy on the reward chart while quietly going brain-dead (entropy collapse), and why the fix is to literally pay the model to stay a little unsure of itself.