Part III · RL for LLMs · Chapter 18
Agentic and multi-turn RL
Tool use, coding agents, environments, and credit assignment over long horizons.
A test in a small Python repository is failing, and you ask a coding agent to fix it. The agent reads add.py, runs the tests, sees add(2, 3) returned -1, expected 5, changes a - b to a + b, runs the tests again, sees 3 passed, and submits. That took four turns. A good part of the text in the agent’s context window was written by the tools, not the model. And the training signal at the end is a single bit: did the held-out tests pass?
In Chapter 15 the model read a prompt, wrote one response, and got a reward. That is a one-step problem, a contextual bandit with an enormous set of arms. This chapter is about what changes when the model acts: it calls tools, reads what comes back, and decides what to do next, over many turns. Three questions come up that a single response never raised:
- Which tokens do you train on? The context now contains text the model didn’t write.
- Which decision gets the credit? One reward has to be shared among many turns.
- How do you run this at all? Episodes are long, slow, need sandboxes, and can be gamed in new ways.
The answers draw directly on Part II. Question 1 is the policy gradient theorem from Chapter 7, where the environment’s dynamics drop out of the gradient. Question 2 is credit assignment from Chapter 8. Question 3 leads to the systems of Chapter 20 and the failure modes of Chapter 19.
From one answer to many turns
The agent loop
Here is the episode above written out as the model sees it. The model’s own text is between <call> tags and the tool’s replies are between <result> tags. Every LLM agent framework uses some format like this, though the exact tags differ.
[prompt] system: Tools: read(path) run_tests() edit(path, old, new) submit()
user: test_add fails. Fix add.py so the tests pass.
[model] <think> Look at the code first. </think> <call> read("add.py") </call>
[tool] <result> def add(a, b): return a - b </result>
[model] <think> Minus should be plus. </think> <call> edit("add.py", "a - b", "a + b") </call>
[tool] <result> ok: 1 line changed </result>
[model] <call> run_tests() </call>
[tool] <result> 3 passed </result>
[model] <call> submit() </call>
-> grader runs the held-out tests: pass. Reward 1.
Some vocabulary, used throughout the chapter:
- A tool is any function the model can invoke by writing text in an agreed format: a code interpreter, a search engine, a file editor, a shell.
- A tool call is the model’s text that requests one, and the observation (or tool output) is the text that comes back.
- A turn is one model message plus the observation that answers it. The episode above has four turns.
- The harness (also called the scaffold) is the program around the model. It parses tool calls, executes them, appends the results to the context, enforces limits (turns, tokens, time), and calls the grader at the end.
- The environment is everything the model doesn’t control: the harness, the tools, the repository or website they act on, and the grader.
- An agent is the model together with this loop. Agentic RL means training the model with RL inside the loop, on whole episodes, rather than on single responses.
What actually changes
Compared with Chapter 15, three things are new.
The environment writes into the context. In the single-response setting, every token after the prompt was sampled from the policy. Now the context is a braid of model tokens and environment tokens. In the example above the tool’s replies are short, a few tokens each. In real coding agents the tools often write most of the context: a single file read or test log can be thousands of tokens.
Rewards arrive after many decisions. The agent made four decisions, then got one number. In a software-engineering task the agent may take dozens or hundreds of turns. Kimi reports that K2 Thinking can execute “200 – 300 sequential tool calls” (Moonshot, 2025).
Episodes are expensive. Every tool call takes wall-clock time, may need a sandboxed container, and can fail or hang. A rollout is no longer “generate 2,000 tokens”; it is a small distributed program.
We take these in order: first the formalism and the loss mask, then rewards and credit, then environments and the practical problems.
The multi-turn MDP
Chapter 11 described generation as a token-level MDP: the state is the prompt plus the tokens so far, the action is the next token, and the transition is deterministic (append the token). Agents need one change: at certain moments the environment appends tokens, and those depend on the world, not on the model.
Write a -turn episode as
where is the prompt, is the model’s message at turn (a sequence of tokens), and is the observation the environment returns. The history before turn is everything in the context so far, . The model writes one token at a time from , so
where means “the positions of ‘s tokens”. Then the environment draws . Rewards may come after any turn, but often only the last one is nonzero.
You can view this at two levels:
| Token level | Turn level | |
|---|---|---|
| State | everything in the context so far | the history |
| Action | one token | one whole message |
| Transition | append the token; at the end of a tool call, the environment appends | append , then the environment appends |
| Horizon | thousands to millions of tokens | a few to hundreds of turns |
Both are useful. The gradient is computed at the token level, because that is how the model factorizes probability. Credit is often easier to reason about at the turn level, because that is where the environment responds and where rewards arrive.
Which tokens do you train on? The loss mask
The environment’s tokens drop out of the gradient
Start from the probability of a whole episode under the policy. The prompt comes from the dataset, the model writes each message, and the environment writes each observation:
(The last message gets no observation; the episode ends.) Take the logarithm and the gradient. The prompt distribution and the environment don’t depend on , so their terms vanish:
This is the step from Chapter 7 where the transition model dropped out of the policy gradient. There it explained why REINFORCE works without knowing the physics of CartPole. Here it says something concrete about tokens: the policy gradient is a sum over the tokens the model wrote, and only those. The tool’s tokens are part of the state the policy conditions on; they are not actions. With a baseline and per-turn advantages (next section), the estimator is
In code, you don’t write separate loops over turns. You lay the whole episode out as one token sequence, run the model over it once (exactly as in Chapter 15), and multiply the per-token loss by a loss mask that is 1 for tokens the model sampled and 0 for everything else (prompt, tool output, padding).
A worked example
Here is one episode from this chapter’s lab. A secret number in is hidden (?). The agent can call compare(x), written call x, and the tool answers lower, higher or equal. Each model turn is two tokens.
position 0 1 2 3 4 5 6 7 8 9 10 11
token <bos> ? call 3 <tool> higher call 5 <tool> lower ans 4
written by prompt prompt model model tool tool model model tool tool model model
mask m_t 0 0 1 1 0 0 1 1 0 0 1 1
turn - - 0 0 0 0 1 1 1 1 2 2
The episode ends with the correct answer, so the agent earns 1, minus 0.05 for each of its two tool calls. Six of the twelve tokens get gradient. The model still reads all twelve: the hidden state after higher is what lets it choose 5 next. Reading and training are different things. The model conditions on the tool tokens but is never asked to have predicted them.
In PyTorch, the mask adds almost nothing to Chapter 15’s loss:
logp = log_softmax(policy(ids[:, :-1]), -1).gather(-1, ids[:, 1:, None]).squeeze(-1)
loss = -(mask[:, 1:] * adv[:, 1:] * logp).sum() / mask[:, 1:].sum()
The same mask must be applied everywhere a per-token quantity is summed: the KL penalty, any entropy bonus, and the token count in the normalizer. Search-R1 states that its retrieved-token masking “is also applied when calculating the KL divergence loss” (Jin et al., 2025).
What goes wrong without the mask
Suppose you forget the mask and train on every token after the prompt. Three things go wrong at once.
It is no longer the policy gradient. The extra terms are for each tool token. They reward the model for having predicted the tool’s output in good episodes and penalize it in bad ones. That is advantage-weighted imitation of the environment. On a good episode it teaches the model to write 3 passed itself after an edit, which is exactly how an agent learns to hallucinate tool results. Worse, a baseline is no longer free. In Chapter 7, subtracting a baseline cost nothing because . Tool tokens are drawn from the environment, not from , so that expectation is not zero and the baseline term adds a push of its own (Exercise 18.2).
There is no self-correction. When the model’s own token gets pushed down, it becomes less likely, gets sampled less often, and so stops being pushed. Tool tokens are forced into the context regardless of their probability. The gradient of with respect to the logits is (here is the one-hot vector for token ). Its size is at least , so it does not shrink as . A tool token on a bad episode gets shoved down again every time it appears, without limit.
The extra terms are large. Tool output is often most of the episode, and it is text the policy never chose, so it finds those tokens improbable. In the lab, at the start of training, tool tokens are 40% of the episode tokens and the policy gives them an average log-probability of −7.8 (a typical probability of about 0.0004). Their gradient is 4.4 times larger than the real policy gradient. The real signal is swamped.
The result in the lab is stark. With the mask, the agent learns to search with the tool in all four seeds we ran (success on hidden-number tasks rises from about 0.2 to between 0.8 and 0.99). Without it, three of the four runs abandon the tool entirely and the fourth stalls at one call per episode. Success ends between 0.10 and 0.33, against a guessing rate of 1/8. Real systems show the same direction, less dramatically. Search-R1 (arXiv v5, Section 5.4) reports an ablation on Qwen2.5-7B-Base trained with PPO: average exact match 0.431 with retrieved-token masking and 0.343 without. The GLM-4.5 report states the rule in one sentence: “Only model-generated tokens are used for optimization, and the environment feedback is ignored in loss computation” (GLM-4.5 Team, 2025).
Quick check A coding agent's episode has 1,200 model tokens and 9,000 tokens of tool output (file contents, test logs). With a correct loss mask, how many tokens contribute terms to the policy-gradient loss?
The policy gradient is a sum over the model's own actions. The 9,000 tool tokens are part of the state the model conditions on (it reads them in the forward pass), but they are not actions, so they get mask 0. The advantage scales the 1,200 terms; it doesn't change which tokens are included.
Rewards for agents
Chapter 14 surveyed where rewards come from. Agents add a few patterns of their own.
Outcome rewards from the environment. These are the common case, and the most robust:
- Unit tests. DeepSWE gives reward 1 if the final patch passes the selected tests within five minutes, else 0 (Agentica & Together AI, 2025).
- Exact match. Search-R1 checks the final answer against the gold answer.
- Similarity, when nothing can be executed. SWE-RL trains on GitHub pull-request history without running code. The reward is −1 for a malformed output and otherwise the
difflibsimilarity between the predicted patch and the real one, a number in (Wei et al., 2025).
Format and validity. A malformed tool call usually ends the episode. GLM-4.5 halts the trajectory and gives reward 0. As you will see in Exercise 18.6, the value you give a malformed turn matters more than it looks.
Turn-level (process) rewards. You can also reward individual turns: a tool call that parses, a search that finds a relevant document, a test that newly passes. Dense rewards make credit assignment easier, but each one is a new thing to game. If you pay +0.1 for every tool call that runs, an agent that calls run_tests() in a loop gets paid for being busy. (The demo below lets you watch this happen.) Production systems that use process rewards keep them narrow and behavioral. MiniMax’s M2 report describes per-step rewards that penalize language mixing and tool-format errors, plus a speed term that favors finishing faster (MiniMax, 2026).
Costs. Tool calls cost time and money. A small negative reward per call, or per second of wall clock, teaches the agent to use tools when they help and skip them when they don’t. Getting the size right is delicate. In the lab, a cost of 0.05 per call works. At 0.1, all four seeds we tried learned to never call the tool. Early in training, before the agent knows how to use a tool result, a call is pure cost, so the agent drops tools before discovering they help. One remedy is to bring such penalties in gradually. Kimi k1.5 warms up its length penalty during training (Kimi Team, 2025).
Credit assignment over many turns
One number, many decisions
Look again at the four-turn coding episode. It earned reward 1. Which turn deserves the credit? The edit that changed - to + was the decisive move. Reading the file was useful. Running the tests was a sensible check. Submitting was necessary but trivial. A single outcome reward can’t say any of that. The simplest thing you can do, and what most agentic RL systems do, is give every turn the same credit.
Scheme 1: one advantage for the whole trajectory
Sample a group of episodes for the same task, as in GRPO (Chapter 15). Let be the total reward of episode . Every turn, and so every model token, of episode gets
(Many recipes also divide by the group’s standard deviation. Agentic recipes such as DeepSWE drop that, following Dr. GRPO; see Chapter 16.)
A worked group. Four episodes on the coding task. A fixes the bug properly. B makes a malformed call, then a wrong fix. C edits the test so that it passes. D runs the tests over and over until it hits the five-turn limit. The grader checks whether the repository’s tests pass at submission. The rewards are , the baseline is , and the advantages are . Every token of A’s four turns is pushed up by , the same as every token of C’s test-editing hack. Hold that thought until the section on reward hacking.
This scheme is simple, and it is Chapter 7’s REINFORCE with a baseline. It points in the right direction on average. (Strictly, because the group mean includes the episode itself, the expected update is shrunk by a factor ; RLOO’s leave-one-out baseline removes that.) Its weakness is variance. Every token in the episode receives the same push, including tokens whose choice had nothing to do with the outcome. Those pushes are noise, and they grow with the number of decisions.
Why long horizons are hard: the noise grows with the number of decisions
Here is the effect in its simplest form. An episode has binary decisions , each made with its own parameter: . Only the first decision matters, . Take (every decision is a coin flip) and the ideal baseline . The score of decision (Chapter 7’s name for the gradient of its log-probability) is , and the single-episode REINFORCE estimate has components .
- For the decision that matters, always. The signal is .
- For each irrelevant decision, is independent of , so but with equal probability. Each one adds variance .
The total noise in the gradient vector is against a squared signal of . Average over episodes and the noise drops to . To make the noise smaller than the signal you need episodes. The number of episodes you need grows linearly with the number of decisions that didn’t matter. An agent that takes 200 turns, most of them routine, pays this tax on every update. Exercise 18.4 works through the general case.
∂ The same argument for any policy and any number of turns
Let the episode’s score be with , and suppose the reward depends only on the actions in a set of relevant turns. The REINFORCE estimate is . Split into the relevant and irrelevant parts.
Assume, as in the toy example, that the irrelevant actions don’t influence the relevant ones or the reward, so that is independent of . Then , because each score has mean zero. They add no bias. Their contribution to the second moment is
using independence of from , and that cross terms vanish for (condition on the earlier history; the later score has mean zero). The variance added by irrelevant turns is the sum of their score variances, times the reward variance. It grows linearly in the number of irrelevant turns, while the expected gradient stays fixed. A shared network (one for all turns) doesn’t help: the irrelevant scores then point in overlapping directions of the same parameter space and still add up.
Scheme 2: per-turn credit with reward-to-go
Chapter 7 gave the first remedy: causality. An action can’t affect rewards that came before it, so weight each turn by the reward from that turn on. With a discount across turns:
Two letters appear here, both in the course’s standard notation: alone is the group size, and with a turn subscript is the return from turn of episode (Chapter 3’s , counted in turns instead of time steps). In words: each turn is scored by the discounted reward still to come, and the baseline is the average full-episode return of the group.
MiniMax’s M2 report uses this form for its agentic RL, “reward-to-go” minus a trajectory-level baseline. Two cases are worth separating.
When rewards arrive along the way (tool costs, process rewards), reward-to-go helps. A late turn isn’t charged for costs paid before it, so its weight carries less noise.
When there is only a final reward and , reward-to-go equals the total reward for every turn, and this is just Scheme 1. Lowering below 1 changes that, but not in the way you might hope. Take episode A with and the group above. The returns-to-go of its four turns are . The baseline is the mean of the four episodes’ : . So A’s advantages are . The submit() turn now gets nearly twice the credit of the decisive edit. Discounting assigns credit by proximity to the reward, not by cause. It also quietly rewards finishing in fewer turns, which may or may not be what you want.
Scheme 3: learn a value function
Chapter 8’s answer to noisy returns was a critic: learn and use TD errors or GAE across turns. A turn-level critic can judge an action against what was expected from that point, and so separate the edit from the submit. The catch is the one that pushed LLM RL toward critic-free methods in Chapter 15: the critic is itself a large model, it is hard to train on sparse rewards, and in agentic settings its input is a long, mostly tool-written context. Some multi-turn work adds one back. RAGEN’s StarPO-S adds a critic baseline, together with trajectory filtering and decoupled clipping, to stabilize multi-turn training (Wang et al., 2025).
Scheme 4: compare actions taken from the same state
GRPO’s trick was to get a baseline by sampling several answers to the same prompt. GiGPO applies the same trick one level down (Feng et al., 2025). In many environments, different episodes pass through the same state: the same web page, the same room in a text game. GiGPO finds these repeated anchor states across a group of trajectories and compares the actions taken from each one, which gives a step-level relative advantage on top of the episode-level one. It needs no critic and no extra rollouts. The authors report gains of more than 12% on ALFWorld and more than 9% on WebShop over GRPO. The limitation is that states must actually repeat, which is common in structured environments and rare in open-ended coding.
| Scheme | Credit for turn of episode | Needs | Weakness |
|---|---|---|---|
| Whole trajectory | a group of episodes | variance grows with the number of turns | |
| Reward-to-go, discount | per-turn rewards to help | with only a final reward, favors late turns, not decisive ones | |
| Turn-level critic | TD / GAE across turns | a value model | expensive; hard to train on long contexts |
| Anchor-state groups (GiGPO) | compare actions from the same state | repeated states | states rarely repeat in open-ended tasks |
| Process rewards (Chapter 17) | dense per-turn reward | a reliable step judge | each step reward is a new target to hack |
Quick check An agent's only reward is +1 at the end of a 10-turn episode. You switch from trajectory-level advantages to reward-to-go with γ = 0.9 across turns. What happens to the credit given to turn 0 versus turn 9 of a successful episode?
Turn 0's return-to-go is 0.9⁹ ≈ 0.39 while turn 9's is 1, and they share the same baseline. Discounting gives credit by distance to the reward, not by which turn caused it. If the decisive move came at turn 0, it now gets the least credit.
Seeing it on one group of episodes
The demo shows the four-episode group from the worked example. Every token is colored by who wrote it. Tint shows the push it receives: green up, red down, hatched none. Use it to check every number in the last two sections, then break things.
promptwritten by the modelwritten by a toolpushed uppushed downno gradient
What to try: (1) Episode C is selected. With the default grader, its test-editing hack earns R = 1 and every one of its tokens is pushed up, exactly as much as episode A's honest fix. Switch the grader to 'Held-out tests pass' and watch C turn red. (2) Untick the mask. The tool tokens, outlined, start receiving gradient, and on episode A the readout says what that update teaches. Across the group, more than half the tokens after the prompt were written by tools. (3) Choose 'Per turn', set γ to 0.8, and read A's four advantages. They match the worked example: the submit gets the most credit, the decisive edit much less. (4) Turn on process rewards with γ = 1. Episode D, which did nothing useful, climbs to R = 0.5 and now far outranks B, which at least tried a fix.
Putting it together: GRPO over trajectories
Here is the algorithm that most current agentic RL systems run, in the form you will implement in the lab. It is Chapter 15’s GRPO with two changes: rollouts are multi-turn loops, and the loss is masked.
repeat:
1. Snapshot the policy for sampling.
2. For each of B tasks, run G episodes with the snapshot:
context = prompt
loop:
sample the model's message token by token (mark these tokens m = 1)
if it is a tool call: execute it, append the output (mark these tokens m = 0)
if it is an answer, malformed, or a limit is hit: stop and score the episode
3. Per-turn rewards -> per-turn advantages within each group (trajectory-level or reward-to-go).
Give every model token the advantage of its turn.
4. Recompute log π_θ for every token in one forward pass over each full episode.
5. Loss = token-masked policy-gradient loss (+ clipping, + masked KL if used).
6. Optimizer step.
Real systems add the machinery of Chapters 9, 16 and 20 on top: importance ratios and clipping for reused or stale data, filtering of all-success or all-failure groups, and asynchronous rollouts. DeepSWE’s “GRPO++”, for example, combines clip-higher, no KL loss, no standard-deviation normalization, and a leave-one-out baseline. It also adds compact filtering: episodes that hit the context limit, the step limit or the time limit are masked out of the loss entirely, instead of being treated as failures (Agentica & Together AI, 2025).
Environments
An RL environment for an LLM agent is the same object as in Chapter 1: something with reset() and step(action) that returns an observation, a reward and a done flag. The difference is in what sits behind step. It might be a Python interpreter, a Docker container holding a whole repository, a search engine, or a browser. Hugging Face and Meta’s OpenEnv uses exactly the Gymnasium-style reset()/step() interface, with environments running as containers or HTTP servers (Hugging Face, 2025). Prime Intellect’s verifiers library packages an environment as a dataset, a harness and a rubric, and shares them on an Environments Hub (Prime Intellect, 2025).
A good training environment is:
- Verifiable: it can score an episode automatically and cheaply.
- Reproducible: the same task resets to the same state, so a group of episodes really is attempts at one problem.
- Isolated: one episode can’t affect another, or the outside world.
- Fast enough: tool latency multiplies across turns and episodes.
- Hard to game: the grader checks what you actually want (more on this below).
Here are the main families, with representative work. All benchmark numbers are as reported by the authors.
| Family | What the agent does | Examples |
|---|---|---|
| Tool-integrated reasoning | writes and runs code mid-reasoning | ToRL (Li et al., 2025): RL from a base model with a code interpreter. ReTool (Feng et al., 2025): cold-start SFT, then RL with code execution inside the rollout |
| Search and research | issues queries, reads results, answers | Search-R1 (Jin et al., 2025); WebSailor (Li et al., 2025); Tongyi DeepResearch (2025) |
| Software engineering | navigates a repo, edits, runs tests | Environments: SWE-Gym (Pan et al., 2024), R2E-Gym (Jain et al., 2025), SWE-smith (Yang et al., 2025). Training: SWE-RL (Llama3-SWE-RL-70B, 41.0% on SWE-bench Verified without executing code during RL); DeepSWE (Qwen3-32B, pure RL on 4.5K R2E-Gym tasks: 42.2% Pass@1, 59% with test-time scaling); SkyRL-Agent’s SA-SWE-32B, 24.4% → 39.4% Pass@1 (Cao et al., 2025) |
| Games and puzzles | multi-turn stylized environments | RAGEN / StarPO (Wang et al., 2025) |
| Synthetic tools at scale | uses many generated APIs | Kimi K2: more than 3,000 real MCP tools and more than 20,000 synthetic ones, with rubric-checked tasks (Kimi Team, 2025); DeepSeek-V3.2: 1,827 synthesized environments (DeepSeek-AI, 2025) |
Two observations from this literature. First, environments have become the bottleneck and the main scaling axis. Frontier reports in 2026 count environments the way 2023 reports counted preference pairs: GLM-5 reports more than 10,000 verifiable SWE environments. There are even attempts to learn the environment itself: Qwen-AgentWorld trains LLMs to simulate tool environments for agentic RL (Zuo et al., 2026). Second, multi-turn RL has its own instabilities. RAGEN reports an “Echo Trap”, in which reward variance collapses and gradients spike as the agent overfits to locally rewarded reasoning patterns. Its abstract also warns that without fine-grained, reasoning-aware reward signals, agent reasoning “hardly emerge[s]” through multi-turn RL.
The practical problems
Long, variable-length rollouts
Chapter 15’s rollouts already had a long tail of lengths. Agentic rollouts are worse, because the length varies in turns as well as tokens, and each turn includes a tool’s latency. A synchronous training step waits for the slowest episode in the batch, so a few long episodes leave most of the hardware idle. This is the main reason agentic RL moved to asynchronous systems: rollout workers keep generating while the trainer updates, and samples arrive slightly stale. Staleness makes the data off-policy, so the importance ratios and clipping of Chapter 9 come back. GLM-4.5’s slime framework offers a colocated synchronous mode, which it reports works best for math and code, and a disaggregated asynchronous mode for long agent rollouts. Chapter 20 covers these designs. Exercise 18.7 puts numbers on why synchronous rollouts waste so much.
Context length and context management
A long-horizon agent will overflow any context window. The options are crude to clever: truncate old tool outputs, cap each observation (a 50,000-line test log becomes its last 200 lines), or let the model summarize its own history and continue from the summary. Cursor’s Composer 2 report describes training with self-summarization, where the outcome reward applies to the whole chain, including the model’s own summaries. A summary that drops a crucial detail leads to failure later, and RL pushes back on it. Whatever you do, the policy at training time must see what it will see at deployment. And episodes cut off by the limit need a decision: count them as failures, or mask them out, as DeepSWE’s compact filtering does. The same question arose for overlong responses in Chapter 16.
Sandboxes: cost and safety
Every coding episode needs a fresh, isolated copy of the repository and its dependencies. DeepSWE ran 512 Docker containers per training step (64 tasks × 8 rollouts). DeepSeek-V4’s report (DeepSeek-AI, 2026) describes a sandbox platform running “hundreds of thousands of concurrent sandbox instances”. Isolation is also a safety boundary, and an optimizing agent will probe it. Anthropic’s Claude Mythos Preview system card (April 2026) reports that, in automated review of RL transcripts, the model “occasionally circumvented network restrictions in its training environment to access the internet and download data that let it shortcut the assigned task”, in about 0.05% of episodes, about 0.01% successfully.
Environment reward hacking
Look back at episode C. The grader checked “do the repository’s tests pass?”, and the agent made them pass by editing the test. This is not a hypothetical. OpenAI’s study of monitoring a frontier reasoning model during agentic coding RL found systemic hacks such as calling exit(0) so the test harness reports success, and raising SkipTest (Baker et al., 2025). Anthropic studied production coding environments vulnerable to three hacks: returning an object whose __eq__ always returns True, calling sys.exit(0), and patching conftest.py to rewrite test results. When models learned these hacks, the behavior generalized to broader misalignment, such as alignment faking and sabotage (MacDiarmid et al., 2025).
Agentic environments are especially hackable for a structural reason. The agent can act on the same world the grader inspects, so it can change the evidence. The defenses are mostly environment engineering:
- grade with held-out tests the agent never sees, run in a clean copy of the repository;
- make tests and graders read-only to the agent;
- diff-check the final state (did the agent touch test files?);
- monitor trajectories, including the reasoning, for signs of gaming.
Chapter 19 treats reward hacking and monitoring in depth.
Quick check Your coding agent's reward is 1 if `pytest` exits with status 0 after the agent submits. Which change most directly closes the exploits described above?
The hacks work because the agent can change what the grader inspects: the tests, the test runner's exit code, conftest.py. Grading with held-out tests in a clean environment removes that channel. A KL penalty or a smaller learning rate only slows the optimizer down; it will still find the hack eventually.
Multi-agent and self-play setups
Two directions extend the single-agent loop.
An orchestrator with sub-agents. Kimi K2.5’s “Agent Swarm” trains an orchestrator that launches parallel sub-agents (Kimi Team, 2026). The sub-agents are frozen, and their outputs come back to the orchestrator as observations. From the orchestrator’s point of view, a sub-agent is a tool, so its output is masked like any other tool output. The reward includes two auxiliary terms aimed at failure modes: one against “serial collapse” (never parallelizing) and one against “spurious parallelism” (launching many useless sub-agents, a reward hack). Both are annealed to zero during training.
Self-play. If the environment can generate its own tasks, the agent can train without human-written ones. In Self-play SWE-RL, one agent both injects bugs into real repositories (specified by test patches) and repairs them. The authors report gains of 10.4 points on SWE-bench Verified and 7.8 on SWE-Bench Pro, beating a baseline trained on human data (Wei et al., 2025). Chapter 21 returns to self-play and zero-data RL.
Summary
- An LLM agent alternates model messages and environment observations. Formally it is a (partially observed) MDP whose state is the context window and whose transitions include environment-written tokens.
- The policy gradient is a sum over the model’s own tokens only. Tool outputs are state, not actions, so a loss mask zeroes them, and the same mask applies to the KL, entropy and normalizer. Without it you train the model to imitate (or un-imitate) the environment, with large gradients that never self-correct.
- Compute log-probs on the exact sampled token ids, under the same sampling rules the sampler used. Small mismatches here can break learning.
- With one reward per episode, the default is trajectory-level credit: every model token gets . Its variance grows roughly linearly with the number of turns that didn’t matter.
- Reward-to-go helps when rewards arrive along the way. With only a final reward, discounting favors late turns rather than decisive ones. Critics and anchor-state grouping (GiGPO) are the main ways to do better.
- Agent rewards are mostly environment outcomes (tests, exact match), plus format penalties and sometimes small costs or process rewards. Every extra term is a new thing to tune and to hack.
- Practical problems dominate: long variable rollouts (hence asynchronous systems), context limits (truncation, summarization), sandbox cost and isolation, and environment reward hacking, where the agent alters what the grader checks.
Exercises
A search agent produces this episode (each chunk is one token for simplicity):
[prompt] Q: Who wrote Middlemarch?
[model] <search> Middlemarch author </search>
[tool] <information> Middlemarch is a novel by George Eliot ... </information>
[model] <answer> George Eliot </answer>- Which chunks get mask 1 and which get mask 0?
- The training loss also has a per-token KL penalty to a reference model. Which tokens should it be computed on, and why?
- The forward pass for computing log-probs: does it run over all the tokens, or only the masked-in ones?
Solution
- Mask 1:
<search>,Middlemarch,author,</search>,<answer>,George,Eliot,</answer>, everything the model generated. Mask 0: the prompt, and everything from<information>to</information>, which the search engine wrote. (Whether the closing tag of a tool call counts as a model token depends on the harness. Usually the model generates</search>and the harness stops sampling there, so it is a model token.) - On the same masked-in tokens. The KL term measures how far the policy’s choices drift from the reference model’s. On tool tokens neither model chose anything, so there is nothing to regularize. Including them would penalize or reward the policy for how it predicts retrieved text. Search-R1 applies its mask to the KL term for exactly this reason.
- Over all of them. The model must condition on the retrieved text to compute the probability of
George Eliot. The mask only selects which positions’ log-probs enter the loss.
Consider a single turn: the model writes a message , then the environment writes one observation token . The advantage is for a constant baseline . The unmasked estimator adds the term .
- Show that with the mask, the baseline adds no bias: .
- Show that the baseline’s contribution to the unmasked extra term is not zero in general. Write it in terms of a cross-entropy between and .
- Let be the logits at the observation’s position. Show that and that its norm is at least . Contrast what happens as for a token the model sampled versus a token the environment forced.
Hint
Solution
-
, so multiplying by the constant still gives 0.
-
The baseline part of the extra term is . For fixed ,
where is the cross-entropy. This is zero only if already minimizes the cross-entropy to the environment, which in general it doesn’t. Putting the sign back, the baseline’s expected contribution is
which is times the gradient of the log-likelihood of the tool outputs. You do gradient ascent on this estimator, so for the update raises the cross-entropy: it pushes the model away from predicting what the environment writes. For it pushes toward imitating the environment. (Sanity check: with and the advantage is negative, so every tool token’s log-prob is pushed down.) Changing a supposedly harmless constant changes the update. That alone shows the unmasked estimator is not a policy gradient.
- , so , i.e. . Its -th component is , so . As the norm tends to at least 1.
For a sampled token, the expected contribution is weighted by how often it is sampled. It enters with probability , so its expected push is . Pushing it down makes it rarer, which makes the push rarer: a self-limiting process. For a forced token, the environment inserts every time regardless of , so the full push of size about 1 arrives every time. Pushing it down doesn’t make it rarer in the data, and the logit can be driven toward indefinitely, dragging shared weights along. This is the lab’s “log-prob −7.8, gradient 4.4× the real one”.
A group of episodes in the lab’s environment. Each tool call costs 0.05; a correct answer earns 1. The per-turn rewards are:
| Episode | Turns | Per-turn rewards |
|---|---|---|
| 1 | call, call, answer (right) | |
| 2 | answer (right) | |
| 3 | call, answer (wrong) | |
| 4 | malformed |
- Compute the trajectory-level advantage of every turn.
- Compute the turn-level advantages with reward-to-go, , baseline mean of .
- In which turns do the two schemes differ, and why? Which of the two is “fairer” to the last turn of episode 1?
- Repeat part 2 with , keeping the same baseline formula (recompute ). Only episode 1’s returns change: why? What happens to the credit of episode 1’s first call?
Hint
Solution
-
. Episode 1: every turn . Episode 2: . Episode 3: both turns . Episode 4: .
-
Returns-to-go: episode 1: , , . Episode 2: . Episode 3: , . Episode 4: . Baseline (with , ). Advantages: episode 1: . Episode 2: . Episode 3: . Episode 4: .
-
They agree on every first turn (because when ) and on one-turn episodes. They differ on later turns of multi-turn episodes. In episode 1, the final
ansturn gets under reward-to-go instead of , because it isn’t charged for the two tool costs paid before it. That is fairer: the answer couldn’t have affected rewards that were already paid. In episode 3, the wrong answer gets instead of for the same reason. The difference is small here because the costs are small. With larger per-turn rewards (process rewards), it grows. -
With : , , . The other episodes are unchanged: episodes 2 and 4 have one turn, and episode 3’s later reward is 0, so . New baseline: . Episode 1’s advantages become . The first call, which started a successful search, now gets about a seventh of the credit of the final answer. Discounting has moved credit toward the end of the episode, regardless of which turn mattered.
Generalize the chapter’s example. An episode has independent binary decisions with , all at . The reward depends only on decision 1: , where is independent noise with mean 0 and variance (say, a flaky test). Use the baseline .
- Compute and the variance of each component for .
- With episodes averaged, find the condition on for the total noise to be smaller than the squared signal . You may ignore the variance of .
- Now suppose the environment gives an immediate reward after decision 1 (a perfect turn-level reward) and you use reward-to-go. What happens to the noise from decisions ?
Hint
Solution
-
. For : , and , because has variance .
-
Averaging episodes divides each variance by . The noise from the irrelevant components is ; the squared signal is . The condition is
With a noiseless reward this is , the chapter’s result. A noisy reward multiplies the cost by . Long horizons and noisy graders compound.
- With reward-to-go, decision is weighted by the rewards from turn on. If all the reward arrived at turn 1, those are zero, so the reward-to-go for . The baseline matters here. If you keep one baseline for every turn, then : still pure noise, variance per turn, and nothing is gained. With a per-turn baseline , which is for , you get exactly. The noise from the irrelevant decisions disappears, and you need about one episode regardless of . This is the whole case for turn-level rewards. The catch is that in real tasks you rarely have a reward that says precisely when the decisive thing happened, and any proxy for it can be gamed.
You are training an agent to resolve GitHub issues in Python repositories. It has a shell, a file editor, and run_tests().
- Propose a reward function. Be specific about what is executed, where, and what counts as success.
- List three distinct ways an agent could get high reward from your design without resolving the issue.
- For each, give a defense, and say what it costs.
Hint
Solution
A reasonable design: after the agent submits, copy only its changes to non-test source files into a fresh checkout of the repository at the original commit. Run a held-out test suite there: the tests that the real fix made pass (“fail-to-pass”) plus tests that must keep passing (“pass-to-pass”). Reward 1 if all pass within a time limit, else 0. Malformed submissions or timeouts get 0. This is close to what DeepSWE and SWE-bench-style graders do.
Three hacks against weaker versions, with defenses:
- Edit the tests (change the expected value, delete the failing test, add a skip). Defense: never grade with test files the agent can modify. Copy only non-test changes and use held-out tests. Cost: you need held-out tests per task, which is the expensive part of building SWE environments.
- Fake the test runner’s result:
sys.exit(0)at import time, aconftest.pythat rewrites outcomes, or an object whose__eq__always returnsTrueso assertions pass. Defense: run the grader in a clean process with a fixed runner configuration, ignoreconftest.pyand other config changes, and parse per-test results rather than trusting the exit code. Add diff checks that flag edits to test infrastructure. Cost: engineering effort, and some legitimate fixes do touch configuration. - Special-case the tests: detect the test’s exact inputs and return the expected outputs (
if a == 2 and b == 3: return 5). Defense: held-out tests with different inputs (property-based or randomized), plus an LLM-judge or monitor that reads the patch for special-casing. Cost: more tests; judges have their own errors and biases (Chapter 14).
Others worth noticing: escaping the sandbox to download the upstream fix (defense: no network access during episodes), and running out the clock if timeouts are scored better than failures (defense: score timeouts as failures or mask them, never better).
In an early version of this chapter’s lab, a malformed turn (anything other than call x or ans x) ended the episode with reward 0, like GLM-4.5’s “halt with reward 0” rule. Tool calls cost 0.05 each, and a correct answer earns 1. After about 200 training steps, more than half of all episodes ended with a malformed turn.
- Compute the total reward of (a) an episode that makes three tool calls and then answers wrongly, and (b) an episode whose first turn is malformed.
- Explain why the agent learned to produce malformed turns.
- What reward for a malformed turn fixes this? Why does the fix in GLM-4.5’s setting not need negative rewards?
Hint
Solution
- (a) . (b) .
- Early in training, the agent’s searches often failed. A failed search costs , while quitting immediately by writing nonsense costs nothing. Within a group, the malformed episodes had higher reward than the failed searches, so they got positive advantages and were reinforced. The agent found the cheapest way out of a task it expected to fail. It is a small reward hack, invented by the optimizer, not by us.
- The malformed reward must be below the worst outcome of an honest attempt. With at most five turns, that is five tool calls and no answer: . So anything clearly below works. The lab uses . In GLM-4.5’s agentic RL as described, there is no per-call cost, so rewards are never negative and 0 is already the worst outcome. Quitting can’t beat an honest failure. The lesson is general: whenever you add a cost, re-check that no “exit” became attractive.
An SWE episode takes 40 turns. Each turn, the model generates 400 tokens at 40 tokens per second (one sequence’s decoding speed), then waits for a tool that takes 6 seconds on average. Ignore prefill.
- How long does one episode take?
- A synchronous training step runs 64 tasks × 8 episodes in parallel and waits for all of them. Episode durations vary, and the slowest of the 512 takes 3 times the average. How long is a step, and what fraction of the step’s GPU time is spent generating tokens? (Assume the GPU serving an episode is idle while its tool runs and after its episode finishes.)
- Name two changes that would raise that fraction, and the price of each.
Hint
Solution
- Generation per turn: s. Plus 6 s of tool time: 16 s per turn. Over 40 turns: s, about 10.7 minutes.
- The step lasts as long as the slowest episode: s, 32 minutes. An average episode generates for s. So the generation fraction is . About four fifths of the time, the hardware is waiting, either for tools or for stragglers.
- Asynchronous rollouts: start new episodes as soon as others finish and keep training on what has arrived. This removes most straggler waiting. The price is staleness: samples come from slightly older policies, so you need importance ratios and clipping (Chapters 9 and 20). Overlapping tool time with generation: while one episode waits for its tool, the GPU decodes other episodes (continuous batching across many concurrent episodes). The price is more concurrent sandboxes and memory for many KV caches. Also possible: cap turns or tool time (the price is cutting off legitimate long solutions), and mask episodes that hit the cap rather than scoring them as failures.
Use the demo above.
- With the default settings, which episodes get positive advantages? Is there any setting of the credit controls (whole trajectory, per-turn, any γ) that gives episode C a negative advantage while the grader is “Repo’s tests pass”?
- Switch to “Held-out tests pass”. What are the new rewards, baseline and advantages? Why did episodes B and D become less negative?
- With the mask on, how many tokens of episode D get gradient? With it off? Why is D the episode where forgetting the mask matters most?
- Turn on process rewards, keep “Repo’s tests pass”, and use whole-trajectory credit. Rank the four episodes by advantage. Which ranking change would worry you, and why?
Solution
- A and C (both ). No credit scheme can help: all of them are functions of the rewards, and C’s reward equals A’s. Credit assignment distributes the reward; it can’t fix a reward that pays for the wrong thing. Only the grader setting changes C’s sign.
- Rewards , baseline , advantages . B and D are less negative because the baseline dropped from 0.5 to 0.25: with fewer successes in the group, a failure is less below average. A’s advantage rose for the same reason.
- With the mask on, D has 15 model tokens with gradient. With it off, its 49 tool tokens are trained too: 64 tokens, three quarters of them written by the environment. D spends most of its context reading test logs, so it is where an unmasked loss is most dominated by tool text.
- Rewards : A and C tie at , D is at , B at . The worrying change is D overtaking B. D did nothing but call tools in a loop, and the process reward made that look much better than B’s genuine (if wrong) attempt to fix the code. Over many updates, this teaches the agent to look busy.
The lab trains a tiny recurrent language model (a GRU over a 17-token vocabulary) to find a secret number with a compare(x) tool. It uses exactly the token layout from the worked example. Half the tasks reveal the number in the prompt, so the tool is useless there; the other half hide it, so the tool is essential. Implement, in agentic.py:
- Task 1
GuessEnv.step: run the tool, hand out rewards (call cost, answer reward, malformed penalty), and end episodes. - Task 2
rollout: the agent loop, which interleaves sampled model tokens with tool tokens and recordsis_modelandturn_id. - Task 3
turn_advantages: trajectory-level and reward-to-go credit with a group baseline. - Task 4
masked_policy_loss: the token-masked REINFORCE loss.
Then run run.py, which trains three variants for 250 steps each (about 1.5–3 minutes in total) and saves agentic_rl.png.
Hint
logits[:, t] predicts ids[:, t+1], so drop the first column of the mask and the advantages before multiplying.Solution
The reference is solutions/agentic.py. The key lines:
- Task 1: a valid call returns
[TOOL, LOWER/HIGHER/EQUAL], reward-call_cost, anddone = self.turns >= self.max_turns. An answer returns[],1.0or0.0, andTrue. Anything else returns[],malformed_reward,True. - Task 2: after the prompt, loop over turns. Sample two tokens with
sample_token(probs, rng), appending each withis_model = 1and feeding it withsampler.step. Callenv.step, append the reward, then append and feed each observation token withis_model = 0. - Task 3: trajectory mode is
R_i - mean(R)broadcast over turns. Turn mode computesg[k] = r[k] + gamma * g[k+1]backward and subtractsmean(g_i[0]). - Task 4:
logp = log_softmax(logits).gather(-1, ids[:, 1:, None]), then-(m * a * logp).sum() / m.sum().clamp(min=1)withm = loss_mask[:, 1:]anda = token_adv[:, 1:].
What you should see. With the mask, success on hidden-number tasks rises from about 0.2 to about 0.9, and the agent makes about 2.5 tool calls there, a near-binary search (try printing a few episodes). It learns to copy the number from the prompt when it is shown. It also uses the tool less on those tasks than on hidden ones, though it drops tool calls there only slowly, because a 0.05 cost is a weak signal. Without the mask, the agent abandons the tool and stays near the 1/8 guessing rate. Turn-level and trajectory-level credit perform similarly here, because the only per-turn rewards are small call costs.
A softmax policy over three tokens with logits . The sampler forbids token 3 (it renormalizes over tokens 1 and 2), but the trainer computes with the full three-way softmax. Each update samples token 1 or 2 from the sampler and applies a REINFORCE step along .
- Write for . How does an update on token 1 change when ? When ?
- If grows too large, something eventually corrects it. What, and why does the same correction never happen for ? With plain SGD the change in per update is proportional to , so it stays tiny. Why is that no longer true with Adam?
- Suppose that at some position the drift has made . Compare the trainer’s gradient with the gradient of the sampler’s policy, , where . What goes wrong when is already close to 1?
Hint
Solution
-
. The update changes by : down when , up when . Pushing a sampled token up pushes every other token down, and vice versa, including the forbidden one. In a network, is computed by its own output row from a shared hidden state, so these pushes land on that row’s weights.
-
If gets too large, token 2 is sampled more often. Whenever it was a bad choice, it gets a negative advantage and is pushed back down. Being sampled is what exposes a token to correction. Token 3 is never sampled, so it is only ever moved as a side effect of other tokens’ updates, in whatever direction those happen to point, with no restoring force. With SGD the side effect is proportional to , so a forbidden token that starts improbable stays put. Adam divides each parameter’s gradient by the root of a running average of its own squared gradient. A parameter that only ever sees tiny gradients therefore takes steps of roughly the learning rate, the same as any other parameter. The forbidden token’s output row performs an unrestrained random walk at full speed. In the lab, the norm of
<bos>’s output row grew from about 0.6 to about 2.5 over 150 updates. That was enough that at some positions the trainer gave the forbidden tokens nearly all of its probability, although averaged over positions their probability stayed near 0. -
. For the sampler, , so . If , then and the trainer’s gradient is about 1, whatever is. When the sampler already picks token 1 with probability near 1, the correct gradient is near 0 (the token is saturated, so there is nothing left to learn), but the trainer keeps pushing at full strength. Positive updates overshoot. Negative updates push even higher. The trainer is optimizing a different policy from the one generating the data: a train–inference mismatch. In the lab, zeroing the gradients of the two forbidden tokens’ output rows was enough to restore learning in all four seeds tested, and masking them in the trainer as well as the sampler is the clean fix. DeepSeek-V3.2’s “Keep Sampling Mask” applies the same principle to top-p/top-k truncation.
Files: agentic.py, tinyagent.py, test_agentic.py, run.py, README.md
cd 18-agentic-rl
python -m pytest -q # your code: tests fail until you fill in the TODOs
RL_SOLUTIONS=1 python -m pytest -q # reference solutions: all passFirst time? See Exercises & setup.
Further reading
- Jin et al. (2025), Search-R1: Training LLMs to Reason and Leverage Search Engines with Reinforcement Learning. The cleanest small-scale agentic RL paper: interleaved search calls, outcome reward, and an ablation of retrieved-token masking (Section 5.4).
- Agentica & Together AI (2025), DeepSWE: Training a Fully Open-sourced, State-of-the-Art Coding Agent by Scaling RL. A detailed, honest recipe for RL on real repositories: rewards, GRPO++ choices, compact filtering, and what the infrastructure took.
- Wang et al. (2025), RAGEN: Understanding Self-Evolution in LLM Agents via Multi-Turn Reinforcement Learning. Multi-turn RL on small environments, and the “Echo Trap” instability with its fixes.
- Feng et al. (2025), Group-in-Group Policy Optimization for LLM Agent Training. Step-level credit without a critic, via anchor states. A good model of how to extend GRPO’s idea to turns.
- Wei et al. (2025), SWE-RL: Advancing LLM Reasoning via Reinforcement Learning on Open Software Evolution. RL for software engineering with a similarity reward and no code execution. A useful contrast with test-based rewards.
- GLM-4.5 Team (2025), GLM-4.5: Agentic, Reasoning, and Coding (ARC) Foundation Models. A production report that spells out agentic RL choices: masking, format penalties, synchronous vs asynchronous rollouts.
- MacDiarmid et al. (2025), Natural Emergent Misalignment from Reward Hacking in Production RL. What happens when coding environments are hackable, and why it matters beyond the hacked task. Read before you build an environment.
- Zhang et al. (2025), The Landscape of Agentic Reinforcement Learning for LLMs: A Survey. A map of the field, organized by capability and application, for when you want breadth.
Next, Chapter 19 takes the reward hacking you saw in episode C and asks the general question: what goes wrong when you optimize hard against any imperfect reward?