TRL documentation
Integración de OpenReward para entrenar LLMs con entornos
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.openrewardy está condicionada al extratrl[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:
spec.train_dataset: deriva undatasets.Dataseta partir de la lista de tareas del entorno (una sola solicitud HTTP a través del SDK). Tiene como mínimoprompt,task_index, además de columnas de metadatos por tarea integradas.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 medianteinspect.getmembers.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
openrewardespera por defecto un diseño de plataforma con dos subdominios (api.<host>para llamadas sin estado ysessions.<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 construirOpenRewardSpec: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 :8000Luego, 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 columnsEste 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))) # rangenum_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
< source >( 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.
Noneutiliza 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 cuandotargetes 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
inputsde TRL. - discover_task_tools (bool, opcional, valor predeterminado True) —
Si
True, abre una sesión ORS de corta duración y usasession.list_tools()para que las herramientas específicas de la tarea (GET …/task_toolssegún ORS — p. ej.@tool(shared=False)ylist_task_tools()) se vinculen para GRPO. Si la sonda falla, solo se recurre aenvironment.list_tools(). EstablezcaFalsepara 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 enindices(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 utilizanum_tasks/ el modo de lista completa, se explora solo la tarea0. Se ignora cuandodiscover_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. EstableceTRL_EXPERIMENTAL_SILENCE=1para silenciar la advertencia en los registros de CI. - Actualmente expone una única
OpenRewardSpecque 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
- Estándar de recompensa abierto
- Plataforma OpenReward
- SDK de Python de
openreward - Echo env Space —
trl-internal-testing/openreward-echo-env