TRL documentation

환경을 활용한 LLM 학습을 위한 OpenReward 통합

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

and get access to the augmented documentation experience

to get started

환경을 활용한 LLM 학습을 위한 OpenReward 통합

OpenReward는 Open Reward Standard (ORS)를 기반으로 구축된 RL 환경용 오픈 생태계입니다. ORS는 환경이 작업, 도구, 세션, 보상을 어떻게 노출하는지를 정의하는 공개적이고 언어 비종속적인 HTTP/SSE 프로토콜입니다. ORS가 프로토콜이기 때문에, 동일한 환경은 OpenReward 플랫폼에서 실행하거나, 컨테이너 서비스에서 자체 호스팅하거나, 개발을 위해 localhost에서 로컬로 실행할 수 있습니다. 바로 사용할 수 있는 환경 카탈로그는 openreward.ai에서 확인할 수 있습니다.

이 가이드는 OpenReward를 TRL에 통합하는 방법을 다룹니다. 표준 자체에 대한 자세한 내용은 ORS 문서를 참고하세요.

통합 코드는 trl.experimental.openreward에 위치하며, trl[openreward] 추가 항목으로 게이트 처리되어 있습니다(레이지 임포트 — 비사용자는 아무 비용도 부담하지 않음).

OpenReward 환경을 사용할 때

GRPOTrainer는 environment_factory 슬롯을 통해 환경 기반 학습을 지원합니다. 일반적인 계약은 OpenEnv를 참고하세요. ORS 기반 환경에 대해 학습하려면 OpenReward를 사용하세요. OpenReward 카탈로그(예: Eigent/SETA, kanishk/EndlessTerminals, nebius/SWE-rebench-V2), 자체 인프라에 셀프 호스팅한 환경, 또는 개발 중인 로컬 서버를 사용할 수 있습니다.

설치

pip install trl[openreward]

이 명령은 openreward Python SDK를 설치합니다. 통합 자체는 openreward를 지연 로드하므로, trl.experimental.openreward를 사용하지 않는 사용자에게는 영향을 주지 않습니다.

빠른 시작

OpenRewardSpec 클래스는 1:1로 해당 kwarg 이름에 매핑되는 프로퍼티를 노출하여 단일 ORS 환경을 TRL 트레이너의 세 슬롯인 train_dataset, environment_factory, reward_funcs에 연결합니다:

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()

OpenRewardSpec는 내부적으로 첫 접근 시 지연 실행으로 세 가지 작업을 수행합니다:

  1. spec.train_dataset: env의 작업 목록에서 datasets.Dataset를 파생합니다(SDK를 통해 HTTP 왕복 1회). 최소한 prompt, task_index를 포함하며, 작업별 메타데이터 열이 병합되어 있습니다.
  2. spec.environment_factory: 각 호출 시 새로운 per-rollout 어댑터를 생성하는 인자 없는 콜러블을 반환합니다. 어댑터는 ORS 도구마다 하나의 Python 메서드를 노출하며, env의 JSON Schema에서 자동 생성된 타입 지정 시그니처와 docstring을 포함합니다. TRL의 tool collector는 inspect.getmembers를 통해 이를 수집합니다.
  3. spec.reward_funcs: 결과만 있는 보상 함수(트래젝토리에서 마지막 null이 아닌 보상)로, SETA와 같은 희소 보상 환경에 적합합니다.

허브 환경 사용

openreward.ai 카탈로그 이름을 대상으로 전달합니다. SDK는 인증을 위해 환경에서 OPENREWARD_API_KEY를 읽습니다.

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

자체 호스팅 환경 사용

URL을 직접 전달합니다. 서버에서 API 키를 요구하지 않는 경우 API 키가 필요하지 않습니다.

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

openreward SDK는 기본적으로 두 개의 서브도메인으로 구성된 플랫폼 레이아웃을 기대합니다(api.<host>는 상태 없는 호출에, sessions.<host>는 SSE 기반 세션 호출에 사용). 단일 호스트 셀프호스팅 서버(모든 것을 하나의 URL로 제공하는 경우)에서는 OpenRewardSpec를 생성하기 전에 아래 오버라이드 환경 변수를 설정하세요:

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")

로컬에서 최소 환경 실행

외부 의존성 없이 통합을 끝에서 끝으로 가장 빠르게 테스트하는 방법은 openreward SDK의 Environment + Server 스캐폴딩으로 정의된 작은 ORS 서버입니다. 아래 예제는 완전한 echo 환경입니다. 모델은 작업의 대상 문자열을 echo(text=...)에 전달하여 호출하면 승리합니다.

# 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)

실행:

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

그런 다음 OpenRewardSpec을 해당 경로로 지정합니다(위에서 설명한 URL 오버라이드를 사용):

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

이것은 TRL 자체 테스트에서 사용하는 픽스처 패턴이기도 합니다 — 배포된 Space는 trl-internal-testing/openreward-echo-env를 참고하세요.

작업 선택

OpenRewardSpec은 개수 또는 명시적인 인덱스 목록을 모두 허용합니다:

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와 indices는 상호 배타적이며, 둘 다 필요한 작업만 가져옵니다(전체 작업 목록을 스캔하지 않음).

도구 바인딩 작동 방식

생성 시 spec은 env의 /tools 엔드포인트를 호출하여 도구 스펙 목록(각각 이름, 설명, 인수의 JSON Schema 포함)을 가져옵니다. 각 도구에 대해 per-rollout 어댑터에 타입이 지정된 시그니처와 스키마에서 파생된 docstring을 가진 Python 메서드를 생성합니다. 이 메서드들은 어댑터의 클래스에 설정되며, TRL의 tool collector가 이를 찾도록 하여 transformers.utils.get_json_schema와 TRL의 inspect.getmembers(type(env), isfunction) 모두 env별 래퍼 코드 없이 모델에 대해 올바른 도구 스키마를 생성합니다.

도구 설명에 Python 소스에 안전하게 삽입할 수 없는 문자가 포함된 경우, 바인더는 실제 환경에서 바인딩이 실패하지 않도록 정제된 형태로 대체합니다.

보상 함수

spec.reward_funcs의 기본값은 결과만 고려하는 보상입니다. 각 rollout에 대해 trajectory 동안 관찰된 마지막 non-null 보상을 반환합니다. 이는 희소 보상 환경(예: submit_solution만 non-null 보상을 반환하는 SETA)에 적합한 기본값입니다.

도구가 null이 아닌 보상을 반환하지 않으면, 기본 보상 함수는 0.0이 아닌 None을 반환합니다. 이는 도구 호출이 없는 롤아웃, 점수화되지 않은 도구 호출만 있는 경우, 또는 실패한 도구 호출만 있는 경우를 포함합니다. 관찰된 0.0 또는 음수 보상은 여전히 유효한 점수입니다. 이후에 발생한 점수화되지 않거나 실패한 도구 호출은 이전 점수를 지우지 않습니다.

GRPO는 모든 보상 함수가 None을 반환하는 롤아웃을 보상 베이스라인에서 제외하고, 해당 롤아웃에 대해 0의 이점을 부여합니다. 이는 해당 롤아웃의 토큰을 손실 정규화에서 제거하거나 KL 정규화 같은 다른 항을 비활성화하지 않습니다. 다른 보상 함수가 해당 롤아웃에 점수를 매긴다면, 여전히 0이 아닌 이점을 받을 수 있습니다.

누락된 점수는 에피소드가 종료된 이유를 식별하지 않습니다. 포기하거나 도구 호출 한도에 도달한 경우를 작업 실패로 간주해야 한다면, 환경 또는 사용자 정의 보상 함수에서 명시적인 실패 보상을 반환하세요. 인프라 또는 채점기 실패는 채점 불가 상태로 남겨둘 수 있으며, 평균 보상과 함께 채점 커버리지를 모니터링하세요.

커스텀 리워드를 사용하려면 일반적인 TRL 리워드 함수를 작성하고 직접 전달하세요:

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,
)

per-rollout 어댑터는 임의의 사후 보상 성형(post-hoc reward shaping)을 위해 TRL이 필요한 실행 상태인 env.reward, env.rewards, env.metadata, env.finished, env.last_output를 노출합니다.

OpenRewardSpec

class trl.experimental.openreward.OpenRewardSpec

< >

( target: strnum_tasks: int | None = Nonesplit: str = 'train'indices: list[int] | None = Noneapi_key: str | None = Nonesecrets: dict[str, str] | None = Noneenv_name: str | None = Noneinclude_metadata: bool = Truediscover_task_tools: bool = Truetask_tools_discovery_index: int | None = None )

매개변수

  • target (str) — openreward.ai 카탈로그 이름(“Eigent/SETA”) 또는 ORS 서버를 가리키는 URL (”https://you-seta.hf.space”, “http://localhost:8080”). 문자열에 ://가 있는지 여부로 자동 감지됩니다.
  • num_tasks (int, 선택 사항) — 데이터셋에 가져올 작업 수의 상한입니다. None을 사용하면 env가 노출하는 모든 작업을 사용합니다.
  • split (str, optional, 기본값 “train”) — 작업 목록을 가져올 스플릿을 지정합니다.
  • indices (list[int], 선택 사항) — 학습할 특정 작업 인덱스입니다. num_tasks와 상호 배타적입니다. 디버깅 또는 커리큘럼 부분 집합에 유용합니다.
  • api_key (str, 선택 사항) — OPENREWARD_API_KEY를 재정의합니다. target이 카탈로그 이름인 경우에만 사용됩니다.
  • secrets (dict[str, str], 선택) — env.session(secrets=)로 전달되는 세션별 secrets입니다.
  • env_name (str, 선택 사항) — 서버에서 조회할 환경 이름에 대한 오버라이드입니다. 거의 필요하지 않습니다.
  • include_metadata (bool, 선택 사항, 기본값 True) — 태스크별 메타데이터(difficulty, category, tags, …)를 데이터셋 행에 포함시켜 보상 함수가 TRL의 inputs 인수를 통해 이를 읽을 수 있도록 합니다.
  • discover_task_tools (bool, 선택 사항, 기본값 True) — True인 경우, 짧은 수명의 ORS 세션을 열고 session.list_tools()를 사용하여 작업별 도구(GET …/task_tools (ORS 기준) — 예: @tool(shared=False) 및 list_task_tools())를 GRPO에 바인딩합니다. 탐지가 실패하면 environment.list_tools()로만 폴백합니다. 추가 세션을 건너뛰려면 False로 설정하세요(공유 도구만 사용 / 오프라인 특수 상황).
  • task_tools_discovery_index (int, optional) — 설정된 경우 discovery 세션에서만 사용되는 task 인덱스입니다. overrides 아래에 설명된 multi-index probing을 덮어씁니다. 생략되고 indices=가 설정된 경우, discovery는 indices의 각 distinct 항목(정렬됨)마다 하나의 probe 세션을 열고 merges tool specs를 이름 기준으로 병합하여, 나열된 모든 task의 task-specific tools가 바인딩되도록 합니다. 생략되고 num_tasks / full-list 모드가 사용되는 경우, task 0만 probe합니다. discover_task_tools=False인 경우 무시됩니다.

TRL trainer에 ORS 환경을 연결하는 단일 spec 객체입니다.

한계

  • 통합은 trl.experimental에 있습니다 — API가 변경될 수 있습니다. CI 로그에서 경고를 비활성화하려면 TRL_EXPERIMENTAL_SILENCE=1을 설정하세요.
  • 현재 하나의 환경만 다루는 단일 OpenRewardSpec만 노출하며, OpenEnv의 “메타-환경” 패턴과 같은 다중 환경 학습은 아직 지원되지 않습니다.
  • 긴 시간 동안 실행되는 롤아웃(에피소드당 15분 이상)에는 keepalive ping이 필요하지만, 아직 연결되어 있지 않습니다.

참고

Update on GitHub