Prompty

موجِّهات (prompts) تنشر مثل الشيفرة: بإصدارات وتقييم واختبار A/B

يتعامل Prompty مع الموجِّه بوصفه أصلًا برمجيًّا له إصدارات، لا سلسلة نصية يعدلها أحدهم في بيئة الإنتاج ثم ينتظر الشكاوى. كل إصدار يقيم على مجموعة مرجعية (golden set) بنموذج تحكيم، وهو نموذج لغوي كبير (LLM)، قبل أن يسمح بنشره، ثم يعرض على حصة من حركة المستخدمين الحقيقية ويحكم عليه بالإحصاء. والنشر والتراجع عملية واحدة: نقل وسم.

النوع
مشروع شخصي، 2026، من تصميمي وتنفيذي بالكامل
المكونات
خدمة FastAPI، و SDK بلغة Python، ولوحة متابعة بـ React
الإحصاء
فترات Wilson، اختبار z، اختبار t لـ Welch، اختبار t المزدوج (paired)، تحليل القوة الإحصائية، فحص SRM
النماذج
أي نقطة وصول متوافقة مع OpenAI، أو نموذج وهمي حتمي (mock)
الاختبارات
151 دالة اختبار (pytest)، مع التحقق من الإحصاءات بالمحاكاة

نسخة أولية تعمل محليًّا: مستخدم واحد، دون مصادقة. بياناتها التجريبية يولدها نموذج وهمي حتمي (mock)، فهي تبين الآلية لا جودة أي نموذج.

إكمال واحد (completion)، من البداية إلى النهاية

التطبيقات تستدعي Prompty بدل النموذج. استدعاء واحد يحدد الإصدار الذي يحصل عليه هذا المستخدم، ويملأ قالبه، ويستدعي النموذج، ويسجل كل ما ستحتاج إليه التجربة لاحقًا.

طلب حي واحد عبر SDK
استدعاء SDK الموجِّه + المستخدم تحديد الهدف تجربة أو وسم تعيين البديل خانة hash ثابتة ملء القالب {{variables}} فقط استدعاء النموذج متوافق مع OpenAI سجل الإكمالات التكلفة والرموز والزمن الاستجابة نص، بديل، تكلفة استدعاء SDK الموجِّه + المستخدم تحديد الهدف تجربة أو وسم تعيين البديل خانة hash ثابتة ملء القالب {{variables}} فقط استدعاء النموذج متوافق مع OpenAI سجل الإكمالات التكلفة والرموز والزمن الاستجابة نص، بديل، تكلفة
  • إدخال أو إخراج
  • استدعاء LLM
  • شيفرة
  • مخزن بيانات
  1. استدعاء SDK client.complete("support-reply", variables={"message": "My order never arrived"}, unit_id="user-42")
  2. تحديد الهدف توجد تجربة جارية على support-reply، فهي التي تحدد الإصدار. ولولاها لحدده الوسم «production».
  3. تعيين البديل الخانة = sha256(experiment:unit) mod 10,000، ثم تمرر على أوزان البدائل المعبر عنها بنقاط الأساس. ويجري حفظ التعيين، فيبقى user-42 على البديل نفسه حتى لو تغيرت الأوزان.
  4. ملء القالب استبدال بسيط لـ {{name}} دون أي منطق قوالب. والمتغير الناقص يقابل بالخطأ 422، لا بموجِّه نصف مملوء.
  5. استدعاء النموذج النموذج والإعدادات الخاصة بالبديل نفسه. تجاوز حد المعدل وأخطاء الاتصال تسجل بالحالة «error» بدل أن ترفع استثناء؛ وحجب المحتوى يسجل «refusal».
  6. سجل الإكمالات صف واحد في جدول الإكمالات الوحيد، مسعر لكل مليون رمز (token) وموسوم بـ source = live. واستدعاءات التقييم والتحكيم تشاركه الجدول نفسه بقيمة source خاصة بها.
  7. الاستجابة النص والبديل والرموز والتكلفة وزمن الاستجابة. ولاحقًا تربط client.track()‎ النتيجة، إعجابًا كانت أو رقمًا، بالبديل نفسه.

مسارات أخرى في المخطط

  • لا تجربة جارية: وسم النشر هو الذي يختار الإصدار، ولا يخزن شيء.
  • لا معرف للوحدة (unit id): سحب عشوائي لا يحفظ.
  • خطأ من المزود: يعاد الإكمال المسجل داخل استجابة 502، فيرى المستدعي ما جرى تسجيله.

من إصدار جديد إلى الإنتاج

على كل إصدار أن يجتاز اختبارين مختلفين: خارج الإنتاج (offline)، أمام إجابات سبق الحكم بجودتها؛ وفي الإنتاج (online)، أمام حركة المستخدمين الحقيقية. وأي منهما قد يوقفه.

إصدار واحد من موجِّه في طريقه إلى الإنتاج
إصدار جديد غير قابل للتعديل تقييم offline مجموعة مرجعية + تحكيم بوابة النشر اختبار t المزدوج تجربة A/B تقسيم ثابت للمستخدمين النتائج SRM، اختبار z، Welch الإنتاج ينتقل الوسم إصدار جديد غير قابل للتعديل تقييم offline مجموعة مرجعية + تحكيم بوابة النشر اختبار t المزدوج تجربة A/B تقسيم ثابت للمستخدمين النتائج SRM، اختبار z، Welch الإنتاج ينتقل الوسم
  • إدخال أو إخراج
  • استدعاء LLM
  • شيفرة
  • فحص أو بوابة
  1. إصدار جديد الإصدار v3 من support-reply. الإصدارات لا تتغير بعد إنشائها؛ والوسوم مؤشرات إليها.
  2. تقييم offline كل حالة مرجعية تمرر على v3، خمس حالات في كل مرة، ثم يمنح نموذج التحكيم الإجابة درجة من 1 إلى 5 وفق سلم تقييم مطلق، لا بمقارنة إجابتين جنبًا إلى جنب، وهذا يجنب انحياز الموضع.
  3. بوابة النشر مقارنة حالة بحالة مع الإصدار الموجود في الإنتاج: اختبار t المزدوج على 5 حالات مشتركة على الأقل. ولا يمنع النشر إلا انخفاض دال إحصائيًّا؛ أما غياب الدليل فلا يمنعه أبدًا.
  4. تجربة A/B تقسم حركة المستخدمين بأوزان معبر عنها بنقاط الأساس، مع بقاء كل مستخدم في مجموعته، وحجم عينة يحدد مسبقًا بتحليل القوة الإحصائية.
  5. النتائج فترات Wilson لكل بديل، واختبار z مجمع (pooled) للنسب، واختبار t لـ Welch للمقاييس المتصلة. وعدم تطابق نسب العينة (SRM) عند p < 0.001 يلغي كل إشارة «دال إحصائيًّا»؛ وضوابط الحماية على التكلفة وزمن الاستجابة ومعدل الأخطاء ترصد أي تدهور.
  6. الإنتاج إنهاء التجربة ينقل وسم الإنتاج إلى البديل الفائز. وإذا سجل أحد ضوابط الحماية تدهورًا رفض النقل بالخطأ 409 ما لم يفرض يدويًّا، وهذا هو التجاوز البشري الوحيد.

مسارات أخرى في المخطط

  • فشل بوابة النشر: يرفض النشر ويبقى الوسم حيث كان.
  • أقل من 5 أحداث في خانة: لا يعتد باختبار z، وينتقل ضابط حماية معدل الأخطاء إلى اختبار Fisher الدقيق.

إحصاءات مختارة عن قصد

منصة اختبارات A/B لا تكون أصدق من اختباراتها. وكل اختيار هنا يرد على طريقة بعينها تضلل بها التجارب.

  • خطأ معياري مجمع للاختبار، وغير مجمع للفترة

    يستخدم اختبار z الخطأ المعياري المجمع (pooled)، كما تقتضي فرضية العدم؛ أما فترة الثقة للفرق فتستخدم الخطأ غير المجمع. ونسبة كل بديل تحصل على فترة Wilson خاصة بها، وهي فترة تبقى معقولة قرب 0 و1.

  • اختبار مزدوج حين تكون الحالات مشتركة

    تشغيلات التقييم خارج الإنتاج تقيم الحالات المرجعية نفسها، فالمقارنات مزدوجة. وفي مجموعة الاختبارات، تعطي 40 حالة مشتركة p < 0.001 بالاختبار المزدوج، مقابل p > 0.05 بالاختبار غير المزدوج على الدرجات نفسها.

  • عدم تطابق نسب العينة أولًا

    إذا أعطى تقسيم 50/50 نسبة 45/55 فالتعيين معطوب وكل رقم يأتي بعده مشكوك فيه. يعمل هذا الفحص ابتداء من 100 مشاهدة عند p < 0.001، وإذا أطلق إنذاره أسكت كل إشارات الدلالة الإحصائية.

  • ضوابط حماية إلى جانب الهدف

    البديل الذي يفوز في الإعجابات لكنه أعلى تكلفة أو أبطأ أو أكثر إخفاقًا ينبه إليه. والتكلفة وزمن الاستجابة يشترط فيهما معًا تدهور نسبي بمقدار 10% ودلالة إحصائية.

  • قيم مجمعة، لا صفوف

    وحدة الإحصاء لا تصل إلى قاعدة البيانات. يغذيها استعلام GROUP BY واحد، فتكلفة نقطة وصول النتائج واحدة مهما كان حجم حركة المستخدمين.

  • تحقق بالمحاكاة

    حساب القوة الإحصائية مختبر بالمحاكاة: 20,000 تشغيل تعطي قوة في حدود 0.02 من 0.80، وفي غياب أي أثر حقيقي يبقى معدل الإيجابيات الكاذبة في حدود 0.01 من 0.05.

خيارات هندسية

  • جدول واحد لكل الاستدعاءات

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

  • النشر والتراجع عملية واحدة

    الإصدارات غير قابلة للتعديل والوسوم تشير إليها. والتراجع ليس إلا إعادة الوسم إلى موضعه السابق.

  • تعيين ثابت، ومحفوظ

    التعيين ناتج hash للتجربة والمستخدم، ويحفظ عند أول ظهور، فيصمد أمام تغيير الأوزان. وإذا تسابق طلبان أولان للمستخدم نفسه، حسم الأمر للصف المحفوظ.

  • الأخطاء بيانات

    إخفاقات المزود تسجل كأي إكمال، فيتمكن ضابط حماية معدل الأخطاء من رصد بديل يخفق أكثر من غيره.

  • نماذج تحكيم غير قابلة للتعديل

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

  • الفشل عند بدء التشغيل، لا في الفاتورة

    اسم مزود غير معروف يوقف الخدمة عند بدء التشغيل، فلا يمكن لخطأ مطبعي أن ينتهي إلى نقطة وصول مدفوعة.

التقنيات

الواجهة الخلفية
Python، FastAPI، async SQLAlchemy، SQLite (WAL)، Pydantic settings
الإحصاء
SciPy، NumPy
LLM
SDK متوافق مع OpenAI، نموذج تحكيم LLM بمخرجات JSON، مزود وهمي حتمي (mock)
SDK
عميل Python مبني على httpx
الواجهة الأمامية
React 19، TanStack Query، React Router، Radix، Tailwind CSS 4، Vite
الجودة
pytest، pytest-asyncio، اختبارات محاكاة للإحصاءات

هل تبني شيئًا مشابهًا؟

يسعدني أن أشرح التصميم والمفاضلات، أو ما سأغيّره في الخطوة التالية.