النقاط الرئيسية
- تفشل الإعدادات الافتراضية عند 5,000–8,000 مقطع — يتراجع استرجاع النتائج حين يتجاوز الفهرس المتجه حجم RAM ويُعيد البحث بالتشابه الجيبي وحده مقاطع متشابهة معجمياً لكنها خاطئة دلالياً.
- اختر المعمارية حسب حجم المجموعة لا بحسب تفضيل الميزة: AnythingLLM محسَّن لـ 100–1,000 مستند؛ LlamaIndex محلي لـ 1,000–5,000؛ Ollama+ChromaDB مخصص لـ 5,000–10,000؛ Ollama+Qdrant لـ 10,000+.
- ثلاثة تحسينات بترتيب الأثر: بحث هجين (BM25 + متجه)، إعادة ترتيب أفضل 50 مرشحاً بمُشفِّر تقاطع صغير، تصفية مسبقة بيانات وصفية. يُفيد الاسترجاع الهرمي ابتداءً من 10,000+.
- ميزانية التخزين: 10–30 MB لكل 100 صفحة PDF حسب حجم المقطع وأبعاد التضمين. مجموعة من 50,000 صفحة تحتاج 5–15 GB على القرص للمتجهات فقط.
- وقت الفهرسة: خطي مع عدد المستندات. خطط لـ 30–90 دقيقة لكل 5,000 ملف PDF على أجهزة المستهلكين مع nomic-embed-text-v1.5؛ Apple Silicon أسرع من x86 بـ CPU فقط.
- الحد الأدنى من الأجهزة لـ 10,000+ مستند: 32 GB RAM وNVMe SSD وGPU منفصل بـ 8 GB+ VRAM أو Apple Silicon بذاكرة موحدة 32 GB+.
- تغيير نموذج التضمين يُجبر على إعادة فهرسة كاملة في جميع المعماريات. اختر أداة التضمين قبل فهرسة 10,000 مستند؛ اختيار خاطئ يُكلّف ساعات للتراجع عنه.
لماذا تفشل إعدادات RAG الافتراضية مع أكثر من 1,000 مستند
نمطا فشل يتراكمان بين 1,000 و10,000 مستند: الفهرس يتجاوز RAM والبحث بالتشابه الجيبي وحده يُعيد مقاطع متشابهة معجمياً لكنها خاطئة دلالياً. العرض التجريبي الذي نجح مع 20 ملف PDF يصبح غير قابل للاستخدام في مكتبة بحثية شخصية، ليس لأن الكود خاطئ بل لأن الافتراضات المدمجة في الإعدادات الافتراضية تتوقف عن التحقق.
- الفهرس خارج RAM: تبدأ LanceDB وChromaDB وFAISS كلها بالذاكرة المقيمة. حين يتجاوز الفهرس الذاكرة المتاحة (عادةً 5–8 GB من المتجهات على حاسوب محمول بـ 16 GB) تنتقل للقراءة من القرص ويقفز زمن استجابة p95 من ~300 ms إلى 1–3 ثوانٍ.
- التشابه الجيبي وحده يفشل مع المصطلحات النادرة: التضمينات الكثيفة تُقلّل من وزن الأسماء غير الشائعة وأسماء الأدوية وأرقام القوانين ومعرفات الكود. استعلام "Section 230(c)(1)" يسترجع مقاطع عن "Section 9" لأن التضمين لا يستطيع تمييز الخصوصية العددية. يلتقطها BM25؛ البحث بالتشابه الجيبي وحده يُفوِّتها.
- top-K من 4 ضيق جداً على نطاق واسع: مع 1,000 مقطع top-4 له استرجاع معقول. مع 50,000 مقطع يكون أفضل مقطع في الغالب في الرتبة 12–30 خارج نافذة top-4. يبدو الاسترجاع يعمل (الإجابات معقولة) لكنه يستند إلى مقاطع خاطئة.
- بدون تصفية بيانات وصفية يُهدَر الفهرس: السؤال "ما الذي قاله Smith عن X؟" على مجموعة من 10,000 مستند يبحث في جميع مقاطع الفهرس، حين يجب على النظام أن يُصفّي أولاً إلى "مستندات كتبها Smith". RAG الأساسي لا يمتلك مفهوم التصفية المسبقة بالبيانات الوصفية.
- حجم المقطع الافتراضي 512/0 يُجزّئ السياقات الطويلة: فقرات PDF والأقسام القانونية نادراً ما تناسب 512 رمزاً. التداخل الافتراضي 0 يُضيّع المعنى بين الأجزاء. يحل الضبط 1,000/200 هذا لمجموعات الحجم المتوسط؛ يلزم تقطيع هرمي إلى ما هو أبعد من 5,000 مستند.
- انجراف التضمين عند التحديث: حين تضيف 1,000 ملف PDF جديد بعد ثلاثة أشهر من الفهرس الأصلي ربما تكون إصدارات نموذج sentence-transformer قد تغيرت. خلط تضمينات من إصدارين مختلفين في نفس الفهرس يُدهوِر الاسترجاع بصمت — جميع المعماريات تُجبر على إعادة فهرسة كاملة عند تغيير أداة التضمين.
📌Note: "منحدر التوسع" ليس رقماً واحداً. إنه النقطة التي تتفاعل فيها مجموعتك وأجهزتك وإعدادات الاسترجاع بشكل سيء بما يكفي لتتراجع الإجابات بشكل ملحوظ. على حاسوب محمول بـ 16 GB يقع المنحدر عند حوالي 5,000 مقطع. على محطة عمل بـ 32 GB مع NVMe ينتقل إلى 15,000–20,000. الحلول في هذا المقال — بحث هجين وإعادة ترتيب وتصفية بيانات وصفية — تُزيل المنحدر كلياً.
شجرة قرار المعمارية: اختر أولاً حسب حجم المجموعة
اختر أبسط معمارية تُدير عدد مستنداتك. إضافة البحث الهجين وإعادة الترتيب أو الفهارس الهرمية سهل لاحقاً؛ تغيير مخزن المتجهات بالكامل ليس كذلك. استخدم هذه الشجرة قبل فتح أي مثبّت.
📍 في جملة واحدة
أسرع إعداد RAG محلي للمحادثة مع ما يصل إلى 1,000 ملف PDF هو تطبيق AnythingLLM Desktop مع حجم مقطع 1,000 / تداخل 200 وnomic-embed-text-v1.5 كأداة تضمين — بدون كود ويعمل بالكامل على جهازك.
💬 بعبارات بسيطة
اختر المعمارية حسب عدد المستندات: AnythingLLM لأقل من 1,000 ملف PDF (بدون كود، سحب وإفلات)؛ LlamaIndex محلي لـ 1,000–5,000 (150 سطر Python)؛ Ollama + ChromaDB مخصص لـ 5,000–10,000 (300–400 سطر، يضيف بحثاً هجيناً وإعادة ترتيب)؛ Ollama + Qdrant لـ 10,000+ (Docker، تصفية بيانات وصفية، درجة إنتاج). الخيار الصحيح هو الأبسط الذي يُدير مجموعتك — الإفراط في هندسة المعمارية يضيف تكلفة صيانة بدون تحسين جودة الإجابة للمجموعات الأصغر.
- أقل من 1,000 مستند (أقل من ~5,000 مقطع): تطبيق AnythingLLM Desktop مع حجم مقطع 1,000 / تداخل 200 وnomic-embed-text-v1.5 كأداة تضمين. بدون كود مخصص. راجع الدليل خطوة بخطوة في 30 دقيقة للإعداد.
- 1,000–5,000 مستند (5,000–25,000 مقطع): LlamaIndex في الوضع المحلي بالكامل مع فهارس هرمية (DocumentSummaryIndex + VectorStoreIndex) وOllama كمزود LLM وnomic-embed-text-v1.5 كأداة تضمين وLanceDB أو ChromaDB كمخزن متجهات. ~150 سطر Python، يعمل كعملية طويلة الأمد.
- 5,000–10,000 مستند (25,000–50,000 مقطع): مكدّس مخصص مع Ollama وChromaDB وبحث هجين BM25 عبر Whoosh أو Tantivy وأداة إعادة ترتيب BGE-reranker-v2-m3 على أفضل 50 مرشحاً. ~300–400 سطر Python. أداة إعادة الترتيب ضرورية على هذا النطاق.
- 10,000+ مستند (50,000+ مقطع): Ollama + Qdrant في وضع عقدة واحدة مع تصفية بيانات وصفية قائمة على الحمولة وبحث هجين باستخدام متجهات Qdrant المتفرقة الأصلية وBGE-reranker-v2-m3 وفهرس ملخصات هرمي بمعرّفات المستندات. إعداد درجة إنتاج لمستخدم واحد.
- متعدد المستخدمين (أي نطاق): Open WebUI أمام أي من السابقة، أو غلاف FastAPI صغير حول نفس خلفية Qdrant + Ollama. تعدد المستخدمين يُغيّر التركيز التشغيلي (المصادقة والعزل وحد المعدل) لكن ليس معمارية الاسترجاع.
💡Tip: إذا كنت في شك، ابدأ مستوى فوق حجم مجموعتك الحالية. إذا كان لديك 800 ملف PDF اليوم وتتوقع إضافة 200/شهراً، ابدأ في مستوى LlamaIndex — إعادة الهندسة من AnythingLLM لاحقاً أكثر إيلاماً من الإفراط في الهندسة خطوة الآن.
جدول مقارنة المعماريات
أربع معماريات مقارنة على مجموعات بيانات متطابقة عند 100 و1,000 و10,000 مستند. إعداد الاختبار: ملفات PDF بحثية بمتوسط 12 صفحة لكل منها (~120,000 صفحة عند 10,000 مستند). الأجهزة: NVIDIA RTX 4070 (12 GB VRAM، 32 GB RAM للنظام) على Windows 11؛ مُتحقَّق منه على M5 MacBook Pro (32 GB موحد). النموذج: Llama 3.3 8B Q4_K_M عبر Ollama. أداة التضمين: nomic-embed-text-v1.5. جميع الأرقام متوسطات ثلاث جلسات بعد الإحماء.
| المعمارية | تعقيد الإعداد | الحد الأقصى من المستندات المختبرة | استعلام p50 @ 1,000 مستند | استعلام p50 @ 10,000 مستند | مثالية لـ |
|---|---|---|---|---|---|
| AnythingLLM (افتراضي) | سحب وإفلات، بدون كود | ~2,000 مستند قبل تراجع الاسترجاع | ~450 ms | غير قابل للاستخدام (الاسترجاع يقل عن 50%) | العروض التجريبية والمجموعات الصغيرة جداً؛ لا تستخدم لأكثر من 500 ملف PDF |
| AnythingLLM (محسَّن) | بدون كود؛ فقط إعدادات (1000/200 + nomic-embed-text) | ~3,000 مستند بشكل مريح | ~310 ms | ~1.4 ثانية، استرجاع ~70% | 100–1,000 مستند، بدون ميزانية للكود المخصص |
| LlamaIndex محلي | ~150 سطر Python، عملية طويلة الأمد | ~8,000 مستند | ~280 ms | ~700 ms مع فهارس هرمية | 1,000–5,000 مستند، مسارات استرجاع منظمة |
| Ollama + ChromaDB مخصص | ~300–400 سطر Python، تكامل BM25 + أداة إعادة ترتيب | ~12,000 مستند | ~340 ms | ~520 ms مع هجين + إعادة ترتيب | 5,000–10,000 مستند، بحث هجين ضروري |
| Ollama + Qdrant | ~500 سطر Python، Docker، مخططات الحمولة | 50,000+ مستند | ~310 ms | ~410 ms مع هجين + تصفية أصلية | 10,000+ مستند، تصفية مكثفة بيانات وصفية |
الخيار 1: AnythingLLM محسَّن (100–1,000 مستند)
الخيار الأقل احتكاكاً الذي لا يزال يُدير مجموعة شخصية من 1,000 مستند عند ضبطه بشكل صحيح. يشمل تطبيق AnythingLLM Desktop قاعدة LanceDB مدمجة ويحلّل PDF/DOCX/MD بشكل أصلي ويتواصل مع Ollama كمزود LLM. تفشل الإعدادات الافتراضية عند حوالي 500 مستند؛ الضبط التالي يرفعه إلى 2,000–3,000.
- النموذج: Llama 3.3 8B Q4_K_M عبر Ollama (5 GB RAM أثناء الاستدلال). على الأنظمة بـ 24 GB+، يُحسِّن Qwen 3 14B Q4 التوليف بشكل ملحوظ.
- أداة التضمين: غيّر من أداة التضمين الافتراضية لـ AnythingLLM إلى nomic-embed-text-v1.5 عبر Ollama. أداة التضمين الافتراضية هي السبب الرئيسي لتقارير "AnythingLLM لا يتوسع".
- التقطيع: 1,000 رمز مع تداخل 200 رمز، يُضبط لكل مساحة عمل في إعدادات Vector Database. الافتراضي 512/0 خاطئ لأي مجموعة أكبر من بضع عشرات من المستندات.
- Top-K: ارفع من الافتراضي 4 إلى 6–8. مع 1,000 مستند، يكون أفضل مقطع في الغالب في الرتبة 5–7، والنموذج يستطيع تجاهل مقاطع ضعيفة أفضل مما يستطيع اختراع المفقودة.
- التقسيم حسب مساحة العمل: أنشئ مساحة عمل لكل فئة مستند (مقالات، عقود، ملاحظات). لكل مساحة عمل LanceDB مفهرس بشكل منفصل؛ الاستعلامات عبر مساحات العمل غير مدعومة لكن الاسترجاع لكل مساحة عمل أعلى بكثير من تجمّع كبير واحد.
⚠️Warning: لا يمتلك AnythingLLM بحثاً هجيناً أصلياً ولا أداة إعادة ترتيب أصلية. إلى ما هو أبعد من ~2,000 مستند ستصادف أخطاء "مستند صحيح، مقطع خاطئ": يستشهد النموذج بمقال لكن يقتبس من المقطع الخاطئ. هذا العرض هو الإشارة للانتقال إلى مستوى LlamaIndex.
الخيار 2: LlamaIndex محلي (1,000–5,000 مستند)
يستبدل LlamaIndex في الوضع المحلي بالكامل 30 دقيقة من إعداد Python باسترجاع هرمي وتوجيه استعلامات ومنحنى توسع أفضل بكثير. نفس خلفية Ollama، نفس أداة التضمين nomic-embed-text-v1.5، لكن طبقة الاسترجاع مبنية لمسارات منظمة بدلاً من top-K أحادي الخطوة.
- المكدّس: Ollama + LlamaIndex + LanceDB (أو ChromaDB) + nomic-embed-text-v1.5 عبر محوّل OllamaEmbedding. مستمر على القرص؛ يعمل كعملية Python طويلة الأمد تتفاعل معها عبر CLI أو غلاف FastAPI صغير.
- DocumentSummaryIndex على VectorStoreIndex: يبني LlamaIndex ملخصاً لكل مستند في وقت الفهرسة، ثم يختار الاسترجاع أولاً المستندات ذات الصلة (بحث الملخصات) ثم يبحث في المقاطع داخل تلك المستندات. هذا أرخص نمط استرجاع هرمي.
- توجيه الاستعلامات: يُرسل RouterQueryEngine استعلامات استرجاع الحقائق إلى فهرس المقاطع واستعلامات التوليف إلى فهرس الملخصات. ~30 سطر من الكود؛ يُضاعف جودة الإجابة في مجموعات المستندات الطويلة.
- استرجاع نافذة الجمل: فهرس ثانٍ اختياري يسترجع جملة هدف بالإضافة إلى N جملة محيطة. مفيد للمجموعات القانونية والأكاديمية حيث تكون الإجابة جملة واحدة لكن معناها يعتمد على الفقرة المحيطة.
- الاستمرارية:
index.storage_context.persist(persist_dir=...)يحفظ كل شيء. وقت إعادة التحميل لفهرس من 5,000 مستند يتراوح بين 10 و30 ثانية على NVMe SSD.
# Minimal LlamaIndex local RAG with hierarchical indices (~30 lines)
from llama_index.core import VectorStoreIndex, DocumentSummaryIndex, SimpleDirectoryReader
from llama_index.embeddings.ollama import OllamaEmbedding
from llama_index.llms.ollama import Ollama
from llama_index.core import Settings
Settings.llm = Ollama(model="llama3.3:8b-instruct-q4_K_M", request_timeout=120)
Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text:latest")
Settings.chunk_size = 1000
Settings.chunk_overlap = 200
docs = SimpleDirectoryReader("./pdfs").load_data()
# Summary index for routing + chunk index for retrieval
summary_index = DocumentSummaryIndex.from_documents(docs)
chunk_index = VectorStoreIndex.from_documents(docs)
summary_index.storage_context.persist("./storage/summary")
chunk_index.storage_context.persist("./storage/chunks")
# At query time, route by question type
response = chunk_index.as_query_engine(similarity_top_k=8).query(
"What sample size did Smith et al. use?"
)
print(response)الخيار 3: Ollama + ChromaDB مخصص (5,000–10,000 مستند)
عند 5,000 مستند تبدأ الإعدادات الافتراضية لـ LlamaIndex في إظهار ضغط: الاسترجاع الخالص بالمتجه يُفوِّت الاستعلامات المحددة معجمياً، وبحث التشابه الجيبي على 50,000 مقطع يتجاوز الميزانية لـ "سريع بما يكفي". مكدّس مخصص مع ChromaDB وبحث هجين BM25 وأداة إعادة ترتيب BGE يُدير 10,000 مستند على محطة عمل بـ 32 GB.
- المكدّس: Ollama + ChromaDB (وضع الخادم) + Whoosh أو Tantivy لـ BM25 + BGE-reranker-v2-m3 (~570 MB، يعمل على CPU بـ 50–100 مرشح/ثانية). يُستضاف كعملية Python واحدة أو مقسّم إلى عمال استيعاب + استعلام.
- البحث الهجين في وقت الاسترجاع: شغّل BM25 والاسترجاع الكثيف بالمتجه بشكل متوازٍ، خذ أفضل 25 من كل منهما، أزِل التكرارات ثم أعِد ترتيب أفضل 50 مدمج بالمُشفِّر التقاطعي. أفضل K نهائي من 6–8 يذهب للنموذج.
- حقول بيانات الوصف في ChromaDB: اشترط
source_filenameوpage_numberوdocument_typeوauthorوyearفي كل مقطع في وقت الفهرسة. التصفية في وقت الاستعلام (where={"document_type": "contract"}) تُقلل نطاق بحث الاسترجاع بين 5 و10 أضعاف بدون فقدان جودة. - الفهرسة دفعةً دفعة: يولّد ChromaDB التضمينات في دفعات من 32–128 مقطعاً. على RTX 4070، BGE-reranker هو عنق الزجاجة (50–100 مرشح/ثانية على CPU؛ 400+/ثانية على GPU).
- الاستمرارية: يكتب ChromaDB في مجلد SQLite + Parquet. فهرس من 50,000 مقطع على القرص ~3–5 GB. النسخ الاحتياطي هو نسخ المجلد.
💡Tip: BGE-reranker-v2-m3 هو الإضافة الأعلى أثراً على هذا النطاق. بدونها، تحصل على مستندات صحيحة لكن مقاطع خاطئة حوالي 15–25% من الوقت. معها ينخفض ذلك إلى أقل من 5% وتكون للنموذج قاعدة نظيفة للعمل عليها. ضَع في ميزانيتك 200–500 ms التي تضيفها لزمن استجابة الاستعلام — تستحق كل ميلي ثانية.
الخيار 4: Ollama + Qdrant (10,000+ مستند)
إلى ما هو أبعد من 10,000 مستند يبدأ ChromaDB في العملية الواحدة في فقدان مزايا الاستجابة. يُدير Qdrant في وضع Docker بعقدة واحدة 50,000+ مستند مع بحث هجين أصلي وتصفية قائمة على الحمولة وفهرسة HNSW مضبوطة للاستعلامات في أقل من ثانية. نفس خلفية Ollama؛ الفرق هو مخزن المتجهات.
- المكدّس: Ollama + Qdrant (Docker، عقدة واحدة) + متجهات متفرقة أصلية (ما يعادل BM25 مدمج في Qdrant 1.10+) + BGE-reranker-v2-m3 + طبقة تنسيق Python صغيرة.
- الهجين الأصلي: يدعم Qdrant متجهات كثيفة + متفرقة في نفس المجموعة مع دمج موزون في وقت الاستعلام. لا عملية BM25 منفصلة للصيانة.
- ضبط HNSW: مع 50,000+ متجه، ارفع
ef_constructإلى 200 وmإلى 32 لبناء الفهرس، واستخدمef=128في وقت الاستعلام. الإعدادات الافتراضية تعمل لكنها تتبادل ~10% من الاسترجاع مقابل سرعة البناء. - مخططات الحمولة للتصفية: يتعامل Qdrant مع الحمولات كمواطنين من الدرجة الأولى. فهرس
authorوdocument_typeوyearوtagsكحمولات كلمات مفتاحية لتفعيل التصفية المسبقة في أقل من ميلي ثانية. - الاسترجاع الهرمي: حافظ على مجموعتين —
summaries(متجه واحد لكل مستند) وchunks(المعتادة). وجِّه الاستعلامات أولاً عبر مجموعة الملخصات ثم ابحث في مقاطع معرّفات المستندات المطابقة. - الاستمرارية: يكتب Qdrant في وحدة تخزين واحدة مرفقة. مجموعة من 100,000 مقطع تشغل ~6–12 GB على القرص حسب حجم الحمولة وإعدادات HNSW.
# Qdrant collection with dense + sparse vectors and metadata filtering
from qdrant_client import QdrantClient
from qdrant_client.models import (
Distance, VectorParams, SparseVectorParams, SparseIndexParams
)
client = QdrantClient(host="localhost", port=6333)
client.create_collection(
collection_name="docs",
vectors_config={
"dense": VectorParams(size=768, distance=Distance.COSINE), # nomic-embed-text-v1.5
},
sparse_vectors_config={
"bm25": SparseVectorParams(index=SparseIndexParams(on_disk=False)),
},
)
# Query: hybrid search + payload filter, no separate BM25 process needed
from qdrant_client.models import Filter, FieldCondition, MatchValue, Prefetch
results = client.query_points(
collection_name="docs",
query=dense_vec,
using="dense",
prefetch=[
Prefetch(query=sparse_vec, using="bm25", limit=25),
Prefetch(query=dense_vec, using="dense", limit=25),
],
query_filter=Filter(
must=[FieldCondition(key="document_type", match=MatchValue(value="contract"))]
),
limit=50, # before rerank
)البحث الهجين: BM25 + متجه يتفوق على أيٍّ منهما منفرداً
الاسترجاع الخالص بالتشابه الجيبي يُفوِّت الاستعلامات التي تعتمد على أسماء أعلام نادرة وأرقام قوانين ومعرفات محددة. BM25 الخالص يُفوِّت الاستعلامات المصاغة بشكل مختلف عن النص المصدر. الجمع بينهما يتفوق على أيٍّ منهما منفرداً، خاصةً إلى ما هو أبعد من 1,000 مستند. تكلفة التطبيق: استدعاء استرجاع إضافي واحد وخطوة دمج.
- لماذا يفشل الكثيف وحده: التضمينات تُقلّل من وزن الرموز النادرة. استعلامات مثل "RFC 9110 القسم 7.4" أو "MNDA-2024-0143" تُضمَّن بالقرب من مقاطع IETF/عقد عامة. BM25 يلتقط المعرف الدقيق؛ البحث بالتشابه الجيبي وحده يُفوِّته.
- لماذا يفشل BM25 وحده: المطابقة المعجمية تُفوِّت الأساليب الأخرى. استعلام "كيف نُلغي؟" على مقطع بعنوان "إجراءات الإنهاء" يطابق في الفضاء الكثيف لكن يحصل على 0 في BM25.
- Reciprocal Rank Fusion (RRF) هو الجامع المعياري: لكل مقطع يظهر في أي قائمة نتائج، درجّه كـ
1/(60+rank_dense) + 1/(60+rank_bm25). رتّب بشكل تنازلي. 60 ثابت تمهيد؛ تعمل القيم بين 30–100 عملياً. - الوصفة العملية: استرجع أفضل 25 من كل أسلوب، ادمج عبر RRF، خذ أفضل 50، أرسل لأداة إعادة الترتيب ثم أفضل 6–8 للنموذج. هذا هو خط أنابيب الإنتاج القياسي على أي نطاق يتجاوز 1,000 مستند.
- تكلفة التخزين: فهارس BM25 صغيرة (~50–150 MB لـ 10,000 مستند) مقارنةً بالفهارس الكثيفة (~500 MB–2 GB على نفس النطاق). إضافة BM25 لمخزن كثيف موجود اقتصادية.
📌Note: Qdrant 1.10+ وWeaviate يدعمان البحث الهجين بشكل أصلي. ChromaDB يتطلب إضافة Whoosh أو Tantivy. LanceDB له دعم هجين تجريبي لكن الواجهة البرمجية تتغير حتى مايو 2026 — راجع التوثيق الحالي قبل الالتزام. الهجين الأصلي يُبرر اختيار مخزن المتجهات.
إعادة الترتيب: خطوة تنقية أفضل N
أداة إعادة الترتيب هي مُشفِّر تقاطع صغير يُدرِّج أزواج (استعلام، مرشح) بشكل مشترك بدلاً من بشكل مستقل. شغّلها على أفضل 25–50 مرشحاً من البحث الهجين لتصحيح حالات الفشل "مستند صحيح، مقطع خاطئ". أعلى رافعة جودة فردية بين 5,000 و50,000 مستند.
- BGE-reranker-v2-m3 (~570 MB، متعدد اللغات، Apache 2.0) هو الخيار الافتراضي في مايو 2026. يعمل بـ 50–100 مرشح/ثانية على CPU حديث؛ 400+ /ثانية على GPU. تكلفة زمن الاستجابة لإعادة ترتيب أفضل 50 هي ~200–500 ms على CPU، ~80–150 ms على GPU.
- لماذا تتفوق المُشفِّرات التقاطعية في الاسترجاع: التضمينات الكثيفة تُشفِّر الاستعلام والمستند بشكل مستقل لذا لا يراهما النموذج معاً أبداً. مُشفِّر تقاطع يقرأ `[CLS] استعلام [SEP] مرشح [SEP]` بشكل مشترك ويُدرِّج الزوج مباشرةً. يقفز Recall@5 عادةً 15–25 نقطة.
- أين تحقن أداة إعادة الترتيب: بعد البحث الهجين وقبل النموذج. خذ أفضل 50 من الهجين، أعِد الترتيب إلى أفضل 6–8، وأرسل تلك للنموذج كسياق.
- بديل — Cohere Rerank API: جودة أعلى لكن يتطلب استدعاءً سحابياً. للمكدسات المحلية بالكامل، BGE-reranker-v2-m3 هو الافتراضي العملي. mxbai-rerank-base-v2 مرشح بديل قوي.
- تخطّي أداة إعادة الترتيب مقبول دون 1,000 مستند: مكسب الجودة لا يبرر تكلفة زمن الاستجابة. إلى ما هو أبعد من 5,000 مستند، تركها يُبقي ~15–25% من الإجابات مستندةً إلى مقاطع خاطئة.
تصفية بيانات الوصف: تقليص نطاق البحث مسبقاً
تخزين بيانات وصفية منظمة في كل مقطع يُتيح لك تقليص الفهرس قبل تشغيل البحث بالمتجهات. في مجموعة من 10,000 مستند، يُقلص تصفية حمولة نموذجية نطاق الاسترجاع بين 5 و10 أضعاف بدون فقدان جودة. رخيصة الإضافة في وقت الفهرسة؛ مكلفة الإضافة لاحقاً.
- حقول الحمولة الشاملة لملء في وقت الفهرسة:
source_filenameوpage_numberوdocument_type(مقال / عقد / ملاحظة / ويكي) وauthorوyearوlanguageبالإضافة إلى علامات خاصة بالمجال (مثلcase_numberوproject_idوclient_id). - التصفية المسبقة في وقت الاستعلام: "ما الذي قالته محاضر مجلس الإدارة للربع الثالث 2024 عن التسعير؟" ← صفِّ
document_type=board_minutes AND year=2024 AND quarter=3أولاً، ثم بحث بالمتجه داخل ~12 مستند بدلاً من 10,000. - دعم مخزن المتجهات: تدعم حمولات Qdrant وخصائص Weaviate وبيانات وصف ChromaDB وأعمدة مخطط LanceDB جميعها التصفية. يتفاوت الأداء — تصفية حمولة Qdrant على حقول مفهرسة أقل من ميلي ثانية؛ تصفية بيانات وصف ChromaDB على أكثر من 100,000 مقطع قد تضيف 50–150 ms.
- الاستخراج التلقائي للبيانات الوصفية: للمجموعات القانونية، خطوة نموذج صغيرة في وقت الفهرسة يمكنها استخراج أرقام القضايا والتواريخ وأسماء الأطراف لكل مستند. تكلف ~30 ثانية لكل مستند على Llama 3.3 8B؛ تُشغَّل مرة واحدة لكل استيعاب.
- دمج مع البحث الهجين: تصفية الحمولة تُقلص الكون ← استرجاع BM25 + كثيف داخل المجموعة المصفاة ← إعادة الترتيب. تصفية الحمولة هي أرخص تسريع 5–10 أضعاف في أي نظام RAG كبير.
الاسترجاع الهرمي: الملخص أولاً، المقاطع لاحقاً
يحافظ الاسترجاع الهرمي على فهرسين — فهرس ملخصات لكل مستند وفهرس مقاطع — ويوجّه الاستعلامات عبر كليهما. بحث الملخصات يجد المستندات الصحيحة؛ بحث المقاطع يجد المقاطع الصحيحة داخلها. يُقلص الضوضاء في استعلامات التوليف؛ غير ضروري إلى حد بعيد لاسترجاع الحقائق.
- ملخصات لكل مستند: في وقت الفهرسة، اطلب من النموذج كتابة ملخص من 100–200 رمز لكل مستند. أنشئ تضمينات تلك الملخصات في مجموعة
summariesمنفصلة. التكلفة ~30–90 ثانية لكل مستند على Llama 3.3 8B. - الاسترجاع على مرحلتين: (1) أنشئ تضمين الاستعلام، ابحث في
summaries، خذ أفضل 5 مستندات؛ (2) داخل تلك المستندات الخمسة، استرجع أفضل 8 مقاطع عبر بحث هجين؛ (3) طبّق إعادة الترتيب إن لزم؛ (4) أرسل للنموذج. - متى يُفيد أكثر: استعلامات التوليف والمتعددة المستندات ("قارن كيف تتناول هذه المقالات X"). استرجاع الحقائق ("ما القيمة التي أفادت بها Smith؟") يعمل جيداً بفهرس المقاطع فقط — الانحراف عبر الملخص يضيف زمن استجابة بدون مكسب جودة.
- مقايضة التكلفة: يضاعف تخزين الفهرس (الملخصات صغيرة لكن الفهرس نفسه بنية تحتية مضاعفة). يضاعف زمن الاستجابة للاستعلامات غير الموجَّهة. المكسب في تقليص الضوضاء من 10,000+ مستند.
- LlamaIndex يدمجه:
DocumentSummaryIndexبالإضافة إلىRouterQueryEngineتطبيق من 30 سطر. Python مخصص مع ChromaDB أو Qdrant هو ~80–120 سطر.
قياسات موثوقة عند 100 و1,000 و10,000 مستند
المعماريات الأربع مقارنة على مجموعات بيانات متطابقة. منصة الاختبار: NVIDIA RTX 4070 (12 GB VRAM، 32 GB RAM)، Windows 11 + WSL2، NVMe SSD. مُتحقَّق منه على M5 MacBook Pro (32 GB موحد). الأرقام متوسطات ثلاث جلسات بعد الإحماء. وقت الفهرسة والتخزين على القرص وزمن استجابة الاستعلام p50 وp95 على نطاقات مختلفة.
| المكدّس | المقياس | @ 100 مستند | @ 1,000 مستند | @ 10,000 مستند |
|---|---|---|---|---|
| AnythingLLM محسَّن | وقت الفهرسة | ~1 دقيقة | ~12 دقيقة | غير مختبر لأكثر من 3,000 مستند |
| AnythingLLM محسَّن | متجهات على القرص | ~30 MB | ~280 MB | غير متاح |
| AnythingLLM محسَّن | استعلام p50 / p95 | ~180 / 420 ms | ~310 / 880 ms | غير متاح (الاسترجاع منخفض جداً) |
| LlamaIndex محلي | وقت الفهرسة | ~3 دقائق (شامل الملخصات) | ~25 دقيقة | ~3.5 ساعات |
| LlamaIndex محلي | التخزين على القرص | ~45 MB | ~340 MB | ~3.6 GB |
| LlamaIndex محلي | استعلام p50 / p95 | ~210 / 480 ms | ~280 / 720 ms | ~700 / 1,400 ms |
| Ollama+ChromaDB مخصص | وقت الفهرسة | ~2 دقيقتان | ~18 دقيقة | ~2.8 ساعة |
| Ollama+ChromaDB مخصص | التخزين على القرص | ~40 MB | ~310 MB | ~3.2 GB |
| Ollama+ChromaDB مخصص | استعلام p50 / p95 | ~240 / 540 ms (مع إعادة ترتيب) | ~340 / 760 ms | ~520 / 1,100 ms |
| Ollama + Qdrant | وقت الفهرسة | ~2 دقيقتان | ~17 دقيقة | ~2.6 ساعة |
| Ollama + Qdrant | التخزين على القرص | ~55 MB | ~410 MB | ~4.4 GB |
| Ollama + Qdrant | استعلام p50 / p95 | ~220 / 480 ms | ~310 / 690 ms | ~410 / 920 ms |
تحديد حجم التخزين ومتطلبات الأجهزة
يتوسع التخزين خطياً مع المستندات لكن RAM يتوسع بشكل شبه خطي لأن معظم محركات الاسترجاع تُعيّن فهارس الذاكرة بدلاً من تحميلها بالكامل. الأرقام التالية تفترض nomic-embed-text-v1.5 (768 بُعداً) ومقاطع من 1,000 رمز مع تداخل 200. خطط لمساحة قرص 3–5 أضعاف حجم المجموعة الخام.
- النص الخام لـ 1,000 ملف PDF (~12 صفحة لكل منها): ~50–150 MB من النص المستخرج. يتفاوت بشكل كبير حسب الكثافة.
- متجهات لـ 1,000 مستند: ~300–400 MB على القرص شاملاً تكلفة فهرس HNSW. ~120–180 MB إذا تجاهلت فهرس HNSW واستخدمت البحث بالقوة الغاشمة (مقبول دون 5,000 مستند).
- متجهات لـ 10,000 مستند: ~3–5 GB على القرص. بناء HNSW يستغرق 10–30 دقيقة على CPU حديث.
- متجهات لـ 50,000 مستند: ~15–25 GB على القرص. وقت بناء الفهرس هو عنق الزجاجة — خطط لـ 2–4 ساعات من عمل CPU لمرة واحدة.
- RAM أثناء الاستعلام: الاسترجاع الكثيف يحتاج ~30–50% من الفهرس في ذاكرة العمل لاستعلامات ذات زمن استجابة منخفض. فهرس من 5 GB يُستعلَم بشكل مريح بـ 8–16 GB RAM مع HNSW؛ القوة الغاشمة تحتاج الفهرس كاملاً في الذاكرة.
- RAM أثناء الفهرسة: يرتفع إلى 2–3 أضعاف حجم نموذج التضمين (~600 MB لـ nomic-embed-text) بالإضافة إلى النص لكل دفعة. 8 GB RAM حرة كافية لخطوة الفهرسة.
- GPU مقابل CPU: إنتاجية التضمين أسرع 4–8 أضعاف على GPU منفصل أو Apple Silicon. للفهرسة على مرور واحد مع 10,000+ مستند، يوفر GPU 1–3 ساعات. للتضمين في وقت الاستعلام (استعلام واحد في كل مرة)، CPU كافٍ.
- نوع القرص مهم: NVMe SSD هو الحد الأدنى العملي من 5,000+ مستند. SATA SSD يضيف 30–100% لزمن استجابة الاستعلامات الباردة؛ القرص الدوار غير قابل للاستخدام إلى ما هو أبعد من ~2,000 مستند.
الفهرسة التدريجية وإزالة التكرار
إضافة 100 ملف PDF جديد لفهرس من 10,000 مستند يجب ألا تتطلب إعادة فهرسة جميع الـ 10,000. جميع المعماريات في هذا الدليل تدعم الإضافات التدريجية؛ المشكلة الأصعب هي كشف المستندات المكررة تقريباً وإزالتها، التي تُضاعف المقاطع بصمت وتُربك الاسترجاع.
- إزالة التكرار الدقيق القائم على التجزئة عند الاستيعاب: SHA-256 لبايتات الملف الخام. تخطَّ الملفات التي تجزئتها موجودة بالفعل في الفهرس. رخيص، يلتقط الملفات المتطابقة لكن يُفوِّت شبه المكررة (مسحات ضوئية OCR مختلفة لنفس المستند، تحويلات الصيغ).
- إزالة التكرار بتجزئة المحتوى: SHA-256 للنص الخام المستخرج بعد حذف المسافات البيضاء. يلتقط نفس المستند بصيغ ملفات مختلفة. يضيف ~5 ms لكل ملف في الاستيعاب.
- MinHash لشبه المكررات: للمجموعات القانونية والأكاديمية حيث تتراكم مسودات متعددة لنفس المستند، احسب بصمة MinHash (~128 بايت لكل مستند) وتخطَّ الملفات ضمن حد تشابه Jaccard لمدخل موجود.
- معرّفات المستندات دائمة: لا تعيد استخدام معرّف مستند بعد حذفه. كثيراً ما تحتفظ مخازن المتجهات بمتجهات يتيمة لفترة وجيزة؛ إعادة استخدام المعرّفات يُسبب ارتباكاً صامتاً. استخدم UUID أو معرّفات قائمة على التجزئة.
- إعادة التضمين عند تغيير أداة التضمين: جميع المعماريات تُجبر على إعادة فهرسة كاملة عند تغيير نموذج التضمين. خطط لاختيار أداة تضمين تلتزم بها لمدة سنة على الأقل قبل فهرسة 10,000 مستند.
- الحذف: ChromaDB وQdrant يدعمان حذف النقاط بالمعرّف. LanceDB يتطلب خطوة ضغط لاستعادة مساحة القرص — خطط لها أسبوعياً إذا حذفت أكثر من ~5% من المجموعة شهرياً.
⚠️Warning: أكثر الأعطال صمتاً في أنظمة RAG الشخصية طويلة الأمد هو الاستيعاب المكرر: نفس المقال مضاف بصيغتين مختلفتين، أو نفس صفحة الويكي مُصدَّرة مرتين. الأعراض تشمل "النموذج يستمر في الاستشهاد بنفس المقطع ثلاث مرات" و"استعلامات التوليف تصبح غريبة التكرار بشكل لافت". أضف إزالة التكرار بتجزئة المحتوى قبل تجاوز 1,000 مستند.
مراقبة جودة RAG على نطاق واسع
نظام RAG من 10,000 مستند يتراجع بصمت مع الوقت مع إضافة مستندات وتغيير النماذج واكتشاف الحالات الحدية. الحل هو منصة تقييم صغيرة — 30–50 زوجاً استعلام/إجابة مختاراً بعناية — تُعاد تشغيلها عند كل تغيير مهم. خمس دقائق من التقييم تمنع أسابيع من البحث المحيّر.
- بناء مجموعة ذهبية صغيرة: 30–50 استعلاماً تعرف الإجابة الصحيحة لها، مستخرجة من الاستخدام الفعلي. تشمل: استرجاع حقائق (5–10)، توليف (5–10)، عبر مستندات (5–10)، حالات حدية (5–10)، واستعلامات فقدان معروف (5–10) حيث الإجابة غير موجودة في المجموعة.
- تتبع ثلاثة مقاييس لكل استعلام: استرجاع الاسترجاع (هل ظهر المقطع الصحيح في أفضل K?)، دقة التوليد (هل الإجابة تطابق المقطع?)، ومعدل الرفض (هل يقول النظام بشكل صحيح "غير موجود في المجموعة" لاستعلامات الفقدان المعروف?).
- أعِد التشغيل عند كل تغيير مهم: دفعات استيعاب جديدة، تغييرات أداة التضمين، تغييرات حجم المقطع، تعديلات الكلمة التوجيهية. قارن النتائج بالتشغيل السابق؛ ضَع علامة على أي استعلام تغير فيه استرجاع الاسترجاع أو الإجابة.
- Trulens أو RAGAS لأطر التقييم الآلي. كلاهما يعمل محلياً ويتكامل مع LlamaIndex. التقييم اليدوي لـ 30–50 استعلاماً صالح أيضاً وغالباً أدق.
- ميزانيات زمن الاستجابة: تتبع زمن استجابة الاستعلام p50 وp95 بمرور الوقت. قفز 50% في p95 يعني عادةً أن الفهرس تجاوز RAM — الإشارة المبكرة بأنك تحتاج للانتقال إلى المستوى التالي من المعمارية.
الأسئلة الشائعة
عند أي عدد من المستندات تفشل إعدادات RAG الافتراضية؟
على حاسوب محمول بـ 16 GB مع إعدادات افتراضية (مقاطع من 512 رمز، بدون تداخل، أداة تضمين افتراضية، top-K من 4)، تبدأ جودة الاسترجاع في التراجع بشكل ملحوظ عند 1,000–2,000 مستند وتصبح غير قابلة للاستخدام إلى ما هو أبعد من 5,000. نمطا الفشل هما "مستند صحيح، مقطع خاطئ" (top-K ضيق جداً على النطاق الواسع) وتراجعات استرجاع صامتة حين يتجاوز الفهرس RAM. الإعدادات المحسَّنة لـ AnythingLLM (مقاطع 1,000/200 + nomic-embed-text-v1.5) ترفع المنحدر إلى ~3,000 مستند. إلى ما هو أبعد من ذلك، تحتاج بحثاً هجيناً وأداة إعادة ترتيب.
هل يجب أن أستخدم البحث الهجين (BM25 + متجه)؟
نعم، إلى ما هو أبعد من 1,000 مستند. الاسترجاع الكثيف وحده يُفوِّت الاستعلامات التي تحتوي أسماء أعلام نادرة وأرقام قوانين ومعرفات محددة (مثل "Section 230(c)(1)" أو رقم MSA لعقد ما). BM25 وحده يُفوِّت الاستعلامات المُعاد صياغتها. Reciprocal Rank Fusion للقائمتين الأولى 25 هو الجامع المعياري. Qdrant وWeaviate يدعمان الهجين بشكل أصلي؛ ChromaDB يتطلب إضافة Whoosh أو Tantivy. تكلفة الاسترجاع الإضافية ~50–100 ms؛ مكسب الجودة كبير.
كم مساحة تخزين تحتاج 1,000 ملف PDF بعد إنشاء التضمينات؟
حوالي 250–400 MB على القرص للفهرس المتجه الكثيف باستخدام nomic-embed-text-v1.5 (768 بُعداً) مع مقاطع من 1,000 رمز وتداخل 200 رمز. أضف ~50–150 MB لفهرس BM25 إذا استخدمت البحث الهجين، و~50–100 MB للملخصات لكل مستند إذا استخدمت الاسترجاع الهرمي. معظم قواعد بيانات المتجهات لا تخزن ملفات PDF الأصلية — فقط النص المستخرج والتضمينات. مجموعة من 10,000 ملف PDF تحتاج ~3–5 GB للمتجهات بالإضافة إلى ما تشغله ملفات PDF الأصلية.
هل تُفيد إعادة الترتيب على النطاق الواسع؟
نعم — إعادة الترتيب هي الإضافة الأعلى أثراً الفردية بين 5,000 و50,000 مستند. بدون أداة إعادة ترتيب، تحدث حالات فشل "مستند صحيح، مقطع خاطئ" ~15–25% من الوقت على هذا النطاق. مع BGE-reranker-v2-m3 على أفضل 50 مرشحاً من البحث الهجين، ينخفض ذلك إلى أقل من 5%. تضيف أداة إعادة الترتيب ~200–500 ms على CPU أو ~80–150 ms على GPU. دون 1,000 مستند مكسب الجودة لا يبرر تكلفة زمن الاستجابة؛ إلى ما هو أبعد من 5,000 مستند، تجاهلها يُبقي نتائج استرجاع حقيقية على الطاولة.
كيف أتعامل مع المستندات المكررة أو شبه المكررة؟
إزالة التكرار على ثلاث طبقات: SHA-256 لبايتات الملف الخام (يلتقط الملفات المتطابقة)، SHA-256 للنص الخام المستخرج بعد تطبيع المسافات البيضاء (يلتقط صيغ ملفات مختلفة بنفس المحتوى) وبصمات MinHash بحد Jaccard ~0.85 (يلتقط شبه المكررات كمسودات متعددة أو نسخ OCR مختلفة). شغّل الثلاثة في الاستيعاب قبل التضمين. أكثر أعراض إزالة التكرار المهملة شيوعاً هو "استعلامات التوليف تصبح غريبة التكرار بشكل لافت" — نفس المقطع مخزَّن ثلاث مرات تحت ثلاثة معرّفات، لذا يراه النموذج ثلاث مرات في السياق.
هل يمكنني إضافة مستندات بشكل تدريجي بدون إعادة فهرسة كل شيء؟
نعم، جميع المعماريات في هذا الدليل تدعم الإضافات التدريجية. ChromaDB وQdrant يقبلان مقاطع جديدة عبر استدعاءات إدراج بسيطة؛ LanceDB يُضيف إلى ملفاته الإلحاقية فقط؛ LlamaIndex يُغلّف أياً منهما. الاستثناء هو تغيير نموذج التضمين — ذلك يُجبر على إعادة فهرسة كاملة لأن خلط تضمينات من إصدارين مختلفين من النموذج في فهرس يُدهوِر الاسترجاع بصمت. اختر أداة التضمين قبل تجاوز 5,000 مستند والتزم بها لمدة سنة على الأقل.
هل يجب أن أستخدم تصفية بيانات الوصف للمجموعات الكبيرة؟
نعم — تصفية بيانات الوصف هي أرخص تسريع 5–10 أضعاف على النطاق الواسع. اشترط source_filename وpage_number وdocument_type وauthor وyear وأي علامات خاصة بالمجال في كل مقطع في وقت الفهرسة. في وقت الاستعلام، صفِّ مسبقاً بالحمولة قبل تشغيل البحث بالمتجهات. في مجموعة من 10,000 مستند، يُقلص تصفية نموذجية نطاق البحث إلى بضع مئات من المقاطع بدون فقدان جودة. Qdrant وWeaviate لديهما دعم حمولة من الدرجة الأولى؛ ChromaDB وLanceDB يدعمانه أيضاً لكن بتنفيذ تصفية أبطأ قليلاً إلى ما هو أبعد من 100,000 مقطع.
كيف أراقب جودة RAG على النطاق الواسع؟
ابنِ مجموعة ذهبية صغيرة — 30–50 زوجاً استعلام/إجابة مختاراً بعناية يغطي استرجاع الحقائق والتوليف والمتعدد المستندات والحالات الحدية واستعلامات الفقدان المعروف — وأعِد تشغيلها عند كل تغيير مهم (استيعاب جديد، تغيير أداة التضمين، تغيير حجم المقطع، تعديل الكلمة التوجيهية). تتبع استرجاع الاسترجاع (هل ظهر المقطع الصحيح في أفضل K?)، دقة التوليد (هل الإجابة تطابق المقطع?) ومعدل الرفض (هل يقول النظام "غير موجود في المجموعة" عند الحاجة?). Trulens وRAGAS يُؤتمتان هذا؛ التقييم اليدوي لـ 30 استعلاماً صالح أيضاً وغالباً أدق.
ما الأجهزة التي أحتاجها لـ 10,000 مستند؟
الحد الأدنى: 32 GB RAM للنظام وNVMe SSD مع 50+ GB حرة وGPU منفصل بـ 8 GB+ VRAM أو Apple Silicon بذاكرة موحدة 32 GB+. GPU/Apple Silicon لسرعة الفهرسة على مرور واحد (يوفر 1–3 ساعات في مرور فهرسة 10,000 مستند)؛ الاستدلال في وقت الاستعلام يعمل جيداً على CPU بعد بناء الفهرس. SATA SSD مقبول لكن يضيف 30–100% لزمن استجابة الاستعلامات الباردة؛ القرص الدوار غير قابل للاستخدام إلى ما هو أبعد من ~2,000 مستند. RAM هو القيد الذي يظهر أولاً — فهرس من 5 GB يُستعلَم بشكل مريح بـ 16 GB RAM مع فهرسة HNSW.
هل يمكنني تشغيل RAG متعدد المستخدمين محلياً؟
نعم — ضع Open WebUI أمام أي من معماريات هذا الدليل، أو غلّف مكدّس Python المخصص في خدمة FastAPI صغيرة. تعدد المستخدمين يُغيّر التركيز التشغيلي (المصادقة، عزل المستندات لكل مستخدم، حد المعدل، مساحات عمل اختيارية لكل مستخدم) لكن ليس معمارية الاسترجاع. Open WebUI يُدير المصادقة وOAuth والوصول إلى المستندات القائم على الأدوار بشكل أصلي. لـ 5+ مستخدمين متزامنين على مجموعة من 10,000 مستند، خطط لتشغيل أداة التضمين على GPU أثناء الفهرسة وعلى CPU أو GPU للتضمين في وقت الاستعلام حسب QPS — أداة تضمين CPU واحدة تُدير ~3–5 QPS بشكل مريح.