TRL documentation
تكامل OpenReward لتدريب نماذج اللغة الكبيرة مع بيئات
تكامل OpenReward لتدريب نماذج اللغة الكبيرة مع بيئات
OpenReward هو نظام بيئي مفتوح لبيئات التعلم المعزز (RL) مبني على المعيار المفتوح للمكافآت (ORS) — وهو بروتوكول عام HTTP/SSE مستقل عن اللغة يحدد كيفية تعرض البيئة لمهامها وأدواتها وجلساتها ومكافآتها. وبما أن ORS مجرد بروتوكول، يمكن تشغيل نفس البيئة على منصة OpenReward، أو استضافتها ذاتيًا على أي خدمة حاويات، أو محليًا على localhost لأغراض التطوير. تتوفر قائمة بيئات جاهزة للاستخدام على openreward.ai.
يتناول هذا الدليل كيفية دمج OpenReward مع TRL. لمزيد من المعلومات حول المعيار نفسه، راجع وثائق ORS.
توجد عملية التكامل في
trl.experimental.openrewardوهي محمية خلف الإضافةtrl[openreward](تُستورد بشكل كسول — غير المستخدمين لا يدفعون شيئاً).
متى تُستخدم بيئات OpenReward
يدعم GRPOTrainer التدريب القائم على البيئة عبر الفتحة environment_factory — راجع OpenEnv لمعرفة العقد العام. استخدم OpenReward عندما ترغب في التدريب ضد بيئة تتحدث بواجهة ORS: كتالوج OpenReward (مثل Eigent/SETA، kanishk/EndlessTerminals، nebius/SWE-rebench-V2)، أو بيئة تستضيفها بنفسك على بنيتك التحتية، أو خادم محلي تقوم بتطويره.
التثبيت
pip install trl[openreward]
يقوم هذا الأمر بتثبيت حزمة openreward الخاصة بلغة بايثون. أما التكامل نفسه فيستورد openreward بشكل كسول، لذا لا يتأثر المستخدمون الذين لا يتعاملون مع trl.experimental.openreward.
البدء السريع
تربط فئة OpenRewardSpec بيئة ORS واحدة بالخانات الثلاث في مدرّب TRL — train_dataset، environment_factory، reward_funcs — من خلال كشف خصائص تُطابق تلك أسماء المعاملات بمعدل 1:1:
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 بثلاث عمليات، بشكل كسول عند أول وصول:
spec.train_dataset: يُشتقdatasets.Datasetمن قائمة مهام البيئة (من خلال دورة HTTP واحدة عبر SDK). يحتوي على الأقل علىpromptوtask_index، بالإضافة إلى أعمدة بيانات وصفية لكل مهمة مدمجة.spec.environment_factory: يُرجع دالة قابلة للاستدعاء بدون حُجج، تُنتج مُكيّفًا جديدًا لكل تمريرة عند كل استدعاء. يعرض المُكيّف طريقة بايثون واحدة لكل أداة ORS، مع توقيع مُنمّط وتعليق توثيقي مُولَّد تلقائيًا من مخطط JSON الخاص بالبيئة. يجمع جامع الأدوات في TRL هذه الطرق عبرinspect.getmembers.spec.reward_funcs: دالة مكافأة تعتمد على النتيجة فقط (المكافأة غير الفارغة الأخيرة في المسار)، ومناسبة لبيئات المكافآت المتناثرة مثل SETA.
استخدام بيئة مركز
مرّر اسم كتالوج من openreward.ai كهدف. تقرأ مجموعة أدوات المطوّر OPENREWARD_API_KEY من البيئة للمصادقة.
spec = OpenRewardSpec("Eigent/SETA", num_tasks=64)استخدام بيئة مستضافة ذاتياً
مرّر عنوان URL مباشرةً. لا حاجة إلى مفتاح API إذا لم يفرض خادمك ذلك.
spec = OpenRewardSpec("https://my-org-my-env.hf.space", env_name="my_env")يتوقع SDK الخاص بـ
openrewardافتراضياً تخطيط منصة مكوّناً من نطاق فرعيين (api.<host>للاستدعاءات غير الحالة وsessions.<host>لاستدعاءات الجلسات القائمة على SSE). بالنسبة لخوادم المضيف الواحد ذاتية الاستضافة (رابط واحد يقدّم كل شيء)، اضبط متغيرات البيئة التالية قبل إنشاء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")
تشغيل بيئة دنيا محلياً
أسرع طريقة لتجربة التكامل من البداية إلى النهاية دون اعتماد على مكتبات خارجية هي خادم ORS صغير مُعرَّف بهيكل Environment + Server الخاص بـ SDK openreward. المثال أدناه هو بيئة 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وهذا هو نمط البيانات التجريبية (fixture) المستخدم أيضًا في اختبارات TRL الخاصة — راجع trl-internal-testing/openreward-echo-env للفضاء (Space) المُنفَّذ.
اختيار المهام
يقبل 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))) # rangenum_tasks وindices متنافيان، وكلاهما يسترجع فقط المهام التي يحتاجها (دون مسح كامل لقائمة المهام).
كيف يعمل ربط الأدوات
عند الإنشاء، يستدعي المواصفة نقطة النهاية /tools في البيئة لجلب قائمة مواصفات الأدوات (حيث تحتوي كل أداة على اسم ووصف ومخطط JSON Schema للحوامل). ولكل أداة، يولّد طريقة Python على مُكيّف كل تمريرة (per-rollout adapter) بتوقيع مُنمّط (typed signature) وسلسلة توثيق (docstring) مشتقة من المخطط. وتُضبط هذه الطرق على فئة المُكيّف، حيث يجدها جامع أدوات TRL، وبالتالي ينتج كل من transformers.utils.get_json_schema وinspect.getmembers(type(env), isfunction) الخاص بـ TRL مخطط الأداة الصحيح للنموذج دون الحاجة إلى أي كود غلاف (wrapper) لكل بيئة.
إذا احتوى وصف الأداة على أحرف غير آمنة للإدراج في مصدر Python، فإن المُربط (binder) يلجأ إلى شكل معقّم حتى لا يفشل الربط في البيئات الفعلية.
دوال المكافأة
spec.reward_funcs افتراضيًا مكافأة تعتمد على النتيجة فقط — لكل مسار يُرجع آخر مكافأة غير فارغة رُصدت خلال المسار. هذا هو الافتراضي الصحيح للبيئات ذات المكافآت المتناثرة (مثل SETA، حيث يُرجع submit_solution فقط مكافأة غير فارغة).
إذا لم تُرجِع أي أداة مكافأة غير فارغة، فإن دالة المكافأة الافتراضية تُرجع None، وليس 0.0. ويشمل ذلك عمليات التمرين التي لا تتضمن أي استدعاءات للأدوات، أو استدعاءات غير مُقيَّمة فقط، أو استدعاءات فاشلة فقط. تبقى المكافأة المرصودة 0.0 أو السالبة نتيجة صالحة. ولا يُمحو استدعاء أداة لاحق غير مُقيَّم أو فاشل نتيجة سابقة.
يستثني GRPO عمليات التوليد التي تُرجع جميع دوال المكافأة فيها قيمة None من خط الأساس الخاص بالمكافأة، ويمنحها ميزة تساوي صفراً. ولا يؤدي هذا إلى إزالة رموزها من تطبيع الدالة الخاسرة أو تعطيل مصطلحات أخرى مثل تنظيم KL. وإذا قيّمت دالة مكافأة أخرى عملية التوليد، فقد لا تزال تحصل على ميزة غير صفرية.
عدم وجود درجات لا يحدد سبب انتهاء الحلقة. إذا كان يجب اعتبار الاستسلام أو بلوغ حد استدعاء الأداة فشلاً في المهمة، فعُدّ مكافأة فشل صريحة من بيئتك أو من دالة المكافأة المخصصة. أما أعطال البنية التحتية أو المُقيِّم فيمكن أن تبقى غير قابلة للتقييم؛ راقب تغطية التقييم إلى جانب متوسط المكافأة.
إذا كنت ترغب في مكافأة مخصصة، فاكتب دالة مكافأة 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,
)يكشف مُكيّف كل تمريرة عن الحالة التشغيلية التي يحتاجها TRL — env.reward، env.rewards، env.metadata، env.finished، env.last_output — لتشكيل المكافآت بعد التنفيذ بشكل تعسفي.
OpenRewardSpec
class 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 )
المعاملات
- target (str) — إما اسم من كتالوج openreward.ai (“Eigent/SETA”) أو عنوان URL يشير إلى أي خادم ORS (”https://you-seta.hf.space”، “http://localhost:8080”). يتم اكتشافه تلقائيًا بناءً على وجود :// في النص.
- num_tasks (int، اختياري) —
الحد الأقصى لعدد المهام التي تُستخرج إلى مجموعة البيانات. استخدام
Noneيعني تضمين جميع المهام التي يوفرها البيئة. - split (str، اختياري، الافتراضي “train”) — قائمة المهام الخاصة بأي تقسيم سيتم السحب منها.
- indices (list[int]، اختياري) —
فهارس المهام المحددة للتدريب عليها. يتعارض مع
num_tasks. مفيد للتصحيح أو لمجموعات المنهج الفرعية. - api_key (str، اختياري) —
تجاوز
OPENREWARD_API_KEY. يُستخدم فقط عندما يكونtargetاسم كتالوج. - secrets (dict[str, str]، اختياري) —
أسرار لكل جلسة تُمرَّر إلى
env.session(secrets=). - env_name (str، اختياري) — تجاوز لاسم البيئة للبحث عنه على الخادم. نادرًا ما يكون مطلوبًا.
- include_metadata (bool، اختياري، القيمة الافتراضية True) —
دمج بيانات الوصف الخاصة بكل مهمة (difficulty، category، tags، …) في صفوف مجموعة البيانات بحيث يمكن لدوال المكافأة قراءتها عبر معامل
inputsفي TRL. - 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، اختياري) —
مؤشر المهمة المستخدم فقط لجلسة الاكتشاف عند تعيينه؛ يتجاوز الاستكشاف متعدد المؤشرات أدناه. عند
إهماله وتعيين
indices=، تفتح عملية الاكتشاف جلسة استكشاف واحدة لكل عنصر مختلف فيindices(مرتبة) وتدمج مواصفات الأدوات بالاسم بحيث تُربط الأدوات الخاصة بالمهام من كل مهمة مدرجة. عند إهماله واستخدامnum_tasks/ وضع القائمة الكاملة، تستكشف المهمة0فقط. يُتجاهل عندdiscover_task_tools=False.
كائن مواصفات واحد يربط بيئة ORS بمدرّب TRL.
القيود
- التكامل موجود في
trl.experimental— قد تتغير واجهات برمجة التطبيقات. اضبطTRL_EXPERIMENTAL_SILENCE=1لكتم التحذير في سجلات CI. - يُعرِّف حاليًا كائن
OpenRewardSpecواحدًا يغطي بيئة واحدة؛ ولا يُدعم التدريب متعدد البيئات (على غرار نمط "البيئة الفوقية" في OpenEnv) بعد. - تتطلب عمليات النشر طويلة الأمد (>15 دقيقة لكل حلقة) نبضة إبقاء نشط — لم يتم ربطها بعد.
مرجع
- المعيار المفتوح للمكافآت
- منصة OpenReward
- وحدة تطوير البرمجيات
openrewardبلغة بايثون - بيئة الإيكو —
trl-internal-testing/openreward-echo-env