تقطيع النصوص الضخمة (Text Splitters) إلى أجزاء صغيرة تتناسب مع حجم الـ LLMs

دقائق القراءة: 5

ما المقصود بتقطيع النصوص الضخمة ولماذا يُعد خطوة حاسمة؟

عند بناء أي تطبيق يعتمد على LLMs، فإن أول قيد هندسي يظهر مباشرة هو حد النافذة السياقية Context Window. النموذج لا يستطيع استقبال كتاب كامل أو ملف PDF ضخم دفعة واحدة بدون خسارة في الأداء أو ارتفاع هائل في التكلفة. هنا تأتي وظيفة Text Splitters: تقسيم المحتوى إلى مقاطع صغيرة قابلة للمعالجة، مع الحفاظ قدر الإمكان على المعنى والسياق.

هذه العملية ليست مجرد تقطيع ميكانيكي للنص، بل قرار معماري يؤثر مباشرة على جودة البحث، دقة الاسترجاع، أداء نظام RAG، وفعالية بناء التضمينات Embeddings. إذا كانت المقاطع كبيرة جداً، فقد تتجاوز السعة أو تحتوي على أفكار متعددة تربك الاسترجاع. وإذا كانت صغيرة أكثر من اللازم، فسوف تفقد الترابط الدلالي وتنتج نتائج مبتورة.

المشكلة الهندسية: من النص الخام إلى وحدات قابلة للفهم

في خطوط معالجة البيانات الخاصة بالتطبيقات التوليدية، يبدأ التدفق عادةً من مصدر مثل ملف PDF أو صفحة ويب أو قاعدة معرفية داخلية، ثم يمر بمراحل: الاستخراج، التنظيف، التقطيع، التحويل إلى Embeddings، التخزين في قاعدة بيانات متجهة Vector Database، ثم الاسترجاع والإرسال إلى النموذج.

مرحلة التقطيع تقع في منتصف هذا المسار، لكنها عملياً تتحكم في نجاح المراحل اللاحقة. عندما تقسم الوثيقة، فأنت تحدد:

  • حجم الوحدة التي سيتم تمثيلها عددياً.
  • كمية السياق التي ستدخل لكل متجه Vector.
  • مدى دقة التطابق أثناء Semantic Search.
  • التكلفة المرتبطة بعدد المقاطع وحجمها.

ولهذا السبب، فهم إدارة الرموز Tokens مهم جداً قبل اختيار استراتيجية التقسيم.

أنواع استراتيجيات التقسيم الشائعة

1) التقسيم حسب عدد الأحرف

أبسط أسلوب هو قطع النص كل عدد ثابت من الأحرف باستخدام Character Splitter. هذا النهج سريع، لكنه غير ذكي دلالياً، لأنه قد يقطع الجملة أو الفقرة في منتصفها.

يصلح هذا الأسلوب للمعالجة الأولية أو عندما تكون البنية النصية ضعيفة وغير منتظمة، لكنه ليس الخيار الأمثل لتطبيقات الاسترجاع الدقيقة.

2) التقسيم التكراري الهرمي

الأسلوب الأشهر عملياً هو RecursiveCharacterTextSplitter في إطار LangChain. فكرته أنه يحاول التقسيم أولاً عند الفواصل المنطقية مثل الفقرات، ثم الأسطر، ثم المسافات، ثم الأحرف إذا اضطر. بهذه الطريقة، يحافظ على المعنى أكثر من القطع الثابت.

3) التقسيم حسب الرموز

بعض النماذج لا يهمها عدد الأحرف بقدر ما يهمها عدد Tokens. لذلك يُفضل أحياناً استخدام قواطع تعتمد على Tokenizer نفسه. هذا أدق من ناحية التكلفة والتوافق مع نافذة النموذج، خصوصاً في الإنتاج.

4) التقسيم الدلالي

في الحالات المتقدمة، يمكن تقسيم النص بناءً على التحولات المعنوية بين الجمل أو الفقرات، وليس فقط على الطول. هذا النهج أكثر تعقيداً، لكنه مفيد عندما تكون الوثائق غنية بالأفكار المتعددة، مثل المستندات القانونية أو الأدلة التقنية الطويلة.

عنصر حاسم: التداخل بين المقاطع Chunk Overlap

من الأخطاء الشائعة تقطيع النص إلى مقاطع منفصلة تماماً. المشكلة هنا أن الفكرة قد تبدأ في نهاية مقطع وتكتمل في بداية المقطع التالي. إذا لم تضف تداخلاً بسيطاً، فقد تضيع المعلومة أثناء الاسترجاع.

لذلك نستخدم قيمة مثل chunk_overlap=100 أو أكثر حسب نوع المحتوى. هذا يعني أن آخر جزء من المقطع السابق يُعاد تضمينه في المقطع التالي، مما يحافظ على الاستمرارية الدلالية.

تطبيق عملي باستخدام LangChain

قبل البدء، من المفيد مراجعة إعداد بيئة العمل ثم استخراج النصوص من ملفات PDF. بعد الحصول على النص الخام، يمكن تقسيمه كالتالي:

from langchain_text_splitters import RecursiveCharacterTextSplitter

text = open("document.txt", "r", encoding="utf-8").read()

splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,
    chunk_overlap=120,
    separators=["\n\n", "\n", ". ", " ", ""]
)

chunks = splitter.split_text(text)

for i, chunk in enumerate(chunks[:5], start=1):
    print(f"Chunk {i}:")
    print(chunk)
    print("-" * 80)

هذا المثال يوضح فلسفة التقسيم الهرمي: يبدأ الفصل من الفقرات، ثم الأسطر، ثم الجمل، ثم الكلمات. النتيجة عادةً أفضل بكثير من تقسيم أعمى يعتمد فقط على الطول.

كيف يدخل التقطيع في معمارية RAG؟

في أنظمة RAG، كل مقطع يتحول إلى تمثيل عددي مستقل، ثم يُخزن في قاعدة مثل ChromaDB أو Pinecone. عندما يرسل المستخدم سؤالاً، يتم تحويل السؤال أيضاً إلى Embedding، ثم البحث عن المقاطع الأقرب معنى.

إذا كانت المقاطع مصممة جيداً، فسيتم استرجاع وحدات معرفة مركزة ومتماسكة. أما إذا كانت سيئة التقسيم، فقد يرجع النظام أجزاءً غير مكتملة أو مقاطع طويلة مليئة بضوضاء سياقية. هذا يضعف الإجابة النهائية حتى لو كان النموذج نفسه قوياً.

خطوات البناء البرمجية باختصار

  • استخراج النص من المصدر وتنظيفه من الفراغات والرموز غير المفيدة.
  • اختيار نوع Text Splitter المناسب.
  • ضبط chunk_size وchunk_overlap.
  • تحويل المقاطع إلى متجهات دلالية.
  • تخزينها داخل محرك البحث الدلالي.
  • استرجاع أفضل المقاطع وتمريرها إلى النموذج داخل سلسلة معالجة Chain.

مثال على تجهيز المقاطع قبل التخزين

documents = []

for index, chunk in enumerate(chunks):
    documents.append({
        "id": f"doc_chunk_{index}",
        "text": chunk,
        "metadata": {
            "source": "document.txt",
            "chunk_index": index
        }
    })

print(documents[0])

وجود metadata مهم جداً، لأنه يسمح لاحقاً بإرجاع مصدر المعلومة، ترتيبها، أو إعادة تجميعها عند العرض.

أفضل الممارسات عند اختيار حجم المقطع

لا يوجد رقم سحري يصلح لكل المشاريع، لكن توجد قواعد عملية جيدة:

  • المحتوى التفسيري أو التعليمي يناسبه غالباً حجم متوسط بين 500 و1000 رمز أو ما يكافئه تقريباً.
  • العقود والنصوص القانونية تحتاج مقاطع أكثر حذراً مع تداخل أعلى.
  • الأسئلة الدقيقة جداً تستفيد من المقاطع الصغيرة نسبياً.
  • التلخيصات والتحليل العام قد تستفيد من مقاطع أكبر.

قسّم النص بحيث تحتوي كل وحدة على فكرة متماسكة واحدة قدر الإمكان، ثم اختبر الاسترجاع فعلياً بدلاً من الاعتماد على التخمين.

أخطاء شائعة تضعف جودة النتائج

  • اعتماد chunk_size كبير جداً بدافع تقليل عدد المقاطع.
  • إلغاء overlap بالكامل.
  • تجاهل بنية المستند مثل العناوين والفقرات والقوائم.
  • استخدام نفس استراتيجية التقسيم لكل أنواع المحتوى.
  • عدم اختبار جودة الاسترجاع بعد الفهرسة.

الخلاصة الهندسية

تقطيع النصوص ليس خطوة مساعدة هامشية، بل طبقة أساسية في هندسة التطبيقات المعتمدة على LLMs. نجاح RAG، كفاءة Embeddings، وجودة الاسترجاع كلها تبدأ من هنا. كلما كان التقسيم مبنياً على فهم لطبيعة البيانات، حدود Tokens، وسلوك النموذج، حصلت على تطبيق أكثر دقة وأقل تكلفة وأسهل في التطوير.

وفي المشاريع الاحترافية، لا يُكتفى بتنفيذ Text Splitter واحد ثم المضي قدماً، بل تتم مقارنة عدة إعدادات وقياس أثرها على الاسترجاع، ثم ربطها مع صياغة البرومبتات داخل الكود وتنسيق المخرجات للحصول على سلسلة إنتاج متماسكة وقابلة للتوسع.

7 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *