انتقل إلى المحتوى الرئيسي

الوحدة 9 — التقييم المنهجي للتعليمة

في الوحدات السابقة اقترحنا كلّ تحسين مع فكرة أنّه «يجعل النموذج أفضل». تُقدّم هذه الوحدة الأداة التي تحوّل هذه الفكرة من رجاء إلى قياس، ومن قياس إلى قرار: جملة اختبار مُوسَمة، وعمليّة تقييم مُؤتمَتة، ومقارنة بأدلّة رقميّة بين نُسَخ التعليمة.

بدون جملة اختبار، لا تعليمة قابلة للاعتماد

مشكلة هندسة التعليمات الأكثر خطورة ليست تقنيّة، بل ثقافيّة. المهندسون معتادون على وحدات اختبار (unit tests) في الشيفرة التقليدية، لكنّهم يكتبون تعليماتهم للنماذج ثم يجرّبونها على مثالين أو ثلاثة، ويعلنون النجاح. المثالان بعد ذلك يصيران بيئة الاختبار، وكلّ تعديل «يُحسِّن» بمعنى: يُنجح المثالين نفسهما، ولا شيء آخر.

النتيجة معروفة في الميدان: تعليمة تعمل جيّدًا في العرض، وتتعثّر أوّل مرّة في الإنتاج على مُدخَل لم يتخيّله المهندس. الحلّ ليس سرًّا: بناء جملة اختبار قبل تعديل التعليمة، لا بعده.

بناء جملة اختبار مُوسَمة

في الفيل الأحمر، نجمع 50 رسالة عميل حقيقيّة (بعد إخفاء الهُويّة). لكلّ رسالة، نُوثِّق يدويًّا الحقول الأربعة المتوقَّعة: sujet، produit، urgence، action. هذا العمل يستغرق ساعتين إلى أربع، ويُثمر أثمن أصل في مشروع هندسة تعليمات.

قواعد بناء الجملة:

  • تنوّع في المصادر: لا تأخذ كلّ الرسائل من قناة واحدة أو من فترة زمنيّة قصيرة.
  • تنوّع في الصعوبة: ضمِّن رسائل واضحة، ورسائل ملتبسة، ورسائل بحقول ناقصة، ورسائل تحوي حالتين في آنٍ.
  • حالات حدّية: أضِف رسائل قصيرة جدًّا (سطر واحد)، ورسائل طويلة جدًّا (فقرات عدّة)، ورسائل تحوي دارجة.
  • عيّنات من أخطاء الإنتاج: كلّما ظهر خطأ في الإنتاج، أضِف مُدخَله إلى الجملة. الجملة تنمو مع الوقت.

نُخزِّنها في ملف بسيط:

import json
from pathlib import Path

# jeu_test.jsonl : سطر واحد لكلّ حالة
{"email": "طلبتُ الجهاز منذ...", "attendu": {"sujet": "retard", "produit": "ترموستات", "urgence": "haute", "action": "التسليم قبل الجمعة"}}
{"email": "الفاتورة تحتوي...", "attendu": {"sujet": "facture", "produit": None, "urgence": "moyenne", "action": "مراجعة الفاتورة"}}

مقاييس لكلّ حقل، لا مقياس واحد

الغلطة الأخرى الشائعة: قياس «نسبة الحالات الصحيحة كليًّا». هذا مقياس غير مفيد لأنّه يُخفي أين الخطأ. الحقول الأربعة لها طبائع مختلفة، وتستحقّ مقاييس مختلفة.

الحقلنوعهالمقياس
sujetتصنيف من 4 أصنافالدقّة (accuracy)، ومصفوفة الالتباس
urgenceترتيبي من 3 مستوياتالدقّة، ومتوسّط الخطأ المطلق برتبة
produitاستخراج + nullالدقّة الصارمة، ونسبة الاسترجاع (recall)
actionنصّ حرّتطابق دلالي (نموذج ثانٍ يحكم)

الحقل action هو الأصعب. لا يمكن مقارنة نصوص حرّة بمساواة سلاسل بسيطة، لأنّ صياغتين مختلفتين قد تكونان مكافئتين معنى. الحلّ العملي هو حكم LLM (llm-as-judge): نموذج ثانٍ يستقبل الجواب المتوقَّع والجواب الفعلي، ويُصنِّف الفعلي «مكافئ» أو «مختلف». يظلّ هذا الحكم متحيّزًا، لكنّه أفضل بكثير من مقارنة الحروف.

سكربت تقييم بسيط

import json
from pathlib import Path

def evaluer(chemin_jeu: str, extraire) -> dict:
stats = {"total": 0, "sujet_ok": 0, "urgence_ok": 0, "produit_ok": 0, "action_ok": 0}
erreurs = []

for ligne in Path(chemin_jeu).read_text(encoding="utf-8").splitlines():
cas = json.loads(ligne)
stats["total"] += 1
try:
predit = extraire(cas["email"]).model_dump()
except Exception as e:
erreurs.append({"email": cas["email"][:80], "erreur": str(e)})
continue

attendu = cas["attendu"]
if predit["sujet"] == attendu["sujet"]:
stats["sujet_ok"] += 1
if predit["urgence"] == attendu["urgence"]:
stats["urgence_ok"] += 1
if predit["produit"] == attendu["produit"]:
stats["produit_ok"] += 1
# action évaluée avec un juge séparé
stats.setdefault("cas_action", []).append((attendu["action"], predit["action"]))

return {"stats": stats, "erreurs": erreurs}

هذا السكربت يستغرق دقائق للتنفيذ على 50 حالة، ويعطي أرقامًا يمكن التصرّف بناءً عليها.

مقارنة A/B بين نُسَخ التعليمة

الاستعمال الأهمّ للتقييم: مقارنة نسختين من التعليمة قبل تبنّي إحداهما. نُسمّي النسخة القائمة A والنسخة المرشَّحة B. نُطلقهما على نفس جملة الاختبار، ونقارن المقاييس حقلًا بحقل.

resultats_a = evaluer("jeu_test.jsonl", extraire_avec_prompt_a)
resultats_b = evaluer("jeu_test.jsonl", extraire_avec_prompt_b)

print(f"sujet: A={resultats_a['stats']['sujet_ok']}/50 B={resultats_b['stats']['sujet_ok']}/50")
print(f"urgence: A={resultats_a['stats']['urgence_ok']}/50 B={resultats_b['stats']['urgence_ok']}/50")

القاعدة الحاسمة: قِس فرقًا معنويًّا، لا تقلّبًا عشوائيًّا. على 50 حالة، فرق بحالتين لا يعني الكثير. فرق بست حالات فأكثر (12%) يستحقّ الاعتبار. لتقييم أدقّ، أعِد التجربة ثلاث مرّات مع seed مختلف (أو temperature > 0)، وخذ المتوسّط.

قاعدة عمليّة أخيرة: حسِّن فقط ما تقيسه. إن كانت تعليمتك تسجّل 96% في sujet و72% في produit، لا تنفق ساعات على تحسين sujet من 96% إلى 97%. حسِّن produit، فهذا حيث الخطأ الأكبر يسكن.

اكتشاف الانحدار بعد تغيير النموذج

سيناريو حاسم: مزوّد نموذجك يُصدر نسخة جديدة (gpt-4o صار gpt-4.1). التغيير قد يُحسِّن كثيرًا، وقد يكسر تعليمة كنت راضيًا عنها. جملة الاختبار هي أداتك لكشف ذلك في دقائق، لا في اكتشاف تشكّي عملاء بعد أسابيع.

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

كلفة التقييم

الاعتراض المتوقّع: التقييم مكلف. صحيح جزئيًّا. 50 حالة × 2 نداء (استخراج + حكم) × نموذج بسعر 0.30 دينار لكلّ مليون جَتون يعطي كلفة بضعة دنانير للجولة الواحدة. ليس مجّانًا، ليس فلكيًّا.

قواعد الاقتصاد:

  • لا تُطلق التقييم بعد كلّ تعديل صغير. اجمع تعديلاتك، ثم قِس.
  • جملة اختبار صغيرة تكفي في البداية. 50 حالة كافية لالتقاط الاتّجاهات الكبرى. 500 حالة تصير ضروريّة حين تُقارب الدقّة العالية.
  • استخدم نموذجًا أرخص للحكم. gpt-4o-mini يقوم بحكم llm-as-judge مقبول بعُشر ثمن gpt-4o.
حذار من الملاءمة على جملة الاختبار

إن كرّرت تعديل التعليمة على أساس نتائج جملة الاختبار عشرات المرّات، ستُنتج تعليمة تُتقن جملة الاختبار دون أن تُعمّم على الإنتاج. الحلّ: احتفظ بجملة اختبار مُبقاة (held-out) لا تلمسها إلّا نادرًا. جملة تعمل عليها يوميًّا (dev)، وجملة تلمسها كلّ شهر لتُصادِق على الحال (test).

اجعل التقييم جزءًا من CI

اربط سكربت التقييم بأنبوب النشر: كلّ تعديل للتعليمة يُشغّل جملة الاختبار آليًّا، وينشر النتائج. إن انحدرت المقاييس، لا تُدمَج التغييرات. هذا يُحوِّل التقييم من ممارسة اختياريّة إلى بوّابة نشر إلزاميّة.

في الخلاصة

  • بدون جملة اختبار مُوسَمة، لا يُمكن تحسين تعليمة تحسينًا مبنيًّا على أدلّة.
  • استعمِل مقياسًا لكلّ حقل؛ المقياس الكلّي يخفي أين الخطأ.
  • قِس فرق نسختين على نفس الجملة؛ الفروق دون 10% على 50 حالة ضجيج.
  • حذار من الملاءمة على جملة الاختبار؛ افصِل dev عن test كما في التعلّم الآلي.

الوحدة التالية: كيف نُنظِّم كلّ ما بنيناه في مكتبة تعليمات قابلة لإعادة الاستخدام مع نُسَخ ومراجعة أقران.