Skip to main content
التشغيل الطويل للوكيل يملأ نافذة السياق (context window) بنتائج الأدوات في معظمها: محتويات ملفات، ونتائج بحث، واستجابات API قرأها النموذج مرة واحدة ولم يعد يحتاج إليها كاملة. ضغط السياق (compaction) يُبقي تشغيلًا كهذا دون حدّ النموذج على مرحلتين: يضع أولًا علامة قصيرة مكان نتائج الأدوات القديمة، وإن لم يكفِ ذلك وضع مكان أقدم الدورات ملخصًا يكتبه نموذج (أقل تكلفة).

ضغط سياق وكيل

مع createAgent()، فعّل ضغط السياق بالخيار compaction. القيمة true تثبّت الخطّاف بإعداداته الافتراضية (تقليم نتائج الأدوات القديمة فوق 90% من نافذة النموذج)؛ والكائن يضبطه، وsummarizer يختار twoPhaseStrategy() مع ذلك النموذج (سلسلة "provider/model" أو LLMProvider):
يقبل الكائن strategy وthresholdPercent وcontextWindow وprotectedTokens (كما في الجدول أدناه) وsummarizer؛ والجمع بين summarizer وstrategy خطأ في الإعداد (مرِّر twoPhaseStrategy({ model }) بوصفه strategy بدلًا من ذلك). يقبل createAgent({ hooks }) أي خطّافات AgentHook أخرى، وهي تعمل قبل خطّاف ضغط السياق، فيرى الضغط ما أضافته. تنطبق الخطّافات وضغط السياق على send() وstream() والجلسات.

أحداث البث

يبلّغ agent.stream() وsession.stream() وAgentExecutor.stream() عن كل عملية ضغط بحدثين، داخل الخطوة وقبل استدعاء النموذج الذي أثارها (انظر البث): كل حدث compaction.start يتبعه حدث compaction.done واحد بالضبط. حين لا تستطيع الاستراتيجية تقليص شيء، يساوي tokensAfter قيمة tokensBefore؛ وحين تفشل (أو يفشل نموذج التلخيص فيرجع الخطّاف إلى التقليم)، يُضبط error ويستمر التشغيل. تكون summary بقيمة true حين يوضع ملخص مكان الدورات القديمة (النص نفسه لا يُرسَل؛ استخدم onCompaction للحصول عليه). استدعاء send() غير المبثوث لا يصدر أحداثًا. تضيف الخطّافات أحداثها الخاصة بـ ctx.emit?.(...) على سياق preGenerate، وهو موجود في التشغيلات المبثوثة فقط.

ضغط سياق تشغيل

يعيد createCompactionHook() خطّافًا من نوع AgentHook اسمه compaction. سجّله ومرِّر السجل إلى AgentExecutor.execute(). الإعداد الموصى به هو استراتيجية المرحلتين مع نموذج تلخيص رخيص:
قبل كل استدعاء للنموذج يقدّر الخطّاف حجم الطلب بـ estimateTokens (انظر النماذج والرموز والتكلفة). حين يتجاوز الحجم نسبة thresholdPercent من نافذة السياق، يشغّل الخطّاف استراتيجيته (وينتظرها إن كانت غير متزامنة) ويستدعي onCompaction بأعداد الرموز (tokens)، ومعرّفات toolCallId التي قُلِّمت، والملخص إن وُجد، واسم الاستراتيجية. ضغط السياق لا يُفشل التشغيل أبدًا. إذا رمت الاستراتيجية استثناءً، أو فشل استدعاء نموذج التلخيص، استمر التشغيل (بالمحادثة المقلَّمة، أو دون تغيير) وتلقّت onCompaction قيمة error. يعيد الخطّاف كتابة سجل محادثة التشغيل نفسه، لا نسخة منه: فمصفوفة messages في الطلب هي قائمة رسائل التشغيل، والخطّاف يغيّرها في مكانها. ولذلك تبقى النتيجة المقلَّمة أو الملخص في الخطوات اللاحقة، وفي نقاط الحفظ (الجلسة المستأنفة لا تستعيد السجل الكامل) وفي result.messages، ولا يُضغط مرة أخرى في الخطوة التالية. ضغط السياق يفقد معلومات: إذا احتاج النموذج إلى نتيجة مقلَّمة مرة أخرى، فعليه أن يستدعي الأداة من جديد.

الاستراتيجيات

تقليم نتائج الأدوات

تضع pruneToolResultsStrategy() مكان content في كل نتيجة أداة أقدم من الذيل المحمي علامةً مثل [pruned: search result, 18234 chars]. ولا تغيّر أبدًا:
  • رسائل النظام، ولا رسائل المستخدم (ومنها الأولى)، ولا دورات المساعد، فيحتفظ كل استدعاء أداة برسالة نتيجته ويبقى سجل المحادثة صالحًا لكل مزوّد؛
  • نتائج أحدث دورة للمساعد، وهي التي لم يقرأها النموذج بعد، حتى لو كانت أكبر من protectedTokens؛
  • النتائج المثبَّتة، ولا النتائج التي هي علامة أصلًا، ولا النتائج الأقصر من العلامة.

تلخيص الدورات القديمة

ترسل summarizeStrategy() الرسائل السابقة للذيل المحمي إلى نموذج التلخيص مع تعليمة مركّزة، وتضع مكانها رسالة user واحدة:
يُبقي الملخص سجل المحادثة صالحًا لكل مزوّد:
  • رسائل النظام والرسائل المثبَّتة تبقى في مواضعها، ويوضع الملخص حيث كانت أول رسالة ملخَّصة؛
  • دورة المساعد تُلخَّص أو تُترك مع جميع نتائج أدواتها معًا، فلا يفقد استدعاء أداة نتيجته (ولا نتيجة استدعاءها)؛
  • الرسالة الأخيرة ونتائج أحدث دورة للمساعد تبقى دائمًا.
إذا فشل استدعاء التلخيص (أو لم يُعِد شيئًا)، ترجع الاستراتيجية إلى التقليم وتعيد الفشل في error.

المرحلتان

تقبل twoPhaseStrategy() الخيارات نفسها. تقلّم نتائج الأدوات أولًا، وهذا بلا تكلفة، ولا تستدعي نموذج التلخيص إلا حين تبقى المحادثة المقلَّمة فوق نسبة thresholdPercent من نافذة السياق. عندها يقرأ نموذج التلخيص المحادثة المقلَّمة. وإذا فشل، تُترك المحادثة المقلَّمة ويُبلَّغ عن error.

تثبيت الرسائل

تعيد pinMessage(message) نسخة من الرسالة موسومة بأنها مثبَّتة (تضبط metadata.pinned: true؛ وMessage.metadata بيانات خاصة بالتطبيق لا تُرسَل إلى النموذج أبدًا). الاستراتيجيات المدمجة لا تقلّم رسالة مثبَّتة ولا تلخّصها أبدًا؛ ونتيجة الأداة المثبَّتة تحفظ دورة المساعد التي تنتمي إليها كاملة. ثبّت ما يجب أن يراه الوكيل كاملًا دائمًا، مثل نص المهمة أو مستند أساسي:
ينبغي أن تراعي الاستراتيجيات المخصَّصة isPinned() أيضًا.

الضغط يدويًا

تشغّل compactMessages(messages, options) استراتيجية مرة واحدة، أيًّا كان حجم المحادثة، وتعيد وعدًا نتيجته مصفوفة جديدة (مدخلها لا يُعدَّل). استخدمها لتقليص سجل محادثة مخزَّن قبل أن تكمله:

ضغط سياق جلسة

تضغط session.compact(options?) سجل محادثة جلسة فورًا، أيًّا كان حجمه، وتحفظه في مخزن الجلسة (الذاكرة أو ملف أو SQLite أو KV) وتعيد وعدًا نتيجته { messagesBefore, messagesAfter, tokensBefore, tokensAfter, strategy, error? }. تشغّل options.strategy، وإلا فاستراتيجية agent.session({ compaction }) (وهي القيمة نفسها التي يقبلها createAgent({ compaction })، ويُستخدم compaction الخاص بالوكيل حين لا تضبط الجلسة قيمة)، وإلا فتقلّم نتائج الأدوات القديمة. تبقى الرسائل المثبَّتة. والجلسة التي لا رسائل فيها تنتهي دون فعل شيء. يُرفض الاستدعاء بالخطأ LOUSHO_SESSION_BUSY ما دامت دورة قيد التنفيذ، وبالخطأ LOUSHO_SESSION_TURN_PENDING / LOUSHO_SESSION_AWAITING_APPROVAL ما دامت دورة متينة لم تكتمل. المستمعون المضافون بـ session.on() يتلقّون compaction.start وcompaction.done مع trigger: 'manual'. أما session.clear() فتفرّغ سجل المحادثة وتصدر context.cleared.

كتابة استراتيجية

الاستراتيجية اسم ودالة compact()، ويجوز أن تكون غير متزامنة. تتلقى الرسائل، وعدّاد رموز لنموذج الطلب، ونافذة السياق، وprotectedTokens، وthresholdTokens (الحجم المطلوب النزول دونه) وإشارة الإلغاء signal الخاصة بالتشغيل، وتعيد الرسائل الجديدة مع أعداد الرموز قبل الضغط وبعده (واختياريًا summary أو error). أعِد مصفوفة الإدخال دون تغيير حين لا يوجد ما يُفعل: عندها يترك الخطّاف التشغيل على حاله ولا يستدعي onCompaction.
تحصل الاستراتيجية المخصَّصة على حدثَي compaction.start / compaction.done نفسيهما كما تحصل عليهما الاستراتيجيات المدمجة. وتظل onCompaction (على createCompactionHook()) تتلقى نص الملخص وكائن Error.