[Agent RL] Qwen3.5 history re-templating causes false trajectory forks
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 8.5k
- Forks
- 1.3k
- Avg merge
- 5h 36m
- Merged PRs (30d)
- 22
Description
Context
This issue is specific to multi-turn agent RL with Qwen3.5 and a Claude Code-compatible Anthropic adapter. Claude Code sends the full structured message history on each turn, while Slime currently re-applies the model chat template to that history before every SGLang request.
For an RL trajectory, the required invariant is stricter than semantic equivalence:
next_prompt_ids[:len(previous_prompt_ids + previous_output_ids)]
== previous_prompt_ids + previous_output_ids
Without that exact prefix relationship, the stored action tokens and rollout log probabilities no longer describe the next prompt.
Observed behavior
In a real Qwen3.5-35B-A3B + Claude Code + TMax run:
8 environment rollouts
-> 64 training Samples
-> 1,825,684 trajectory tokens
Adjacent segments first diverged at historical assistant output, so TrajectoryManager classified many ordinary turns as forks. The duplicated prefixes then substantially increased packing and critic memory pressure.
Root cause
Two message-to-token round trips are not lossless:
- The Qwen3/3.5 chat template normally removes reasoning from assistant turns before the latest user/tool message. Claude Code may also omit earlier thinking blocks when it replays history.
- Parsed model output passes through Claude's structured message representation. Text, whitespace, and tool-call argument formatting may be normalized before the next request.
Slime already owns the exact prompt_ids, output_ids, and rollout log probabilities generated by SGLang, but the adapter reconstructs old assistant tokens from the client replay instead of continuing from those canonical token IDs.
Fully-async rollout does not create the mismatch. It makes the impact more visible because the false forked Samples enter the asynchronous training queue and inflate token volume.
Expected behavior
For this adapter/model combination:
- The adapter server keeps an exact per-session token ledger.
- Historical assistant tokens come from the server's previous
prompt_ids + output_ids, not from re-tokenizing the client echo. - Only new user/tool observations and the next generation prompt are rendered and appended.
- A non-append-only continuation fails explicitly instead of silently becoming a trajectory fork.
- Reasoning remains enabled and trainable; this must not be fixed by disabling the Qwen
<think>generation prefix.
Validated result
With canonical token continuation implemented in #2287, the same eight-task rollout produced:
8 environment rollouts
-> 8 training Samples
-> 265,001 trajectory tokens
All 128 assistant action segments retained reasoning through </think>, with aligned loss_mask, rollout_log_probs, and response_length. Critic forward and backward also completed without the previous memory failure.
Scope
This issue tracks the Qwen3.5/Claude Code history-alignment bug only. It does not claim that fully-async rollout itself creates forks, and it does not cover legitimate context compaction, sub-agent branching, generic nested fan-out, group reward models, or GRPO normalization.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No specific files or tests are named. Start with the Claude Code-compatible adapter server and TrajectoryManager, then inspect the canonical token continuation implemented in #2287. Done means each session preserves the exact prompt/output token prefix, rejects non-append-only continuation explicitly, and keeps reasoning and rollout metadata aligned.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- ai, machine-learning
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 30/100