TRL documentation

Integración de OpenReward para entrenar LLMs con entornos

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

Integración de OpenReward para entrenar LLMs con entornos

OpenReward es un ecosistema abierto para entornos de RL construido sobre el Open Reward Standard (ORS), un protocolo HTTP/SSE público e independiente del lenguaje para que un entorno exponga sus tareas, herramientas, sesiones y recompensas. Dado que ORS es solo un protocolo, el mismo entorno puede ejecutarse en la plataforma OpenReward, autoalojado en cualquier servicio de contenedores, o localmente en localhost para desarrollo. Un catálogo de entornos listos para usar está disponible en openreward.ai.

Esta guía cubre cómo integrar OpenReward con TRL. Para más información sobre el estándar en sí, consulte la documentación de ORS.

La integración se encuentra en trl.experimental.openreward y está condicionada al extra trl[openreward] (se importa de forma perezosa: los usuarios que no la utilicen no incurren en ningún coste).

Cuándo usar entornos de OpenReward

GRPOTrainer admite el entrenamiento basado en entornos a través del slot environment_factory; consulte OpenEnv para el contrato general. Utilice OpenReward cuando desee entrenar contra un entorno que hable ORS: el catálogo de OpenReward (p. ej., Eigent/SETA, kanishk/EndlessTerminals, nebius/SWE-rebench-V2), un entorno que autoaloje en su propia infraestructura o un servidor local que esté desarrollando.

Instalación

pip install trl[openreward]

Esto instala el SDK de Python openreward. La propia integración importa openreward de forma perezosa, por lo que los usuarios que no utilicen trl.experimental.openreward no se ven afectados.

Inicio rápido

La clase OpenRewardSpec conecta un único entorno ORS con los tres espacios del entrenador TRL — train_dataset, environment_factory, reward_funcs — mediante propiedades que se mapean 1:1 con esos nombres de parámetros:

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

Por debajo, OpenRewardSpec hace tres cosas, de forma perezosa en el primer acceso:

  1. spec.train_dataset: deriva un datasets.Dataset a partir de la lista de tareas del entorno (una sola solicitud HTTP a través del SDK). Tiene como mínimo prompt, task_index, además de columnas de metadatos por tarea integradas.
  2. spec.environment_factory: devuelve un callable sin argumentos que genera un nuevo adaptador por rollout en cada llamada. El adaptador expone un método Python por herramienta de ORS, con una firma tipada y una docstring generadas automáticamente a partir del JSON Schema del entorno. El colector de herramientas de TRL las recupera mediante inspect.getmembers.
  3. spec.reward_funcs: una función de recompensa solo de resultado (la recompensa no nula final en la trayectoria) adecuada para entornos de recompensa dispersa como SETA.

Uso de un entorno de hub

Pase un nombre de catálogo de openreward.ai como destino. El SDK lee OPENREWARD_API_KEY del entorno para la autenticación.

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

Uso de un entorno autoalojado

Pasa la URL directamente. No se necesita una clave de API si tu servidor no la exige.

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

El SDK openreward espera por defecto un diseño de plataforma con dos subdominios (api.<host> para llamadas sin estado y sessions.<host> para llamadas de sesión basadas en SSE). Para servidores autoalojados de un solo host (una única URL que sirve todo), configure las variables de entorno de anulación a continuación antes de construir 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")

Ejecutar un entorno mínimo localmente

La forma más rápida de probar la integración de principio a fin sin dependencias externas es un pequeño servidor ORS definido con el andamiaje Environment + Server del SDK openreward. El ejemplo de abajo es un entorno echo completo: el modelo gana al llamar a echo(text=...) con la cadena objetivo de la tarea.

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

Ejecútalo:

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

Luego, dirija OpenRewardSpec hacia él (con las anulaciones de URL descritas anteriormente):

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

Este es también el patrón de fixture utilizado por las propias pruebas de TRL; consulte trl-internal-testing/openreward-echo-env para el Space desplegado.

Seleccionar tareas

OpenRewardSpec acepta un recuento o una lista de índices explícita:

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 y indices son mutuamente excluyentes y ambos obtienen solo las tareas que necesitan (sin escanear la lista completa de tareas).

Cómo funciona la vinculación de herramientas

En la construcción, la especificación llama al endpoint /tools del entorno para obtener una lista de especificaciones de herramientas (cada una con un nombre, una descripción y un JSON Schema para los argumentos). Para cada herramienta, genera un método Python en el adaptador por rollout con una firma tipada y una docstring derivada del esquema. Los métodos se establecen en la clase del adaptador, donde el colector de herramientas de TRL los encuentra, de modo que transformers.utils.get_json_schema y inspect.getmembers(type(env), isfunction) de TRL producen el esquema de herramienta correcto para el modelo sin código de envoltura por entorno.

Si la descripción de una herramienta contiene caracteres que no son seguros para insertar en el código fuente de Python, el binder recurre a una forma saneada para que la vinculación nunca falle en entornos reales.

Funciones de recompensa

spec.reward_funcs tiene como valor predeterminado una recompensa solo de resultado: para cada rollout, devuelve la última recompensa no nula observada durante la trayectoria. Este es el valor predeterminado adecuado para entornos con recompensa dispersa (p. ej. SETA, donde solo submit_solution devuelve una recompensa no nula).

Si ninguna herramienta devuelve una recompensa no nula, la función de recompensa predeterminada devuelve None, no 0.0. Esto incluye los rollouts sin llamadas a herramientas, solo con llamadas a herramientas sin puntuar o solo con llamadas a herramientas fallidas. Una recompensa observada de 0.0 o negativa sigue siendo una puntuación válida. Una llamada a herramienta posterior sin puntuar o fallida no borra una puntuación anterior.

GRPO excluye de la línea base de recompensa los despliegues para los que todas las funciones de recompensa devuelven None y les asigna una ventaja cero. Esto no elimina sus tokens de la normalización de la pérdida ni desactiva otros términos, como la regularización KL. Si otra función de recompensa puntúa el despliegue, este aún puede recibir una ventaja distinta de cero.

Las puntuaciones ausentes no identifican por qué terminó un episodio. Si rendirse o alcanzar el límite de llamadas a herramientas debe considerarse un fallo de la tarea, devuelve una recompensa de fallo explícita desde tu entorno o función de recompensa personalizada. Los fallos de infraestructura o del evaluador pueden, en cambio, permanecer sin puntuar; monitorea la cobertura de puntuación junto con la recompensa media.

Si deseas una recompensa personalizada, escribe una función de recompensa TRL regular y pásala directamente:

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

El adaptador por rollout expone el estado en ejecución que TRL necesita — env.reward, env.rewards, env.metadata, env.finished, env.last_output — para la modelación posterior de recompensas.

OpenRewardSpec

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

Parámetros

  • target (str) — Nombre de catálogo de openreward.ai (“Eigent/SETA”) o una URL que apunte a cualquier servidor ORS (”https://you-seta.hf.space”, “http://localhost:8080”). Se detecta automáticamente por la presencia de :// en la cadena.
  • num_tasks (int, opcional) — Límite en el número de tareas extraídas en el conjunto de datos. None utiliza todas las tareas que el entorno expone.
  • split (str, optional, por defecto “train”) — De qué split se extrae la lista de tareas.
  • indices (list[int], opcional) — Índices de tareas específicas en las que entrenar. Es mutuamente excluyente con num_tasks. Útil para depuración o subconjuntos de currículo.
  • api_key (str, opcional) — Sustitución de OPENREWARD_API_KEY. Solo se usa cuando target es un nombre de catálogo.
  • secrets (dict[str, str], opcional) — Secretos por sesión que se reenvían a env.session(secrets=).
  • env_name (str, opcional) — Sustitución del nombre del entorno a buscar en el servidor. Rara vez necesario.
  • include_metadata (bool, opcional, valor predeterminado True) — Incorpora los metadatos por tarea (difficulty, category, tags, …) en las filas del conjunto de datos para que las funciones de recompensa puedan leerlos a través del argumento inputs de TRL.
  • discover_task_tools (bool, opcional, valor predeterminado True) — Si True, abre una sesión ORS de corta duración y usa session.list_tools() para que las herramientas específicas de la tarea (GET …/task_tools según ORS — p. ej. @tool(shared=False) y list_task_tools()) se vinculen para GRPO. Si la sonda falla, solo se recurre a environment.list_tools(). Establezca False para omitir la sesión adicional (solo herramientas compartidas / peculiaridades de modo sin conexión).
  • task_tools_discovery_index (int, opcional) — Índice de tarea utilizado solo para la sesión de descubrimiento cuando se establece; anula la exploración multiíndice siguiente. Cuando se omite y indices= está establecido, el descubrimiento abre una sesión de exploración por cada entrada distinta en indices (ordenadas) y combina las especificaciones de herramientas por nombre para que se vinculen las herramientas específicas de cada tarea de todas las tareas enumeradas. Cuando se omite y se utiliza num_tasks / el modo de lista completa, se explora solo la tarea 0. Se ignora cuando discover_task_tools=False.

Objeto de especificación única que conecta un entorno ORS con un entrenador de TRL.

Limitaciones

  • La integración está en trl.experimental — las API pueden cambiar. Establece TRL_EXPERIMENTAL_SILENCE=1 para silenciar la advertencia en los registros de CI.
  • Actualmente expone una única OpenRewardSpec que cubre un solo entorno; el entrenamiento multi-entorno (al estilo del patrón de “meta-entorno” de OpenEnv) aún no está soportado.
  • Los despliegues de larga duración (>15 min por episodio) necesitan un ping de mantenimiento — aún no está configurado.

Referencia

Update on GitHub