TRL documentation

Tích hợp OpenReward để huấn luyện LLM với các môi trường

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

Tích hợp OpenReward để huấn luyện LLM với các môi trường

OpenReward là một hệ sinh thái mở dành cho các môi trường RL được xây dựng dựa trên Open Reward Standard (ORS) — một giao thức HTTP/SSE công khai, không phụ thuộc ngôn ngữ, quy định cách một môi trường công bố các tác vụ, công cụ, phiên và phần thưởng của nó. Vì ORS chỉ là một giao thức, cùng một môi trường có thể chạy trên nền tảng OpenReward, tự lưu trữ trên bất kỳ dịch vụ container nào, hoặc chạy cục bộ trên localhost để phát triển. Danh mục các môi trường sẵn sàng sử dụng có sẵn tại openreward.ai.

Hướng dẫn này bao gồm cách tích hợp OpenReward với TRL. Để biết thêm về chính tiêu chuẩn, hãy xem tài liệu ORS.

Tích hợp này nằm tại trl.experimental.openreward và được đặt sau extra trl[openreward] (nhập theo kiểu lazy — người dùng không sử dụng sẽ không phải trả thêm chi phí gì).

Khi nào nên sử dụng môi trường OpenReward

GRPOTrainer hỗ trợ huấn luyện dựa trên môi trường thông qua slot environment_factory — xem OpenEnv để biết về hợp đồng chung. Sử dụng OpenReward khi bạn muốn huấn luyện đối với một môi trường nói ngôn ngữ ORS: OpenReward catalog (ví dụ Eigent/SETA, kanishk/EndlessTerminals, nebius/SWE-rebench-V2), một môi trường do bạn tự lưu trữ trên hạ tầng của mình, hoặc một máy chủ cục bộ mà bạn đang phát triển.

Cài đặt

pip install trl[openreward]

Lệnh này cài đặt SDK Python openreward. Bản thân tích hợp chỉ import openreward một cách lười (lazy), nên người dùng không chạm đến trl.experimental.openreward sẽ không bị ảnh hưởng.

Bắt đầu nhanh

Lớp OpenRewardSpec kết nối một môi trường ORS duy nhất vào ba vị trí của trình huấn luyện TRL — train_dataset, environment_factory, reward_funcs — bằng cách phơi bày các thuộc tính ánh xạ 1:1 với các tên tham số đó:

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

Bên trong, OpenRewardSpec thực hiện ba việc, được thực hiện một cách lười biếng khi truy cập lần đầu:

  1. spec.train_dataset: tạo ra một datasets.Dataset từ danh sách tác vụ của môi trường (một vòng lặp HTTP duy nhất qua SDK). Có ít nhất prompt, task_index, cùng các cột metadata riêng cho từng tác vụ được gộp vào.
  2. spec.environment_factory: trả về một callable không tham số, tạo ra một adapter mới cho mỗi lần rollout khi được gọi. Adapter này phơi bày một phương thức Python cho mỗi công cụ ORS, với chữ ký kiểu dữ liệu và docstring được tự động tạo từ JSON Schema của env. Bộ thu thập công cụ của TRL sẽ nhận chúng thông qua inspect.getmembers.
  3. spec.reward_funcs: một hàm phần thưởng chỉ dựa trên kết quả (phần thưởng khác null cuối cùng trong quỹ đạo), phù hợp với các môi trường phần thưởng thưa như SETA.

Sử dụng môi trường hub

Truyền tên catalog openreward.ai làm mục tiêu. SDK đọc OPENREWARD_API_KEY từ môi trường để xác thực.

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

Sử dụng môi trường tự lưu trữ

Truyền URL trực tiếp. Không cần API key nếu máy chủ của bạn không yêu cầu.

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

SDK openreward mặc định kỳ vọng bố cục nền tảng có hai subdomain (api.<host> cho các cuộc gọi không trạng thái và sessions.<host> cho các cuộc gọi phiên dựa trên SSE). Đối với các máy chủ tự lưu trữ single-host (một URL phục vụ mọi thứ), hãy đặt các biến môi trường ghi đè bên dưới trước khi khởi tạo 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")

Chạy môi trường tối thiểu cục bộ

Cách nhanh nhất để thử nghiệm tích hợp đầu-cuối mà không cần phụ thuộc bên ngoài là một máy chủ ORS nhỏ được định nghĩa bằng bộ khung Environment + Server của SDK openreward. Ví dụ bên dưới là một môi trường echo hoàn chỉnh — mô hình chiến thắng bằng cách gọi echo(text=...) với chuỗi đích của tác vụ.

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

Chạy nó:

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

Sau đó, trỏ OpenRewardSpec đến nó (với các ghi đè URL được mô tả ở trên):

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

Đây cũng là mẫu fixture được sử dụng bởi chính các bài kiểm tra của TRL — xem trl-internal-testing/openreward-echo-env cho Space đã triển khai.

Chọn các tác vụ

OpenRewardSpec chấp nhận một số lượng hoặc một danh sách chỉ mục rõ ràng:

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 và indices là hai tham số loại trừ lẫn nhau và cả hai đều chỉ lấy các tác vụ cần thiết (không quét toàn bộ danh sách tác vụ).

Cách hoạt động của việc liên kết công cụ

Khi khởi tạo, spec gọi endpoint /tools của env để lấy danh sách các tool spec (mỗi spec gồm tên, mô tả và JSON Schema cho các tham số). Với mỗi tool, nó tạo ra một phương thức Python trên adapter cho từng rollout, có chữ ký kiểu dữ liệu và docstring được suy ra từ schema. Các phương thức này được đặt trên class của adapter, nơi bộ thu thập tool của TRL tìm thấy chúng, do đó cả transformers.utils.get_json_schema và inspect.getmembers(type(env), isfunction) của TRL đều tạo ra đúng tool schema cho model mà không cần mã wrapper riêng cho từng env.

Nếu mô tả công cụ chứa các ký tự không an toàn để ghép vào mã nguồn Python, trình liên kết sẽ chuyển sang dạng đã được làm sạch để việc liên kết không bao giờ thất bại trong các môi trường thực tế.

Hàm phần thưởng

spec.reward_funcs mặc định là phần thưởng chỉ dựa trên kết quả — với mỗi rollout, nó trả về phần thưởng không rỗng cuối cùng được quan sát trong suốt quỹ đạo. Đây là mặc định phù hợp cho các môi trường có phần thưởng thưa (ví dụ SETA, nơi chỉ submit_solution trả về phần thưởng không rỗng).

Nếu không có công cụ nào trả về phần thưởng khác null, hàm phần thưởng mặc định sẽ trả về None, chứ không phải 0.0. Điều này bao gồm các lượt rollout không có lời gọi công cụ, chỉ có các lời gọi công cụ không được chấm điểm, hoặc chỉ có các lời gọi công cụ thất bại. Phần thưởng quan sát được là 0.0 hoặc âm vẫn là một điểm số hợp lệ. Một lời gọi công cụ không được chấm điểm hoặc thất bại ở sau đó sẽ không xóa bỏ điểm số trước đó.

GRPO loại bỏ các rollout mà tất cả các hàm phần thưởng đều trả về None khỏi baseline phần thưởng và gán cho chúng lợi thế bằng không. Điều này không loại bỏ các token của chúng khỏi việc chuẩn hóa loss, cũng không vô hiệu hóa các thành phần khác như điều chỉnh KL. Nếu một hàm phần thưởng khác chấm điểm cho rollout, nó vẫn có thể nhận được lợi thế khác không.

Các điểm bị thiếu không xác định được lý do một episode kết thúc. Nếu việc từ bỏ hoặc đạt đến giới hạn gọi công cụ nên được tính là một thất bại của tác vụ, hãy trả về một phần thưởng thất bại rõ ràng từ môi trường hoặc hàm phần thưởng tùy chỉnh của bạn. Các lỗi hạ tầng hoặc lỗi bộ chấm điểm có thể vẫn ở trạng thái không chấm điểm được; hãy theo dõi phạm vi bao phủ của việc chấm điểm cùng với phần thưởng trung bình.

Nếu bạn muốn sử dụng hàm thưởng tùy chỉnh, hãy viết một hàm thưởng TRL thông thường và truyền nó trực tiếp:

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

Adapter cho từng lượt rollout cung cấp trạng thái chạy mà TRL cần — env.reward, env.rewards, env.metadata, env.finished, env.last_output — cho việc định hình phần thưởng sau khi chạy tùy ý.

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 )

Tham số

  • target (str) — Tên trong danh mục openreward.ai (“Eigent/SETA”) hoặc một URL trỏ đến bất kỳ máy chủ ORS nào (”https://you-seta.hf.space”, “http://localhost:8080”). Được tự động phát hiện dựa trên sự hiện diện của :// trong chuỗi.
  • num_tasks (int, tuỳ chọn) — Giới hạn số lượng tác vụ được đưa vào bộ dữ liệu. None sẽ sử dụng mọi tác vụ mà môi trường cung cấp.
  • split (str, optional, mặc định là “train”) — Danh sách tác vụ của split nào để lấy.
  • indices (list[int], optional) — Các chỉ mục tác vụ cụ thể để huấn luyện. Loại trừ lẫn nhau với num_tasks. Hữu ích cho việc gỡ lỗi hoặc các tập con theo chương trình giảng dạy.
  • api_key (str, tuỳ chọn) — Ghi đè OPENREWARD_API_KEY. Chỉ được sử dụng khi target là tên catalog.
  • secrets (dict[str, str], tuỳ chọn) — Các bí mật theo phiên được chuyển tiếp đến env.session(secrets=).
  • env_name (str, không bắt buộc) — Ghi đè tên môi trường để tìm kiếm trên máy chủ. Hiếm khi cần.
  • include_metadata (bool, tuỳ chọn, mặc định là True) — Gộp metadata của từng tác vụ (difficulty, category, tags, …) vào các dòng của dataset để các hàm reward có thể đọc chúng thông qua đối số inputs của TRL.
  • discover_task_tools (bool, tuỳ chọn, mặc định là True) — Nếu True, sẽ mở một phiên ORS có thời gian sống ngắn và sử dụng session.list_tools() để các công cụ dành riêng cho tác vụ (GET …/task_tools theo ORS — ví dụ @tool(shared=False) và list_task_tools()) được liên kết cho GRPO. Nếu quá trình dò tìm thất bại, chỉ chuyển sang environment.list_tools(). Đặt False để bỏ qua phiên bổ sung (chỉ dùng công cụ chia sẻ / các vấn đề ngoại lệ khi ngoại tuyến).
  • task_tools_discovery_index (int, optional) — Chỉ mục tác vụ chỉ được sử dụng cho phiên khám phá khi được đặt; ghi đè việc dò nhiều chỉ mục bên dưới. Khi bỏ qua và indices= được đặt, khám phá sẽ mở một phiên dò cho mỗi mục khác nhau trong indices (đã sắp xếp) và ghép các thông số công cụ theo tên để ràng buộc các công cụ cụ thể cho tác vụ từ mọi tác vụ được liệt kê. Khi bỏ qua và sử dụng num_tasks / chế độ danh sách đầy đủ, chỉ dò tác vụ 0. Bị bỏ qua khi discover_task_tools=False.

Đối tượng spec đơn lẻ kết nối môi trường ORS vào trình huấn luyện TRL.

Hạn chế

  • Tích hợp này nằm trong trl.experimental — API có thể thay đổi. Đặt TRL_EXPERIMENTAL_SILENCE=1 để tắt cảnh báo trong nhật ký CI.
  • Hiện tại chỉ cung cấp một OpenRewardSpec bao phủ một môi trường; việc huấn luyện đa môi trường (theo mô hình “meta-environment” của OpenEnv) chưa được hỗ trợ.
  • Các lượt rollout kéo dài (>15 phút mỗi episode) cần một ping keepalive — hiện chưa được tích hợp.

Tham khảo

Update on GitHub