Skip to content

fix(sft): tolerate trace-shape tool calls; opt-in skip for unrenderable samples#3081

Open
mikasenghaas wants to merge 1 commit into
mainfrom
fix/sft-skip-invalid-samples
Open

fix(sft): tolerate trace-shape tool calls; opt-in skip for unrenderable samples#3081
mikasenghaas wants to merge 1 commit into
mainfrom
fix/sft-skip-invalid-samples

Conversation

@mikasenghaas

@mikasenghaas mikasenghaas commented Jul 18, 2026

Copy link
Copy Markdown
Member

Problem

Plugging a verifiers rollout dataset (e.g. PrimeIntellect/SyntheticData-GLM5.2-scaleswe-reward0, scaleswe_rlm_glm51) into SFT crashes twice over:

  1. Immediately, on the first tool-call sample: these datasets store tool_calls entries as flat JSON strings ('{"id", "name", "arguments"}'), and deserialize_tool_calls calls .get on them → AttributeError (src/prime_rl/utils/chat_template.py).
  2. On any sample the renderer rejects: SFTDataset.__iter__ calls _process bare, so a renderer ValueError propagates through the dataloader and kills the run. Measured on the dataset above: ~1% of samples are degenerate teacher outputs (garbage tool names like 'ipy'/'ipython<tool_call>ipython…', missing code arg) that a strict renderer correctly refuses.

Change

  • deserialize_tool_calls now accepts tool-call entries as JSON strings and normalizes the flat verifiers shape into the OAI {"function": {...}} form (id/type preserved). Dict-shaped OAI entries behave exactly as before.
  • New opt-in data.skip_invalid_samples: bool = False: when on, SFTDataset.__iter__ catches ValueError from _process, warns (mirroring the existing zero-trainable-tokens skip log), and continues. Default off — data problems keep failing loudly.

Tests

tests/unit/train/sft/test_sft_dataset.py: trace-shape + OAI-shape deserialization; raising sample crashes with the knob off and is skipped (good samples still yielded) with it on. Full file: 22 passed.

🤖 Generated with Claude Code


Note

Low Risk
Localized SFT data preprocessing and an opt-in flag; default behavior stays fail-loud, with no auth or persistence changes.

Overview
Makes SFT usable on verifiers rollout datasets that store tool calls differently and may include a small fraction of unrenderable rows.

deserialize_tool_calls now accepts each tool-call entry as a JSON string or a flat {id, name, arguments} dict, normalizes them to the OAI function shape, and still parses string arguments the same way as before for dict-shaped entries.

data.skip_invalid_samples (default false) wires through to SFTDataset: when enabled, ValueError from rendering/_process is logged and the example is skipped instead of aborting the run; when off, behavior is unchanged (fail fast).

Unit tests cover trace vs OAI deserialization and the skip knob.

Reviewed by Cursor Bugbot for commit c9acf6b. Bugbot is set up for automated code reviews on this repo. Configure here.

…le samples

Verifiers rollout datasets store tool_calls as flat JSON strings
({"id","name","arguments"}); deserialize_tool_calls crashed on them with
AttributeError before the renderer ever ran. Normalize both the string
encoding and the flat shape to the OAI form.

Renderer/template raises inside SFTDataset._process previously
propagated out of the dataloader and killed the run on the first bad
sample. New opt-in data.skip_invalid_samples (default False so data
problems still fail loudly) skips-and-logs those samples, mirroring the
existing zero-trainable-tokens skip.

Measured motivation: scaleswe rlm traces (SyntheticData-GLM5.2) crash on
the first tool-call sample without the deserialize fix, and carry ~1%
degenerate samples (garbage tool names, missing code arg) that the rlm
renderer correctly rejects.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant