بناء أداة تقييم آلية
أنشئوا pipeline تقييم قابلة للتكرار تشغّل نظام RAG الكامل على مجموعة اختبار، وتحسب جميع المقاييس، وتنشئ تقريرًا يتيح لكم تتبّع التحسينات بمرور الوقت.
بناء أداة تقييم آلية درس مجاني في AI Engineering Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Engineering Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.
ما أداة التقييم؟
أداة التقييم هي مسار معالجة آلي قابل للتكرار يشغّل نظام RAG كاملًا على مجموعة اختبار موحّدة، ويحسب جميع المقاييس، وينتج تقريرًا. والكلمة الأساسية هنا هي قابل للتكرار: ففي كل مرة تُجري فيها تغييرًا على استراتيجية تقسيم النصوص، أو نموذج التمثيلات، أو المطالبة، أو نموذج LLM، تشغّل أداة التقييم نفسها وتقارن النتائج بخط أساس. ويحوّل ذلك تطوير RAG من تجارب ذاتية إلى هندسة قائمة على البيانات.
بنية أداة التقييم
تتكون أداة التقييم المصممة جيدًا من أربع طبقات: إدارة بيانات الاختبار (تحميل مجموعة البيانات الذهبية وإدارة إصداراتها)، وتنفيذ المسار (تشغيل كل سؤال اختباري عبر مسار RAG الكامل)، وحساب المقاييس (حساب جميع مقاييس الاسترجاع والتوليد)، وإنشاء التقارير (حفظ النتائج مع معلومات الإصدار وإنتاج مقارنة بالفارق بينها وبين خط الأساس السابق). وينبغي أن تكون كل طبقة قابلة للاختبار والتهيئة بشكل مستقل.
class RAGEvaluationHarness:
def __init__(self, retriever, llm_client, config):
self.retriever = retriever
self.llm_client = llm_client
self.config = config # chunk_size, top_k, model, threshold, etc.
self.results = []
def run(self, golden_dataset):
for item in golden_dataset:
result = self._evaluate_single(item)
self.results.append(result)
metrics = self._compute_metrics()
self._save_report(metrics)
return metricsتشغيل كل حالة اختبار
لكل سؤال في مجموعة البيانات الذهبية، شغّل مسار RAG الكامل وسجّل جميع المخرجات الوسيطة: معرّفات الكتل المسترجَعة ودرجاتها، والسياق المنسّق، والإجابة المُولَّدة، وعدد الرموز. ويُعد تخزين هذه القيم الوسيطة ضروريًا لتصحيح حالات الفشل — فعندما تحصل مسألة ما على درجة منخفضة، يمكنك فحص الكتل التي استُرجعت بالضبط وسبب خطأ الإجابة، من دون إعادة تشغيل المسار المكلف.
import time
def _evaluate_single(self, item):
start = time.perf_counter()
query_vector = embed_query(item['question'])
chunks = self.retriever.retrieve(query_vector, top_k=self.config['top_k'])
filtered_chunks = filter_by_score(chunks, self.config['threshold'])
context = format_context(filtered_chunks)
answer_result = generate_answer(item['question'], context, self.llm_client)
latency_ms = (time.perf_counter() - start) * 1000
return {
'question': item['question'],
'expected_answer': item['answer'],
'generated_answer': answer_result['answer'],
'retrieved_chunk_ids': [c['id'] for c in filtered_chunks],
'retrieved_scores': [c['score'] for c in filtered_chunks],
'relevant_chunk_ids': item['relevant_chunk_ids'],
'context_texts': [c['text'] for c in filtered_chunks],
'tokens_used': answer_result['tokens_used'],
'latency_ms': round(latency_ms)
}حساب جميع المقاييس في مرور واحد
بعد جمع مخرجات جميع حالات الاختبار، احسب المجموعة الكاملة من المقاييس في مرور واحد على النتائج. افصل مقاييس الاسترجاع (المحسوبة من معرّفات الكتل) عن مقاييس التوليد (المحسوبة من خلال استدعاء نموذج LLM المُقيِّم). وجمّع استدعاءات نموذج LLM المُقيِّم لتحقيق أقصى كفاءة — اجمع تقييمات الأمانة وأرسلها بالتوازي باستخدام asyncio بدلًا من إرسالها بالتتابع. وسجّل مستوى التقدم، لأن مقاييس التوليد قد تستغرق عدة دقائق لأكثر من 100 حالة اختبار.
def _compute_metrics(self):
# Retrieval metrics (no LLM calls needed)
hit_rates = []
mrr_scores = []
for r in self.results:
retrieved = r['retrieved_chunk_ids']
relevant = set(r['relevant_chunk_ids'])
hit = any(rid in relevant for rid in retrieved)
hit_rates.append(1.0 if hit else 0.0)
for rank, rid in enumerate(retrieved, 1):
if rid in relevant:
mrr_scores.append(1.0 / rank)
break
else:
mrr_scores.append(0.0)
metrics = {
'hit_rate_at_5': sum(hit_rates) / len(hit_rates),
'mrr': sum(mrr_scores) / len(mrr_scores),
'mean_latency_ms': sum(r['latency_ms'] for r in self.results) / len(self.results),
'mean_tokens': sum(r['tokens_used'] for r in self.results) / len(self.results)
}
return metricsحفظ النتائج مع معلومات الإصدار
ينبغي حفظ كل عملية تقييم مع بيانات وصفية للإصدار حتى تتمكن من مقارنة النتائج بين التهيئات المختلفة. أدرج تجزئة التزام Git للكود، ومعلمات التهيئة (نموذج التمثيلات، وحجم الكتلة، وK، والحد، ونموذج LLM)، والطابع الزمني، ووصفًا مفهومًا للتشغيل. خزّن النتائج في ملف JSON Lines أو جدول قاعدة بيانات. وينشئ ذلك سجلًا دائمًا يوضح كيفية تطور نظامك.
import json
import subprocess
from datetime import datetime
def _save_report(self, metrics):
git_hash = subprocess.check_output(
['git', 'rev-parse', '--short', 'HEAD']
).decode().strip()
report = {
'run_id': datetime.utcnow().strftime('%Y%m%d_%H%M%S'),
'git_commit': git_hash,
'config': self.config,
'metrics': metrics,
'n_test_cases': len(self.results),
'timestamp': datetime.utcnow().isoformat()
}
with open('eval_history.jsonl', 'a') as f:
f.write(json.dumps(report) + '\n')
print(f'Saved evaluation run: {report["run_id"]}')
print(json.dumps(metrics, indent=2))المقارنة بخط الأساس
بعد كل عملية تشغيل، أجرِ تلقائيًا مقارنة بخط الأساس السابق وعلّم حالات التراجع. والتراجع هو انخفاض أي مقياس بأكثر من حد معين (مثل نقطتين مئويتين). اطبع جدول مقارنة يوضح تغيّرات المقاييس. وإذا تراجع أي مقياس بشكل ملحوظ، فينبغي أن تفشل عملية التقييم برمز خروج غير صفري، مما يؤدي إلى إيقاف نشر هذا التغيير عبر مسار CI/CD.
def compare_to_baseline(current_metrics, baseline_file='best_eval.json'):
import json
from pathlib import Path
if not Path(baseline_file).exists():
print('No baseline yet. Saving current as baseline.')
Path(baseline_file).write_text(json.dumps(current_metrics, indent=2))
return True
baseline = json.loads(Path(baseline_file).read_text())
regressions = []
print('\nMetric comparison (current vs baseline):')
for metric, current_val in current_metrics.items():
baseline_val = baseline.get(metric, 0)
delta = current_val - baseline_val
status = 'OK' if delta >= -0.02 else 'REGRESSION'
print(f' {metric}: {current_val:.3f} vs {baseline_val:.3f} ({delta:+.3f}) {status}')
if status == 'REGRESSION':
regressions.append(metric)
return len(regressions) == 0الدمج في CI/CD
تكون أداة التقييم أقوى ما يمكن عند دمجها في مسار CI/CD. اضبطها لتعمل تلقائيًا عند كل طلب سحب يعدّل منطق تقسيم النصوص، أو تهيئة نموذج التمثيلات، أو قوالب المطالبات، أو معلمات الاسترجاع. ولا ينجح المسار إلا إذا استوفت جميع المقاييس الحدود الدنيا ولم يتراجع أي مقياس عن خط أساس الفرع الرئيسي. ويمنع ذلك وصول التراجعات العرضية في الجودة إلى بيئة الإنتاج.
# GitHub Actions workflow (eval.yml)
# on:
# pull_request:
# paths:
# - 'rag/**'
# - 'prompts/**'
# - 'config/**'
# jobs:
# evaluate:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# - name: Install dependencies
# run: pip install -r requirements.txt
# - name: Run evaluation harness
# run: |
# python eval/run_harness.py \
# --test-set eval/golden_dataset.json \
# --config config/rag_config.yaml \
# --fail-on-regression
# env:
# OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}إنشاء تقارير مفهومة للبشر
بالإضافة إلى ملفات المقاييس الخام، أنشئ تقرير HTML أو Markdown مفهومًا للبشر يمكن لفريقك مراجعته ضمن تعليقات طلب السحب. أدرج جدولًا موجزًا لجميع المقاييس، وقائمة بحالات الاختبار الفاشلة تتضمن السؤال، والإجابة المتوقعة، والإجابة المُولَّدة، والكتل التي استُرجعت، ومخططًا اتجاهيًا يوضح المقاييس خلال آخر 10 عمليات تشغيل. تساعد التقارير المرئية أصحاب المصلحة غير التقنيين على فهم ما إذا كان النظام يتحسن.
def generate_markdown_report(metrics, failed_cases, run_id):
lines = [
f'# RAG Evaluation Report — {run_id}\n',
'## Summary Metrics',
'| Metric | Score | Target |',
'|--------|-------|--------|',
f'| Hit Rate@5 | {metrics["hit_rate_at_5"]:.1%} | > 80% |',
f'| MRR | {metrics["mrr"]:.3f} | > 0.70 |',
f'| Mean Latency | {metrics["mean_latency_ms"]:.0f}ms | < 500ms |',
'',
f'## Failed Cases ({len(failed_cases)} failures)'
]
for case in failed_cases[:10]: # show first 10
lines += [
f'**Q:** {case["question"]}',
f'**Expected:** {case["expected_answer"]}',
f'**Generated:** {case["generated_answer"]}\n'
]
return '\n'.join(lines)تتبّع تكلفة كل عملية تقييم
تكلّف عمليات التقييم أموالًا — فهي تستدعي واجهة برمجة تطبيقات التمثيلات، وواجهة برمجة تطبيقات نموذج LLM، ونموذج LLM المُقيِّم. تتبّع تكلفة كل عملية تقييم إلى جانب مقاييس الجودة. وعادةً ما يتكلف التقييم الشامل لـ 100 حالة اختبار من 0.50 إلى 2.00 دولار، بحسب النماذج المستخدمة. استخدم نماذج أقل تكلفة لاستدعاءات التقييم (GPT-4o-mini لتسجيل الأمانة) واحتفظ بالنماذج المكلفة للتوليد. وأدرج التكلفة التقديرية للتشغيل في التقرير المحفوظ حتى تتمكن من وضع ميزانية للتقييم ضمن دورة التطوير.
def estimate_run_cost(results, config):
# Embedding cost
embed_tokens = sum(len(r['question'].split()) * 1.3 for r in results)
embed_cost = (embed_tokens / 1_000_000) * 0.02 # $0.02/1M tokens
# Generation cost
total_gen_tokens = sum(r['tokens_used'] for r in results)
gen_cost = (total_gen_tokens / 1_000_000) * 5.0 # gpt-4o approx
# Judge cost (faithfulness evals)
judge_cost = len(results) * 0.001 # ~$0.001 per eval with gpt-4o-mini
total = embed_cost + gen_cost + judge_cost
print(f'Evaluation cost estimate: ${total:.2f}')
print(f' Embedding: ${embed_cost:.3f}')
print(f' Generation: ${gen_cost:.3f}')
print(f' Judgment: ${judge_cost:.3f}')
return totalالتقييم المجدول لمراقبة الإنتاج
إلى جانب التقييم عبر CI/CD عند تغييرات الكود، شغّل أداة التقييم وفق جدول زمني في بيئة الإنتاج — يوميًا أو أسبوعيًا — واختبرها على استعلامات مستخدمين حقيقية مأخوذة عيّنيًا من السجلات. يكشف ذلك انحراف البيانات: فمع تطور مجموعة المستندات وتغير أنماط استعلامات المستخدمين، قد تتدهور جودة النظام من دون أي تغيير في الكود. وجدول عمليات تقييم أسبوعية تأخذ عينة من 50 استعلامًا حديثًا للمستخدمين، وتقيّمها، وترسل تلقائيًا ملخصًا للجودة إلى قناة Slack الخاصة بفريقك.
# Example scheduled evaluation (cron job or scheduled cloud function)
import random
def sample_production_queries(query_log_file, n=50):
with open(query_log_file) as f:
all_queries = [json.loads(line) for line in f]
sample = random.sample(all_queries, min(n, len(all_queries)))
# Convert to golden dataset format (without expected answers — use LLM judge)
return [
{'question': q['user_question'], 'relevant_chunk_ids': []}
for q in sample
]
# Run weekly evaluation against production queries
if __name__ == '__main__':
prod_queries = sample_production_queries('/var/log/rag_queries.jsonl')
harness = RAGEvaluationHarness(retriever, llm_client, config)
metrics = harness.run(prod_queries)
send_slack_digest(metrics)تصوير اتجاهات المقاييس بمرور الوقت
يصعب تفسير الأرقام الخام في ملف JSONL بنظرة سريعة. أنشئ تصويرًا بسيطًا للاتجاهات يرسم كل مقياس خلال آخر 20 عملية تقييم على مخطط خطي. استخدم الطابع الزمني للتشغيل على المحور السيني، ودرجة المقياس على المحور الصادي. ارسم خطًا أفقيًا عند الحد الأدنى المقبول. وعندما ينخفض أحد المقاييس تحت خط الحد، تصبح المشكلة ظاهرة فورًا من دون قراءة البيانات الخام. وتناسب هذه المهمة أدوات مثل Matplotlib أو لوحة معلومات ويب بسيطة (Grafana، Streamlit).
import json
import matplotlib.pyplot as plt
from pathlib import Path
def plot_metric_trends(history_file='eval_history.jsonl', metric='hit_rate_at_5'):
records = [
json.loads(line)
for line in Path(history_file).read_text().strip().split('\n')
]
timestamps = [r['timestamp'][:10] for r in records[-20:]]
scores = [r['metrics'].get(metric, 0) for r in records[-20:]]
plt.figure(figsize=(10, 4))
plt.plot(timestamps, scores, marker='o', label=metric)
plt.axhline(y=0.80, color='r', linestyle='--', label='Min threshold')
plt.title(f'{metric} over last 20 evaluations')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig(f'eval_trend_{metric}.png')
print(f'Saved trend chart for {metric}')تحقق سريع
اختبر مدى فهمك لمفاهيم هندسة الذكاء الاصطناعي الواردة في هذا الدرس.
مراجعة الدرس
تعلّمت في هذا الدرس: كيفية هيكلة أداة تقييم كاملة تتضمن إدارة بيانات الاختبار، وتنفيذ المسار، وحساب المقاييس، وإنشاء التقارير، وكيفية مقارنة عمليات التشغيل بخط أساس وإفشال CI/CD عند حدوث تراجعات، وكيفية إنشاء تقارير مفهومة للبشر لمراجعة الفريق، وكيفية تشغيل مراقبة مجدولة في بيئة الإنتاج لاكتشاف انحراف البيانات من دون تغييرات في الكود. ولديك الآن أساس متكامل لبناء أنظمة RAG الخاصة ببيئة الإنتاج وتقييمها.
الأسئلة الشائعة
هل درس «بناء أداة تقييم آلية» مجاني؟
نعم — نص درس «بناء أداة تقييم آلية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Engineering Academy، انتقل إلى CoddyKit PRO. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.
ماذا ستتعلم في «بناء أداة تقييم آلية»؟
أنشئوا pipeline تقييم قابلة للتكرار تشغّل نظام RAG الكامل على مجموعة اختبار، وتحسب جميع المقاييس، وتنشئ تقريرًا يتيح لكم تتبّع التحسينات بمرور الوقت. تتمرن على AI Engineering Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ AI Engineering Academy؟
لا تُشترط خبرة سابقة. AI Engineering Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «بناء أداة تقييم آلية»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس AI Engineering Academy هذا؟
نعم. كل درس في AI Engineering Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- لماذا يهم التقييم في RAG
- مقاييس الاسترجاع: معدل الإصابة وMRR وNDCG
- مقاييس التوليد: الأمانة وملاءمة الإجابة
- بناء أداة تقييم آلية