# Ortamlarla LLM'leri Eğitmek İçin OpenReward Entegrasyonu

[OpenReward](https://openreward.ai), [Open Reward Standard (ORS)](https://openrewardstandard.io) üzerine kurulu, RL ortamları için açık bir ekosistemdir — ORS, bir ortamın görevlerini, araçlarını, oturumlarını ve ödülleri nasıl sunduğunu tanımlayan herkese açık, dil bağımsız bir HTTP/SSE protokolüdür. ORS yalnızca bir protokol olduğu için, aynı ortam [OpenReward platformu](https://openreward.ai) üzerinde, herhangi bir konteyner servisinde kendi kendine barındırılarak veya geliştirme için `localhost` üzerinde yerel olarak çalıştırılabilir. Hazır kullanıma uygun ortamların bir kataloğu [openreward.ai](https://openreward.ai) adresinde mevcuttur.

Bu kılavuz, **OpenReward'ın TRL ile nasıl entegre edileceğini** kapsar. Standart hakkında daha fazla bilgi için [ORS belgelerini](https://docs.openreward.ai/) inceleyin.

> [!NOTE]
> Entegrasyon `trl.experimental.openreward` konumundadır ve `trl[openreward]` ek özelliği arkasında kapalıdır (tembel içe aktarma — kullanıcı olmayanlar hiçbir şey ödemez).

## OpenReward ortamlarının ne zaman kullanılacağı

[GRPOTrainer](/docs/trl/main/tr/grpo_trainer#trl.GRPOTrainer), `environment_factory` yuvası üzerinden ortam tabanlı eğitimi destekler — genel sözleşme için [OpenEnv](openenv)'e bakın. ORS konuşan bir ortama karşı eğitim yapmak istediğinizde OpenReward kullanın: [OpenReward kataloğu](https://openreward.ai) (ör. `Eigent/SETA`, `kanishk/EndlessTerminals`, `nebius/SWE-rebench-V2`), kendi altyapınızda barındırdığınız bir ortam veya üzerinde çalıştığınız yerel bir sunucu.

## Kurulum

```bash
pip install trl[openreward]
```

Bu, `openreward` Python SDK'sını yükler. Entegrasyonun kendisi `openreward` kütüphanesini tembel (lazy) olarak içe aktarır, bu nedenle `trl.experimental.openreward` modülüne dokunmayan kullanıcılar etkilenmez.

## Hızlı başlangıç

`OpenRewardSpec` sınıfı, tek bir ORS ortamını üç TRL eğitimci yuvasına — `train_dataset`, `environment_factory`, `reward_funcs` — bağlar; bu yuva adlarıyla birebir eşleşen özellikler sunar:

```python
from trl import GRPOConfig, GRPOTrainer
from trl.experimental.openreward import OpenRewardSpec

spec = OpenRewardSpec("Eigent/SETA", num_tasks=64)

trainer = GRPOTrainer(
    model="Qwen/Qwen3-4B",
    args=GRPOConfig(
        num_generations=2,
        max_steps=5,
        max_tool_calling_iterations=20,
        log_completions=True,
    ),
    train_dataset=spec.train_dataset,
    environment_factory=spec.environment_factory,
    reward_funcs=spec.reward_funcs,
)
trainer.train()
```

Arka planda `OpenRewardSpec`, ilk erişimde tembelce üç şey yapar:

1. **`spec.train_dataset`**: env'in görev listesinden bir `datasets.Dataset` türetir (SDK üzerinden tek bir HTTP gidiş-dönüşü). En azından `prompt`, `task_index` ve görev başına eklenen metadata sütunlarını içerir.
2. **`spec.environment_factory`**: her çağrıda yeni bir rollout başına adapter üreten, argüman almayan bir çağrılabilir nesne döndürür. Adapter, ORS araçlarının her biri için bir Python metodu sunar; imza ve docstring, env'in JSON Şemasından otomatik olarak oluşturulur. TRL'nin araç toplayıcısı bunları `inspect.getmembers` üzerinden alır.
3. **`spec.reward_funcs`**: yalnızca sonuç odaklı bir ödül fonksiyonu (yörüngedeki son null olmayan ödül), SETA gibi seyrek ödüllü ortamlar için uygundur.

## Bir hub ortamı kullanma

Hedef olarak bir [openreward.ai](https://openreward.ai) kataloğu adı geçin. SDK, kimlik doğrulama için ortamdan `OPENREWARD_API_KEY` değerini okur.

```python
spec = OpenRewardSpec("Eigent/SETA", num_tasks=64)
```

## Kendi barındırdığınız bir ortamı kullanma

URL'yi doğrudan iletin. Sunucunuz bir API anahtarı zorlamıyorsa API anahtarı gerekmez.

```python
spec = OpenRewardSpec("https://my-org-my-env.hf.space", env_name="my_env")
```

> [!IMPORTANT]
> `openreward` SDK varsayılan olarak iki alt alan adlı bir platform düzeni bekler (durumsuz çağrılar için `api.<host>` ve SSE tabanlı oturum çağrıları için `sessions.<host>`). **tek ana makine** tabanlı kendi kendine barındırılan sunucular için (her şeyi tek bir URL üzerinden sunan), `OpenRewardSpec` oluşturulmadan önce aşağıdaki geçersiz kılma ortam değişkenlerini ayarlayın:
>
> ```python
> import os
>
> URL = "https://my-org-my-env.hf.space"
> os.environ["OPENREWARD_API_URL"]     = URL
> os.environ["OPENREWARD_SESSION_URL"] = URL
>
> spec = OpenRewardSpec(URL, env_name="my_env")
> ```

## Yerel olarak minimal bir ortam çalıştırma

Harici bağımlılıklar olmadan entegrasyonu uçtan uca denemenin en hızlı yolu, `openreward` SDK'sının `Environment` + `Server` iskeletiyle tanımlanmış küçük bir ORS sunucusudur. Aşağıdaki örnek, tam bir `echo` ortamıdır — model, görevin hedef dizisini `echo(text=...)` ile çağırarak kazanır.

```python
# server.py
from pydantic import BaseModel
from openreward.environments import Environment, JSONObject, Server, TextBlock, ToolOutput, tool

class EchoTaskSpec(BaseModel):
    target: str

class EchoParams(BaseModel):
    text: str

class EchoEnvironment(Environment):
    def __init__(self, task_spec: JSONObject = {}, secrets: dict[str, str] = {}):
        super().__init__(task_spec)
        self.config = EchoTaskSpec.model_validate(task_spec)

    @classmethod
    def list_splits(cls) -> list[str]:
        return ["train"]

    @classmethod
    def list_tasks(cls, split: str) -> list[JSONObject]:
        return [{"target": "hello"}, {"target": "world"}]

    def get_prompt(self) -> list[TextBlock]:
        return [TextBlock(type="text", text=f"Echo '{self.config.target}' to win.")]

    @tool
    async def echo(self, params: EchoParams) -> ToolOutput:
        """Submit a string. Reward 1.0 + finished if it matches the target.

        Args:
            text: The string to echo back.
        """
        correct = params.text == self.config.target
        return ToolOutput(
            blocks=[TextBlock(type="text", text="match" if correct else "no match")],
            reward=1.0 if correct else 0.0,
            finished=correct,
        )

if __name__ == "__main__":
    Server([EchoEnvironment]).run(host="0.0.0.0", port=8000)
```

Çalıştırın:

```bash
pip install openreward fastapi uvicorn pydantic
python server.py     # listens on :8000
```

Ardından `OpenRewardSpec`'i buna yönlendirin (yukarıda açıklanan URL geçersiz kılma ayarlarıyla):

```python
import os
URL = "http://127.0.0.1:8000"
os.environ["OPENREWARD_API_URL"]     = URL
os.environ["OPENREWARD_SESSION_URL"] = URL

from trl.experimental.openreward import OpenRewardSpec
spec = OpenRewardSpec(URL, env_name="echoenvironment")
print(spec.train_dataset)        # 2 rows, task_index + target columns
```

Bu, TRL'nin kendi testlerinde de kullanılan sabit (fixture) desenidir — dağıtılmış Space için [`trl-internal-testing/openreward-echo-env`](https://huggingface.co/spaces/trl-internal-testing/openreward-echo-env) adresine bakın.

## Görev seçimi

`OpenRewardSpec` bir sayı veya açık bir indeks listesi kabul eder:

```python
spec = OpenRewardSpec("Eigent/SETA", num_tasks=10)                      # first 10 tasks
spec = OpenRewardSpec("Eigent/SETA", indices=[0, 5, 13, 27])            # specific indices
spec = OpenRewardSpec("Eigent/SETA", indices=list(range(50, 100)))      # range
```

`num_tasks` ve `indices` birbirini dışlar ve her ikisi de yalnızca ihtiyaç duydukları görevleri getirir (tam görev listesi taraması yapılmaz).

## Araç bağlama nasıl çalışır

Oluşturma sırasında spec, araç özelliklerinin (her biri bir ad, açıklama ve argümanlar için JSON Schema içeren) listesini almak için env'in `/tools` uç noktasını çağırır. Her araç için, şemadan türetilmiş bir docstring'e ve tipli bir imzaya sahip bir Python metodu, rollout başına adapter üzerinde oluşturulur. Yöntemler, TRL'nin araç toplayıcısının onları bulduğu adapter sınıfında ayarlanır; böylece `transformers.utils.get_json_schema` ve TRL'nin `inspect.getmembers(type(env), isfunction)` çağrıları, env başına sarmalayıcı kodu gerektirmeden model için doğru araç şemasını üretir.

Bir araç açıklaması, Python kaynak koduna güvenli bir şekilde eklenemeyecek karakterler içeriyorsa, binder gerçek ortamlarda bağlama işlemi asla başarısız olmaz diye bir temizlenmiş biçime geri düşer.

## Ödül işlevleri

`spec.reward_funcs` varsayılan olarak yalnızca sonuç odaklı bir ödül kullanır — her rollout için, yörünge boyunca gözlemlenen son null olmayan ödülü döndürür. Bu, seyrek ödüllü ortamlar (ör. yalnızca `submit_solution` null olmayan ödül döndüren SETA) için doğru varsayılandır.

Hiçbir araç null olmayan bir ödül döndürmezse, varsayılan ödül fonksiyonu `0.0` değil, `None` döndürür. Bu, araç çağrısı içermeyen, yalnızca puanlanmamış araç çağrıları içeren veya yalnızca başarısız araç çağrıları içeren rollout'ları kapsar. Gözlemlenen `0.0` veya negatif bir ödül geçerli bir puan olarak kalır. Daha sonraki bir puanlanmamış veya başarısız araç çağrısı, önceki bir puanı silmez.

GRPO, ödül tabanından, **tüm** ödül fonksiyonlarının `None` döndürdüğü rollout'ları hariç tutar ve bunlara sıfır avantaj verir. Bu, token'ların kayıp normalizasyonundan çıkarılmasını veya KL düzenlemesi gibi diğer terimleri devre dışı bırakmaz. Başka bir ödül fonksiyonu rollout'a puan verirse, hâlâ sıfırdan farklı bir avantaj alabilir.

Eksik puanlar, bir bölümün neden sonlandığını belirlemez. Vazgeçme veya araç çağrısı sınırına ulaşma durumlarının bir görev başarısızlığı olarak sayılması gerekiyorsa, ortamınızdan veya özel ödül işlevinizden açık bir başarısızlık ödülü döndürün. Altyapı veya değerlendirici hataları ise puanlanamaz olarak kalabilir; ortalama ödülün yanı sıra puanlama kapsamını da izleyin.

Özel bir ödül istiyorsanız, standart bir TRL ödül fonksiyonu yazın ve doğrudan iletin:

```python
def my_reward(environments, **kwargs) -> list[float | None]:
    rewards = spec.reward_funcs(environments=environments)
    return [2.0 * reward if reward is not None else None for reward in rewards]

trainer = GRPOTrainer(
    ...,
    reward_funcs=my_reward,
)
```

Rollout başına adaptör, TRL'in ihtiyaç duyduğu çalışma durumunu — `env.reward`, `env.rewards`, `env.metadata`, `env.finished`, `env.last_output` — keyfi sonradan ödül şekillendirme için açığa çıkarır.

## OpenRewardSpec[[trl.experimental.openreward.OpenRewardSpec]]

#### trl.experimental.openreward.OpenRewardSpec[[trl.experimental.openreward.OpenRewardSpec]]

```python
trl.experimental.openreward.OpenRewardSpec(target: str, num_tasks: int | None = None, split: str = 'train', indices: list[int] | None = None, api_key: str | None = None, secrets: dict[str, str] | None = None, env_name: str | None = None, include_metadata: bool = True, discover_task_tools: bool = True, task_tools_discovery_index: int | None = None)
```

[Kaynak](https://github.com/huggingface/trl/blob/main/trl/experimental/openreward/_spec.py#L79)

**Parametreler:**

target (*str*) : openreward.ai kataloğu adı (*"Eigent/SETA"*) veya herhangi bir ORS sunucusuna işaret eden bir URL (*"https://you-seta.hf.space"*, *"http://localhost:8080"*). Dizide *://* bulunup bulunmamasına göre otomatik olarak algılanır.

num_tasks (*int*, *opsiyonel*) : Veri setine çekilen görev sayısının üst sınırı. `None`, ortamın sunduğu tüm görevleri kullanır.

split (*str*, *opsiyonel*, varsayılan *"train"*) : Görev listesinin hangi bölümden çekileceğini belirtir.

indices (*list[int]*, *isteğe bağlı*) : Eğitim yapılacak belirli görev dizinleri. `num_tasks` ile birbirini dışlar. Hata ayıklama veya müfredat alt kümeleri için kullanışlıdır.

api_key (*str*, *isteğe bağlı*) : `OPENREWARD_API_KEY` geçersiz kılma. Yalnızca `target` bir kataloğ adı olduğunda kullanılır.

secrets (*dict[str, str]*, *isteğe bağlı*) : `env.session(secrets=)` parametresine iletilen oturum başına gizli bilgiler.

env_name (*str*, *isteğe bağlı*) : Sunucuda aranacak ortam adının geçersiz kılınması. Nadiren gereklidir.

include_metadata (*bool*, *isteğe bağlı*, varsayılan *True*) : Görev başına meta verileri (*difficulty*, *category*, *tags*, ...) ödül fonksiyonlarının TRL'nin `inputs` argümanı üzerinden okuyabilmesi için veri seti satırlarına ekler.

discover_task_tools (*bool*, *opsiyonel*, varsayılan *True*) : `True` ise, kısa ömürlü bir ORS oturumu açılır ve `session.list_tools()` kullanılarak görev özelindeki araçlar (`GET …/task_tools` ORS başına — örn. `@tool(shared=False)` ve `list_task_tools()`) GRPO için bağlanır. Sonda başarısız olursa yalnızca `environment.list_tools()` kullanılır. Ek oturumu atlamak (yalnızca paylaşılan araçlar / çevrimdışı durumlar) için `False` olarak ayarlayın.

task_tools_discovery_index (*int*, *opsiyonel*) : Ayarlandığında yalnızca keşif oturumunda kullanılan görev indeksi; **aşağıdaki çoklu indeks sorgulamasını geçersiz kılar**. Atlandığında ve `indices=` ayarlandığında, keşif `indices` içindeki her **ayrı** giriş için (sıralı) bir sorgu oturumu açar ve her listedeki görevden gelen görev özelindeki araçları bağlamak için araç tanımlarını ada göre **birleştirir**. Atlandığında ve `num_tasks` / tam liste modu kullanıldığında, yalnızca `0` numaralı görevi sorgular. `discover_task_tools=False` olduğunda yok sayılır.

Bir TRL eğitimcisine ORS ortamını bağlayan tek bir spec nesnesi.

## Kısıtlamalar

- Entegrasyon `trl.experimental` içinde — API'ler değişebilir. CI günlüklerindeki uyarıyı susturmak için `TRL_EXPERIMENTAL_SILENCE=1` değerini ayarlayın.
- Şu anda tek bir `OpenRewardSpec` maruz bırakır ve tek bir ortamı kapsar; çoklu ortam eğitimi (OpenEnv "meta-ortam" deseni tarzında) henüz desteklenmemektedir.
- Uzun süreli rollouts (epizot başına >15 dk) bir keepalive ping gerektirir — henüz bağlanmadı.

## Referans

- [Açık Ödül Standardı](https://openrewardstandard.io)
- [OpenReward platformu](https://openreward.ai)
- [`openreward` Python SDK'sı](https://pypi.org/project/openreward/)
- [Echo env Space — `trl-internal-testing/openreward-echo-env`](https://huggingface.co/spaces/trl-internal-testing/openreward-echo-env)

