برمجة ذاكرة الملخصات (Summary Memory) للتعامل مع المحادثات الطويلة جداً بأقل تكلفة

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

ما هي Summary Memory ولماذا نحتاجها؟

عند بناء تطبيقات محادثية تعتمد على نماذج اللغة الكبيرة، تظهر مشكلة عملية مع ازدياد طول الحوار: كل رسالة جديدة تتطلب إعادة إرسال جزء كبير من السجل إلى LLM حتى يحافظ على السياق. هذا يرفع التكلفة، يزيد زمن الاستجابة، ويقرّبنا من حدود context window.

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

بالمقارنة مع Buffer Memory التي تخزن السجل الخام، فإن Summary Memory مناسبة عندما تصبح المحادثة طويلة جداً، أو عندما يكون التطبيق متعدد الجلسات، أو عند الحاجة إلى تقليل كلفة الاستدعاءات في الأنظمة الإنتاجية.

البنية الهندسية لتدفق البيانات داخل ذاكرة الملخصات

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

  • سجل رسائل حديثة قصير يحتفظ بآخر N رسائل.
  • ملخص تراكمي محفوظ كنص منظم.
  • مولد تلخيص يعتمد على LLM أو على خوارزمية مخصصة.
  • آلية قرار تحدد متى يتم تحديث الملخص.
  • مُنشئ prompt النهائي الذي يجمع: تعليمات النظام + الملخص + آخر الرسائل + السؤال الحالي.

التدفق المنطقي عادة يكون كالتالي:

  1. يصل سؤال المستخدم الجديد.
  2. يتم ضمه مؤقتاً إلى السجل الحديث.
  3. إذا تجاوز السجل الحديث عتبة معينة من الرسائل أو tokens، تبدأ عملية التلخيص.
  4. يتم دمج السجل القديم مع الملخص السابق لإنتاج ملخص أحدث وأكثر تكثيفاً.
  5. يُحذف الجزء القديم من السجل الخام ويُحتفظ فقط بآخر الرسائل القريبة زمنياً.
  6. عند الاستدعاء التالي، يُرسل الملخص مع الرسائل الحديثة للنموذج.

هذا النمط مفيد أيضاً إذا كنت تعمل مع LangChain أو أنظمة هجينة تجمع بين الذاكرة والاسترجاع الدلالي والمخرجات المهيكلة.

متى تتفوق Summary Memory على الأنواع الأخرى؟

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

  • جلسات دعم فني طويلة تضم عشرات الرسائل.
  • وكلاء كتابة أو تحليل يعملون على مشروع مستمر عبر عدة جولات.
  • مساعدات تعليمية تتذكر تفضيلات المستخدم وأهدافه.
  • تطبيقات إنتاجية ذات حساسية عالية للتكلفة.
  • أنظمة تستخدم نماذج قوية لكنها مكلفة لكل ألف tokens.

تصميم برومبت التلخيص بشكل يمنع فقدان السياق المهم

أكبر خطر في Summary Memory هو أن التلخيص قد يحذف معلومة محورية. لذلك يجب أن يكون prompt موجهاً بدقة، وهي نقطة ترتبط مباشرة بمقال هندسة الأوامر داخل الكود.

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

هذا النوع من التعليمات يقلل الضجيج ويجعل الملخص أقرب إلى “حالة عمل” بدلاً من “نص موجز” فقط. ويمكنك كذلك طلب مخرجات JSON إذا كنت تريد استهلاكها برمجياً.

تنفيذ عملي باستخدام Python وLangChain

قبل التنفيذ، من المفيد مراجعة إعداد بيئة العمل وجلب مفاتيح API. المثال التالي يبني ذاكرة تلخيصية بسيطة قابلة للتطوير:

from langchain_openai import ChatOpenAI
from langchain.memory import ConversationSummaryMemory
from langchain.chains import ConversationChain

llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0.2
)

memory = ConversationSummaryMemory(
    llm=llm,
    return_messages=True
)

conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True
)

response_1 = conversation.predict(input="أنا أبني مساعداً قانونياً داخلياً لشركة ناشئة.")
response_2 = conversation.predict(input="يجب أن يلتزم بالردود المختصرة وعدم اختراع مواد قانونية.")
response_3 = conversation.predict(input="ما البنية المناسبة لتقليل التكلفة عند زيادة عدد المستخدمين؟")

print(response_3)

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

تنفيذ مخصص بعتبة رسائل وتلخيص تراكمي

إذا كنت تريد تحكماً كاملاً، فابنِ طبقة ذاكرة خاصة بك:

from openai import OpenAI

client = OpenAI()

recent_messages = []
running_summary = ""

def summarize_messages(old_messages, previous_summary):
    transcript = "\n".join(
        f"{m['role']}: {m['content']}" for m in old_messages
    )

    prompt = f"""
Previous summary:
{previous_summary}

New conversation chunk:
{transcript}

Update the summary while preserving:
- user goals
- constraints
- decisions made
- unresolved issues
- factual details
"""

    response = client.chat.completions.create(
        model="gpt-4o-mini",
        temperature=0,
        messages=[
            {"role": "system", "content": "You are a precise conversation summarizer."},
            {"role": "user", "content": prompt}
        ]
    )

    return response.choices[0].message.content

def add_message(role, content, threshold=6):
    global recent_messages, running_summary
    recent_messages.append({"role": role, "content": content})

    if len(recent_messages) > threshold:
        old_chunk = recent_messages[:-2]
        running_summary = summarize_messages(old_chunk, running_summary)
        recent_messages = recent_messages[-2:]

def build_context():
    context_messages = []
    if running_summary:
        context_messages.append({
            "role": "system",
            "content": f"Conversation summary: {running_summary}"
        })
    context_messages.extend(recent_messages)
    return context_messages

هذا التصميم يمنحك مرونة هندسية أكبر، مثل:

  • تلخيص الرسائل القديمة فقط دون المساس بآخر رسالتين أو ثلاث.
  • استخدام نموذج أرخص لعملية التلخيص ونموذج أقوى للإجابة النهائية.
  • تخزين الملخص في قاعدة بيانات تقليدية أو Redis.
  • إضافة حقول منظمة مثل preferences وconstraints وtasks.

خفض التكلفة دون الإضرار بالجودة

القيمة الحقيقية لـ Summary Memory لا تأتي فقط من تقليل طول المحادثة، بل من طريقة دمجها مع استراتيجيات أخرى:

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

في بعض الأنظمة، أفضل حل ليس الاعتماد على الملخص وحده، بل بنية هجينة: ملخص تراكمي للنية والقرارات + استرجاع من Vector DB للوثائق أو التفاصيل البعيدة. هذا يفصل بين “الذاكرة الحوارية” و“الذاكرة المعرفية”.

أخطاء شائعة يجب تجنبها في الإنتاج

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

ولعلاج مشكلة تدهور الملخص عبر الزمن، من الجيد أحياناً تنفيذ refresh summarization عبر إعادة بناء ملخص جديد من لقطات محفوظة بدلاً من الاكتفاء بتلخيص تراكمي لا نهائي.

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

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

4 comments

اترك تعليقاً

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