TRL documentation

Ortamlarla LLM Eğitiminde OpenEnv Entegrasyonu

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v1.17.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Ortamlarla LLM Eğitiminde OpenEnv Entegrasyonu

OpenEnv, pekiştirmeli öğrenme (RL) ve ajan tabanlı iş akışlarında ortamları tanımlamak, dağıtmak ve bu ortamlarla etkileşime girmek için kullanılan açık kaynaklı bir çerçevedir. Ortam etkileşimi için standartlaştırılmış API'ler sunar ve ortamların arka uç sunucuları olarak çalıştırılmasını destekler (WebSocket veya konteynerize çalıştırma yoluyla). Hazır kullanıma uygun OpenEnv ortamlarının bir koleksiyonunu Hugging Face Hub'da bulabilirsiniz.

Bu kılavuz, OpenEnv'in TRL ile nasıl entegre edileceğini kapsar. OpenEnv'in kendisi hakkında daha fazla bilgi için OpenEnv belgelerini inceleyin.

Hazır OpenEnv örnekleri: grpo_echo (minimal), grpo_catch, grpo_wordle, grpo_sudoku, grpo_multi_env, grpo_browsergym, grpo_carla ve async_grpo_harbor (yerel ve HF Jobs).

Ortamların ne zaman kullanılacağı

GRPOTrainer, ajanları eğitmek için kullanılabilir. Ajanik görevler için iki modu destekler: tools, modelin harici fonksiyonları çağırmasına olanak tanır ancak her çağrı durumdan bağımsızdır (stateless) ve environments, turlar arasında durumu koruyarak ajanın eylemlerinin gelecekteki gözlemleri şekillendirdiği gerçek çok turlu etkileşimi mümkün kılar. Süreklilik önemli olduğunda ortamları kullanın; örneğin bir oyunda gezinme, bir web sayfasını görüntüleme veya ajanın bir sonraki göreceğinin önceki eylemlerine bağlı olduğu herhangi bir görev.

Ortam entegrasyonu seçimi

OpenEnv, burada belgelenen yerel yoldur. OpenReward ve Harbor olmak üzere iki ek entegrasyon, aynı environment_factory sözleşmesine uyar ve TRL düzeyinde birbirinin yerine kullanılabilir. Görevinize uygun ekosisteme sahip olanı seçmek için GRPO kılavuzundaki ortam entegrasyonlarının karşılaştırması bölümüne bakın.

Kurulum

OpenEnv ortamları, pip ile kurulabilir Git depoları olan Hugging Face Spaces olarak barındırılır:

# Echo environment
pip install "openenv-echo-env @ git+https://huggingface.co/spaces/openenv/echo_env"

# Wordle (TextArena) environment
pip install "openenv-textarena @ git+https://huggingface.co/spaces/openenv/wordle"

# Catch (OpenSpiel) environment
pip install "openenv-openspiel-env @ git+https://huggingface.co/spaces/openenv/openspiel_env"

Bu, uzak ortam sunucusuyla WebSocket üzerinden iletişim kuran ortam istemcisini (ör. EchoEnv) ve eylem/gözlem modelleri ile tüm gerekli bağımlılıkları (arasında openenv de dahil) yükler.

Herhangi bir ortamın kurulum komutunu ilgili HF Space sayfasında bulabilirsiniz. Kurulum talimatlarını görmek için ⋮ (üç nokta) menüsüne tıklayıp “Bu Space’i kullan” seçeneğini seçin.

Ayrıca çekirdek paketi pip install "openenv>=0.3.1" komutuyla PyPI'den de yükleyebilirsiniz ancak ortamla ilgili bağımlılıkların ayrı olarak kurulması gerekebilir.

Geliştirme için OpenEnv deposunu klonlayıp yerel olarak kurabilirsiniz:

git clone https://github.com/openenv/OpenEnv.git
cd OpenEnv/envs/echo_env
pip install -e .

TRL'deki her ortam betiği, uv ile doğrudan çalıştırılabilmesi için satır içi bağımlılık meta verileri (PEP 723) içerir:

uv run examples/grpo_echo/grpo_echo.py

Bu, gerekli ortam paketini yalıtılmış sanal bir ortamda otomatik olarak yükler.

Hızlı başlangıç

Entegrasyonu anlamak için en hızlı yol tam bir örnektir. echo.py betiği, tamamlamaları metin uzunluklarına göre ödüllendiren Echo ortamı ile bir model eğitir:

from datasets import Dataset
from echo_env import EchoEnv
from echo_env.models import EchoAction

from trl import GRPOConfig, GRPOTrainer

ENV_URL = "https://huggingface.co/proxy/openenv-echo-env.hf.space"

class EchoToolEnv:
    def __init__(self):
        self.env = EchoEnv(base_url=ENV_URL)
        self.reward = 0.0

    def reset(self, **kwargs) -> str | None:
        self.reward = 0.0
        return None

    def echo(self, message: str) -> str:
        """
        Echo the message back from the environment.

        Args:
            message: The message to echo

        Returns:
            The echoed message.
        """
        observation = self.env.step(EchoAction(message=message))
        self.reward = observation.observation.reward
        return observation.observation.echoed_message

def reward_func(environments, **kwargs):
    return [env.reward for env in environments]

dataset = Dataset.from_dict(
    {"prompt": [[{"role": "user", "content": "Try to echo 'Hello World!' in the environment."}]] * 64}
)

trainer = GRPOTrainer(
    model="Qwen/Qwen3-0.6B",
    train_dataset=dataset,
    reward_funcs=reward_func,
    args=GRPOConfig(
        chat_template_kwargs={"enable_thinking": False},
        log_completions=True,
    ),
    environment_factory=EchoToolEnv,
)
trainer.train()

İşte hepsi. Arka planda olanlar şunlar:

  1. environment_factory=EchoToolEnv: Eğitmen, her üretim için bir EchoToolEnv örneği oluşturur (sınıfı, bir örnek değil, iletin).
  2. reset(), her bölümün başlangıcında durumu başlatmak için çağrılır. Bir gözlem dizesi (veya None) döndürür.
  3. Araç keşfi: Eğitmen, ortam örneğindeki tüm genel yöntemleri (burada echo()) keşfeder ve bunları fonksiyon çağırma araçları olarak sunar. Her yöntemin, eğitmenin araç şemasını oluşturmak için kullandığı, tipli argümanlara sahip uygun bir docstring'e sahip olması gerekir.
  4. Çok turlu döngü: Eğitmen bir tamamlama üretir, araç çağrılarını ayrıştırır, echo() işlevini çalıştırır, sonucu ekler ve modelin araç çağrılarını durdurmasına ya da max_completion_length sınırına ulaşılmasına kadar yeniden üretir.
  5. Ödül fonksiyonu: Bölümün ardından (ortam sıfırlanmadan önce) her ortam örneğinden env.reward değerini okur.
# Run the example
python examples/grpo_echo/grpo_echo.py

# Customize model and environment URL
python examples/grpo_echo/grpo_echo.py --model Qwen/Qwen3-0.6B --env-host https://huggingface.co/proxy/openenv-echo-env.hf.space

Aşağıda eğitimden gelen ödül eğrisi yer almaktadır:

Bu sayfanın üstündeki notta daha fazla hazır OpenEnv örneğini inceleyebilirsiniz.

environment_factory nasıl çalışır

TRL’nin GRPOTrainer bileşeni, environment_factory argümanı aracılığıyla etkileşimli ortam eğitimini destekler. Bu argüman sağlandığında, eğitimci çok turlu araç çağırma döngüsünü otomatik olarak yönetir: tamamlamaları üretir, araç çağrılarını ayrıştırır, bunları ortamda çalıştırır ve sonuçları modele geri besler. Tüm bunlar özel rollout kodu gerektirmeden yapılır.

Environment sınıfı gereksinimleri

Ortam sınıfınız şu kurallara uymalıdır:

  • __init__(self) (isteğe bağlı): Sağlanırsa, argüman almamalıdır. Durum veya istemcileri başlatmak için kullanın. Harici yapılandırma (ör. bir URL) gerekiyorsa, bunu kapsayan kapsamdan veya modül düzeyindeki değişkenlerden yakalayın.
  • reset(self, **kwargs): Her bölümün başında çağrılır. Tüm veri seti sütunlarını anahtar kelime argümanları olarak alır. Bir string gözlem döndürür (başlangıç gözlemi yoksa None).
  • Araç yöntemleri: reset dışında, _ ile başlamayan her halka yöntem (public method) otomatik olarak bir araç olarak sunulur. Eğitimcinin (trainer) model için araç şemasını oluşturmak için bunları kullandığından, her araç yönteminin Args: açıklamaları içeren bir docstring'e sahip olması gerekir.

Ortam sınıfları için ipuçları

  • Ödül durumu: Ortam örneğinde istediğiniz herhangi bir durumu (ör. self.reward, self.done vb.) saklayabilir ve ödül fonksiyonunuzda environments parametresi üzerinden erişebilirsiniz. Bu desenin bir örneği için Hızlı Başlangıç kılavuzuna bakın.
  • Hata yönetimi: Bir araç metodu bir istisna fırlattığında (ör. ValueError("Game over.")), eğitimci bunu yakalar ve hata mesajını modelin araç yanıtı olarak geri besler. Bir eylemin geçersiz olduğunu veya bölümün sona erdiğini bildirmek için önerilen yöntem budur.
ENV_URL = "https://huggingface.co/proxy/my-env.hf.space"

class MyEnv:
    def __init__(self):
        self.client = MyClient(base_url=ENV_URL)  # captured from enclosing scope
        self.reward = 0.0

    def reset(self, **kwargs) -> str | None:
        self.reward = 0.0
        return "Initial observation for the model"

    def my_tool(self, arg1: str, arg2: int) -> str:
        """
        Description of what this tool does.

        Args:
            arg1: Description of arg1
            arg2: Description of arg2

        Returns:
            The result message.
        """
        self.reward = 1.0
        return "Tool result"

Araçlar, açıklayıcı adlara ve tipli argümanlara sahip bireysel yöntemler olmalıdır (ör. guess(word: str), move(direction: str)). Modelin araç çağrısını öğrenebilmesi için anlamlı araç adlarına ve argüman açıklamalarına ihtiyaç duyması nedeniyle, step(action) gibi genel yöntemlerin kullanılmasını önermiyoruz.

Ödül işlevleri

Ödül fonksiyonları, environments parametresini (ortam örneklerinin bir listesi) alır, böylece bölüm sırasında saklanan herhangi bir duruma erişebilirsiniz:

def reward_func(environments, **kwargs) -> list[float]:
    return [env.reward for env in environments]

Ödül fonksiyonları hakkında daha fazla bilgi için GRPO - Özel Ödül Fonksiyonları bölümüne bakın.

Ödül fonksiyonları için ipuçları

OpenEnv ortamları ve GRPO ile çalışırken faydalı bulduğumuz birkaç şey:

  • Grupların farklı olduğundan emin olun. GRPO, tamamlamaları bir grup içinde karşılaştırır; bu nedenle mutlak değerlerden çok göreli sıralama önemlidir ve her tamamlamanın aynı ödülü aldığı bir grup sinyal vermez. Modelin bazen başarılı olduğu durumlarda ikili ödül (başarı için 1.0, aksi halde 0.0) temizdir. Nadiren başarılı olduğunda kısmi kredi ekleyin: Sudoku örneği çözülen ödülüne doldurulan hücrelerin oranını, Wordle örneği ise en iyi tahminin yeşillerini ekler.
  • Son durumu, yolu değil kontrol edin. Mümkün olduğunda, modelin belirli bir eylem dizisini izleyip izlemediğini kontrol etmek yerine, sonucu ortamın değerlendirmesini sağlayın (ör. “model bulmacayı çözdü mü?”). Bu, modelin kendi stratejilerini keşfetmesi için ona özgürlük tanır.
  • Eğitimden önce ödülünüzü test edin. Ortamın mantıklı ödüller döndürdüğünü doğrulamak için birkaç bölümü manuel olarak çalıştırın (Wordle örnek defterine bakın). Yetkin bir model, rastgele bir baz çizgisinden daha yüksek puan alamıyorsa, ödül sinyali ayarlanmalıdır.

çok turlu bölümlerde max_completion_length

max_completion_length parametresi, tek bir üretim değil, çok turlu konuşmanın tamamındaki toplam token sayısını (tüm model üretimleri + araç sonuçları bir arada) sınırlar. Çok sayıda tura sahip ortamlarda (örneğin, onlarca hamle içeren Sudoku) bunu artırmanız gerekebilir:

args = GRPOConfig(
    max_completion_length=4096,  # default is usually 256-1024, increase for long episodes
    # ...
)

Eğer bölümler yarıda kesiliyorsa (model oyunun ortasında duruyorsa), bunun nedeni büyük olasılıkla budur.

Bir Space'e karşı uzun süreli çalıştırmalar

Bir Space, saatlerce açık kalan WebSockets’leri kapatabilir (yaklaşık her 2 saatte bir gözlemledik). 0.11.0 ve öncesi OpenEnv istemcileri, yeni bir ortam oturumuna yeniden bağlanır ve bir oyun devam ediyorsa, sonraki step() istemcinin asla sıfırlamadığı bir oyunda, hata vermeden çalışır. OpenEnv 0.12.0’dan itibaren istemciler bunun yerine SessionLostError fırlatır, böylece oyun başarısız olur. Kopmaları eğitimden uzak tutmak için, her bağlantının bir bölüm (episode) sürmesi amacıyla reset() içinde yeni bir istemci açın ve eski oturumların asenkron olarak serbest bırakıldığı için MAX_CONCURRENT_ENVS değerini, aynı anda oynanan oyun sayısından biraz yüksek ayarlayın:

def reset(self, **kwargs) -> str | None:
    self.client.close()
    self.client = TextArenaEnv(base_url=env_url).sync()
    result = self.client.reset()
    ...

Gelişmiş örnek: Wordle

TextArena ortamını kullanarak Wordle oynamak için bir model eğitelim. Bu, çok turlu etkileşimi, kümülatif geri bildirim işleme, birden fazla terime ayrılan ödülü ve istisnalar aracılığıyla bölüm sonlanmasını gösterir.

OpenEnv Wordle öğreticisi, donanım ve maliyetler dahil olmak üzere tüm hattı kapsar: SFT verileri, SFT ısınma süreci, bu GRPO adımı ve değerlendirme. Bu örneğin defter (notebook) sürümü grpo_wordle.ipynb'dir.

TextArena Ortamı

TextArena, Wordle, Snake, XOX gibi metin tabanlı oyunlar kullanarak LLM'lerin akıl yürütme becerilerini değerlendirmek için tasarlanmış, rekabetçi metin tabanlı oyunlardan oluşan açık kaynak bir koleksiyondur.

image of TextArena

Neden Wordle?

Wordle, geri bildirim hakkında akıl yürütme gerektirmesi, tamamen metin tabanlı olması ve 1B parametreye sahip modellerin bu konuda gelişme gösterebilmesi nedeniyle ortam tabanlı RL için iyi bir referans noktasıdır.

Wordle nasıl çalışır? Wordle, oyuncunun 6 denemede 5 harfli bir kelimeyi bulmaya çalıştığı bir kelime tahmin oyunudur. Her tahminin ardından ortam, harf harf geri bildirim sağlar:

G U E S S
X G Y X X

X = kelime içinde değil, G = doğru konum (yeşil), Y = yanlış konum (sarı). Burada “U” doğru ve yerinde, “E” ise kelime içinde ama yanlış yerde.

SFT ısınma turundan başlayın

Qwen3-1.7B neredeyse hiç oyun kazanmadığından, temel modelden GRPO'nun öğrenecek pek bir şeyi yoktur: hiçbiri kazanılmamış bir oyun grubu sinyal vermez. Örnek, aynı araç çağırma biçiminde, her tahminden önce kısa bir akıl yürütme içeren, bir çözücü tarafından oynanan 1.000 oyunda bir epoch boyunca eğitilmiş openenv/Qwen3-1.7B-Wordle-SFT modelinden başlar.

Environment sınıfı

WordleEnv sınıfı TextArena istemcisini sarar, guess() işlevini araç olarak sunar ve ödülün gerektirdiği bilgileri saklar:

import re

from textarena_env import TextArenaAction, TextArenaEnv

FEEDBACK = re.compile(r"Feedback:\n([A-Z ]+)\n([GYX ]+)")

class WordleEnv:
    def __init__(self):
        self.client = TextArenaEnv(base_url="https://<user>-wordle.hf.space")

    def reset(self, **kwargs) -> str | None:
        result = self.client.reset()
        self._last_full_feedback = result.observation.messages[0].content
        self.done = False
        self.won = False
        self.num_guesses = 0
        self.best_greens = 0
        self.invalid_moves = 0
        return self._last_full_feedback

    def guess(self, guess: str) -> str:
        """
        Make a guess in the Wordle environment.

        Args:
            guess: The guessed word, formatted as '[abcde]'

        Returns:
            The feedback message from the environment.
        """
        if self.done:
            raise ValueError("Game over.")
        result = self.client.step(TextArenaAction(message=guess))
        _full_feedback = result.observation.messages[0].content
        feedback = _full_feedback[len(self._last_full_feedback):]
        self._last_full_feedback = _full_feedback
        if "invalid move" in feedback.lower():
            self.invalid_moves += 1
        else:
            self.num_guesses += 1
            match = FEEDBACK.search(feedback)
            if match:
                self.best_greens = max(self.best_greens, match.group(2).count("G"))
            self.won = result.done and result.reward >= 1.0
        self.done = result.done
        return feedback

Temel tasarım tercihleri:

  • reset(), modelin gördüğü ilk gözlem olarak başlangıç oyun mesajını döndürür.
  • guess() tek araçtır. Model, her turda 5 harfli bir kelimeyle bunu çağırır.
  • Kümülatif geri dilimleme: TextArena her turda tam oyun geçmişini döndürür. Bağlamı tekrarlamamak için yalnızca yeni kısmı dilimler.
  • done'da istisna: Oyun bittikten sonra model tahmin yapmaya çalışırsa, guess() bir ValueError fırlatır. Eğitmen bunu yakalar ve "Game over." metnini modelin araç yanıtı olarak geri besler ve bunu tools/failure_frequency içinde sayar.

Ödül fonksiyonları ve eğitim

Ortamın kendi ödülü, 1 tahminde veya 6 tahminde kazanıldığında aynı tutarı öder ve kısmi kredi yalnızca oyunun sonunda verir. Düşünme açıkken, bir politika daha az düşünmeyi ve sona ulaşmak için 6 tahminin tamamını kullanmayı öğrenebilir. Bunu önleyen üç ödül terimi şunlardır:

from datasets import Dataset
from trl import GRPOConfig, GRPOTrainer

def reward_win(environments, **kwargs) -> list[float]:
    return [1.0 + 0.5 * (1 - env.num_guesses / 6) if env.won else 0.0 for env in environments]

def reward_partial(environments, **kwargs) -> list[float]:
    return [0.0 if env.won else 0.1 * env.best_greens for env in environments]

def reward_invalid(environments, **kwargs) -> list[float]:
    return [-0.1 * env.invalid_moves for env in environments]

prompt = """You are an expert Wordle solver with deep knowledge of English vocabulary...
Use the tool `guess` to make a guess."""

dataset = Dataset.from_dict({"prompt": [[{"role": "user", "content": prompt}]] * 600})

trainer = GRPOTrainer(
    model="openenv/Qwen3-1.7B-Wordle-SFT",
    reward_funcs=[reward_win, reward_partial, reward_invalid],
    train_dataset=dataset,
    args=GRPOConfig(
        use_vllm=True,
        vllm_mode="colocate",
        chat_template_kwargs={"enable_thinking": True},
        max_completion_length=4096,
        max_tool_calling_iterations=12,
        vllm_importance_sampling_mode="token_truncate",
        num_generations=16,
        per_device_train_batch_size=8,
        gradient_accumulation_steps=8,
        learning_rate=1e-6,
        lr_scheduler_type="constant",
        max_steps=150,
    ),
    environment_factory=WordleEnv,
)
trainer.train()

Kazanç, ne kadar hızlı gelirse o kadar yüksek olur (bir tahminde 1.42, altıda 1.0), kayıp ise oyun bitip bitmediğine bakılmaksızın oyunun en iyi tahmini için ödenir ve her geçersiz hamle 0.1 maliyetine mal olur. TRL her terimi ayrı ayrı kaydeder, bu nedenle rewards/reward_win/mean kazanma oranıyla birlikte yükselir.

Örneğin çalıştırılması

Her adım 64 oyun oynar, her biri bir ortam oturumu. openenv/wordle Space'ini çoğaltın ve kopyanızda MAX_CONCURRENT_ENVS=64 değişkenini ayarlayın.

colocate
sunucu

Colocate modu (1 GPU, önerilen)

python examples/grpo_wordle/grpo_wordle.py --vllm-mode colocate --env-url https://<user>-wordle.hf.space

Bu, vLLM'yi eğitimle aynı süreçte çalıştırır ve yalnızca tek bir GPU gerektirir. Çalışmamızda, tek bir A100 80GB üzerinde 150 adım yaklaşık 2 saat 15 dakika sürdü.

Sonuçlar

Çalışmamızdan, model başına bir eğitim çalıştırmasıyla, aynı 30 kelimenin açgözlüce oynanmasıyla:

ModelKazanımlarKazanım başına tahminGeçersiz tahminler
Qwen3-1.7B0/30-24
+ SFT10/303.241
+ SFT + GRPO (model)20/304.13

GRPO, tekrarlanan ve uydurma kelimeleri büyük ölçüde ortadan kaldırdı ve daha fazla oyun kazandı. Yeni kazanımların çoğu 4 ila 6 tahmin arasında gerçekleştiğinden, kazanım başına tahmin sayısı arttı. 30 kelime, modellerin eğitim sırasında da gördüğü ve TextArena'nın sırlarını buradan seçtiği 156 isimden geliyor; yeni bir çalıştırma birkaç kazanım farkıyla sonuçlanabilir (aynı tarifle iki SFT çalıştırması 10 ve 13 oyun kazandı). Üç modelin Wordle Arena'da oynamasını izleyin ve eğitim eğrilerini Trackio'da görün.

Çoklu ortam eğitimi

Tek bir modeli birden fazla ortamda eş zamanlı olarak eğitebilirsiniz. Bir modelin paralel olarak farklı beceriler öğrenmesini istediğinizde bu işe yarar. Örneğin, aynı eğitim çalışmasında Wordle (dil çıkarımı) ve Catch (uzamsal çıkarım) oynatmak.

Temel fikir, bir veri seti sütununu kullanarak her örneği doğru ortama yönlendiren ve birden fazla ortamı saran bir meta-ortam sınıfı oluşturmaktır.

Nasıl çalışır

  1. Veri setinize, her örneğin hangi ortama ait olduğunu belirten bir "env" sütunu (veya benzeri) ekleyin.
  2. reset(**kwargs) içinde, o bölüm için etkin ortamı seçmek üzere kwargs["env"] değerini okuyun.
  3. Tüm ortamlardan araçları dışa aktarın; eğitimci tüm genel yöntemleri keşfeder.
  4. Ortam başına ayrı ödül fonksiyonları kullanın ve o ortama ait olmayan örnekler için None döndürün. TRL, None değerlerini nansum/nanmean ile işler.

Örnek: Wordle + Catch

grpo_multi_env.py betiği Wordle ve Catch üzerinde eş zamanlı eğitim yapar:

class MultiEnv:
    def __init__(self):
        self._wordle_client = None
        self._catch_client = None
        self.active = None
        self.reward = 0.0
        self.done = False

    def reset(self, **kwargs) -> str | None:
        self.active = kwargs.get("env", "wordle")
        self.reward = 0.0
        self.done = False

        if self.active == "wordle":
            if self._wordle_client is not None:
                try:
                    self._wordle_client.close()
                except Exception:
                    pass
            self._wordle_client = TextArenaEnv(base_url=WORDLE_URL)
            result = self._wordle_client.reset()
            self._last_full_feedback = result.observation.messages[0].content
            self.reward = 0.0
            return self._last_full_feedback
        elif self.active == "catch":
            if self._catch_client is not None:
                try:
                    self._catch_client.close()
                except Exception:
                    pass
            self._catch_client = OpenSpielEnv(base_url=CATCH_URL)
            result = self._catch_client.reset()
            self.done = result.observation.done
            return _format_catch_obs(result.observation.info_state)

    # Wordle tool
    def guess(self, guess: str) -> str:
        """Make a guess in the Wordle environment. ..."""
        ...

    # Catch tools
    def move(self, direction: str) -> str:
        """Move the paddle left or right. ..."""
        ...

    def stay(self) -> str:
        """Do nothing and let the ball fall one step. ..."""
        ...

Temel kalıplar:

  • Gecikmeli istemci başlatma: Gereksiz WebSocket bağlantılarını önlemek için istemcileri reset() içinde, __init__() içinde değil oluşturun.
  • Yeniden açmadan önce kapat: Sunucu kapasite hatalarını önlemek için yeni bir istemci oluşturmadan önce önceki istemciyi kapatın.
  • kwargs yönlendirme: Veri setindeki "env" sütunu, reset() fonksiyonuna anahtar kelime argümanı olarak iletilir.
  • Tüm araçlar eşzamanlı olarak açığa çıkarılır: Model, aktif ortamdan bağımsız olarak guess, move ve stay araçlarını kullanılabilir olarak görür. Yanlış aracı çağırırsa (ör. Wordle sırasında move), yöntem, eğiticinin zarifçe yakaladığı bir ValueError fırlatır. Uygulamada, modeller sistem istemine dayanarak doğru araçları kullanmayı öğrenir.

Ortam başına ödül işlevleri

Her ödül fonksiyonu, diğer ortamlardan gelen örnekler için None döndürür:

def wordle_reward(environments, **kwargs) -> list[float | None]:
    return [env.reward if env.active == "wordle" else None for env in environments]

def catch_reward(environments, **kwargs) -> list[float | None]:
    rewards = []
    for env in environments:
        if env.active != "catch":
            rewards.append(None)
        elif env.done:
            rewards.append(max(env.reward, 0.0))
        else:
            rewards.append(0.0)
    return rewards

TRL, None değerini içsel olarak nan olarak dönüştürür ve toplulaştırma için nansum/nanmean kullanır; bu sayede her örnek yalnızca ilgili ödül fonksiyonuyla puanlanır.

Ortam yönlendirmeli veri seti

n = 500
dataset = Dataset.from_dict({
    "prompt": (
        [[{"role": "user", "content": wordle_prompt}]] * n
        + [[{"role": "user", "content": catch_prompt}]] * n
    ),
    "env": ["wordle"] * n + ["catch"] * n,
})

Çoklu ortam örneğini çalıştırma

python examples/grpo_multi_env/grpo_multi_env.py \
    --wordle-url https://huggingface.co/proxy/openenv-wordle.hf.space \
    --catch-url https://huggingface.co/proxy/openenv-openspiel-env.hf.space \
    --vllm-mode colocate \
    --gradient-accumulation-steps 4 \
    --num-generations 8

Çevreler arasında eğitim yapılırken, birleşik train/reward yerine ödül fonksiyonu başına metrikleri (train/reward_func_0, train/reward_func_1 vb.) izleyin. Birleşik metrik, ortamlar arasında dönüşümlü olarak değiştiğinden gürültülü görünebilir.

Ortamların çalıştırılması

environment_factory kullanıldığında, trainer ortam sunucusuna otomatik olarak bağlanır. Sadece sunucunun çalışıyor olması yeterlidir. Bir OpenEnv ortam sunucusunu çalıştırmak için üç yol vardır:

space
docker
yerel

Uzak bir Hugging Face Space'e bağlan (en basit)

Çoğu örnek betik, varsayılan olarak barındırılan bir Space kullanır (kurulum gerekmez):

env = EchoEnv(base_url="https://huggingface.co/proxy/openenv-echo-env.hf.space")

Eğitim için, eşzamanlılık sorunlarını önlemek üzere Space'i kendi hesabınıza kopyalayın. Eğitimci, N eşzamanlı WebSocket bağlantısı açar (her üretim için bir tane) ve paylaşılan Space'ler bunu desteklemeyebilir. Ayrıntılar için Sunucu eşzamanlılığı bölümüne bakın.

Ortam kataloğu

Bakımı yapılan ortamların güncel kataloğunu keşfetmenin en iyi yolu, resmi OpenEnv kataloğunu ziyaret etmektir.

Kendi ortamınızı oluşturmak için OpenEnv ile Kendi Ortamınızı Oluşturma kılavuzuna göz atın. Ortamlar Hub ile sıkı bir şekilde entegre olduğundan, topluluğun yeniden kullanması için yeni ortamlar itebilirsiniz.

Sunucu eşzamanlılığı

environment_factory kullanıldığında, trainer N adet ortam örneği oluşturur (her üretim için bir adet) ve her biri sunucuya bir WebSocket bağlantısı açar. Varsayılan olarak OpenEnv sunucuları yalnızca 1 eşzamanlı oturuma izin verir; bu durum eğitim sırasında hatalara yol açar.

Paralel eğitimi desteklemek için sunucuyu eşzamanlılık için yapılandırın:

  1. Ortam dosyanızda eşzamanlı oturum desteğini bildirin:
SUPPORTS_CONCURRENT_SESSIONS: bool = True
  1. Sunucu uygulamanızda eşzamanlılık sınırını ayarlayın:
app = create_app(
    create_my_environment,
    MyAction,
    MyObservation,
    max_concurrent_envs=64,  # match or exceed generation_batch_size
)

max_concurrent_envs, generation_batch_size'den (varsayılan değeri per_device_train_batch_size × gradient_accumulation_steps olan) büyük veya eşit olmalıdır. Örneğin, gradient_accumulation_steps=64 ve batch boyutu 1 ile en az 64 eşzamanlı oturuma ihtiyaç duyarsınız.

environment_factory ve rollout_func

GRPOTrainer, ortam tabanlı eğitim için iki yaklaşımı destekler:

  • environment_factory (önerilen): Araç yöntemleri içeren bir ortam sınıfı tanımlarsınız ve eğitimci, üretim, araç çağrısı ayrıştırma ve çok turlu döngüyü otomatik olarak yönetir. Bu kılavuz boyunca kullanılan yaklaşım budur.
  • rollout_func: Tüm üretim ve ortam etkileşim döngüsünü kendiniz yazarısınız. Bu, tamamlamaların nasıl üretileceği, araçların nasıl çalıştırılacağı ve ödüllerin nasıl hesaplanacağı üzerinde tam kontrol sağlar.

environment_factory kullanım senaryonuza uymuyorsa rollout_func kullanın. Örneğin, dış bir sunucunun üretim döngüsünü sahiplendiği ve kendi ajan-ortam etkileşim protokolünü yönettiği dış ajan sunucuları.

Test platformlarında eğitim: gerçek kodlama ajanlarının eğitimi (Harbor)

Yukarıdaki entegrasyonlar white-box niteliğindedir: TRL, çok turlu döngüyü kendisi yönetir. Her turda örneklem alır, araç çağrılarını ayrıştırır, bunları çalıştırır ve sonuçları geri besler.

Bazı ajanlar kendi döngülerine sahip oldukları için bu şekilde yönlendirilemez. opencode veya claude-code gibi üretim kodlama ajanı iskeletleri kendi planlayıcısına, araç setine, bağlam yönetimine ve durdurma koşuluna sahiptir. Yeniden bir uygulama değil, tam olarak o ajanı eğitmek istersiniz.

Bunun için TRL, experimental.async_grpo.AsyncGRPOTrainer üzerine kurulu deneysel bir siyah kutu (döngü sahibi) yolunu sağlar: HarnessAsyncGRPOTrainer, bir OpenEnv oturum fabrikasını yönetir. Ajanlar ve kum havuzları, openenv harbor serve ile OpenEnv üzerinden sunulan Harbor'dan gelir; böylece Harbor'ın kurduğu her ajan aynı şekilde eğitilebilir: --harness ile birini seçersiniz. Hugging Face Jobs başlatıcısını da içeren tam bir örnek için examples/async_grpo_harbor'a bakın.

Bu yol, TrainingTrace yakalama API'sine sahip ilk sürüm olan openenv>=0.7.0 sürümünü gerektirir: pip install "openenv>=0.7.0".

Nasıl çalışır

TRL burada her turu örneklemiyor. Ajan kendi başına tamamlanana kadar çalışır ve TRL, ajanın ne yaptığını geri okur:

  1. OpenEnv Harbor sunucusu, ajanı bir Harbor görevinde bir kum havuzunda (örneğin E2B) başlatır. Ajanın yaptığı her model çağrısı, sunucunun yakalama vekili (capture proxy) üzerinden vLLM sunucunuza gider; bu sunucu, motorun kendi prompt ve tamamlama token kimliklerini, örneklenen logprobs değerlerini ve token başına kayıp maskesini kaydeder.
  2. Ajan durduğunda, görevin kendi doğrulayıcısı sonucu puanlar ve TRL, OpenEnv'den doğrulanmış TrainingTrace nesnesini alır; eğitim satırlarını bu nesnenin token kimlikleri ve maskelerinden oluşturur. TRL, yakalanan istekleri yeniden tokenleştirmez.
  3. GRPO, bu satırlar üzerinde eğitim yapar. Ödül, grup-göreli avantaj yoluyla her eğitimli token'a iletilir ve yeni ağırlıklar aynı vLLM sunucusuna geri senkronize edilir.

Her rollout, kendi izole oturumunda, kendi sandbox'ında ve kendi yakalama oturumunda çalışır. İzolasyon iki nedenle önemlidir: proxy, tam olarak o rollout'un token'larını yakalamalı ve bir rollout, diğerini etkilememelidir. max_concurrent_rollouts ayarı, aynı anda kaç rollout'un çalışacağını kontrol eder ve sunucunun MAX_CONCURRENT_ENVS değeri en az max_concurrent_rollouts + 1 olmalıdır (fabrika, görev metadata'sı için bir ek bağlantı tutar).

Bağlantı

HarnessAsyncGRPOTrainer, experimental.async_grpo.AsyncGRPOTrainer gibi model, yapılandırma ve veri setini alır; ancak reward_funcs, tools ve environment_factory yerine bir oturum fabrikası kullanır. harness_adapter yoksa döngünün sahibi ajan olur. Eğitmen, kendi örneklem politikasıyla oturum fabrikasını oluşturur; bu nedenle hazır bir fabrika yerine partial(HarborSessionFactory, ...) gibi çağrılabilir bir nesne iletirsiniz. Her oturum, tam motor jetonlarını, davranış logprobs değerlerini ve önceden doldurulmuş maskeleri içeren bir OpenEnv TrainingTrace döndürür. rollout_reward_fn isteğe bağlıdır; belirtilmezse TRL, oturumun doğrulayıcı ödülünü kullanır.

from functools import partial

from harbor_env.harness import HarborSessionFactory

from trl.experimental.async_grpo import AsyncGRPOConfig
from trl.experimental.async_grpo.openenv_harness import HarnessAsyncGRPOTrainer

factory = partial(
    HarborSessionFactory,
    "http://localhost:8200",       # the OpenEnv Harbor server
    split="<hf-dataset>",          # a Harbor task dataset the server serves
    harness="mini-swe-agent",      # or "opencode", "claude-code", ...
    sandbox="e2b",
    llm_url=vllm_url,
    model=model,
)
config = AsyncGRPOConfig(num_generations=8, max_concurrent_rollouts=8, vllm_server_base_url=vllm_url)
trainer = HarnessAsyncGRPOTrainer(
    model=model,
    harness_session_factory=factory,  # called by the trainer with its sampling policy
    args=config,
    train_dataset=dataset,
    rollout_reward_fn=my_reward,      # outcome -> float | None
)
trainer.train()

Tanımlamanız gerekenler

OpenEnv, yakalama doğrulamasından ve jeton seçiminden sorumludur. TRL, üreticinin tam dizin maskesini dahili tamamlama maskesine dönüştürür, sonuçlanan satırları paketler ve GRPO uygular. Jetonları yeniden oluşturmak veya hangi çağrıların ajana ait olduğunu çıkarmakla ilgilenmez.

rollout_reward_fn : bir rollout'un nasıl puanlanacağı

Callable[[HarnessRolloutOutcome], float | None]

TRL, göreviniz için başarının ne anlama geldiğini bilmediğinden, tamamlanan her rollout'u bir skaler ödülüne dönüştürür. İşlev, ajanın ne yaptığını açıklayan bir HarnessRolloutOutcome alır:

  • env_reward (float | None): görev doğrulayıcısından gelen ödül, rollout puanlanamadığında None.
  • completion (list[dict]): son mesaj dökümü.
  • trace (list[TraceEntry]): seçilen OpenEnv yakalama kayıtları, sıfır maskeli turlar dahil.
  • tool_call_count ve tool_failure_count (int): ajanın yaptığı araç çağrılarının sayısı ve başarısız görünenlerin sayısı.
  • tool_calls_by_name (dict[str, int]): araç başına çağrı sayısı, örneğin {"bash": 3, "edit": 2}.
  • timed_out (bool): ajanın zaman bütçesinin tükendiğini belirtir.

float döndürün veya grup baz çizgisinden düşürülüp sıfır olarak sayılmaması için rollout’u puanlanamaz olarak işaretlemek için None döndürün. Bu işlevi iletmezseniz, ham env_reward olduğu gibi kullanılır. Harbor örneği, doğrulayıcının doğruluğunu ana sinyal olarak korur ve görev çözüldüğünde yalnızca küçük bir araç verimliliği bonusu ekler.

Neden doğrudan doğrulayıcıyı kullanmıyoruz? Doğrulayıcı, ortamın görevidir ve “sonuç ne kadar doğruydu?” sorusuna yanıt vererek temiz ve değerlendirme için yeniden kullanılabilir kalır. Eğitimde kullandığınız ödül ise ayrı bir, eğitim zamanı kararıdır (skoru ikili hale getirme, dejeneratif davranışı cezalandırma, puanlanamayan rollout’ları düşürme). Ayrıca doğrulayıcının asla görmediği sinyallere de ihtiyaç duyar; çünkü doğrulayıcı yalnızca nihai sonucu incelerken rollout_reward_fn aynı zamanda yörüngeyi (araç sayıları, timed_out, iz) de alır. Örneğin, bir rollout bazı testleri geçse bile bash çalıştırmayabilir; bunu görebilecek ve cezalandırabilecek tek fonksiyon rollout_reward_fn’dir.

Token uygunluğu OpenEnv'den gelir

session.fetch_training_trace(), doğrulanmış bir TrainingTrace döndürür. Her turda benzersiz bir node_id, prompt_token_ids, completion_token_ids, per_token_logps ve prompt ile tamamlama üzerine zorunlu bir loss_mask bulunur. Prompt konumları sıfırdır. Kısmi tamamlama maskeleri, asistan yanıtı içindeki sıfırlar dahil olmak üzere korunur.

Örneğin, [10, 11] istemi, [20, 21, 22] tamamlama ve [0, 0, 1, 0, 1] maskesi, 20 ve 22 jetonlarında eğitim yapar. 21 jetonu bağlam olarak kalır. Tamamen maskelenmiş bir tamamlama, bağlam ve kullanım muhasebesi için korunur.

Producer yardımcı çağrıları ve atılan yeniden denemeleri hariç tutar. Bu API'de train_turn_fn veya agent_turn_fn parametreleri bulunmaz. Mevcut entegrasyonlar seçim mantığını OpenEnv maskelerine taşımak zorundadır. Görevin doğrulayıcısı, token uygunluğundan bağımsız olarak kalır.

Bozuk yakalamalar OpenEnv sınırında başarısız olur ve eğitimi durdurur. Taşıma hataları puanlanamaz olarak kalır. Yeniden yazılan geçmişler ayrı satırlarla başlar; örneklenen tokenlar ve logprobs korunur. Birden fazla satır yine de rollout ödülünü paylaşır; bu API, GRPO’nun ağırlıklandırmasını değiştirmez.

Gereksinimler

OpenEnv Harbor sunucusu veri setinin ve kum havuzlarının (sandbox) sahibidir. Kum havuzu altyapısının kimlik bilgilerine (örneğin E2B_API_KEY) ihtiyaç duyar:

MAX_CONCURRENT_ENVS=9 openenv harbor serve --dataset <hf-dataset> --port 8200 --capture-port 8300 --expose gradio

vLLM sunucusu, araç çağrılarını ve gerçek token kimliklerini dışa açmalı ve NCCL ağırlık senkronizasyonunu etkinleştirmelidir; böylece ajan her zaman güncel politikaya erişir. Rollout'lar ve ağırlık güncellemeleri aynı vLLM sunucusunu kullanmalıdır:

vllm serve <model> \
    --enable-auto-tool-choice --tool-call-parser <parser> \
    --logprobs-mode processed_logprobs \
    --return-tokens-as-token-ids \
    --weight-transfer-config '{"backend":"nccl"}'

Loop-owning eğitim trl.experimental altında yer alır ve API'si değişebilir. Örnek, test edildiği OpenEnv revizyonunu sabitler; kesin kurulum için README'sine bakın.

Update on GitHub