انتقل إلى المحتوى الرئيسي

الوحدة 6 — نافذة السياق وإدارة الذاكرة

نموذجنا لمساعد الدعم يستقبل مُطالبات متنوّعة الأطوال: سؤال قصير، أو محادثة من عشر رسائل مع إرفاق سطر من فاتورة، أو تذكرة قديمة كاملة يريد فريق الدعم تلخيصها. مهما كان النموذج فطنًا، سلوكه يعتمد على ما يُعطى في نافذة السياق: العدد الأقصى من الرموز الذي يستطيع معالجته دفعة واحدة. هذه الوحدة تُشرّح هذه النافذة: حدودها، وكلفتها، وطرق تجاوزها.

ما هي النافذة، وأين تكمن حدودها؟

النافذة عدد أقصى من الرموز — لا من الكلمات ولا من الأحرف. تختلف بين النماذج: 4 آلاف رمز لنماذج قديمة، و8 إلى 32 ألفًا لنماذج الجيل الحالي المفتوحة، ومئات الآلاف لنماذج حديثة مِلكية أو نصف مِلكية. الحدّ ليس تعسّفيًا: تُحدّده بنية الانتباه، وموارد الذاكرة، وطول التسلسلات التي رأى النموذج في التدريب.

نقطة كثيرًا ما تُنسى: الطول التدريبي يحكم. نموذج تدرَّب على تسلسلات بطول 4 آلاف رمز يمكن أن يقبل تقنيًا 8 آلاف عبر تمديد الترميز الوضعي، لكنّ جودته تتدهور فوق الطول التدريبي. أعلن المزوّد أنّ النموذج يقبل 32 ألف رمز؟ اسأل: هل تدرَّب على تسلسلات بهذا الطول فعلًا، أم أنّه امتداد نظري؟

الكلفة التربيعية للانتباه

الانتباه الذاتي، أساس المحوّل، يحسب كلّ زوج (رمز، رمز) في السياق. الكلفة الحسابية تنمو بمربّع الطول LL:

كلفة الانتباهL2d\text{كلفة الانتباه} \propto L^2 \cdot d

حيث dd حجم الحالة المخفيّة. مضاعفة السياق تضرب الكلفة أربعة. ذاكرة الوسائط (وتُسمّى kv-cache، وهي المفاتيح والقيم المخزَّنة لكلّ طبقة) تنمو خطّيًا مع الطول، لكن مضاعفها الثابت كبير: لنموذج 7 مليار وسيط بسياق 32 ألف رمز، يمكن أن تتجاوز kv-cache نحو 8 غيغابايت — أكثر بكثير من الأوزان في التكميم المُوَفَّر (سنراه في الوحدة 8).

النتيجة العملية: السياق ليس مجانيًا. مضاعفة طول المُطالبة لا تُبطئ الاستدلال مرّتين، بل قد تُبطئه أربعة.

ضياع الوسط

ورقة شهيرة عام 2023 كشفت ظاهرة تُسمّى Lost in the Middle. حين تُدسّ معلومة مطلوبة في وسط سياق طويل، يفشل النموذج في استرجاعها كثيرًا. المنحنى المرسوم يشبه U مقلوبة: النموذج يستعمل جيّدًا ما في بداية السياق (تأثير الأوّليّة) وما في نهايته (تأثير الحداثة)، لكن ما في وسطه يُنسى نسيانًا فعليًا.

الاستنتاج المخالف للحدس: إعطاء المزيد من السياق قد يُخفّض الأداء. لو كانت الإجابة تحتاج فقرة واحدة، فتقديم عشر فقرات ذات صلة قد يجعل النموذج يفوّت الفقرة الجيّدة إذا كانت في الوسط. لهذا يجب هندسة ترتيب السياق: الأهمّ في البداية أو النهاية، لا في الوسط.

التلخيص المنزلق

لمحادثات مساعد الدعم الطويلة، لا يمكن الاحتفاظ بالتاريخ كاملًا. الحلّ الكلاسيكي: تلخيص منزلق. تُحفظ الرسائل الأخيرة كما هي، وتُلخَّص الرسائل السابقة في فقرة قصيرة، ثمّ يُعاد التلخيص كلّما تجاوز التاريخ حدًّا.

def gerer_historique(messages, seuil_tokens=3000, tokenizer=None, modele=None):
"""يحفظ آخر ستّ رسائل ويُلخّص الباقي."""
total = sum(len(tokenizer.encode(m["content"])) for m in messages)
if total <= seuil_tokens:
return messages

a_lyer = messages[:-6]
a_garder = messages[-6:]

prompt_resume = [
{"role": "system", "content": "لخّص المحادثة التالية في فقرة قصيرة تحفظ الوقائع والقرارات."},
{"role": "user", "content": "\n".join(f"{m['role']}: {m['content']}" for m in a_lyer)},
]
entrees = tokenizer.apply_chat_template(prompt_resume, return_tensors="pt", add_generation_prompt=True)
sortie = modele.generate(entrees.to(modele.device), max_new_tokens=250, do_sample=False)
resume = tokenizer.decode(sortie[0, entrees.shape[1]:], skip_special_tokens=True)

return [{"role": "system", "content": f"ملخص المحادثة السابقة: {resume}"}] + a_garder

هذا يعمل جيّدًا لمحادثة طويلة، لكنّه يفقد التفاصيل تدريجيًا. سؤال عن رقم فاتورة ذُكر منذ عشر رسائل قد يضيع في التلخيص. عوّض ذلك بحفظ بيانات وصفية بنيوية (رقم التذكرة، اسم العميل، الفاتورات المذكورة) خارج التلخيص، في قاموس Python بسيط يُحقن مع كلّ مُطالبة.

الذاكرة الخارجية

للمحادثات الطويلة جدًّا، أو للمحادثات المتقطّعة على أيّام، تُحفظ الرسائل في قاعدة خارجية (Redis، أو قاعدة توجّه، أو ملفّ JSON بسيط بحسب حجم المشروع). لكلّ تفاعل جديد، يُسترجَع تاريخ محادثات المستخدم عند الحاجة. هذا يُخرج الذاكرة من نافذة السياق ويجعلها متينة عبر الجلسات.

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

RAG: الجواب الحقيقي لمسألة المعرفة

بدل تكبير النافذة أو الضبط الدقيق، الحلّ المُعتمَد على نطاق واسع لتلقين النموذج معرفة خاصّة هو RAG (Retrieval-Augmented Generation): البحث في قاعدة معرفة عن المقاطع ذات الصلة بالسؤال، ثمّ حقنها في السياق قبل التوليد.

المزايا مقارنة بالسياق الطويل: كلفة استدلال أقلّ (لا نحمل مليون رمز، بل عشرة)، وتحديثات فورية للمعرفة (نُضيف مقالًا إلى القاعدة، فينعكس فورًا)، وإمكانية اقتباس المصدر (نعرف من أيّ وثيقة جاءت المعلومة). المسار الكامل — مُشفّرات، ومتّجهات، وقواعد فِهرَست — موضوع الدورة 18 المخصّصة له. نكتفي هنا بذكر أنّ RAG هو الحلّ المفضّل لتلقين النموذج معرفة عن منتجات الشركة وسياستها في الدعم.

السياق الطويل ليس بديل RAG

النماذج التي تُعلن دعم مليون رمز في السياق تُغري بحلٍّ بسيط: احشُر كلّ الوثائق في المُطالبة. لا تفعل. الكلفة تتضاعف تربيعيًا، وضياع الوسط يبتلع المعلومات المدسوسة في الأعماق، وحديث النموذج بلغة أفضل عندما يُقدَّم له المقاطع الخمسة الصحيحة عوض ألف صفحة تحوي هذه المقاطع. RAG يفوز اقتصاديًا ومعرفيًا على السياق الطويل في تقريبًا كلّ الحالات الإنتاجيّة.

في الخلاصة

  • كلفة الانتباه تربيعية في طول السياق، وذاكرة kv-cache خطّية لكن بثوابت كبيرة؛ السياق ليس مجانيًا.
  • ضياع الوسط ظاهرة موثَّقة: النموذج يُهمل ما دُسّ في وسط سياق طويل؛ اجعل الأهمّ في البداية أو النهاية.
  • التلخيص المنزلق يحلّ ذاكرة الجلسة الحاليّة؛ والذاكرة الخارجية تصلح للاستمرار عبر الجلسات، مع تبعات ضبطيّة.
  • RAG، لا السياق الطويل، هو الحلّ المتين لتلقين النموذج معرفة خاصّة؛ يُغطّى في الدورة 18.

الوحدة التالية: الهلوسة — لماذا يخترع النموذج المعلومات بثقة، وما الذي يعمل فعلًا للحدّ منها، وما الحلول التي تبدو منطقيّة لكنّها لا تُنجح.