الانتقال إلى المحتوى الرئيسي
الاستراتيجيات المدمجة — الأرخص والجودة والمتوازن والتكيّفي — تختار نموذجًا بحسب السعر والجودة. أمّا لغة التوجيه (Routing DSL) فهي الطبقة الأدنى منها، لحين يعتمد النموذج الصحيح على ماهية الطلب فعلًا: دورة برمجة وكيلية طويلة، أو استدعاء تصنيف رخيص، أو طلب رؤية، أو إعادة محاولة بعد فشل اختبار. أنت تكتب القواعد؛ وتقوم البوّابة بتقييمها لكلّ طلب وتوجّهه تبعًا لذلك. إنها استراتيجية dsl ضمن موجّه مسمّى — فيبقى تطبيقك يستدعي orcarouter/{name}، بينما يعيش منطق التوجيه في لوحة التحكّم، مُؤرشَفًا بالإصدارات وقابلًا للتعديل دون إعادة نشر.

متى تلجأ إلى الـ DSL

استخدم استراتيجية مدمجة حين يلتقط “أرخص نموذج نشط” أو “أعلى جودة” مقصدك. والجأ إلى الـ DSL حين يعتمد التوجيه على محتوى أو سياق الطلب:
  • تخصّص المهام — أرسل الشيفرة إلى نموذج برمجة، والرؤية إلى نموذج رؤية، والمحادثة الرخيصة إلى نموذج رخيص.
  • توجيه واعٍ بالصعوبة — صعّد الطلبات الصعبة فقط إلى نموذج باهظ؛ وأبقِ السهلة منها رخيصة.
  • توجيه واعٍ بالوكيل — وجّه بشكل مختلف بحسب حالة الجلسة (أيّ أدوات استخدمها الوكيل، وهل فشلت الاختبارات للتوّ، وكم عدد الأدوار التي بلغها).
  • قواعد الوقت / المستأجر / الترويسة — توجيه مختلف بحسب الساعة، أو فئة المستخدم، أو ترويسة في الطلب.

تفعيلها

في لوحة التحكّم ضمن التوجيه، افتح موجّهًا واضبط الاستراتيجية على DSL. عندئذٍ يظهر محرّر الـ DSL لهذا الموجّه. ويبقى كلّ ما يخصّ الموجّه ساريًا — نمط glob لـ النماذج المسموح بها، وشبكة أمان النموذج الافتراضي، واستدعاء orcarouter/{name}.

المحرّر

بُني المحرّر لينقلك من المقصد إلى مجموعة قواعد عاملة بسرعة:
  • القوالب مُهيّأة بالنماذج الحقيقية في مساحة عملك أنت (عبر حوار ربط طبقات يُجرى لمرة واحدة)، فلا تبدأ أبدًا من ملف فارغ ولا تصطدم بجدار “نموذج غير معروف”.
  • الإدراج (Insert) — أدرِج نموذجًا أو موجّهًا (orcarouter/<name>) أو مجموعة من الإكمال التلقائي بدلًا من كتابة المعرّفات يدويًا.
  • التوليد (Generate) — صِف التوجيه الذي تريده بلغة طبيعية فتحصل على DSL مُترجَم نظيف من أخطاء التحقّق ومبنيّ على نماذجك الحقيقية.
  • الشرح (Explain) — إعادة صياغة بالإنجليزية البسيطة لما تفعله مجموعة القواعد الحالية.
  • التحقّق المضمّن (Inline lint) — يبلّغ كلّ خطأ عن {line, column, message}، ولكلّ رمز تحقّق شارحٌ بعلامة ?. وتُبرَز الأسبقية (الفوز للمطابقة الأولى) وأنماط CEL الشائعة في موضعها.

بنية الملف

مجموعة القواعد هي YAML بثلاثة مفاتيح عليا:
version: 1              # required — currently must be 1
rules: [...]            # required — 1 to 30 rules, evaluated in order
default: {...}          # required — the effect when no rule matches
القاعدة هي شرط when: وأثر use::
rules:
  - id: hard_code              # required: ^[a-z][a-z0-9_]{0,39}$, unique
    when: |                    # optional CEL boolean; absent ⇒ always matches
      task_class == "code" && difficulty > 0.6
    use:
      model: "anthropic/claude-sonnet-4-6"
default:
  delegate: balanced           # fall back to a built-in strategy
تُقيَّم القواعد من الأعلى إلى الأسفل؛ وتفوز أوّل قاعدة يكون شرط when: فيها صحيحًا. وإن لم تطابق أيّ قاعدة، يُطبَّق default:. رتّب قواعدك من الأخصّ أوّلًا — فقاعدة عامة مبكرة تحجب كلّ ما تحتها.

when: — الشرط

تُكتب الشروط بلغة CEL (Common Expression Language): آمنة بحكم التصميم — بلا حلقات، بلا إدخال/إخراج، تقييم بالميكروثانية، وتعابير نمطية RE2 فقط. وتغطّي هذه الأنماط الستة الغالبية العظمى من القواعد الحقيقية:
النمطالمثال
الوصول إلى حقلtask_class == "agent"
مقارنة عدديةdifficulty > 0.6 && request.input_tokens < 50000
منطق منطقيagent_state.has_edited && !agent_state.has_run_tests
العضوية في قائمة"Edit" in agent_state.tools_used
ماكرو تعبير نمطيsystem_prompt_matches("(?i)planning agent")
ماكرو أدواتtool_calls_present_any(["Edit","Write","apply_patch"])

المتغيّرات

شكل الطلب
المتغيّرالنوع
modelstring
request.input_tokensint
request.output_max_tokensint
request.streambool
request.visionbool
request.message_countint
request.has_system_promptbool
request.has_toolsbool
التصنيف (تحسبه البوّابة لكلّ طلب)
المتغيّرالنوعالمعنى
task_classstringchat / code / agent / vision / audio / rag / creative
difficultydouble0.01.0
code_keyword_densitydouble0.01.0
reasoning_cue_countintإشارات الاستدلال المكتشفة في الطلب
tool_countintتعريفات الأدوات المتمايزة في الطلب
جلسة الوكيل (agent_state.*، تُحفظ عبر المحادثة)
المتغيّرالنوع
agent_state.turnint
agent_state.tools_usedlist<string>
agent_state.files_readlist<string>
agent_state.has_editedbool
agent_state.has_run_testsbool
agent_state.last_test_failedbool
agent_state.consecutive_errorsint
agent_state.elapsed_secondsint
agent_state.models_triedlist<string>
السياق
المتغيّرالنوع
headers["x-foo"]string
user.id / user.groupint / string
token.id / token.nameint / string
time.hour / time.weekdayint (UTC)
workspace.idint

الماكروات

دوال CEL المُسجَّلة لفحوص “النظر داخل الطلب” الشائعة:
الماكرويُعيد
system_prompt_matches(regex)RE2 على رسائل النظام المدمجة
user_message_matches(regex)RE2 على آخر رسالة مستخدم
tool_definitions_include(name)أداة مُعلَنة في الطلب
tool_calls_present_any(list)يحمل الطلب أيًّا من استدعاءات الأدوات هذه
tool_results_from_any(list)يحوي الطلب رسائل بدور أداة من أيٍّ منها
header_matches(name, regex)RE2 على قيمة ترويسة

use: — الأثر

تسمّي كتلة use: وجهة (واحدة بالضبط) وأيّ عدد من المقابض (knobs) الاختيارية لكلّ استدعاء.

الوجهة

use:
  model:    "anthropic/claude-sonnet-4-6"   # one upstream model
  models:   ["openai/gpt-4o-mini", "..."]   # load-balance across a list
  pool:     "@pool:<name>"                   # an admin-curated pool
  delegate: balanced                         # hand off to a built-in
                                             #   strategy: cheapest |
                                             #   quality | balanced |
                                             #   linucb | gated_adaptive
delegate: dsl مرفوض (لأنه سيؤدّي إلى تكرار ذاتي). والتثبيت على قنوات محدّدة (channels: / @channel:) غير متاح حاليًا ويُعلَّم في التحقّق كغير مدعوم — وجّه عبر model أو models أو pool بدلًا من ذلك.

المقابض لكلّ استدعاء

ادمجها مع أيّ وجهة لتشكيل الاستدعاء التصاعدي:
use:
  reasoning_effort:       low | medium | high     # OpenAI o-series, Gemini
  thinking_budget_tokens: 1024..64000             # Claude / Gemini thinking
  samples:                1..16                    # the n parameter
  temperature:            0.0..2.0
  param_override:         { ... }                  # merged into upstream params
  header_override:        { ... }                  # merged into upstream headers
  reason_tag:             "<[a-z0-9_]+>"           # shows up in logs/telemetry
  affinity_ttl:           "5m"                      # channel stickiness window
  model_rewrite:          "<upstream-model>"       # send under a different name
يفرض param_override وheader_override قائمة حظر — فلا يمكنك تجاوز model أو messages أو stream أو tools أو ترويسات المصادقة، إلخ. (فذلك سيقوّض الفوترة أو التدقيق أو حالة الوكيل).

التتالي والمجموعات الواثقة (متقدّم)

أثَران متقدّمان يتيحان لقاعدة أن تتفاعل مع إجابة أولى ضعيفة أو أن تتوزّع عبر عدّة نماذج. ويُكتبان بالطريقة نفسها مثل أيّ قاعدة. التتالي (Cascade) — أعِد المحاولة عند إشارة ثقة منخفضة بأثر أقوى:
rules:
  - id: code_with_repair
    when: task_class == "code"
    use:
      model: "openai/gpt-4o-mini"
    on_low_confidence:
      signals: [patch_invalid, self_doubt, next_turn_test_failed]
      use:
        model: "anthropic/claude-sonnet-4-6"   # repair attempt
المجموعة (Ensemble) — أطلِق عدّة أرجل بالتوازي ودع حَكَمًا يختار:
use:
  parallel:
    - { model: "anthropic/claude-sonnet-4-6" }
    - { model: "openai/gpt-4o-mini", samples: 2 }
  arbiter:
    strategy: best_of_n        # or majority | first | tests_pass
    model:    "anthropic/claude-sonnet-4-6"   # judge (best_of_n only)
  max_latency_ms: 120000
زمن تشغيل المجموعة / التتالي مُقيَّد ومُعطَّل افتراضيًا. ولأنّ كلّ رِجل متوازية وكلّ إصلاح تتالٍ تُفوتَر كاستدعاء مستقلّ، يبقى زمن تشغيل التوزّع خلف راية على الخادم ريثما تُتحقَّق فوترة كلّ رِجل. وعند تعطيله، تُقدّم قاعدة parallel: الرِجل الأولى فقط، ويسجّل التتالي إشارته دون إعادة إرسال — وتبقى مجموعة القواعد تجتاز التحقّق وتُحفظ وتوجّه أثرها الأساسي بشكل طبيعي. تواصل معنا لتفعيل زمن تشغيل المجموعة لمساحة عملك.

الطرح بأمان

لا تستولي مجموعة قواعد جديدة على حركتك لحظة حفظها:
  • وضع الظلّ (Shadow mode) — خلال نافذة بعد أوّل حفظ، يُقيَّم الـ DSL لكن لا يُستخدَم: تبقى استراتيجيتك السابقة تخدم الحركة بينما تسجّل البوّابة ما كان الـ DSL سيفعله. وتعرض لوحة التحكّم تقرير فروق — نسبة المسارات المختلفة، والفارق المتوقّع في التكلفة، وعدد مرّات إطلاق كلّ قاعدة، وكم مرّة سقط إلى default:. اقرأه قبل أن تثق بالقواعد.
  • الكناري (Canary) — صعّد الـ DSL تدريجيًا على نسبة من الحركة الحيّة (5 ← 25 ← 50 ← 100)، مع مراقبة المقاييس لكلّ شريحة، وتراجع فوريًّا بإنزال النسبة إلى 0.
كما يمكنك التشغيل التجريبي (dry-run) لمجموعة قواعد مقابل طلب اصطناعي (صنف المهمة، الصعوبة، حالة الوكيل، شكل الطلب) داخل المحرّر مباشرةً ورؤية الأثر والقاعدة المطابقة — بلا حركة، ودون حفظ أيّ شيء.

الحدود والتحقّق

كلّ حفظ يُجري تحقّقًا صارمًا؛ وتُرفَض مجموعات القواعد غير الصالحة مع {line, column, message, rule}:
  • المخطّط (Schema) — المفاتيح المطلوبة، والأنواع/قيم enum الصحيحة، بلا حقول مجهولة.
  • الحجم — ‏≤ 30 قاعدة، ‏≤ 16 KiB من YAML، ‏≤ 200 حرف لكلّ when:.
  • CEL — يُحلَّل لغويًّا، ويُتحقَّق نوعيًّا مقابل بيئة المتغيّرات، بلا معرّفات مجهولة، ويجب أن يُقيَّم when: إلى bool.
  • الأثر — وجهة واحدة بالضبط لكلّ كتلة use:؛ وكلّ مراجع model / models / @pool: يجب أن تُحلّ في مساحة عملك.
  • نطاقات المقابضthinking_budget_tokens ∈ [1024, 64000]، temperature ∈ [0, 2]، samples ∈ [1, 16].
  • محجوز — معرّفات القواعد التي تبدأ بـ _ محجوزة؛ ويُرفَض default كمعرّف قاعدة (استخدم كتلة default: العليا).
كلّ حفظ وتراجع يكتب سطر تدقيق؛ وتُكتشَف التعديلات المتزامنة، ويُطلَب من الحفظ الثاني إعادة المحاولة مقابل حالة جديدة.

مثال كامل

version: 1
rules:
  - id: vision
    when: request.vision
    use: { model: "openai/gpt-4o" }

  - id: cheap_chat
    when: task_class == "chat" && difficulty < 0.3
    use: { delegate: cheapest }

  - id: hard_code
    when: task_class == "code" && difficulty > 0.6
    use:
      model: "anthropic/claude-sonnet-4-6"
      thinking_budget_tokens: 8000
      reason_tag: hard_code

  - id: agent_after_failed_test
    when: agent_state.last_test_failed && agent_state.consecutive_errors >= 2
    use:
      model: "anthropic/claude-sonnet-4-6"
      reason_tag: repair

default:
  delegate: balanced
للتأكّد من النموذج الذي حلّ إليه الطلب، اقرأ ترويستَي الاستجابة X-Orca-Router وX-Orca-Resolved-Model ترويسات الاستجابة.

مرجع API

يُدار الـ DSL لكلّ موجّه؛ وتتطلّب الكتابة صلاحية Developer+.
الطريقة والمسارالدورالغرض
GET /api/user/routers/:id/dslMemberالمصدر + الإصدار + حالة الظلّ/الكناري.
PUT /api/user/routers/:id/dslDeveloper+تحقّق + حفظ (إصدار جديد، مُدقَّق).
POST /api/user/routers/:id/dsl/lintMemberتحقّق من مسوّدة ← {errors:[…]}.
POST /api/user/routers/dsl/lintMemberتحقّق عديم الحالة (بلا معرّف موجّه).
POST /api/user/routers/:id/dsl/dryrunMemberتقييم طلب اصطناعي ← أثر + قاعدة مطابقة.
GET /api/user/routers/:id/dsl/historyMemberسجلّ الإصدارات، الأحدث أوّلًا.
POST /api/user/routers/:id/dsl/rollback/:versionDeveloper+إعادة تحقّق واستعادة إصدار أقدم.

الأسئلة الشائعة

إنها استراتيجية فعلًا — خيار dsl إلى جانب الأرخص / الجودة / المتوازن / التكيّفي. الأخرى تختار بحسب السعر والجودة؛ أمّا الـ DSL فيختار بحسب قواعد تكتبها أنت على شكل الطلب وتصنيفه وحالة الوكيل. ويبقى بإمكانك التفويض delegate: إلى استراتيجية مدمجة كأثر لقاعدة أو كافتراضي.
يُطبَّق أثر default: العلوي. وهو مطلوب، لذا يوجد دائمًا نتيجة محدّدة — وغالبًا delegate: balanced أو نموذج شبكة أمان محدّد.
نعم. يعمل CEL في صندوق رمليّ بدوال المكتبة القياسية فقط، ومهلة تقييم من بضعة ملّي ثانية، وتعابير نمطية RE2 (بزمن خطّي، بلا ReDoS)، وبلا وصول إلى قاعدة البيانات أو الشبكة أو نظام الملفّات. بيئة المتغيّرات مجموعة ثابتة من القيم القياسية والقوائم.
بثلاث طرق: التشغيل التجريبي (dry-run) مقابل طلب اصطناعي في المحرّر، وتركها في وضع الظلّ وقراءة تقرير الفروق، ثم الكناري بنشرها على نسبة صغيرة من الحركة الحيّة قبل التصعيد إلى 100%.