تقييم واختبار RAG
مقاييس تقييم RAG
3 دقيقة للقراءة
تقييم أنظمة RAG يتطلب مقاييس تتجاوز دقة التعلم الآلي التقليدية. تحتاج لقياس جودة الاسترجاع وأمانة التوليد معاً.
تحدي تقييم RAG
المقاييس التقليدية لا تلتقط إخفاقات RAG المحددة:
# المقاييس التقليدية تفتقد مشاكل حرجة:
# السيناريو 1: درجة BLEU عالية، لكن حقائق مُهلوَسة
generated = "الشركة تأسست في 2015 بواسطة جون سميث"
reference = "الشركة تأسست في 2015 بواسطة جين سميث"
# BLEU: 0.85 (يبدو جيداً!)
# الواقع: اسم مؤسس خاطئ (خطأ حرج)
# السيناريو 2: درجة BLEU منخفضة، لكن صحيحة واقعياً
generated = "جين سميث أسست العمل في 2015"
reference = "الشركة تأسست في 2015 بواسطة جين سميث"
# BLEU: 0.42 (يبدو سيئاً!)
# الواقع: نفس الحقائق، صياغة مختلفة (مقبول)
التقييم المبني على المكونات
أنظمة RAG لديها ثلاثة مكونات للتقييم:
┌─────────────────────────────────────────────────────────────┐
│ إطار تقييم RAG │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ جودة │───▶│ جودة │───▶│ جودة │ │
│ │ الاسترجاع │ │ السياق │ │ التوليد │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ • استدعاء السياق • الصلة • الأمانة │
│ • دقة السياق • نسبة الضوضاء • صلة الإجابة │
│ • MRR, NDCG • التغطية • الصحة │
│ │
└─────────────────────────────────────────────────────────────┘
مقاييس الاسترجاع
دقة السياق
تقيس إذا كانت المستندات المسترجعة ذات صلة:
def context_precision(retrieved_contexts: list, relevant_contexts: list) -> float:
"""
ما نسبة السياقات المسترجعة ذات الصلة فعلاً؟
دقة عالية = مستندات غير ذات صلة قليلة مسترجعة
دقة منخفضة = مستندات كثيرة غير ذات صلة تلوث السياق
"""
relevant_retrieved = set(retrieved_contexts) & set(relevant_contexts)
if not retrieved_contexts:
return 0.0
return len(relevant_retrieved) / len(retrieved_contexts)
# مثال
retrieved = ["doc1", "doc2", "doc3", "doc4", "doc5"]
relevant = ["doc1", "doc3", "doc7"]
precision = context_precision(retrieved, relevant)
# النتيجة: 2/5 = 0.4 (فقط 2 من 5 مستندات مسترجعة ذات صلة)
استدعاء السياق
يقيس إذا تم استرجاع كل المعلومات ذات الصلة:
def context_recall(retrieved_contexts: list, relevant_contexts: list) -> float:
"""
ما نسبة السياقات ذات الصلة التي تم استرجاعها؟
استدعاء عالي = كل المعلومات ذات الصلة وُجدت
استدعاء منخفض = سياق مهم مفقود
"""
relevant_retrieved = set(retrieved_contexts) & set(relevant_contexts)
if not relevant_contexts:
return 1.0
return len(relevant_retrieved) / len(relevant_contexts)
# مثال
retrieved = ["doc1", "doc2", "doc3", "doc4", "doc5"]
relevant = ["doc1", "doc3", "doc7"]
recall = context_recall(retrieved, relevant)
# النتيجة: 2/3 = 0.67 (استرجع 2 من 3 مستندات ذات صلة، فقد doc7)
متوسط الرتبة المتبادلة (MRR)
يقيس مدى ارتفاع رتبة أول نتيجة ذات صلة:
def mean_reciprocal_rank(queries_results: list[list], relevant_docs: list[set]) -> float:
"""
متوسط 1/الرتبة لأول نتيجة ذات صلة لكل استعلام.
MRR = 1.0 يعني النتيجة الأولى دائماً ذات صلة
MRR = 0.5 يعني أول نتيجة ذات صلة عادةً في الرتبة 2
"""
reciprocal_ranks = []
for results, relevant in zip(queries_results, relevant_docs):
for rank, doc in enumerate(results, 1):
if doc in relevant:
reciprocal_ranks.append(1 / rank)
break
else:
reciprocal_ranks.append(0)
return sum(reciprocal_ranks) / len(reciprocal_ranks)
# مثال
query_results = [
["doc2", "doc1", "doc3"], # استعلام 1: doc1 ذات الصلة في الرتبة 2
["doc5", "doc6", "doc7"], # استعلام 2: لا مستندات ذات صلة
["doc8", "doc9", "doc4"], # استعلام 3: doc4 ذات الصلة في الرتبة 3
]
relevant = [{"doc1"}, {"doc10"}, {"doc4"}]
mrr = mean_reciprocal_rank(query_results, relevant)
# النتيجة: (1/2 + 0 + 1/3) / 3 = 0.278
مقاييس التوليد
الأمانة
تقيس إذا كانت الإجابة مؤسسة على السياق المسترجع:
def assess_faithfulness(answer: str, context: str) -> dict:
"""
الأمانة تتحقق إذا كان كل ادعاء في الإجابة
يمكن التحقق منه من السياق المسترجع.
تستخدم نهج LLM كحَكَم.
"""
# الخطوة 1: استخراج الادعاءات من الإجابة
claims_prompt = f"""
استخرج كل الادعاءات الواقعية من هذه الإجابة:
الإجابة: {answer}
اذكر كل ادعاء في سطر جديد.
"""
# الخطوة 2: التحقق من كل ادعاء مقابل السياق
verify_prompt = f"""
لكل ادعاء، حدد إذا كان يمكن التحقق منه من السياق.
السياق: {context}
الادعاءات: {claims}
لكل ادعاء، أجب بـ:
- مدعوم: الادعاء مدعوم مباشرة من السياق
- غير_مدعوم: الادعاء لا يمكن التحقق منه من السياق
"""
# الخطوة 3: حساب درجة الأمانة
# الأمانة = الادعاءات_المدعومة / إجمالي_الادعاءات
return {
"score": supported_claims / total_claims,
"unsupported_claims": unsupported_list
}
# مثال للمخرج
# {
# "score": 0.75, # 3 من 4 ادعاءات مدعومة
# "unsupported_claims": ["الشركة لديها 500 موظف"]
# }
صلة الإجابة
تقيس إذا كانت الإجابة تعالج السؤال:
def assess_answer_relevancy(question: str, answer: str) -> float:
"""
صلة الإجابة تتحقق إذا كانت الإجابة فعلاً
تعالج ما سُئل.
النهج: توليد أسئلة من الإجابة،
مقارنة التشابه الدلالي مع السؤال الأصلي.
"""
# توليد أسئلة ستعالجها الإجابة
generated_questions = generate_questions_from_answer(answer, n=3)
# مقارنة كل سؤال مولد مع الأصلي
similarities = []
for gen_q in generated_questions:
sim = cosine_similarity(
embed(question),
embed(gen_q)
)
similarities.append(sim)
return sum(similarities) / len(similarities)
# مثال
question = "ما هي عاصمة فرنسا؟"
answer = "باريس هي عاصمة فرنسا، تقع على نهر السين."
# الأسئلة المولدة من الإجابة:
# - "ما هي عاصمة فرنسا؟"
# - "أين تقع باريس؟"
# - "أي نهر يمر عبر باريس؟"
# التشابه مع الأصلي: [0.95, 0.3, 0.2]
# درجة الصلة: 0.48
دليل اختيار المقاييس
| المقياس | يقيس | استخدم عندما |
|---|---|---|
| دقة السياق | دقة الاسترجاع | لديك تسميات حقيقة أرضية |
| استدعاء السياق | تغطية الاسترجاع | المعلومات المفقودة تسبب فشلاً |
| MRR | جودة الترتيب | النتائج الأولى مهمة أكثر |
| الأمانة | منع الهلوسة | الدقة حرجة |
| صلة الإجابة | جودة الاستجابة | الإجابات تبدو خارج الموضوع |
التسجيل المجمع
def rag_quality_score(
context_precision: float,
context_recall: float,
faithfulness: float,
answer_relevancy: float,
weights: dict = None
) -> float:
"""
مزيج موزون من مقاييس RAG.
اضبط الأوزان بناءً على أولوياتك.
"""
weights = weights or {
"context_precision": 0.2,
"context_recall": 0.2,
"faithfulness": 0.4, # عادةً الأهم
"answer_relevancy": 0.2
}
score = (
weights["context_precision"] * context_precision +
weights["context_recall"] * context_recall +
weights["faithfulness"] * faithfulness +
weights["answer_relevancy"] * answer_relevancy
)
return score
# مثال
quality = rag_quality_score(
context_precision=0.8,
context_recall=0.7,
faithfulness=0.9,
answer_relevancy=0.85
)
# النتيجة: 0.2*0.8 + 0.2*0.7 + 0.4*0.9 + 0.2*0.85 = 0.83
رؤية رئيسية: الأمانة عادةً هي المقياس الأكثر أهمية لأنظمة RAG الإنتاجية. المستخدمون يمكنهم تحمل إجابات خارج الموضوع قليلاً، لكن الحقائق المُهلوَسة تدمر الثقة.
التالي، لننفذ هذه المقاييس باستخدام إطار RAGAS. :::