Training on External Agent Harnesses
Training on External Agent Harnesses
An external agent harness runs its own model-calling loop and returns a finished transcript to Gym. Claude Code is one example. The transcript contains the conversation text, but it does not contain the exact token ids and log probabilities produced by each model call.
Training needs those original token ids. Re-tokenizing the final text can produce a different sequence from the one sampled by the policy. Gym’s training-token capture records the ids while they are still available in the model server, associates the calls with their rollout, and rebuilds them into the token-bearing response expected by the trainer.
Decide whether you need token capture
Ordinary evaluation does not require training-token capture. Enable it when the collected rollouts will be used to optimize a policy.
How capture works
Every model call carries the rollout id. For a multi-call rollout, Gym verifies which earlier call the new request continues. After the harness finishes, Gym reads the captured calls and replaces the rollout’s text-only response.output with output items that carry the original token ids and log probabilities.
Gym does not guess when a call is missing or its parent cannot be proven. It sets mask_sample: true so the trainer can exclude that rollout from the loss.
Configure local capture
The default setup writes capture records to a node-local directory and lets Gym rebuild the response.
1. Configure the model server for training
Use responses_api_models/vllm_model/configs/vllm_model_for_training.yaml as the model-server config. It enables token information in model responses.
External harnesses often omit sampling parameters or send serving-oriented defaults. Pin the parameters used by training with sampling_overrides so every request uses the policy’s intended sampling configuration:
Replace the example values with the sampling settings used by the trainer. If the training framework starts vLLM, keep its tokenizer enabled. For NeMo RL, set policy.generation.vllm_cfg.skip_tokenizer_init: false.
2. Enable the capture store
Add the run-wide capture settings:
delta_records: true avoids storing the growing full prompt again for every resolved continuation. Root and unresolved calls remain self-contained so Gym can diagnose a broken chain.
max_mask_fraction is an optional safety limit. After at least mask_fraction_min_samples finalized rollouts, collection stops if the masked fraction exceeds this value. Omit it to disable the limit.
3. Opt in the external agent
Enable capture on each external harness that returns no token ids:
Both the run-wide enabled setting and the agent opt-in are required. To capture every configured agent, set token_id_capture.all_agents: true instead of setting the flag on each agent.
Native Gym agents normally leave token_id_capture disabled because their responses already contain the token ids needed for training.
4. Confirm that tool calls are enabled
A tool-call parser converts model output into structured calls that the harness can execute. Without the correct parser, an agentic rollout may stop after one model call even though capture itself is working.
Configure the parser expected by the model, such as tool_parser: hermes in the inference server’s chat-serving settings. Check n_calls on the first collected rollouts before relying on reward results.
Consume the rebuilt rollout
When rebuild_response remains at its default value of true, gym eval run performs the complete lifecycle:
- The model server records every correlated call.
- Gym freezes the records after the harness and verifier finish.
- Gym reconstructs one verified model-call chain and updates
response.output. - Gym writes the rollout result durably.
- Gym retires successfully consumed capture records.
The trainer reads the rebuilt response.output in the same way it reads output from a native agent. Prompt positions provide context, while generated positions retain the captured log probabilities used for policy optimization.
Masked or failed builds are retained for diagnosis. Successfully delivered records are removed after the output row is durable.
Check the first run
Gym adds capture metrics under _ng_token_capture on each rebuilt rollout.
A rollout with no _ng_token_capture field was not rebuilt. Verify that capture is enabled, the agent is opted in, and its model calls use the rollout-correlated model-server URL.
Optionally supply exact prefix tokens
Some harnesses reshape an assistant turn before sending the next request. A chat template or reasoning template can also render the previous turn differently. In these cases, the next prompt may not begin with the tokens that the policy actually sampled.
Prefix supply asks a compatible inference backend to begin the next prompt with the verified parent’s exact tokens. Enable the Gym model-server side with this config overlay:
The backend must support Gym’s required-prefix request and return the prompt token ids actually used for generation. Gym verifies that evidence before accepting prefix supply. A missing or mismatched proof fails the model call instead of silently producing an off-policy capture.
Stock vLLM does not implement this prefix-supply extension. Leave the overlay disabled unless the inference backend supports both the required-prefix request and generation-time prompt-token response. Capture can still work without prefix supply when each rendered prompt naturally extends the preceding sampled tokens.
Prefix supply is not supported with use_completions_api: true or is_responses_native: true.
Use framework-owned capture storage
The default file store is intended for a model server and rollout collector that share one node-local directory. A distributed training system can instead provide a shared transport.
Configure a sink and lineage resolver that connect to the same backend:
The sink receives completed call records from each model-server worker. The lineage resolver lets any worker find a previously committed call from the same rollout. The framework creates a source in its rollout-consumer or trainer process to freeze and read the same records.
With rebuild_response: false, Gym stops after capture. The framework then performs the consumer side:
Call finalize_rollout_token_capture before training and exclude any result with mask_sample: true. Call retire_rollout_token_capture only after the rebuilt result has been accepted by durable downstream storage.
Run nemo_gym.token_id_capture.conformance.run_conformance against custom sink, source, and lineage factories before using the transport for training. For a multi-process deployment, run the check with independent clients connected to the real shared backend.
Configure sink and lineage classes by import path so Gym constructs them inside every model-server worker. Installing an object only in the launcher process does not configure separately spawned workers.
Provide unique rollout ids
Gym normally derives the capture id from the task and rollout indices. If a custom training loop restarts those indices on each step, explicitly provide a unique _ng_rollout_id:
The id may contain letters, digits, dots, dashes, and underscores, and it must begin with a letter or digit.
Current limitations
- Gym delivers one verified model-call chain per rollout. When Gym can attribute the verifier-scored response to a captured terminal call, it delivers that call’s intact ancestor chain and excludes unrelated calls. Without terminal attribution, multiple plausible chains cause masking.
- Harness-generated title, compaction, retry, or sub-agent calls can appear as additional chains. Inspect
terminal_attribution,chains, anddelivered_fractionto confirm that Gym selected the intended chain. - Full-tree training requires a trainer data contract that accepts multiple related trajectories.
- Prefix supply requires a compatible inference backend and is not available in stock vLLM.