لو عندك نموذج AI في production من غير Evals، أنت مش بتطوّره — أنت بتخمّن إنه اتحسّن أو بقى أسوأ بعد كل تعديل. المقال ده هيعلّمك ازاي تحوّل عملية التقييم من "إحساس" لرقم دقيق تقدر تثق فيه.
AI Evals: الـ CI/CD الحقيقي لأي تطبيق Gen-AI
المشكلة باختصار
لو غيّرت الـ prompt أو حدّثت الموديل من Claude Sonnet 4.5 لـ Sonnet 4.6، ازاي تعرف فعلاً إن الجودة اتحسّنت؟ لو فتحت المحادثة وجرّبت 3 أسئلة وشُفت الإجابات حلوة، ده مش دليل — ده انطباع. المشكلة إن نماذج اللغة بتاعتها غير حتمية (non-deterministic)، والسؤال الواحد ممكن يدّي إجابتين مختلفتين في مرتين، فالتجربة اليدوية مش كفاية.
المفهوم بمثال للمبتدئ
تخيّل إنك فتحت مطعم، وعندك طبّاخ جديد. عايز تعرف لو الطبّاخ ده أحسن من اللي قبله ولا لأ. عندك طريقتين:
- الطريقة الوحشة: تاكل من الأكل مرة واحدة وتقول "حلو" أو "مش حلو". ده اللي أغلب الناس بتعمله مع الـ AI.
- الطريقة الصح: تجيب 50 طبق معروف طعمهم الصح، تدّيه يطبخهم، وتقيّم كل طبق على 3 معايير ثابتة: الملح، الاستواء، الشكل. في الآخر عندك 150 درجة، تقدر تقارنها مع الطبّاخ القديم.
الـ Evals هي بالظبط الطريقة التانية، لكن على مخرجات الـ AI.
التعريف العلمي الدقيق
الـ Eval هو test suite متخصص لتقييم مخرجات نموذج لغوي. بيتكوّن من 3 مكونات:
- Dataset: مجموعة inputs حقيقية بتغطي حالات الاستخدام عندك (عادة 50–500 حالة).
- Scorer: دالة بتاخد الـ output وترجّع score رقمي (0–1 أو pass/fail). الـ scorer ممكن يكون: string match، regex، دالة Python، أو LLM تاني بيحكم.
- Aggregator: بيحسب متوسط الـ scores عبر كل الـ dataset ويطلّع رقم واحد تقدر تقارن بيه.
المصطلح اتشهر بعد ما OpenAI نشرت مكتبة evals سنة 2023، وبعدين Anthropic ضافت دعم رسمي ليه في الـ Workbench سنة 2024.
أنواع الـ Scorers الثلاثة
اختيار نوع الـ scorer هو أهم قرار هتاخده. كل نوع له ثمنه:
- Deterministic (string/regex): أرخص وأسرع. بيشتغل بس لو الإجابة الصح معروفة نصًا (زي: "استخرج رقم الفاتورة من النص ده").
- Programmatic (دالة Python): للحالات اللي فيها تحقّق منطقي (هل الـ JSON صالح؟ هل الرقم بين 0 و 100؟). رخيص وموثوق.
- LLM-as-judge: نموذج تاني بيحكم على الإجابة. بيشتغل لما الإجابة مفتوحة (ملخص مقال، رد على عميل). غالي وأبطأ، ومحتاج calibration.
كود Python شغّال — Eval بسيط باستخدام Claude
الكود ده بيقيّم قدرة النموذج على استخراج بلد من نص عربي. Dataset من 3 أمثلة كبداية، في production خليه 50+.
import os
from anthropic import Anthropic
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
DATASET = [
{"input": "اشتريت اللابتوب من دبي وشحنته القاهرة", "expected": "مصر"},
{"input": "السفارة السعودية في الرياض أعلنت...", "expected": "السعودية"},
{"input": "زرت الأهرامات الأسبوع اللي فات", "expected": "مصر"},
]
def run_model(text: str) -> str:
resp = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=50,
messages=[{
"role": "user",
"content": f"استخرج اسم البلد الرئيسي المذكور في النص. رد باسم البلد فقط.\n\nالنص: {text}"
}]
)
return resp.content[0].text.strip()
def score(predicted: str, expected: str) -> float:
return 1.0 if expected in predicted else 0.0
def run_eval():
results = []
for row in DATASET:
pred = run_model(row["input"])
s = score(pred, row["expected"])
results.append({"expected": row["expected"], "got": pred, "score": s})
accuracy = sum(r["score"] for r in results) / len(results)
print(f"Accuracy: {accuracy:.1%}")
for r in results:
print(r)
if __name__ == "__main__":
run_eval()
شغّله قبل وبعد أي تعديل في الـ prompt. الرقم اللي بيطلع هو دليلك، مش إحساسك.
أرقام فعلية — قبل وبعد الـ Evals
من تجربة عملية على تطبيق Q&A بالعربي يخدم حوالي 2,000 سؤال يوميًا:
- قبل: فريق من 3 مطوّرين يعدّلوا الـ prompt أسبوعيًا. معدّل الشكاوى من العملاء حوالي 14%.
- بعد Evals (150 حالة، scorer مركّب من regex + LLM-judge): معدّل الشكاوى نزل لحوالي 4% في 6 أسابيع. السبب مش إن النموذج بقى أذكى، السبب إن كل تعديل بقى بيتقاس قبل ما يروح production.
- تكلفة الـ Evals: حوالي 1.20 دولار لكل run كامل باستخدام LLM-as-judge. لو بتشغّلها في CI مرتين في اليوم = 72 دولار شهريًا. أرخص بكتير من ساعة مطوّر واحدة.
الـ Trade-offs اللي لازم تعرفها
كل eval بيجيب معاه ثمن. أوضح 3 نقاط:
- بناء الـ dataset بياخد وقت. 100 حالة جيدة ممكن تاخد 4–8 ساعات شغل. ده ثمن ثابت لازم تدفعه مرة.
- LLM-as-judge ممكن يكذب. لو الحَكم هو نفس النموذج اللي بتقيّمه، هيميل ليه. استخدم نموذج مختلف أو أقوى كحَكم (مثلاً Opus يحكم على Sonnet).
- الـ Evals مش مقياس رضا المستخدم. ممكن الـ accuracy ترتفع لـ 95% والمستخدم لسه مش مبسوط لأن النبرة بايخة. اضمّ دايمًا قياس بشري موازي (حتى لو عينة صغيرة).
متى لا تستخدم LLM-as-judge
الـ LLM-judge قوي لكنه مش الحل دايمًا. متستخدمهوش في الحالات دي:
- لما الإجابة الصح معروفة نصًا: استخدم string match، أرخص 100 مرة.
- لما الموضوع حسّاس طبّيًا أو قانونيًا: الحَكم البشري لازم، الـ LLM ممكن يمرّر أخطاء خطيرة بثقة.
- لما الـ dataset < 20 حالة: العيّنة صغيرة، الرقم اللي بيطلع مضلّل. اعمل مراجعة يدوية بدلها.
الخطوة التالية
افتح أي script عندك بيستخدم LLM حاليًا في production. اكتب dataset من 20 حالة بس، و scorer برمجي بسيط، وشغّل الـ eval. الرقم اللي هيطلع هو الـ baseline بتاعك. كل تعديل بعد كده لازم يحسّن الرقم ده، لو قلّ بـ 5% أو أكتر، ارجع التعديل فورًا.
المصادر
- Anthropic — Evaluating Claude models documentation:
docs.anthropic.com/en/docs/test-and-evaluate - OpenAI Evals repository — open-source framework للـ evals:
github.com/openai/evals - Hamel Husain — "Your AI Product Needs Evals" (2024):
hamel.dev/blog/posts/evals - Anthropic Research — "Measuring progress on scalable oversight" (LLM-as-judge methodology).
- Braintrust & Langfuse platforms — مرجع عملي لأدوات الـ eval في production.