RAG مش كافي: شو يحتاج نظام الذكاء الاصطناعي الموثوق فوقه
وين RAG ينكسر بالإنتاج وشو لازم تبني فوقه. جودة الـ chunks، طبقات التنسيق، البحث الهجين، حدود الهلوسة، إدارة التكاليف، ومتى تتخطى RAG كلياً.
فخ الـ RAG Demo
كل RAG demo بيشتغل. ارفع شوية PDFs، قسّمهم chunks، حوّلهم embeddings، اسأل سؤال، واحصل على جواب. الـ demo دايماً مبهر. أصحاب القرار متحمسين. الفريق يقدّر إنه يوصل للإنتاج بأسبوعين.
بعد ست شهور، النظام لسا غير موثوق. المستخدمين بيحصلوا على أجوبة غلط من chunks قديمة. الموديل بيستشهد بثقة بوثائق تقول عكس اللي بيدّعيه الجواب. التكاليف 10 أضعاف التقدير الأولي. وما حدا قادر يفهم ليش نفس السؤال بيعطي أجوبة مختلفة حسب الوقت.
RAG مش حل. RAG هو نمط retrieval. نظام ذكاء اصطناعي موثوق يحتاج طبقة تنسيق، ضوابط جودة، بحث هجين، حدود للهلوسة، إدارة تكاليف، ومراقبة فوق RAG. هالمقال بيغطي اللي تعلمناه من بناء أنظمة RAG للإنتاج.
للسياق الأوسع حول بنية RAG للمؤسسات وبنية البحث المتجهي، هالأدلة بتغطي الأنماط الأساسية. هالمقال بيركز على وين هالأنماط بتنكسر وشو تحتاج فوقها.
وين RAG بينكسر
| نوع الفشل | شو بيصير | قديش شائع |
|---|---|---|
| جودة الـ Chunk | حدود التقسيم الغلط بتقطع السياق، والجواب مبني على معلومات ناقصة | شائع جداً |
| بيانات قديمة | الـ index مش محدّث، والجواب مبني على وثيقة قديمة | شائع |
| فشل الاسترجاع | الوثيقة المطلوبة موجودة بس الـ embedding similarity ما بيطلّعها | شائع |
| هلوسة رغم الاسترجاع | الموديل بيتجاهل السياق المسترجع وبيولّد من بيانات التدريب | شائع |
| طفحان context window | chunks كتير بتنسترجع، الموديل بيفقد التركيز | متوسط |
| خلط بين الوثائق | chunks من وثائق مختلفة بتنخلط، الموديل بيدمج حقائق متناقضة | متوسط |
| انفجار التكاليف | تكاليف الـ embedding + الاسترجاع + التوليد بتتضاعف مع حجم الاستعلامات | تدريجي |
| طفرات بالتأخير | البحث المتجهي + إعادة الترتيب + التوليد بياخد وقت طويل للاستخدام التفاعلي | متوسط |
جودة الـ Chunk هي كل شي
أكتر مشكلة بتنقلل قيمتها. إذا الـ chunks تبعك قاطعين فقرة بنص فكرة، السياق المسترجع ناقص. إذا الـ chunks كبار كتير، المحتوى الغير مرتبط بيخفف المعلومات المفيدة. إذا الـ chunks ما بتحافظ على بنية الوثيقة (عناوين، جداول، قوائم)، الموديل بيخسر السياق التنظيمي.
// سيء: chunks بحجم ثابت بتقطع السياق
function naiveChunk(text: string, size: number): string[] {
const chunks = [];
for (let i = 0; i < text.length; i += size) {
chunks.push(text.slice(i, i + size));
}
return chunks;
// المشكلة: بتقطع الجمل والفقرات والجداول بنصهم
}
// أحسن: تقسيم دلالي مع تداخل
function semanticChunk(text: string, options: ChunkOptions): Chunk[] {
const sections = splitByHeadings(text); // احترم بنية الوثيقة
const paragraphs = sections.flatMap(s =>
splitByParagraphs(s, { maxSize: options.maxChunkSize })
);
return paragraphs.map((p, i) => ({
content: p.text,
metadata: {
section: p.sectionTitle,
pageNumber: p.pageNumber,
documentId: p.documentId,
position: i,
},
// تداخل: أضف آخر جملتين من الـ chunk السابق
prefix: i > 0 ? getLastSentences(paragraphs[i - 1].text, 2) : '',
}));
}
التداخل مهم. بدونه، سؤال يمتد على chunk-ين بيحصل على سياق جزئي من كل واحد وجواب كامل من ولا واحد. مع تداخل 2-3 جمل، الموديل عنده سياق كافي يربط حدود الـ chunks.
الـ metadata تبع الـ chunk مهمة بنفس المستوى. كل chunk لازم يحمل معه ID الوثيقة المصدر، عنوان القسم، رقم الصفحة، والموقع. بدون metadata، ما فيك تقول للمستخدم من وين إجا الجواب. بدون نسبة للمصدر، الجواب ما بينتحقق منه.
جودة الاسترجاع مقابل كمية الاسترجاع
استرجاع chunks أكتر ما يعني أجوبة أحسن. عملياً، لقينا إنه 3-5 chunks عالية الجودة دايماً بيتفوقوا على 10-15 chunk متوسطة.
| عدد الـ Chunks المسترجعة | جودة الجواب | التأخير | التكلفة |
|---|---|---|---|
| 1-2 | خطر فقدان السياق | سريع | منخفضة |
| 3-5 | أفضل توازن (موصى به) | متوسط | متوسطة |
| 5-10 | عوائد متناقصة، شوية تشويش | أبطأ | أعلى |
| 10+ | تخفيف السياق، الموديل بيتلخبط | بطيء | عالية |
الحل: استرجع بنطاق واسع، بعدين أعد الترتيب بقوة.
async function retrieveAndRerank(query: string, options: RetrievalOptions) {
// الخطوة 1: استرجاع واسع (جيب 20 مرشح)
const candidates = await vectorStore.search(query, { limit: 20 });
// الخطوة 2: أعد الترتيب بـ cross-encoder (سجّل كل مرشح ضد الاستعلام)
const reranked = await reranker.rank(query, candidates, {
model: 'cross-encoder/ms-marco-MiniLM-L-12-v2',
});
// الخطوة 3: خذ أعلى 5 بعد إعادة الترتيب
const topChunks = reranked.slice(0, 5);
// الخطوة 4: فلتر حسب حد أدنى لدرجة الملاءمة
return topChunks.filter(c => c.score > options.minRelevanceScore);
}
الـ reranker هو موديل cross-encoder بيسجّل كل مرشح ضد الاستعلام بدقة أعلى بكتير من cosine similarity على الـ embeddings. أبطأ (بيشغّل inference لكل مرشح)، بس تحسين الجودة كبير. تشغيله على 20 مرشح لاختيار 5 بيضيف 100-200ms تأخير، وهالشي مقبول لأغلب حالات الاستخدام.
طبقة التنسيق اللي RAG يحتاجها
RAG الخام هو: حوّل الاستعلام embedding، ابحث بالـ vectors، حشي السياق بالـ prompt، ولّد. نظام إنتاج يحتاج طبقة تنسيق بين الاسترجاع والتوليد.
استعلام المستخدم
│
▼
┌──────────────────┐
│ تحليل الاستعلام │ تصنيف النية، استخراج الكيانات، كشف اللغة
└────────┬─────────┘
│
▼
┌──────────────────┐
│ التوجيه │ أي index؟ أي استراتيجية استرجاع؟ cache hit؟
└────────┬─────────┘
│
▼
┌──────────────────┐
│ الاسترجاع │ بحث متجهي + بحث نصي (هجين)
└────────┬─────────┘
│
▼
┌──────────────────┐
│ إعادة الترتيب │ تسجيل بـ cross-encoder، فلترة الـ chunks المنخفضة
└────────┬─────────┘
│
▼
┌──────────────────┐
│ تجميع السياق │ ترتيب الـ chunks، إضافة metadata، احترام ميزانية التوكنات
└────────┬─────────┘
│
▼
┌──────────────────┐
│ التوليد │ استدعاء LLM مع السياق المجمّع + system prompt
└────────┬─────────┘
│
▼
┌──────────────────┐
│ تحقق المخرجات │ فحص الهلوسة، تحقق الاستشهادات، مسح PII
└────────┬─────────┘
│
▼
الاستجابة
تحليل الاستعلام
مش كل استعلام يحتاج RAG. بعض الاستعلامات محادثة ("مرحبا"، "شكراً"). بعضها عن النظام نفسه ("كيف أستخدم هالأداة؟"). بعضها غامض ويحتاج توضيح. محلل الاستعلام بيصنّف النية قبل ما يفعّل الاسترجاع.
async function analyzeQuery(query: string): Promise<QueryAnalysis> {
// تصنيف سريع (ممكن يكون موديل صغير أو قائم على قواعد)
const intent = await classifyIntent(query);
if (intent === 'greeting' || intent === 'meta') {
return { needsRetrieval: false, intent, response: getStaticResponse(intent) };
}
if (intent === 'ambiguous') {
return { needsRetrieval: false, intent, clarificationNeeded: true };
}
return {
needsRetrieval: true,
intent,
extractedEntities: await extractEntities(query),
detectedLanguage: await detectLanguage(query),
};
}
التوجيه
استعلامات مختلفة ممكن تحتاج indices مختلفة، استراتيجيات استرجاع مختلفة، أو موديلات مختلفة.
| نوع الاستعلام | الـ Index | الاستراتيجية | الموديل |
|---|---|---|---|
| سؤال عن منتج | index المنتجات | هجين (نصي + متجهي) | موديل سريع (GPT-4o-mini) |
| سؤال قانوني/امتثال | index السياسات | متجهي فقط (دقيق) | موديل دقيق (GPT-4o) |
| دعم تقني | index قاعدة المعرفة | هجين + إعادة ترتيب | موديل سريع |
| استعلام متعدد اللغات | index متعدد اللغات | متجهي مع فلتر لغة | موديل متعدد اللغات |
تجميع السياق
بعد الاسترجاع وإعادة الترتيب، الـ chunks لازم تتجمّع بـ prompt يحترم ميزانية التوكنات تبع الموديل.
function assembleContext(chunks: RankedChunk[], tokenBudget: number): string {
let context = '';
let tokensUsed = 0;
for (const chunk of chunks) {
const chunkTokens = estimateTokens(chunk.content);
if (tokensUsed + chunkTokens > tokenBudget) break;
context += `\n\n---\nSource: ${chunk.metadata.documentTitle} (${chunk.metadata.section})\n`;
context += chunk.content;
tokensUsed += chunkTokens;
}
return context;
}
ميزانية التوكنات لازم تحسب الـ system prompt، استعلام المستخدم، السياق المجمّع، وطول الاستجابة المتوقع. غلطة شائعة هي تعبئة كامل الـ context window بـ chunks مسترجعة، وما يضل مجال لاستجابة جيدة.
البحث الهجين: نصي + متجهي
البحث المتجهي لحاله بيفوّت الاستعلامات المبنية على كلمات مفتاحية. مستخدم يبحث عن "error code E-4021" بيحصل على نتائج سيئة من embedding similarity لأنه رموز الأخطاء ما عندها معنى دلالي. البحث النصي لحاله بيفوّت الاستعلامات الدلالية. مستخدم يبحث عن "كيف أصلح مشاكل تسجيل الدخول" ما رح يلاقي وثيقة عنوانها "دليل استكشاف أخطاء المصادقة."
البحث الهجين بيجمع الاتنين:
async function hybridSearch(query: string, options: SearchOptions) {
// تنفيذ متوازي
const [vectorResults, textResults] = await Promise.all([
vectorStore.search(query, { limit: options.vectorLimit }),
textIndex.search(query, { limit: options.textLimit }),
]);
// Reciprocal Rank Fusion (RRF) لدمج النتائج
const merged = reciprocalRankFusion(vectorResults, textResults, {
vectorWeight: 0.6,
textWeight: 0.4,
});
return merged.slice(0, options.totalLimit);
}
function reciprocalRankFusion(
vectorResults: SearchResult[],
textResults: SearchResult[],
weights: { vectorWeight: number; textWeight: number },
): SearchResult[] {
const scores = new Map<string, number>();
const k = 60; // ثابت RRF
vectorResults.forEach((result, rank) => {
const score = (scores.get(result.id) || 0) + weights.vectorWeight / (k + rank + 1);
scores.set(result.id, score);
});
textResults.forEach((result, rank) => {
const score = (scores.get(result.id) || 0) + weights.textWeight / (k + rank + 1);
scores.set(result.id, score);
});
return Array.from(scores.entries())
.sort(([, a], [, b]) => b - a)
.map(([id, score]) => ({ id, score }));
}
نسبة الأوزان (vector 0.6, text 0.4) هي نقطة بداية. عدّلها حسب توزيع استعلاماتك. إذا أغلب الاستعلامات مبنية على كلمات مفتاحية (SKUs منتجات، رموز أخطاء)، زد وزن النص. إذا أغلب الاستعلامات لغة طبيعية، زد وزن الـ vector.
لأكتر عن بنية البحث بسياق التجارة الإلكترونية، شوف دليل منصات التجارة الإلكترونية.
حدود الهلوسة
RAG بيقلل الهلوسة مقارنة بالتوليد الصافي من LLM. بس ما بيلغيها. الموديل لسا ممكن:
- يتجاهل السياق المسترجع ويولّد من بيانات التدريب
- يخلط معلومات من عدة chunks بشكل غلط
- يخترع استشهادات مش موجودة بالسياق المسترجع
- يستنتج أبعد مما السياق بيدعم
استراتيجيات التخفيف
1. System prompts مقيّدة:
You are a support assistant. Answer ONLY based on the provided context.
If the context does not contain enough information to answer, say
"I don't have enough information to answer that question."
Do NOT use information from your training data.
Every claim must reference a specific source from the context.
2. تحقق الاستشهادات:
async function verifyCitations(response: string, chunks: RankedChunk[]): VerificationResult {
const citations = extractCitations(response);
const verified = [];
const unverified = [];
for (const citation of citations) {
const found = chunks.some(chunk =>
chunk.content.includes(citation.claimedText) ||
fuzzyMatch(chunk.content, citation.claimedText, 0.85)
);
(found ? verified : unverified).push(citation);
}
return {
allVerified: unverified.length === 0,
verified,
unverified,
confidenceScore: verified.length / (verified.length + unverified.length),
};
}
3. تسجيل الثقة:
إذا استجابة الموديل ما بتتوافق كويس مع السياق المسترجع (تداخل منخفض، بدون اقتباسات مباشرة)، علّمها كثقة منخفضة. اعرض تحذير للمستخدم أو حوّلها لإنسان.
لأكتر عن أنماط فشل الذكاء الاصطناعي وكيف تتعامل معها، شوف دليل أنماط فشل الذكاء الاصطناعي.
التكلفة والتأخير
تكاليف RAG بتتضاعف مع حجم الاستعلامات على تلات أبعاد:
| المكوّن | محرّك التكلفة | النطاق النموذجي |
|---|---|---|
| Embedding الاستعلام | لكل استعلام (inference الموديل) | $0.0001 لكل استعلام |
| البحث المتجهي | لكل استعلام (حوسبة + I/O) | $0.0005 لكل استعلام |
| إعادة الترتيب | لكل استعلام * المرشحين (inference الموديل) | $0.001 لكل استعلام |
| توليد LLM | توكنات الإدخال (سياق) + توكنات الإخراج | $0.01-0.10 لكل استعلام |
| Embedding الوثائق | مرة وحدة لكل وثيقة (عند الإدخال) | $0.0001 لكل صفحة |
توليد LLM بيسيطر على التكلفة. تقليل حجم السياق (chunks أقل، chunks أقصر) بيقلل مباشرة المكوّن الأغلى.
استراتيجيات التخزين المؤقت
// Semantic cache: خزّن الاستجابات لاستعلامات مشابهة
async function cachedQuery(query: string): Promise<string | null> {
// حوّل الاستعلام لـ embedding
const queryEmbedding = await embedder.embed(query);
// ابحث بـ index الكاش عن استعلامات مشابهة
const cached = await cacheIndex.search(queryEmbedding, {
minSimilarity: 0.95, // حد عالي لـ cache hits
limit: 1,
});
if (cached.length > 0) {
return cached[0].response; // Cache hit
}
return null; // Cache miss، تابع مع pipeline RAG الكامل
}
الـ semantic caching بيشتغل لأنه مستخدمين كتير بيسألوا أسئلة مشابهة بصياغات مختلفة شوي. "كيف أعيد تعيين كلمة المرور؟" و"تعليمات إعادة تعيين كلمة المرور" هم نصوص مختلفة بس دلالياً متطابقين. حد تشابه 0.95 بيضمن إنه بس الاستعلامات شبه المتطابقة بتحصل على استجابات مخزنة.
ميزانية التأخير
للاستخدام التفاعلي (chatbot، مساعد دعم)، الـ pipeline الكامل لازم يخلص بأقل من 3 ثواني:
| المرحلة | الميزانية | التحسين |
|---|---|---|
| تحليل الاستعلام | 50ms | قائم على قواعد أو موديل صغير |
| فحص الكاش | 30ms | index متجهي بالذاكرة |
| البحث المتجهي | 100ms | cluster بحث مخصص |
| البحث النصي | 100ms | متوازي مع البحث المتجهي |
| إعادة الترتيب | 200ms | cross-encoder صغير، حدد المرشحين |
| تجميع السياق | 10ms | بالذاكرة |
| توليد LLM | 1,500ms | Streaming، موديل سريع |
| تحقق المخرجات | 100ms | قائم على قواعد + موديل صغير |
| الإجمالي | ~2,100ms |
عمل streaming لاستجابة LLM للمستخدم أثناء التوليد بيخلي التأخير المحسوس أقل بكتير. المستخدم بيشوف أول التوكنات بـ 300-500ms حتى لو الاستجابة الكاملة بتاخد 1,500ms.
متى تتخطى RAG كلياً
RAG مش دايماً النمط الصح. أحياناً مقاربات أبسط بتشتغل أحسن:
| السيناريو | مقاربة أحسن | ليش |
|---|---|---|
| FAQ ثابت (أقل من 50 سؤال) | مطابقة كلمات مفتاحية + استجابة قالب | أسرع، أرخص، حتمي |
| استعلامات بيانات هيكلية | استعلام SQL/API + قالب | LLM بيضيف تأخير وخطر هلوسة |
| بيانات لحظية (أسعار أسهم، مخزون) | استدعاء API مباشر | الـ Embeddings قديمة بطبيعتها |
| تصنيف بسيط | مصنّف fine-tuned | أرخص، أسرع، أكتر موثوقية |
| تلخيص وثيقة | استدعاء LLM مباشر (بدون retrieval) | الوثيقة الكاملة هي السياق |
RAG منطقي لما عندك قاعدة معرفة كبيرة (مئات لآلاف الوثائق)، استعلامات لغة طبيعية ما بتنطابق بالكلمات المفتاحية، وحاجة لأجوبة مركّبة من عدة مصادر. إذا حالة الاستخدام تبعك ما بتوافق هالملف، مقاربة أبسط رح تكون أكتر موثوقية وأرخص.
لكيف نتعامل مع قرارات البنية هاي بخدمات الذكاء الاصطناعي تبعنا، وللأنماط الأوسع بتصميم سير عمل الذكاء الاصطناعي، هالصفحات بتعطي سياق أكتر.
الأخطاء الشائعة
-
تقسيم بحجم ثابت. الـ chunks اللي بتقطع الفقرات والجداول وبلوكات الكود بنصهم بتنتج استرجاع سيء. استخدم تقسيم دلالي يحترم بنية الوثيقة.
-
بدون تداخل بالـ chunks. بدون تداخل، الاستعلامات اللي بتمتد على حدود الـ chunks بتحصل على سياق جزئي من كل واحد وجواب كامل من ولا واحد.
-
بدون إعادة ترتيب. الـ embedding similarity هو فلتر تقريبي. cross-encoder reranker بيحسّن جودة أعلى 5 نتائج بشكل كبير.
-
تعبئة كامل الـ context window. خلّي مجال للـ system prompt، استعلام المستخدم، والاستجابة المتوقعة. prompt محشي بـ 15 chunk ما بيخلي مجال لجواب جيد.
-
بدون بحث هجين. البحث المتجهي لحاله بيفشل مع استعلامات الكلمات المفتاحية (رموز أخطاء، SKUs منتجات). البحث النصي لحاله بيفشل مع الاستعلامات الدلالية. استخدم الاتنين.
-
بدون semantic caching. أسئلة مشابهة من مستخدمين مختلفين بتفعّل pipeline RAG الكامل كل مرة. semantic cache بحد تشابه 0.95 بيقلل التكاليف بشكل كبير.
-
الوثوق بمخرجات RAG بدون تحقق. RAG بيقلل الهلوسة. ما بيلغيها. تحقق من الاستشهادات ضد السياق المسترجع. علّم الادعاءات الغير متحقق منها.
-
بدون مراقبة. لازم تتابع جودة الاسترجاع (هل الـ chunks الصح انسترجعت؟)، جودة الجواب (هل المستخدم لقى الجواب مفيد؟)، التأخير، التكلفة لكل استعلام، ونسبة cache hit.
النقاط الأساسية
-
RAG هو نمط retrieval، مش حل. نظام موثوق يحتاج تحليل استعلام، توجيه، بحث هجين، إعادة ترتيب، تجميع سياق، توليد، وتحقق مخرجات فوق الاسترجاع.
-
جودة الـ Chunk بتحدد جودة الجواب. التقسيم الدلالي مع التداخل، الـ metadata، والحفاظ على بنية الوثيقة هو الأساس. كل شي تاني مبني فوق chunks جيدة.
-
استرجع بنطاق واسع، أعد الترتيب بقوة. جيب 20 مرشح بـ embedding similarity. سجّلهم بـ cross-encoder. خذ أعلى 5. فلتر حسب حد أدنى للملاءمة.
-
البحث الهجين بيغطي اللي الـ vectors بيفوّتوه. الكلمات المفتاحية، رموز الأخطاء، IDs المنتجات، والمطابقات الدقيقة بتحتاج بحث نصي. الاستعلامات الدلالية بتحتاج بحث متجهي. استخدم الاتنين مع reciprocal rank fusion.
-
توليد LLM بيسيطر على التكلفة. تقليل حجم السياق (chunks أقل وأحسن) هو أكتر تحسين فعّال للتكلفة.
-
أحياناً RAG هو النمط الغلط. FAQs الثابتة، استعلامات البيانات الهيكلية، البيانات اللحظية، والتصنيف البسيط كلها عندها حلول أبسط وأكتر موثوقية.
نحنا بنبني أنظمة RAG للإنتاج كجزء من ممارسة خدمات الذكاء الاصطناعي وهندسة البيانات تبعنا. إذا عم تبني نظام RAG أو عم تصلح واحد غير موثوق، تواصل مع فريقنا أو اطلب عرض سعر. فيك كمان تستكشف صفحة المنهجية تبعنا لكيف نتعامل مع مشاريع الذكاء الاصطناعي.
المواضيع المغطاة
أدلة ذات صلة
أنماط فشل الذكاء الاصطناعي: دليل هندسة الإنتاج
دليل تقني لأعطال أنظمة الذكاء الاصطناعي في الإنتاج. تعرف على الهلوسات، حدود السياق، حقن البرومبت وانحراف النموذج.
اقرأ الدليلالدليل الشامل لأنظمة الذكاء الاصطناعي الوكيلي
دليل تقني لأنظمة الذكاء الاصطناعي الوكيلي في بيئات الأعمال. تعرف على البنية والقدرات والتطبيقات العملية للوكلاء المستقلين.
اقرأ الدليلالتجارة الوكيلية: كيف تخلي وكلاء الذكاء الاصطناعي يشترون بأمان
كيف تصمم تجارة وكيلية محكومة. محركات السياسات، بوابات الموافقة البشرية، إيصالات HMAC، الـ idempotency، عزل المستأجرين، وبروتوكول الدفع الوكيلي الكامل.
اقرأ الدليلجاهز لبناء أنظمة ذكاء اصطناعي جاهزة للإنتاج؟
فريقنا متخصص في بناء أنظمة ذكاء اصطناعي جاهزة للإنتاج. خلينا نحكي كيف نقدر نساعد.
ابدأ محادثة