Skip to main content
Train a language model to write correct Python functions with reinforcement learning (RL). Your training process never runs the untrusted code the model generates. The setup has 2 phases: a supervised fine-tuning (SFT) warmup, then Group Sequence Policy Optimization (GSPO) fine-tuning. A hidden pytest suite scores every completion inside an isolated Tensorlake sandbox.

How it works

Training alternates between generating code and scoring it in sandboxes:
  1. SFT warmup (Phase 1): A supervised pass on correct solutions so the model starts generating valid Python. Without it, all completions score 0, reward variance is 0, and the RL trainer has no gradient signal.
  2. GSPO fine-tuning (Phase 2): GRPOTrainer with importance_sampling_level="sequence" generates G completions per step and dispatches them to G parallel sandboxes.
  3. Sandbox reward: Each sandbox runs a hidden pytest suite against the model’s code and returns tests_passed / total as the reward, from 0.0 to 1.0.
Model-generated code is untrusted, so it must not run in your training process. Each completion runs in its own isolated sandbox instead.

GSPO vs GRPO

GSPO and Group Relative Policy Optimization (GRPO) both use clipped importance sampling (IS), but at different granularities: For long function bodies, token-level clipping lets noisy individual tokens dominate the gradient. Sequence-level clipping treats the entire trajectory as one unit, which fits code generation better.

Prerequisites

You need Python, the packages below, and a Tensorlake API key:
Create a .env file in your project root with your Tensorlake API key. The script calls load_dotenv() to read it:

TypeScript SDK starter

The Node.js version keeps the same reward oracle. It writes each completion into its own sandbox, runs the hidden pytest suite there, and uses the pass ratio as the reward.
This reward function works with the GSPO loop in the full example below. Keep the model and trainer in Python, and move only the sandbox evaluation to TypeScript if your orchestration layer already runs there.

Full example

The script runs 4 stages in order: baseline evaluation, SFT warmup, GSPO fine-tuning, and final evaluation. Pass --smoke for a 5-minute CPU run with 3 tasks, 20 SFT steps, and 1 GSPO epoch.

What happens step-by-step

Each run has 7 steps, from loading the model to the final held-out evaluation:

Key design decisions

Three choices keep the reward signal non-zero and hard to game: a high sampling temperature, an SFT warmup, and hidden tests.

Why temperature=1.4

GSPO needs diversity across the G completions in each group to produce a non-zero reward standard deviation. At low temperature all completions are identical, so reward_std is 0. Advantage normalization then produces zero gradients and training stalls. A high temperature forces the model to explore different implementations.

Why SFT warmup is required

Without warmup, a randomly initialized or instruction-tuned model produces malformed Python that scores 0 on every test case. All-zero rewards mean all-zero advantages after normalization, and GSPO has nothing to optimize. Even 20 supervised steps on correct solutions bootstrap non-zero reward variance.

Why sandboxes prevent reward hacking

The model never has access to the test file. Its only feedback is the pass rate the sandbox returns. The model can’t overfit to specific assertion patterns, so it must implement the correct logic.

What to build next

AI Code Execution

Use a sandbox as a tool inside an agentic LLM loop.

Agentic Swarm Intelligence

Dispatch parallel sandboxes across a swarm of worker agents.