If you train agents with reinforcement learning, the expensive part is often not generating rollouts. It is running the trainer over very long, highly repetitive transcripts. On October 13, 2026, Hugging Face's TRL library merged a change to attack exactly that: tree packing for AsyncGRPOTrainer. A viral post then summarized it as "the same reward with 26x less trainer compute on MiMo Envs."
That headline number is the part we could not verify. The merged pull request (huggingface/trl #7328) and the AsyncGRPO documentation are more modest, and more useful, so this post separates what is claimed from what is measured.
Claimed vs. verified
| Claim | Where it comes from | What we found |
|---|---|---|
| 26x less trainer compute for the same reward on MiMo Envs | A post on X, relayed by an AI news aggregator | Not found in the PR or docs; unverified |
| Forward each unique token once per batch | PR description and docs | Confirmed |
| Single FlashAttention 3 varlen call replaced a FlexAttention version | PR description | Confirmed (gathered FA3 is the final direction) |
| About 1% overhead when nothing is shared | PR microbenchmark (ratio 1.00) | Confirmed: roughly 1% slower |
| Works on MoE and vision-language models | PR parity tests | Confirmed for Qwen3-MoE and Qwen3-VL; some model types refused |
| Rollouts above 100k tokens benefit | Post on X | Plausible by design; not benchmarked in the PR we read |
The PR's numbers: on a microbenchmark (H100, BF16, Qwen3-1.7B, 32K tokens per rollout), gathered FA3 ran between 0.99x and 3.10x versus sequence packing across packing ratios from 1.00 to 3.56, and peak memory fell from 35.2 GiB to 13.5 GiB at the highest ratio. End to end, on an earlier FlexAttention version (Qwen3-8B on SWE-Gym, four FSDP2 ranks and one vLLM GPU), rollouts trained per second rose from 2.9 to 8.2 and trained tokens per second from 376 to 1,297, at a packing ratio of 4.21. The author says the gathered FA3 version is faster than the Flex one, so those figures are a floor.
A bigger multiple on a different benchmark with a different baseline is possible. 26x may measure something else, for example total trainer compute against a naive baseline that re-forwards every shared token, on very long agent traces. But as published in the repo, the verified range is roughly 3x. Treat 26x as a vendor-adjacent claim until a write-up shows the setup. Our guide to reading AI benchmarks covers what to ask in that situation: baseline, hardware, metric and whether the reward actually matched.
Why shared prefixes are the bottleneck in agentic RL
Group-based RL methods like GRPO sample several completions per prompt and compare them. Every completion starts with the same prompt. In agentic training the problem is worse: a multi-turn rollout carries the full history of tool calls and results forward on every turn, so the model re-reads the same thousands of tokens again and again.
A conventional trainer forwards each sample as a separate sequence, repeating that shared history for every one. Sequence packing removes padding but does not remove the repetition.
A learning agent following a path to a reward, illustrating agentic reinforcement learning with GRPO training
How tree packing works
From the TRL docs, rows in a micro-batch become prefix tries. A token shared by several samples is forwarded once, but attention still gives each sample only its own root-to-leaf history. The pipeline has three stages:
- Planner. Grows the trie sample by sample. The
token_budgetbounds unique tokens, not raw ones. - Collator. Lays tokens out depth-first, uses depth as position ids, and maps each trained token back to its original position through a
token_index. - Attention. Gathers keys and values along each path and runs one FlashAttention 3 varlen call with causal masking, so no mask tensor is needed.
The docs' example: two rollouts sharing a three-token prompt have 10 raw tokens but only 8 forwarded tokens. The ratio of raw to forwarded tokens is the packing ratio, and it predicts the gain. The PR measured 1.45 with the default fork threshold and 4.21 with forking enabled on real agentic rollouts, which shows how sensitive the benefit is to configuration.
A back-of-envelope example
Imagine a coding-agent task with a 20,000-token shared history, trained with eight rollouts per prompt, each adding 2,000 new tokens of its own. A conventional trainer forwards 8 x 22,000 = 176,000 tokens for that group. A prefix tree forwards the shared 20,000 once plus 8 x 2,000 unique tokens, 36,000 in total. That is a packing ratio near 4.9 on this toy case, and the saving grows as histories get longer relative to new tokens.
This is illustrative arithmetic, not a benchmark, and real rollouts diverge earlier and more often than this tidy case. It does show why long multi-turn agent traces, such as the over-100k-token rollouts mentioned in the social posts, are the natural target, and why a very large headline multiple is conceivable on a favorable setup even though the repository measures less.
Who should care
- Teams doing agentic RL on coding or tool-use tasks with long, repeated context: this is the case the feature is designed for, and you should benchmark it.
- Researchers running GRPO with many generations per prompt: even short prompts are shared across the group, so a modest gain is likely.
- Anyone fine-tuning with short, independent samples: expect roughly nothing, and about 1% overhead in the worst case measured.
- Teams on linear-attention or hybrid models: wait for the follow-up, since init refuses those architectures for now.
What is AsyncGRPOTrainer?
AsyncGRPOTrainer lives in trl.experimental.async_grpo. It runs the GRPO algorithm but decouples generation from training: a background rollout worker sends prompts to a vLLM server, scores completions and queues samples, while the main loop trains. Every weight_sync_steps steps, weights go to vLLM over NCCL. Samples can come from a slightly older policy, bounded by max_staleness.
Requirements from the docs: vllm plus transformers>=5.2.0, FSDP2 for distributed runs (DeepSpeed ZeRO is not supported), and separate GPUs for the trainer and the vLLM server. A minimal setup:
CUDA_VISIBLE_DEVICES=0 VLLM_SERVER_DEV_MODE=1 vllm serve Qwen/Qwen3-4B \
--max-model-len 4096 \
--logprobs-mode processed_logprobs \
--weight-transfer-config '{"backend":"nccl"}'
from datasets import load_dataset
from trl.experimental.async_grpo import AsyncGRPOTrainer
from trl.rewards import accuracy_reward
dataset = load_dataset("trl-lib/DeepMath-103K", split="train")
trainer = AsyncGRPOTrainer(
model="Qwen/Qwen3-4B",
reward_funcs=accuracy_reward,
train_dataset=dataset,
)
trainer.train()
Launch the trainer on the second GPU with CUDA_VISIBLE_DEVICES=1 accelerate launch train_async_grpo.py. Tree packing needs no extra flag: per the final commit message, it is now the only packing mode.
Limits and caveats to know before you switch
- Unsupported architectures. Initialization rejects models with linear attention or convolution layers (the PR names Qwen3.5, Qwen3-Next and MiMo) and attention sinks (GPT-OSS). Support for linear-attention models is a separate draft PR.
- Slower steps, lower MFU. The PR author recommends judging speed by trained tokens per step divided by forward-backward time, because model FLOPs utilization divides by forwarded tokens and can look worse even when training is faster.
- Fork threshold matters.
fork_threshold_tokensdefaults to 1024; set too low, conversations split and sharing drops. - Open review comment. On October 14 a reviewer noted that the merged placement logic still closes micro-batches early and asked about a follow-up; the thread showed no reply when we read it.
- MoE loss. The load-balancing loss averages over forwarded tokens, so shared tokens count once.
- Experimental module. It lives under
experimental, so APIs can change.
Note that MiMo appears in the 26x claim ("MiMo Envs") and in the PR's list of architectures refused at init. These are not necessarily in conflict, since an environment suite is not the same as the model being trained, but it is another reason to wait for the underlying write-up.
How to evaluate it on your own workload
- Log
batch/packing_ratio. Near 1 means your data share little and you will see little gain. - Compare trained tokens per second before and after, on the same hardware and the same reward curve.
- Watch
rollout/fork_fracandbatch/row_fill_fracto tunefork_threshold_tokensandtoken_budget. - Confirm the reward curve matches a baseline run. The PR reports loss parity within 1e-3 and gradient norms within 5% in bf16 against sequence packing across Qwen2, Gemma2, Qwen3-MoE and Qwen3-VL, but your model may differ.
Where this fits in the RL tooling picture
Agentic RL is getting its own infrastructure layer: sandboxes, environment hubs, and trainers. See our coverage of Prime Sandboxes and fork rollouts, the Hugging Face Hub RL environments guide, Microsoft's Agent Lightning, the broader open-source RL as a service stack, and another compute-saving result in WTF flow-map RL with 280x less compute. Tree packing is the same theme as fork rollouts: when rollouts branch from a shared state, do the shared work once.
Bottom line
Tree packing is a real, merged, well-tested improvement to TRL's asynchronous GRPO trainer, and for agentic workloads with long shared histories the measured speedups are meaningful: up to 3.1x on the attention microbenchmark and about 3.4x trained tokens per second end to end on an earlier version. The 26x figure is not in the repository materials we read. If your rollouts share little, expect almost nothing; if they share a lot, try it and measure.
Details reflect the TRL pull request and docs as of October 15, 2026; the experimental API may change.
