Skip to main content
Multi-turn environments enable back-and-forth interaction between the model and the environment. They’re perfect for games, simulations, debugging tasks, and any scenario where the model needs multiple attempts or receives feedback after each action.

Overview

MultiTurnEnv implements the core rollout loop used by all Verifiers environments (even SingleTurnEnv is just a MultiTurnEnv with max_turns=1). Each rollout follows this pattern:
  1. Initialize statesetup_state() prepares per-rollout resources
  2. Loop until done:
    • Get prompt messages (initial prompt or previous conversation + environment response)
    • Get model response
    • Check stop conditions — exit if any @vf.stop method returns True
  3. Render completion — assemble final conversation into state["completion"]
  4. Cleanup — run all @vf.cleanup methods

The Rollout Loop

Here’s the core structure of a multi-turn rollout:
To build a custom multi-turn environment, you override specific methods:
  • env_response()Required. Define how the environment responds after each model turn
  • setup_state() — Optional. Initialize per-rollout resources
  • @vf.stop methods — Optional. Define custom stop conditions
  • @vf.cleanup methods — Optional. Cleanup resources after each rollout

Building a Custom Environment

Let’s build a simple number guessing game:

Real Example: Wordle

Let’s examine the wordle environment from the repository:
environments/wordle/wordle.py
Key features:
  • Wraps a TextArena game environment
  • Uses XMLParser to extract guesses from structured output
  • Custom feedback_fn cleans up the game state for the model
  • Multiple reward functions: correctness + efficiency bonus

Advanced Patterns

Custom Stop Conditions

Control when rollouts end with @vf.stop decorators:
Priority ordering (higher runs first) lets you check cheap conditions before expensive ones.

Early Termination from env_response

Signal completion directly from the environment response:
Setting state["final_env_response"] bypasses the model response loop and terminates immediately.

Cleanup and Resource Management

Use decorators for proper resource cleanup:
Important: Cleanup methods should be idempotent (safe to call multiple times) and handle errors gracefully. This ensures correct behavior when rollouts are cancelled or interrupted.

Custom Message Assembly

Override get_prompt_messages() for non-linear conversations:

Trajectory Tracking

Add metadata to each turn:

Error Handling

Verifiers provides a hierarchy of error types under vf.Error:
When a vf.Error is raised during a rollout:
  1. It’s caught automatically
  2. Stored in state["error"]
  3. The built-in has_error stop condition triggers
  4. The rollout terminates gracefully
Example:

Monitor Rubrics

Track environment-specific metrics automatically:
MultiTurnEnv automatically tracks num_turns for all multi-turn environments.

Testing Your Environment

Common Pitfalls

Don’t override rollout() — The base implementation handles the core loop correctly. Override specific methods like env_response(), setup_state(), and stop conditions instead.
Return new messages, don’t mutateenv_response() should return a list of new messages to append, not modify existing messages.
Make cleanup idempotent — Cleanup methods may be called multiple times or when resources are in unexpected states. Handle errors gracefully.

Next Steps