Chapter 15 · Section 15.7 · 55 min

Language models as policies

Everything in this chapter so far has been about robots in grids and agents in corridors. Here is why we built it. Take a language model fine-tuned to follow instructions (Chapter 14), give it a prompt, let it write a response, and score the response with a reward model trained on human preferences or with a program that checks the final answer. You want the model to produce higher-scoring responses. That is a reinforcement learning problem, and the model is the policy.

This last section makes that sentence precise. We set up the token-level MDP and the sequence-level bandit and show that they give the same gradient, look at what a single reward at the end of a long response does to credit assignment, and then write down the objective that RLHF, DPO, and GRPO all start from, expected reward minus a KL penalty toward a reference model. We derive its per-token form, run it on a toy language model small enough to solve exactly, find two ways that real implementations get its gradient wrong, and finish with a frank list of what makes RL on language models unusual RL.

Tokens as actions, prefixes as states

Write xx for the prompt, drawn from a distribution D\mathcal{D} of prompts, and y=(y1,…,yT)y = (y_1, \dots, y_T) for the response, a sequence of tokens from the vocabulary V\mathcal{V} ending with an end-of-sequence token or at a maximum length. (We index response tokens from 1, as in the language-model chapters, so step tt produces token yty_t.) The MDP is

  • state st=(x,y<t)s_t = (x, y_{<t}), the prompt and everything generated so far,
  • action at=yt∈Va_t = y_t \in \mathcal{V}, the next token,
  • policy πθ(yt∣x,y<t)\pi_\theta(y_t \mid x, y_{<t}), the model's next-token distribution, the softmax over the vocabulary of §6.4,
  • transition st+1=(x,y≤t)s_{t+1} = (x, y_{\le t}), append the token, which is deterministic and known,
  • start distribution p0=Dp_0 = \mathcal{D}, the prompts,
  • reward rt=0r_t = 0 for t<Tt < T and rT=r(x,y)r_T = r(x, y), a single score for the finished response,

with no discounting, γ=1\gamma = 1, which is safe because every episode ends by the maximum length. The state is the whole history, so the process is Markov by construction (§15.1). The state space is astronomically large, and nobody enumerates it. The network generalizes across prefixes, exactly as it does in pretraining.

Two views of the same policy

The same model is also a policy over whole responses, since the chain rule of probability gives

πθ(y∣x)=∏t=1Tπθ(yt∣x,y<t),log⁡πθ(y∣x)=∑t=1Tlog⁡πθ(yt∣x,y<t).\pi_\theta(y \mid x) = \prod_{t=1}^{T}\pi_\theta(y_t \mid x, y_{<t}), \qquad \log\pi_\theta(y\mid x) = \sum_{t=1}^{T}\log\pi_\theta(y_t\mid x, y_{<t}).

In this sequence-level view, the problem is a contextual bandit (§15.1). The context is the prompt, the action is the entire response, and the reward arrives at once. The objective is

J(θ)=Ex∼D Ey∼πθ(⋅∣x)[r(x,y)],J(\theta) = \mathbb{E}_{x\sim\mathcal{D}}\,\mathbb{E}_{y\sim\pi_\theta(\cdot\mid x)}\big[r(x, y)\big],

and the policy gradient of §15.3, with a baseline b(x)b(x) that may depend on the prompt but not on the response, is

∇θJ=Ex,y[(r(x,y)−b(x))∑t=1T∇θlog⁡πθ(yt∣x,y<t)].\nabla_\theta J = \mathbb{E}_{x, y}\Big[\big(r(x,y) - b(x)\big)\sum_{t=1}^{T}\nabla_\theta\log\pi_\theta(y_t\mid x, y_{<t})\Big].

In the token-level view, the reward-to-go from any step is Gt=∑k≥trk=r(x,y)G_t = \sum_{k\ge t}r_k = r(x, y), since the only reward is at the end. So REINFORCE with reward-to-go gives every token the same weight, r(x,y)r(x,y), and the two views produce exactly the same estimator. They are two descriptions of one problem.

They differ in how you estimate the advantage, and that is the design choice that separates the main LLM RL algorithms.

  • Token-level critic. Learn a value Vψ(x,y<t)V_\psi(x, y_{<t}) (a network with parameters ψ\psi) for every prefix and use GAE over tokens (§15.5). Each token gets its own advantage, A^t≈r(x,y)−Vψ(st)\hat A_t \approx r(x,y) - V_\psi(s_t) when λ=1\lambda = 1, so a token that made a good ending more likely gets more credit than one that did not. This is PPO for RLHF, and the critic is a whole second language model with a scalar head (§16.4).
  • Sequence-level baseline. Sample several responses to the same prompt and use their average reward as b(x)b(x), with every token of a response sharing its advantage r(x,y)−b(x)r(x, y) - b(x). This is RLOO and GRPO, which drop the critic entirely (§18.4).

Here is a toy language model small enough to check everything exactly. It has a vocabulary of 4 tokens and always writes responses of exactly 3 tokens, so there are only 43=644^3 = 64 possible responses. Its policy is a table of logits, one row for each of the 1+4+16=211 + 4 + 16 = 21 possible prefixes, so it can represent any distribution over responses. The reference model's logits are random. The reward is a "verifier" that pays 1 when the response contains token 0 exactly twice.

Python · cell 1

The per-token probabilities multiply into a proper distribution over all 64 responses, and the reference model earns the reward about 8% of the time. Computing sequence log-probabilities this way, by gathering each token's log-probability from a stable log-softmax and summing over the real tokens, is the basic operation of every LLM RL and preference method, and it is worth writing once carefully.

Core

Per-token and sequence log-probabilities with a mask

A batch of BB responses is padded to length TT. logits has shape (B, T, V) (the model's logits at each position), tokens has shape (B, T) (the token produced at each position), and mask has shape (B, T) with 1 for real response tokens and 0 for padding. Implement sequence_logprobs(logits, tokens, mask) returning (token_logp, seq_logp), where token_logp[b, t] =log⁡softmax⁡(logits[b,t])tokens[b,t]= \log\operatorname{softmax}(\text{logits}[b,t])_{\text{tokens}[b,t]} at real positions and 0 at padding, and seq_logp[b] is the sum over real positions. It must be stable for logits in the hundreds.

Hidden tests, hints, and AI help, from $1.99 a month.

Sparse terminal rewards and credit assignment

A reward that arrives only at the end of a 1,000-token response tells you that the response was good or bad, not which tokens made it so. This is the credit assignment problem of §15.1 at its most extreme, and it is why LLM RL needs so many samples. With a sequence-level baseline every token of a good response is pushed up by the same amount, the crucial step in a proof and the filler words around it alike. Over many samples the noise averages out, since tokens that matter are correlated with reward across samples and tokens that do not are not, but the averaging is slow, and the variance grows with the response length (§15.3).

A token-level critic can do better in principle, because Vψ(x,y<t)V_\psi(x, y_{<t}) can notice that the response became much more likely to succeed after a particular step, giving that step a large TD error. In practice, learning such a critic is hard. It must predict the final reward from a partial response, with a single noisy label per response, and an inaccurate critic biases the advantages (§15.4). That difficulty is one reason the critic-free methods of Chapter 18 took over reasoning RL, and why process rewards that score intermediate steps are an active topic (§18.6).

The KL-regularized objective

Maximizing J(θ)J(\theta) alone is dangerous when the reward comes from a learned model. A reward model is accurate on responses that look like its training data and arbitrary elsewhere, and an optimizer strong enough to find its blind spots will find them. This is reward hacking, and Gao, Schulman, and Hilton (2023) measured how the true quality of a policy first rises and then falls as optimization against a proxy reward model continues (§16.5). The standard remedy is to penalize the policy for drifting from a reference policy πref\pi_{\text{ref}}, usually the supervised fine-tuned model the RL starts from,

Jβ(θ)=Ex∼D[Ey∼πθ(⋅∣x)[r(x,y)]−β DKL(πθ(⋅∣x) ∥ πref(⋅∣x))],J_\beta(\theta) = \mathbb{E}_{x\sim\mathcal{D}}\Big[\mathbb{E}_{y\sim\pi_\theta(\cdot\mid x)}\big[r(x,y)\big] - \beta\, D_{\mathrm{KL}}\big(\pi_\theta(\cdot\mid x)\,\Vert\,\pi_{\text{ref}}(\cdot\mid x)\big)\Big],

with a coefficient β>0\beta > 0. In plain words, earn reward, but pay β\beta for every nat of divergence from the model you started with.

The penalty does three jobs. It keeps the policy in the region where the reward model can be trusted. It keeps the language fluent and the knowledge intact, since the reference model is a good language model. And it acts like an entropy bonus that keeps the policy from collapsing onto one response. Stiennon et al. (2020) name the first and the last explicitly, and Ziegler et al. (2019) introduced the penalty to keep the policy from drifting into text the reward model was never trained on. Typical values of β\beta are small, for example 0.05 in Stiennon et al.'s summarization work and 0.02 in InstructGPT (Ouyang et al. 2022), and Ziegler et al. adapted β\beta during training with a controller that targets a chosen KL.

The objective has a closed-form maximizer. Over all policies, the optimum tilts the reference distribution toward high reward,

π⋆(y∣x)=1Z(x) πref(y∣x)exp⁡ ⁣(r(x,y)/β),Z(x)=∑yπref(y∣x)exp⁡ ⁣(r(x,y)/β).\pi^\star(y\mid x) = \frac{1}{Z(x)}\,\pi_{\text{ref}}(y\mid x)\exp\!\big(r(x,y)/\beta\big), \qquad Z(x) = \sum_y\pi_{\text{ref}}(y\mid x)\exp\!\big(r(x,y)/\beta\big).

In plain words, take the reference model's probability of every response, multiply it by er(x,y)/βe^{r(x,y)/\beta}, and renormalize. Two responses that the reference finds equally likely end up in the ratio eΔr/βe^{\Delta r/\beta} if their rewards differ by Δr\Delta r, so a small β\beta piles the probability onto the best responses and a large one barely moves the reference.

Here is the one-line reason it has this shape. Moving a little probability onto a response yy earns its reward r(x,y)r(x, y) and costs β\beta times its log-ratio log⁡(π(y∣x)/πref(y∣x))\log(\pi(y\mid x)/\pi_{\text{ref}}(y\mid x)), plus a constant, so at the optimum that net gain must be the same for every response (otherwise shifting probability from a worse one to a better one would help). That balance condition reads βlog⁡π⋆(y∣x)πref(y∣x)=r(x,y)−βlog⁡Z(x)\beta\log\frac{\pi^\star(y\mid x)}{\pi_{\text{ref}}(y\mid x)} = r(x,y) - \beta\log Z(x), and solving it for π⋆\pi^\star gives the formula, with Z(x)Z(x) the constant that makes the probabilities sum to one.

The result comes with an exact accounting that we will use. For every policy π\pi and prompt xx, the objective at xx equals βlog⁡Z(x)−β DKL(π(⋅∣x) ∥ π⋆(⋅∣x))\beta\log Z(x) - \beta\,D_{\mathrm{KL}}\big(\pi(\cdot\mid x)\,\Vert\,\pi^\star(\cdot\mid x)\big). The first term does not depend on π\pi, and a KL divergence is zero only when its arguments are equal, so π⋆\pi^\star is the unique maximizer, the best value is βlog⁡Z(x)\beta\log Z(x), and every other policy falls short of it by exactly β\beta times its KL to π⋆\pi^\star. That gap is a convenient yardstick, and we will use it to grade training runs below. Both facts are proved step by step, twice, in the derivation of the closed-form optimal policy, which also builds direct preference optimization on the rearranged balance condition, the reward written through the policy as r=βlog⁡(π⋆/πref)+βlog⁡Zr = \beta\log(\pi^\star/\pi_{\text{ref}}) + \beta\log Z.

It is the same exponential tilt that the natural gradient produced in §15.6, now applied to whole responses. The partition function Z(x)Z(x) sums over every possible response, so nobody can compute π⋆\pi^\star for a real model, which is why we optimize toward it with RL instead. For our toy, with only 64 responses, we can compute it exactly, and check the accounting identity numerically.

Python · cell 2

A large β\beta barely moves the policy from the reference. A small one puts nearly all the probability on rewarded responses, at a large KL. And for a policy drawn at random, its objective equals βlog⁡Z\beta\log Z minus β\beta times its KL to π⋆\pi^\star, to every printed digit. The widget shows the same trade-off with a reward model that is wrong in a particular way, over-rating confident, flattering answers.

How does the KL coefficient β trade reward against staying close to the reference model?
Six responses to one prompt. The optimal policy of the KL-regularized objective is the reference distribution tilted by exp(reward / β). The reward model over-rates confident, flattering answers, which a hidden true quality does not.
Loading interactive figure…

The per-token form

The KL between two distributions over whole responses looks impossible to work with, but it decomposes over tokens. Write the log-ratio of sequence probabilities as a sum over tokens, using the chain rule above,

DKL(πθ(⋅∣x)∥πref(⋅∣x))=Ey∼πθ[log⁡πθ(y∣x)πref(y∣x)]=Ey∼πθ[∑t=1Tlog⁡πθ(yt∣st)πref(yt∣st)],D_{\mathrm{KL}}\big(\pi_\theta(\cdot\mid x)\Vert\pi_{\text{ref}}(\cdot\mid x)\big) = \mathbb{E}_{y\sim\pi_\theta}\Big[\log\frac{\pi_\theta(y\mid x)}{\pi_{\text{ref}}(y\mid x)}\Big] = \mathbb{E}_{y\sim\pi_\theta}\Big[\sum_{t=1}^{T}\log\frac{\pi_\theta(y_t\mid s_t)}{\pi_{\text{ref}}(y_t\mid s_t)}\Big],

with st=(x,y<t)s_t = (x, y_{<t}). Taking the expectation of each term first over yty_t given the prefix gives the chain rule for KL divergence, DKL(πθ(⋅∣x)∥πref(⋅∣x))=∑tEst∼πθ[DKL(πθ(⋅∣st)∥πref(⋅∣st))]D_{\mathrm{KL}}(\pi_\theta(\cdot\mid x)\Vert\pi_{\text{ref}}(\cdot\mid x)) = \sum_t\mathbb{E}_{s_t\sim\pi_\theta}[D_{\mathrm{KL}}(\pi_\theta(\cdot\mid s_t)\Vert\pi_{\text{ref}}(\cdot\mid s_t))], the sum over positions of the per-token KL at the prefixes the policy actually reaches.

Substitute the first form into the objective. Everything inside the expectation over yy becomes a sum over tokens, which is exactly a token-level MDP with the per-token reward

rt=−βlog⁡πθ(yt∣st)πref(yt∣st)+1[t=T] r(x,y),r_t = -\beta\log\frac{\pi_\theta(y_t\mid s_t)}{\pi_{\text{ref}}(y_t\mid s_t)} + \mathbb{1}[t = T]\, r(x, y),

whose sum over the response is r(x,y)−βlog⁡πθ(y∣x)πref(y∣x)r(x,y) - \beta\log\frac{\pi_\theta(y\mid x)}{\pi_{\text{ref}}(y\mid x)}, the "full reward" R(x,y)R(x,y) written down by Ziegler et al. and Stiennon et al. In plain words, every token pays a small toll, β\beta times how much more likely the policy made it than the reference would have, and the last token also collects the reward-model score. InstructGPT describes exactly this, a per-token KL penalty from the SFT model at each token, with the reward model's score at the end of the episode.

One subtlety makes this legitimate. The per-token reward depends on θ\theta itself, unlike any reward in an ordinary MDP. Does running a policy gradient on it, with the KL term treated as a fixed reward, give the gradient of JβJ_\beta? It does. The gradient of the penalty term is

∇θ Ey∼πθ[log⁡πθ(y)πref(y)]=Ey∼πθ[log⁡πθ(y)πref(y) ∇θlog⁡πθ(y)]+Ey∼πθ[∇θlog⁡πθ(y)],\nabla_\theta\,\mathbb{E}_{y\sim\pi_\theta}\Big[\log\frac{\pi_\theta(y)}{\pi_{\text{ref}}(y)}\Big] = \mathbb{E}_{y\sim\pi_\theta}\Big[\log\frac{\pi_\theta(y)}{\pi_{\text{ref}}(y)}\,\nabla_\theta\log\pi_\theta(y)\Big] + \mathbb{E}_{y\sim\pi_\theta}\big[\nabla_\theta\log\pi_\theta(y)\big],

by the product rule (the first term from differentiating the sampling distribution, the second from differentiating the integrand), and the second term is zero by the expected-score lemma of §15.4. What remains is the score-function gradient with the log-ratio as the reward, which is exactly what a policy gradient method computes when the KL term is placed in the reward and not differentiated. Keep this in mind, because the next part shows what happens when it is differentiated.

Interview

Per-token KL-penalized rewards for a batch of responses

Given per-token log-probabilities of the sampled tokens under the policy and the reference, logp and logp_ref of shape (B, T), sequence-level scores score of shape (B,), a mask of shape (B, T) (1 at real tokens, each row a run of ones then zeros, at least one real token per row), and a coefficient beta, implement kl_penalized_rewards(logp, logp_ref, score, mask, beta) returning the per-token rewards r of shape (B, T) with rt=−β(log⁡π−log⁡πref)r_t = -\beta(\log\pi - \log\pi_{\text{ref}}) at real tokens, the score added at the last real token of each row, and 0 at padding. Also return the per-sequence KL estimate kl of shape (B,), the sum of the per-token log-ratios over real tokens.

Hidden tests, hints, and AI help, from $1.99 a month.

Two ways to get the KL gradient wrong

Real implementations estimate the KL from the sampled tokens, with the per-token log-ratio (the k1k_1 estimator of §0.5) or with k3=(ρ′−1)−log⁡ρ′k_3 = (\rho' - 1) - \log\rho' where ρ′=πref/πθ\rho' = \pi_{\text{ref}}/\pi_\theta is the reference-to-policy ratio of the sampled token, as GRPO does. Both are unbiased estimates of the KL value. The trouble starts when, instead of putting the estimate in the reward, an implementation adds it to the loss and lets autograd differentiate it. Tang and Munos (2025) pointed out that this is common in open-source RLHF code and in published pseudocode, and that it gives the wrong gradient.

Pitfall one, differentiating the estimate. Differentiating k1=log⁡πθ(y)−log⁡πref(y)k_1 = \log\pi_\theta(y) - \log\pi_{\text{ref}}(y) at a sampled yy gives ∇θlog⁡πθ(y)\nabla_\theta\log\pi_\theta(y), whose expectation is zero by the expected-score lemma. The penalty's gradient is pure noise, and the KL is not regularized at all. Differentiating k3k_3 at the sampled token gives (1−πref/πθ)∇log⁡πθ(1 - \pi_{\text{ref}}/\pi_\theta)\nabla\log\pi_\theta. The first part has expectation zero again, and the second has expectation −∑aπref(a)∇log⁡πθ(a)-\sum_a\pi_{\text{ref}}(a)\nabla\log\pi_\theta(a), which is the gradient of a different divergence, the KL with its arguments swapped, DKL(πref∥πθ)D_{\mathrm{KL}}(\pi_{\text{ref}}\Vert\pi_\theta). In the language of §0.5, the objective penalizes the reverse, mode-seeking KL, while this gradient follows the forward, mass-covering one. It still pulls the policy toward the reference, so training looks fine, but it optimizes a different objective, and the optimum is no longer the tilted distribution above. Differentiating k2=12(log⁡πθ/πref)2k_2 = \frac12(\log\pi_\theta/\pi_{\text{ref}})^2, by contrast, gives log⁡πθπref∇log⁡πθ\log\frac{\pi_\theta}{\pi_{\text{ref}}}\nabla\log\pi_\theta, whose expectation is the correct gradient of DKL(πθ∥πref)D_{\mathrm{KL}}(\pi_\theta\Vert\pi_{\text{ref}}) for a single step, even though k2k_2's value is a biased estimate of the KL. (Pitfall two is about what goes wrong over a whole sequence.) Exercise 15.7c asks you to verify all three by exact enumeration.

The same algebra settles what happens when each estimate is used as a reward instead, with the score-function gradient E[k ∇log⁡πθ]\mathbb{E}[k\,\nabla\log\pi_\theta]. The product rule gives ∇θEπθ[k]=E[k ∇log⁡πθ]+E[∇θk]\nabla_\theta\mathbb{E}_{\pi_\theta}[k] = \mathbb{E}[k\,\nabla\log\pi_\theta] + \mathbb{E}[\nabla_\theta k], so the reward version equals the gradient of the estimator's expected value minus its loss version. Only k1k_1 comes out right both ways of reading. Here is the whole picture for one step, with the token a∼πθa\sim\pi_\theta and D=DKL(πθ∥πref)D = D_{\mathrm{KL}}(\pi_\theta\Vert\pi_{\text{ref}}).

estimator at the sampled tokenexpected valueexpected gradient, differentiated in the lossexpected gradient, used as a reward
k1=log⁡(πθ/πref)k_1 = \log(\pi_\theta/\pi_{\text{ref}})DD, unbiased00, no regularization∇D\nabla D, correct
k2=12log⁡2(πθ/πref)k_2 = \frac12\log^2(\pi_\theta/\pi_{\text{ref}})biased, close to DD when the policies are close∇D\nabla D, correct∇E[k2]−∇D\nabla\mathbb{E}[k_2] - \nabla D, wrong
k3=(ρ′−1)−log⁡ρ′k_3 = (\rho' - 1) - \log\rho', ρ′=πref/πθ\rho' = \pi_{\text{ref}}/\pi_\thetaDD, unbiased∇DKL(πref∥πθ)\nabla D_{\mathrm{KL}}(\pi_{\text{ref}}\Vert\pi_\theta), the swapped KL∇D−∇DKL(πref∥πθ)\nabla D - \nabla D_{\mathrm{KL}}(\pi_{\text{ref}}\Vert\pi_\theta), wrong

In plain words, a good estimate of the KL's value does not come with a good estimate of its gradient. RLHF with PPO uses k1k_1 in the reward, which is correct. GRPO uses k3k_3 in the loss, which regularizes through the swapped KL (§18.4).

Pitfall two, ignoring the sequence. Even with a correct per-token gradient, the penalty at token tt depends on all the earlier tokens, because they decide which prefix the policy is in. A loss that adds the per-token KL at each position and differentiates only through that position's own log-probability misses the effect of earlier tokens on later penalties. The correct gradient multiplies each token's score by the KL to go, the sum of the log-ratios from that token to the end, which is exactly what you get for free by putting the per-token KL in the reward and using reward-to-go or GAE.

The toy model shows the first pitfall clearly. Below we train it with REINFORCE three ways, all with reward-to-go and a per-position batch-mean baseline. In the first, the KL penalty sits in the reward. In the second, the k1k_1 estimate is added to the loss and differentiated. In the third, there is no penalty at all.

Python · cell 3

The last column is the yardstick from above, the KL from the trained policy to π⋆\pi^\star, which is the shortfall in JβJ_\beta divided by β\beta. With the KL in the reward, REINFORCE ends close to the exact optimum π⋆\pi^\star for β=0.5\beta = 0.5, 0.02 nats from it, with a reward of about 0.35 against the optimum's 0.40 and a KL to the reference of 0.30 against 0.38, and it is still converging. With the k1k_1 estimate differentiated in the loss, the result is indistinguishable from having no penalty at all. Both runs push the reward near 1, drift more than 3 nats from the reference, and end about 1.9 nats from π⋆\pi^\star. The penalty was there in the code and did nothing.

Research

Which KL losses have the right gradient

For one step with a softmax policy over KK tokens (logits z) and a reference policy (logits z_ref), implement kl_gradient_audit(z, z_ref) returning a dict of exact expected gradients with respect to z, each of shape (K,), computed by enumerating the KK tokens (no sampling).

  • "true", ∇zDKL(π∥πref)\nabla_{\mathbf z}D_{\mathrm{KL}}(\pi\Vert\pi_{\text{ref}}).
  • "k1_loss", Ea∼π[∇zk1(a)]\mathbb{E}_{a\sim\pi}[\nabla_{\mathbf z}k_1(a)] with k1(a)=log⁡π(a)−log⁡πref(a)k_1(a) = \log\pi(a) - \log\pi_{\text{ref}}(a) differentiated at fixed aa.
  • "k2_loss", the same for k2(a)=12(log⁡π(a)−log⁡πref(a))2k_2(a) = \frac12(\log\pi(a) - \log\pi_{\text{ref}}(a))^2.
  • "k3_loss", the same for k3(a)=πref(a)π(a)−1−log⁡πref(a)π(a)k_3(a) = \frac{\pi_{\text{ref}}(a)}{\pi(a)} - 1 - \log\frac{\pi_{\text{ref}}(a)}{\pi(a)}.
  • "k1_reward", the score-function gradient Ea∼π[k1(a)∇zlog⁡π(a)]\mathbb{E}_{a\sim\pi}[k_1(a)\nabla_{\mathbf z}\log\pi(a)], the KL used as a reward.
Hidden tests, hints, and AI help, from $1.99 a month.

Why RL on language models is unusual RL

Language models fit the RL framework exactly, but they sit in an odd corner of it, and most of the design choices of Chapters 16 to 18 follow from that corner.

  • The dynamics are deterministic and known. The environment is string concatenation. There is nothing to learn about transitions, the agent can "reset" to any prefix it likes, and it can compute the exact probability of any response under itself or the reference. Branching from a shared prefix to compare continuations, tree search over reasoning steps (§18.6), and exact sequence log-probabilities (DPO, §17.2) all depend on this. The whole problem of learning a model of the environment, which model-based reinforcement learning is built around for robots and games, does not arise here.
  • The action space is huge, but the prior is strong. Each step chooses among 50,000 to 200,000 tokens, which would make undirected exploration hopeless. But RL starts from a pretrained model that already produces sensible text, so exploration is sampling from that prior, and RL mostly reweights behaviors the model can already produce. Yue et al. (2025) found that RL-trained reasoning models beat their base models at pass@1 while the base models solve more problems at large kk in pass@k, which they read as RL sharpening rather than expanding the base model's abilities. That interpretation is debated, but the strong prior is not.
  • The horizon is long and the reward is single. Responses run from hundreds to tens of thousands of tokens with one reward at the end, so credit assignment is the hard part, and the choice between a token-level critic and a sequence-level baseline is the main fork between PPO-style RLHF and GRPO-style reasoning RL.
  • The reward is learned and exploitable. A game score is the game. A reward model is a proxy, so optimization pressure finds its flaws, which is why the KL penalty, reward-model ensembles, and early stopping exist (§16.5). Verifiable rewards are harder to hack but not impossible (§18.3).
  • Episodes are expensive and models are big. One episode is a full generation, so reusing each batch for several PPO epochs pays off, and the policy, the reference, the reward model, and a critic can each be a full-size network, the four-model memory bill of §16.4.
  • The data is slightly off-policy for systems reasons. Large systems generate with a separate, optimized inference engine and train with another, and the two compute slightly different log-probabilities for the same tokens. Ratios that should be exactly 1 are not, which is one more reason the importance-sampling machinery of §15.6 matters even in "on-policy" training.
classic RL (Atari, MuJoCo)RL on language models
statean observation, often partialthe prompt and all tokens so far, fully observed
actiona few discrete actions or a small vectorone of 10510^5 tokens
transitionsstochastic, unknowndeterministic, known (append)
rewarddense or shaped, defined by the environmentone score at the end, from a learned or programmatic judge
horizonhundreds to thousands of stepshundreds to tens of thousands of tokens
starting policyrandoma strong pretrained and fine-tuned model
main riskfailing to exploreexploiting the reward model and drifting from the reference
typical γ\gamma, λ\lambda0.99, 0.951, and λ\lambda near 1 (Stiennon et al. used 0.95)

In PyTorch

Here is the per-token RLHF reward computation and a masked PPO loss on a batch of sampled sequences from a tiny GRU language model, with a frozen copy as the reference, the KL penalty in the reward, GAE over tokens with γ=1\gamma = 1, and a critic head. It is a miniature of the training step §16.4 builds at full scale.

🔥 In PyTorchfor a machine with PyTorch

Read more

Watch next

🎬 Deep Dive into LLMs like ChatGPT · Andrej Karpathy · starts at 127:28From supervised fine-tuning to reinforcement learning, DeepSeek-R1, and RLHF, explained for a general audience.
🎬 Reinforcement Learning from Human Feedback explained with math derivations and the PyTorch code. · Umar JamilLanguage models as policies, the KL-penalized reward, and PPO for RLHF, derived and coded.