Skip to main content
Single-turn group relative policy optimization (GRPO) scores one model response per prompt. Multi-turn GRPO runs and scores whole episodes. In each episode, the model takes an action (an assistant message that may carry tool calls), the environment responds, and the loop repeats until the environment ends the episode or a turn limit stops it. The reward comes from the environment when the episode ends, and every assistant turn in the episode trains on it. Use multi-turn GRPO for tool-use agents, multi-step reasoning against an external system, and any task where the model has to act more than once to earn a reward.

Requirements

  • The same requirements as single-turn GRPO: a model with generator support, and a model resource with num_generator_replicas of 1 or more.
  • A cookbook checkout, which provides the environment abstractions in post_training_cookbook.envs.

How an episode runs

Each episode starts from a Task, which carries the prompt, the target the reward checks against, and any metadata the environment needs. The loop then alternates between the model and the environment:
  1. The environment’s reset(task) returns the opening messages, typically a system prompt and the user prompt.
  2. The loop renders the messages and the environment’s tool specs through the model’s codec, samples an assistant message, and parses it back into a structured message with any tool calls.
  3. The environment’s step(message) consumes the assistant message, executes any tool calls, appends the results, and returns a StepResult with the updated history, a reward, and whether the episode is over.
  4. Steps 2 and 3 repeat until the environment terminates the episode, the loop truncates it, or max_turns assistant turns have run.
episodes_per_task is the multi-turn counterpart of group_size in single-turn training. Each task runs that many episodes, and advantages are computed across them.

Write an environment

Subclass Env and implement its four members: reset, step, tool_specs, and messages. The environment owns the conversation history, tool dispatch, and the rule for when an episode ends. The loop owns tokenization and sampling.
Beyond those four members, an environment works with these pieces:
  • Task: The spec for one episode, with prompt, target, and metadata fields.
  • Tool: Anything with name, description, parameters_schema, and an async execute(arguments) -> ToolResult method. tool_to_spec converts a tool into the schema the codec renders into the prompt.
  • ToolResult: The return value of execute. Set should_stop=True to ask the environment to end the episode. Your step decides how to honor the request. The cookbook’s reference environment returns terminated=True.
  • StepResult: The return value of step. terminated means task logic ended the episode, for example on a final answer. truncated means an external policy ended it. reward is the episode’s reward when it ends. The loop reads reward and metrics only from the step that ends the episode, so intermediate steps usually return 0.0 and diagnostics belong in the final step’s metrics.
  • close(): Override it when reset starts background work, such as a subprocess or a connection. It runs even when the loop truncates the episode and the environment never sees a terminal step.
To build your own environment, start from a copy of the cookbook’s reference implementation, ToolUseGameEnv in post_training_cookbook/envs/tool_use_game/. It provides list_fact_keys, lookup, and calculator tools and a bundled task list.

Run multi-turn training

Call train_multi_turn with your tasks, a factory that builds a fresh environment for each episode, and a config that sets max_turns:
This example is the cookbook’s recipes/grpo/tool_use_game.py recipe. These settings are specific to multi-turn training:

How episodes become training samples

A multi-turn episode flattened into one token stream of user context, assistant action, tool context, and assistant action. Context segments get loss mask 0 and aren't trained on. Action segments get loss mask 1, are trained on, and share the episode's advantage.
An episode is a sequence of alternating turns, but the trainer sees flat token sequences. The collector flattens each episode into context segments and action segments. Context segments get loss mask 0, so the model isn’t trained to predict the prompt or the tool results. Action segments get loss mask 1, and every action in the episode carries the episode’s advantage. When the chat template strips earlier content from history, such as a reasoning model’s <think> blocks, the collector starts a new sample at that point, so the tokens stay aligned with the log-probabilities the generator recorded. Thinking settings covers the options that control this.

Truncation

An episode that doesn’t reach a terminal step is truncated. The cause determines whether the soft overlong penalty is added to the episode’s reward. Only the two length-budget causes add it: With overlong_masking=True, truncated episodes of any cause are dropped before samples are built, but their rewards still count toward the group baseline. To track how episodes end, watch the multi-turn metrics in the step log: terminated_ratio, truncated_ratio, context_overflow_ratio, and parse_failure_ratio.

Score a hosted model first

Before you spend GPU time, use the cookbook’s post_training_cookbook.serverless_eval package to get a baseline score for your environment. Its run_and_report function runs any Env against a hosted chat model without a training session. For a worked example, see recipes/serverless_eval/tool_use_game.py. Check a baseline before training explains how to read the score.

Next steps

Reinforcement learning with GRPO

Clipping, dynamic sampling, overlong handling, and async training.

Reward functions

Design guidance that applies to episode rewards too.

Monitoring

The multi-turn and async metrics.

Cookbook reference

Every GRPO config field, including the multi-turn ones.