الانتقال إلى المحتوى

الأدلة الإرشادية

التجارب عبر الإنترنت (اختبارات A/B)

قالت مقارنتك دون اتصال إن الإصدار الجديد أفضل. يطرح اختبار A/B في بيئة الإنتاج السؤال نفسه على مستخدمين حقيقيين. يوزّع الموجّه الخاص بك الوحدات (المستخدمين أو الجلسات) عشوائيًا بين ذراعين؛ ويقرأ oloproof experiment سجلاته ويجيب بالحالات الأربع نفسها التي تجيب بها كل قاعدة أخرى. قُبلت الطريقة في تدقيق مستقل بشروط معلنة: observed_until هو قولك أنت في وقت استخراج سجل النتائج، ووُزّعت الوحدات عشوائيًا باستقلال، ولا تتوقف نتيجة أي وحدة على ذراع وحدة أخرى، ولم تنجرف النتائج أثناء تغيّر التقسيم، وكل نظرة تقرأ السجل كاملًا. خارج هذه الشروط لا تكون الإجابة مشمولة.

السجلات والإعلان

ملفان، CSV أو JSONL: سجل إسناد بصف واحد لكل وحدة (عمود الوحدة الذي تعلنه، وarm)، وسجل نتائج يضم الوحدة وvalue الخاصة بها.

experiment:
  name: checkout-v2
  unit: user
  allocation: {control: 0.5, treatment: 0.5}
  control: control
  treatment: treatment
  assignments: logs/assignments.csv
  outcomes: logs/outcomes.csv
  kind: rate
  rules:
    - {id: lift, kind: superiority}
    - {id: no-harm, kind: non_inferiority, margin: 0.01}
oloproof experiment experiment.yaml --policy release.yaml --json

يأخذ kind: mean قيمة range: [low, high] معلنة؛ ويقرأ direction: max الأدنى على أنه الأفضل. الوحدة المُسندة التي لا صف نتيجة لها مفقودة، وتُحدّ بأسوأ قيمها من كل جانب، ما لم يقل missing_outcome: zero إن غياب الصف يعني صفرًا. سجّل صفًا لكل وحدة، بما في ذلك الأصفار: سجل التحويلات الذي لا يحتوي إلا على من حوّلوا يقرأ كل وحدة أخرى على أنها مفقودة، ويبقى الجواب INSUFFICIENT_EVIDENCE. يفترض الملء بالأصفار أن نافذة النتيجة لكل وحدة محسوبة قد أُغلقت؛ فالوحدة المُسندة قبل ساعة لم تحوّل بعد، وعدّها صفرًا يحابي الذراع الأسرع تحويلًا. أعلن outcome_window_hours وas_of وobserved_until (وقت استخراج سجل النتائج)، مع عمود assigned_at في سجل الإسناد، فلا تُعدّ إلا الوحدات التي أُغلقت نافذتها بحلول as_of؛ ويُرفض missing_outcome: zero من دونها، أيًّا كانت المراقبة. اكتب كل وقت بإزاحة أو بـ Z (2026-10-11T00:00:00Z)؛ ويُرفض الوقت الذي يخلو منهما. لا يجوز أن يكون as_of بعد observed_until، ولا أن يكون أيّ منهما في المستقبل: فالنتيجة التي تقع بعد الاستخراج ليست في السجل. النافذة تختار السؤال: نافذة من 48 ساعة تجيب عن «حوّل خلال 48 ساعة»، لذا يجب أن تغطي تأخر النتيجة التي تقصدها. تُقارن معرّفات الوحدات نصًا بعد حذف المسافات، ويُقرأ 42.0 على أنه 42. رمز الخروج هو رمز أسوأ قاعدة: 0 PASS، 1 FAIL، 3 INSUFFICIENT_EVIDENCE، 4 MANUAL_REVIEW.

ما يفحصه أولًا

  • نسبة العينة. تُختبر أعداد وحدات الذراعين مقابل التوزيع المعلن (اختبار ثنائي الحدين الدقيق لذراعين، ومربع كاي لأكثر، عتبة 0.001). أي عدم تطابق يجعل كل قاعدة MANUAL_REVIEW: فالتقسيم المعطوب يعني أن الذراعين لم تعودا قابلتين للمقارنة، والمزيد من البيانات من النوع نفسه لا يصلحه. ابحث عن السبب (إعادة توجيه تُسقط مستخدمين، أو مرشح روبوتات مطبّق على ذراع واحدة) قبل قراءة أي فرق.
  • وحدة في ذراعين. تسرّب الإسناد؛ تُقرأ كل قاعدة MANUAL_REVIEW.
  • عدة صفوف نتائج لوحدة واحدة. مرفوض، لأن أحداث المستخدم الواحد ليست مستقلة. أعلن aggregate: unit_mean لتكون متوسط كل وحدة الخاص بها هو نتيجتها: يصبح الجواب حينئذ عن المستخدم المتوسط، لا عن الحدث المتوسط.
  • ذراع فارغة. INSUFFICIENT_EVIDENCE حتى تكون لها نتائج.
  • صفوف نتائج لا تطابق أي وحدة مُسندة، تحت missing_outcome: zero. تعتمد الأصفار على الربط، فالربط المعطوب سيقرأ وحدات حقيقية على أنها أصفار؛ وتقرأ كل قاعدة MANUAL_REVIEW حتى تتطابق المعرّفات. وفي الافتراضي تُعدّ وتُستبعد.

كيف يقرّر

يحصل متوسط كل ذراع على الفترة التي يستخدمها Oloproof بالفعل لتشغيل واحد (Clopper-Pearson الدقيقة للمعدل، والمتوسط المحدود بالمراهنة في غير ذلك)، كلٌّ منها بنصف ميزانية الخطأ، ويُحدّ الفرق بالطرفين المتقابلين للفترتين. وهي صالحة عند أي حجم عينة وأعرض من الفترة الطبيعية في الكتب المدرسية. تنجح قاعدة التفوّق عندما تقع الفترة كلها فوق الصفر؛ وتنجح قاعدة عدم الدونية عندما يكون طرفها الأدنى عند سالب الهامش أو فوقه.

يستخدم monitoring: anytime فترة المراهنة للذراعين، وهي صالحة مهما كان عدد مرات نظرك ومتى توقفت. ويصح ذلك ما دامت كل نظرة تمرّر السجل كله حتى تلك اللحظة: لا تُسقط صفوفًا ولا ترشّحها حسب الفترة بعد قراءتها أبدًا. أما الافتراضي، fixed، فيُقرأ مرة واحدة عند حجم العينة الذي خططت له.

عدة معالجات

أعلن treatments: [b, c] بدل treatment: وأعطِ كل قاعدة المعالجة التي تقارنها (treatment: b). تُؤخذ فترة كل ذراع عند 1 - alpha/m لعدد m من الأذرع، فتُغطّى كل معالجة ناقص الضابطة معًا بحدّ الاتحاد: قاعدة لكل معالجة، وادعاء واحد لكل منها، والعائلة كلها صالحة معًا. وكل فترة أعرض منها مع ذراعين، لأن كل ذراع تدفع ثمن الأخريات. ومع المعالجات المتعددة، يسمّي التقرير الأفضل بين تلك التي تجتاز كل قاعدة تسمّيها، وهل هي منفصلة عن كل معالجة مجتازة أخرى: فكل فرق، محدود بالفترات المتزامنة نفسها، يستبعد الصفر. والتعادلات تحفظ الترتيب المُعلن ولا تُفصل أبدًا. وفحص نسبة العينة يقرأ كل الأذرع أصلًا. ويغطي الضمان المشترك أذرع ملف تجربة واحد: وتوزيع المعالجات على عدة ملفات يتخلى عنه.

مقاييس النسبة

معدل النقر هو النقرات على الجلسات، والمستخدم ذو الجلسات الكثيرة ليس مستخدمين مستقلين كثيرين. أعلن النسبة على صف واحد لكل وحدة، مع نطاقات تقع فيها قيم كل وحدة:

  ratio: {numerator: clicks, denominator: sessions, numerator_range: [0, 50], denominator_range: [1, 50]}
  aggregate: unit_sum   # only if a unit has several rows: they are added

المقدار المقدَّر هو متوسط بسط كل ذراع على متوسط مقامها. ويُحدّ كلا المتوسطين بالفترة المعتمدة، كلٌّ بحصته من ميزانية الخطأ، وتُحدّ النسبة بقسمة طرفيهما، فتكون صالحة عند أي حجم عينة دون تقريب طبيعي. والمقام الذي تبلغ فترته الصفر لا يعطي فترة. والقيمة خارج نطاقها خطأ في الإعداد يسمّي الوحدة، ولا تُقصّ أبدًا. وتُعرض فترة طريقة دلتا، وهي أضيق عادةً، بجانبها ولا تقرّر أبدًا.

متغيّر مصاحب من قبل الاختبار

النتيجة التي تتبع شيئًا قيس قبل الاختبار (إنفاق الشهر الماضي، جلسات الأسبوع الماضي) يقلّ تباينها متى أُزيل ذلك منها. أحضر قيمة كل وحدة من قبل الاختبار ومعاملًا مثبّتًا قبل قراءة نتائج هذا الاختبار:

  covariate: {values: logs/pre_period.csv, range: [0, 500], theta_from: logs/history.csv}

النتيجة المقرَّرة هي Y - theta (X - c). ويُعلن theta (theta:، مع center: اختياري، وهو منتصف النطاق افتراضيًا)، أو يُطابَق على ملف تاريخ من فترة سابقة للاختبار (العمودان covariate وoutcome)، ولا يُطابَق أبدًا على نتائج هذا الاختبار نفسه. ولأن X قيس قبل الإسناد، وتحدّد أيضًا قبل الإسناد أيّ الوحدات لها قيمة X، فللفرق المعدَّل المقدار المقدَّر نفسه. والوحدة التي لا قيمة لها في الملف لا تُعدَّل. وقد يبقى التعديل الصالح أعرض من عدمه، لأن نطاق النتيجة المعدّلة أعرض، لذا يعرض التقرير الفترتين ويقول أيهما أضيق؛ ولا يدّعي أي توفير.

الجِدّة والتداخل، معروضان

يقرأ novelty: {exposure_column: exposed_at, time_column: at, days: 7} أول تعرّض لكل وحدة من سجل الإسناد ووقت كل صف نتيجة، ويعرض الفرق في أول days من التعرّض وما بعدها. والفرق المبكر المقرَّر مع فرق لاحق غير مقرَّر أو معاكس يُسمّى "possibly a novelty effect". ولا يقرّر التقسيم قاعدة أبدًا: تُترك منه الوحدات التي لا صفوف لها في نطاق، ولا تُحدّ عند أسوأ قيمها. ويأخذ نتيجة واحدة لكل صف، لا نسبة ولا متغيّرًا مصاحبًا.

يعدّ cluster_column: team الفرق التي تضم وحدات من عدة أذرع ويسأل ما إذا كانت نتيجة وحدة يمكن أن تعتمد على ذراع وحدة أخرى. وإن أمكن ذلك، فوزّع عشوائيًا بالفريق وأعلنه وحدةً.

اعتُمدت المعالجات المتعددة والنسب والمتغيّرات المصاحبة بتدقيق مستقل وتأكيده في 3 نوفمبر 2026، بالشروط نفسها التي اعتُمد بها الذراعان.

دون اتصال وعبر الإنترنت

سمِّ المقارنة دون اتصال ومقياسها (offline_comparison: <id>، offline_metric: pass_rate) فيُبلغ الجواب ما إذا كان الاتجاهان المقرَّران متفقين. يُبلَّغ هذا ولا يقرّر شيئًا أبدًا: الخلاف سبب للنظر في المجموعة، لا حكم على الإصدار.

مزالق

  • الاختلاس المبكر. قراءة اختبار ذي أفق ثابت كل يوم والتوقف في يوم جيد يضخّم الانتصارات الزائفة. خطّط لحجم العينة، أو أعلن monitoring: anytime.
  • الجِدّة والتعلّم. يتفاعل المستخدمون مع أي جديد، ثم يستقرون. قد يتلاشى تحسّن الأسبوع الأول؛ شغّل الاختبار مدة كافية لتغطية دورات مستخدميك، وأعلن novelty: لترى التقسيم.
  • التداخل. تفترض الفترة أن نتيجة وحدة لا تعتمد على ذراع وحدة أخرى. المخزون المشترك والأسواق والميزات الاجتماعية أو ذاكرة تخزين مؤقت سخّنتها ذراع واحدة تكسر ذلك؛ وعندئذ وزّع عشوائيًا بوحدة أكبر (منطقة، فريق)، وأعلن cluster_column: لترى مدى اختلاط العناقيد.
  • الانجراف تحت تقسيم متغيّر. تفترض الفترة أن التوزيع بقي ثابتًا طوال الاختبار، أو أن النتائج لم تنجرف بينما كان يتغيّر. فالرفع التدريجي من 10% إلى 50%، أو 90/10 ثم 10/90 بين يوم عمل وعطلة نهاية أسبوع، يزن الفترات بشكل مختلف في كل ذراع ويخلط أثرًا زمنيًا بالفرق؛ وفحص نسبة العينة يقرأ أعدادًا مجمّعة فلا يراه. أبقِ التقسيم ثابتًا، أو لا تقرّر إلا على الفترة التي تلي الرفع التدريجي.
  • تغيير الوحدة. وزّع عشوائيًا وحلّل بالوحدة نفسها. توزيع المستخدمين عشوائيًا ثم عدّ الجلسات مستقلة يضيّق الفترة زورًا.

ما لا يمكن أن يخبرك به هذا

  • ما إذا كانت النتيجة صالحة لمستخدمين خارج نافذة الاختبار الزمنية أو منطقته أو حركة مروره.
  • أي شيء عن مقياس لم تعلنه قبل الاختبار؛ المقياس المختار بعد الواقعة وصف.
  • ما إذا كان موجّهك قد وزّع عشوائيًا حقًا: فحص نسبة العينة يلتقط الأعطال الكبيرة، لا الدقيقة.
  • أيّ معالجة أفضل بين تلك التي لم تجتز: لا تُرتَّب إلا المعالجات المجتازة. التوزيع الطبقي وتصاميم التبديل الزمني غير مبنية.