نظام RAG في بيئة الإنتاج على نطاق واسع: دروس من معالجة أكثر من 10,000 إعلان يوميًا

قمت ببناء خط معالجة (pipeline) لنظام RAG لمنصة توظيف. كان يعمل بشكل جيد في بيئة الاختبار (staging)، لكنه واجه صعوبات تحت ضغط العمل الحقيقي. إن معالجة آلاف الإعلانات يوميًا تتطلب ما هو أكثر من مجرد مخزن متجهات (vector store) جيد. يجب أن تفهم أين تكمن نقاط الضعف في النظام.

إليكم دروسي حول تقسيم البيانات (chunking)، والتمثيلات المتجهة (embeddings)، والتكاليف، وقابلية المراقبة (observability).

1. لا تعتمد على التخمين في استراتيجية تقسيم البيانات (chunking)

تتعامل معظم الشروحات التعليمية مع تقسيم البيانات كإعداد بسيط. أما في بيئة الإنتاج، فإن استراتيجيتك هي التي تحدد الدقة والتكلفة.

اختبرت ثلاث طرق لإعلانات الوظائف:

  • الأجزاء ذات الحجم الثابت (Fixed-size chunks): فشلت هذه الطريقة، حيث كانت تقسم أقسامًا مثل "المتطلبات" و"المزايا" في نقاط عشوائية، مما يؤدي إلى استرجاع بيانات مشوش (noisy retrieval).
  • التقسيم الدلالي (Semantic chunking): كانت هذه الطريقة أفضل ولكنها غير متسقة؛ فبعض الأجزاء كانت طويلة جدًا والبعض الآخر كان قصيرًا جدًا.
  • التقسيم المتكرر للرموز مع التداخل (Recursive character splitting with overlap): كانت هذه الطريقة هي الأفضل. قمت بالتقسيم بناءً على أسطر جديدة وجمل. استخدمت حجم 400 token مع تداخل قدره 50 token، مما يضمن بقاء الجمل التي تمتد عبر جزأين متصلة ببعضها.

نصيحة احترافية: قم بتوحيد بياناتك (Normalize) قبل عملية التقسيم. المصادر المختلفة مثل Greenhouse أو Lever تعيد تنسيقات مختلفة. قم بتنظيف النص أولاً حتى يرى نظام التقسيم هيكلًا متسقًا.

2. التمثيلات المتجهة (Embeddings): التكلفة مقابل الدقة

اختبرت Llama 3.1 عبر Ollama مقابل OpenAI text-embedding-3-small. كان النموذج المحلي مجانيًا ولكنه واجه صعوبة في المصطلحات المتخصصة مثل "equity compensation". مما أنتج نتائج مشوشة. كانت تكلفة OpenAI أعلى ولكنها قدمت تطابقات دقيقة. اخترت OpenAI لأن الاسترجاع السيئ سيكلف أكثر في استدعاءات LLM لاحقًا.

لتوفير الوقت، أقوم بمعالجة الطلبات في مجموعات (batching). أرسل ما يصل إلى 100 جزء في استدعاء واحد، مما يقلل من زمن الاستجابة (latency) ويحافظ على سرعة خط المعالجة.

3. المقايضة في مخزن المتجهات (Vector Store)

استخدمت Pinecone لعمل النموذج الأولي لأنه سريع الإعداد. ومع ذلك، عند التوسع، ارتفعت التكاليف بشكل كبير جدًا.

انتقلت إلى pgvector داخل PostgreSQL.

  • تطلب إعدادها مجهودًا أكبر.
  • وفرت مبالغ ضخمة من المال.
  • وفرت اتساقًا في المعاملات (transactional consistency).

بما أن التمثيلات المتجهة (embeddings) تعيش في نفس قاعدة البيانات التي تحتوي على بيانات الوظائف، فلديك مصدر واحد للحقيقة (source of truth)، ولن تحتاج إلى مزامنة نظامين مختلفين.

4. التحكم في تكاليف LLM

إن تقييم كل إعلان باستخدام GPT-4o أمر مكلف. استخدمت ثلاث تكتيكات لخفض التكاليف:

  • OpenAI Batch API: أقوم بمعالجة مهام التقييم خلال الليل، مما يوفر خصمًا كبيرًا.
  • التخزين المؤقت (Caching): أقوم بتخزين النتائج مؤقتًا لملفات المرشحين المتكررة.
  • تقسيم مستويات النماذج (Model tiering): أستخدم GPT-4o-mini للأدوار الشائعة مثل "Sales Representative". ولا أستخدم GPT-4o إلا للأدوار المتخصصة حيث تكون الدقة أمرًا حيويًا.

5. ابنِ نظام قابلية المراقبة (Observability) أولاً

فشل خط المعالجة الخاص بي ذات مرة بصمت. تسببت البيانات المشوهة في إنشاء أجزاء فارغة، فتخطاها النظام دون إظهار أي خطأ.

أصلحت ذلك بإضافة سجلات منظمة (structured logging) مع معرف ارتباط (correlation ID). سمح لي ذلك بتتبع إعلان واحد من مرحلة الإدخال حتى التقييم، واستطعت أخيرًا معرفة مصادر البيانات التي كانت تسبب الإخفاقات.

الدرس الأكبر: معظم المشكلات تأتي من البيانات الفوضوية، وليس من الذكاء الاصطناعي. أصلح "سباكة" بياناتك أولاً.

Source: https://dev.to/abdul___rehman/production-rag-at-scale-lessons-from-processing-10000-listings-daily-22gm

Optional learning community: https://t.me/GyaanSetuAi