Skip to content

fix: detect rollouts truncated by the per-turn generation cap - #14

Open
albcui wants to merge 2 commits into
nmp/customizerfrom
albcui/thread-max_output_tokens
Open

fix: detect rollouts truncated by the per-turn generation cap#14
albcui wants to merge 2 commits into
nmp/customizerfrom
albcui/thread-max_output_tokens

Conversation

@albcui

@albcui albcui commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

hit_max_tokens feeds final_batch["truncated"], which grpo.overlong_filtering uses to drop a sample from the loss, but it only tested whether the conversation had filled the context (vllm_cfg.max_model_len). A rollout can also be stopped by policy.generation.max_new_tokens, which NeMo-Gym agents apply per turn, and a run with a small max_new_tokens never fills the context at all -- so every one of its truncated samples kept the near-zero reward that overlong filtering exists to discard.

Check both budgets, and compare with >= rather than ==: the message log is post-processed before it reaches here (reasoning content is re-wrapped in thinking tags, for one), so an exact match can be thrown off by a single token.

truncation_rate and natural_termination_rate derive from the same flag, so runs whose generation cap bound below the context will now report higher truncation than before. The earlier numbers were under-counting.

Bump the Gym submodule for the matching change: verifiers_agent now honors responses_create_params.max_output_tokens, so max_new_tokens actually reaches the agent. The two belong together -- without the Gym half nothing is capped below the context, and without this half the newly honored cap goes undetected.

What does this PR do ?

Add a one line overview of what this PR aims to accomplish.

Issues

List issues that this PR closes (syntax):

Usage

  • You can potentially add a usage example below
# Add a code snippet demonstrating how to use this

Before your PR is "Ready for review"

Pre checks:

  • Make sure you read and followed Contributor guidelines
  • Did you write any new necessary tests?
  • Did you run the unit tests and functional tests locally? Visit our Testing Guide for how to run tests
  • Did you add or update any necessary documentation? Visit our Document Development Guide for how to write, build and test the docs.

Additional Information

  • ...

hit_max_tokens feeds final_batch["truncated"], which grpo.overlong_filtering
uses to drop a sample from the loss, but it only tested whether the
conversation had filled the context (vllm_cfg.max_model_len). A rollout can
also be stopped by policy.generation.max_new_tokens, which NeMo-Gym agents
apply per turn, and a run with a small max_new_tokens never fills the
context at all -- so every one of its truncated samples kept the near-zero
reward that overlong filtering exists to discard.

Check both budgets, and compare with >= rather than ==: the message log is
post-processed before it reaches here (reasoning content is re-wrapped in
thinking tags, for one), so an exact match can be thrown off by a single
token.

truncation_rate and natural_termination_rate derive from the same flag, so
runs whose generation cap bound below the context will now report higher
truncation than before. The earlier numbers were under-counting.

Bump the Gym submodule for the matching change: verifiers_agent now honors
responses_create_params.max_output_tokens, so max_new_tokens actually
reaches the agent. The two belong together -- without the Gym half nothing
is capped below the context, and without this half the newly honored cap
goes undetected.

Signed-off-by: Albert Cui <albcui@nvidia.com>
@albcui
albcui requested a review from anubhutivyas August 20, 2026 20:26
@github-actions

Copy link
Copy Markdown

✅ Submodule Fast-Forward Check Results

Check based on commit: 9a93d65 (PR #14 from albcui/thread-max_output_tokens)

✅ Submodules that are properly updated:

Gym: ✅ PR branch is ahead of nmp/customizer branch (fast-forward)

All submodule changes look good! ✨

The previous commit inferred truncation from token counts because the Gym path
appeared to have no better signal. It does: verifiers_agent now reports
is_truncated, derived from the model server's finish_reason == "length" -- the
same ground truth the native generation path already uses
(vllm_worker_async.py, "is_truncated = generation_details.finish_reason ==
'length'"), and the semantic docs/guides/grpo.md describes for overlong
filtering.

Prefer it. It needs no knowledge of which budget was binding, so it covers
context exhaustion, an environment's own per-turn cap and max_new_tokens
alike, and it does not mistake a turn that emitted EOS on its final allowed
token for one that ran out of budget. This also converges the NeMo-Gym path
with the native path rather than maintaining a second, weaker notion of
truncation.

Keep the length comparison as a fallback: agents other than verifiers_agent
report no flag, and omitting the field selects the previous behaviour.

Bumps the Gym submodule for the reporting change.

Signed-off-by: Albert Cui <albcui@nvidia.com>
@github-actions

Copy link
Copy Markdown

✅ Submodule Fast-Forward Check Results

Check based on commit: a61a49a (PR #14 from albcui/thread-max_output_tokens)

✅ Submodules that are properly updated:

Gym: ✅ PR branch is ahead of nmp/customizer branch (fast-forward)

All submodule changes look good! ✨

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown

This PR is stale because it has been open for 14 days with no activity. Remove stale label or comment or update or this will be closed in 7 days.

@github-actions github-actions Bot added the Stale label Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants