13/09/2026
السلام عليكم
الدرس القادم بحول الله
Context و Memory في Agentic AI
الفرق بين Declarative Agents و Code-Driven Agents
عند بناء Agentic AI، هناك مفهومان أساسيان يجب التفريق بينهما: Context و Memory.
رغم أنهما مرتبطان ببعضهما، إلا أن لكل واحد منهما وظيفة مختلفة.
ببساطة شديدة:
Context هو المعلومات التي يحتاجها الـAgent لكي ينفذ المهمة الحالية.
أما:
Memory فهي المعلومات التي يحتفظ بها النظام لكي يستطيع استخدامها في المستقبل.
وهذا الفرق يبقى صحيحاً سواء كنت تبني الـAgent بطريقة Declarative من خلال ملفات Markdown وHarness، أو بطريقة Code-Driven باستخدام Python وLangChain/LangGraph.
أولاً: ما هو الـContext؟
الـContext هو البيئة المعلوماتية التي يتم تقديمها للـAgent أثناء تنفيذ مهمة معينة.
وهو لا يعني فقط الـSystem Prompt.
يمكن أن يشمل التعليمات، قواعد المشروع، معلومات المستخدم، المهمة الحالية، نتائج الأدوات، الوثائق ذات الصلة، نتائج البحث، والمعلومات التي تم استرجاعها من الـMemory.
بمعنى آخر، الـContext هو:
كل المعلومات التي يحتاج النموذج إلى معرفتها في اللحظة الحالية حتى يستطيع التفكير واتخاذ القرار المناسب.
لذلك يمكن أن نقول إن الـContext يمثل المعرفة الحالية المتاحة للـAgent أثناء التنفيذ.
Context في الـDeclarative Agent
في الـDeclarative Agent أنت لا تصف كل شيء بواسطة Python.
بدلاً من ذلك، تستخدم ملفات مثل:
AGENTS.md
أو:
CLAUDE.md
أو ملفات أخرى يعتمد اسمها وبنيتها على الـHarness الذي تستخدمه.
هذه الملفات تحتوي عادةً على تعليمات المشروع، القواعد، الـworkflow، أسلوب العمل، المعمارية، أو معلومات أخرى يريد المطور أن يعرفها الـAgent.
عندما يقوم الـHarness بقراءة هذه الملفات وإدخال المعلومات المناسبة إلى بيئة عمل الـAgent، تصبح هذه المعلومات جزءاً من الـContext الذي يعتمد عليه الـAgent.
وهنا توجد نقطة مهمة:
وجود الملف على القرص بشكل دائم لا يعني أن الملف نفسه هو Memory.
الملف هو مصدر دائم للمعلومات، وعندما يتم تحميل معلوماته إلى الـAgent تصبح هذه المعلومات Context.
ولهذا يمكن أن يكون لديك Context ثابت نسبياً، مثل قواعد المشروع، وContext ديناميكي يتغير من مهمة إلى أخرى.
Context في الـCode-Driven Agent
في الـCode-Driven Agent، أنت لا تعتمد على Harness ليقرر وحده ما الذي يجب أن يدخل إلى الـContext.
أنت، كمطور، تستطيع أن تتحكم برمجياً في عملية بناء الـContext.
في LangChain مثلاً، يمكن أن يأتي الـContext من الـSystem Prompt، ومن معلومات المستخدم، ومن حالة الـAgent، ومن نتائج الأدوات، ومن الوثائق المسترجعة، ومن Runtime Context، ومن الـMemory التي تم استرجاعها.
وهذا يعطيك تحكماً أكبر بكثير.
لذلك الفرق الأساسي هنا ليس في مفهوم الـContext نفسه، وإنما في من المسؤول عن تكوينه وإدارته.
في الـDeclarative approach، الـHarness يقوم بجزء كبير من هذه العملية بناءً على الملفات والتعليمات التي عرّفتها.
في الـCode-Driven approach، أنت تحدد هذه العملية برمجياً باستخدام LangChain أو LangGraph وغيرها من الأدوات.
ثانياً: ما هي الـMemory؟
الـMemory مختلفة.
الـMemory تعني أن النظام يستطيع الاحتفاظ بمعلومة من الماضي واستعمالها في المستقبل.
فمثلاً، إذا تعلم الـAgent شيئاً عن المستخدم أو عن المشروع أثناء تفاعل سابق، يمكن للنظام حفظ هذه المعلومة واسترجاعها في وقت لاحق.
وهنا تظهر كلمة مهمة جداً:
Persistence
أي الاستمرارية.
فالـContext مرتبط عادةً بالعملية الحالية، بينما الـMemory تهدف إلى جعل بعض المعلومات متاحة بعد انتهاء هذه العملية أو حتى في جلسة مختلفة.
العلاقة بين Memory وContext
وهذه ربما أهم نقطة في الموضوع كله.
الـMemory ليست بالضرورة شيئاً يراه الـLLM مباشرة.
بل غالباً يحدث الآتي من الناحية المفاهيمية:
يتم حفظ المعلومات في Memory، ثم يبحث النظام عن المعلومات المناسبة للمهمة الحالية، ثم يسترجعها، وبعد ذلك يضع المعلومات المسترجعة داخل الـContext.
إذن:
Memory يمكن أن تصبح Context.
لكن:
Context ليس بالضرورة Memory.
كل Memory مسترجعة يمكن أن تصبح جزءاً من Context، لكن ليس كل Context يأتي من Memory.
قد يأتي الـContext من System Prompt أو من ملف مشروع أو من المستخدم أو من Tool أو من RAG.
Memory في الـDeclarative Agent
هنا يجب الانتباه إلى أن كلمة Declarative لا تعني تلقائياً أن Markdown هو Memory.
ملفات مثل AGENTS.md أو CLAUDE.md تستخدم غالباً لوصف التعليمات والسياق التشغيلي للـAgent.
أما إذا كان الـHarness الذي تستخدمه يوفر نظاماً للـpersistent memory، فقد يكون لديه ملفات أو مخازن أو آلية أخرى مخصصة للاحتفاظ بالمعلومات.
في هذه الحالة تصبح الـMemory جزءاً من architecture الخاصة بالـHarness.
لذلك لا يصح أن نقول:
كل شيء مكتوب في Markdown هو Memory.
والصياغة الأدق هي:
Markdown هو طريقة لتعريف المعلومات، أما كون هذه المعلومات Context أو Memory فيعتمد على كيفية استخدام الـruntime أو الـHarness لها.
وهذه نقطة مهمة جداً في فهم الـDeclarative Agents.
Memory في الـCode-Driven Agent
في LangChain/LangGraph، تستطيع بناء نظام Memory بطريقة أكثر برمجية.
وهنا تظهر عادةً فكرتان أساسيتان:
Short-Term Memory
وهي المعلومات المرتبطة بالمحادثة أو الـthread الحالي، مثل الرسائل السابقة وحالة تنفيذ الـAgent.
وLong-Term Memory
وهي المعلومات التي تريد الاحتفاظ بها عبر محادثات أو جلسات مختلفة، مثل تفضيلات المستخدم أو معلومات مهمة عن المشروع.
LangChain الحديث يربط الـShort-Term Memory بشكل وثيق مع State وCheckpoints، بينما يمكن استخدام Store للـLong-Term Memory.
وهذا أكثر دقة من تصور الـMemory على أنها مجرد Buffer يحتوي على كل الرسائل السابقة.
ماذا عن Memory Buffer؟
ستجد في الكثير من المواد التعليمية القديمة في LangChain مفهوم Conversation Buffer Memory.
الفكرة بسيطة: يحتفظ النظام بسجل المحادثة السابقة لكي يستطيع الـAgent الرجوع إليها.
هذا المفهوم مفيد لفهم أساسيات الذاكرة، لكن عند تعلم LangChain الحديث من الأفضل أن تنتقل إلى المفاهيم الأوسع:
State، Checkpointing، Short-Term Memory، Long-Term Memory، وStore.
لأنها تعكس بشكل أفضل architecture الحديثة للـAgentic systems.
الفرق بين Context وMemory في Declarative وCode
المفهوم نفسه في الحالتين.
الاختلاف في طريقة التنفيذ.
في الـDeclarative Agent:
المطور يصف السلوك والمعلومات من خلال ملفات وتعريفات، والـHarness يتولى جزءاً كبيراً من عملية اكتشاف الملفات، تحميلها، تنظيمها، وإدخال المعلومات المناسبة إلى الـAgent.
في الـCode-Driven Agent:
المطور يتحكم مباشرة في هذه العمليات بواسطة الكود، ويمكنه تحديد متى يتم جلب المعلومات، ومن أين، وكيف يتم دمجها مع الـPrompt، وكيف يتم حفظ الـState والـMemory واسترجاعها.
إذن:
Declarative يعطيك مستوى أعلى من الوصف.
بينما:
Code-Driven يعطيك مستوى أعلى من التحكم.
أين تدخل الـRules؟
الـRules ليست Memory بالضرورة.
هي تعليمات تحدد كيف يجب على الـAgent أن يتصرف.
في الـDeclarative Agent تكون عادةً ضمن ملفات التعليمات مثل AGENTS.md أو CLAUDE.md.
وفي الـCode-Driven Agent يمكن تعريفها داخل الـSystem Prompt أو من خلال Middleware أو آليات أخرى.
في الحالتين، الهدف واحد:
تقييد وتوجيه سلوك الـAgent.
وأين تدخل الـSkills؟
الـSkill هي قدرة أو طريقة عمل متخصصة يستطيع الـAgent استخدامها عندما يحتاج إليها.
في الـDeclarative approach يمكن تعريف الـSkills من خلال ملفات Markdown، ويقوم الـHarness بتحميل الـSkill أو تعليمات استخدامها عندما تكون مناسبة.
في الـCode-Driven approach يمكن تمثيل الـSkills من خلال Tools أو workflows أو abstractions برمجية.
مرة أخرى، الاختلاف هو في طريقة التعبير والتنفيذ، وليس في الفكرة الأساسية.
Context Engineering
بعد أن تفهم Context وMemory، تصل إلى مفهوم مهم جداً في Agentic Engineering وهو:
Context Engineering.
وهو ببساطة فن تحديد:
ما المعلومات التي يجب أن تصل إلى الـAgent، ومتى، وبأي كمية، وبأي ترتيب؟
الهدف ليس إعطاء الـAgent أكبر كمية ممكنة من المعلومات.
بل إعطاؤه المعلومات الصحيحة في الوقت الصحيح.
وهذا مهم جداً لأن زيادة الـContext بشكل عشوائي يمكن أن تجعل الـAgent أقل فعالية، حتى لو كان النموذج يستطيع تقنياً استقبال عدد ضخم من الـTokens.
لماذا لا نضع كل الـMemory داخل الـContext؟
لأن الـMemory قد تكون ضخمة.
تخيل Agent يعمل مع مستخدم منذ سنة.
لديه آلاف المحادثات ومئات المعلومات المخزنة.
ليس من المنطقي إرسال كل هذه المعلومات إلى النموذج في كل طلب.
لذلك يوجد مفهوم مهم جداً:
Memory Retrieval.
النظام يبحث في الذاكرة عن المعلومات المتعلقة بالمهمة الحالية فقط، ثم يضع الجزء المناسب منها في الـContext.
وهكذا:
Memory هي المخزن.
Retrieval هو عملية البحث.
Context هو ما يصل فعلياً إلى النموذج.
العلاقة مع RAG
نفس الفكرة تنطبق على RAG.
قاعدة البيانات أو Vector Store تحتوي على كمية كبيرة من المعلومات.
لكن الـAgent لا يرسل قاعدة البيانات كلها إلى النموذج.
بل يتم البحث عن الوثائق المتعلقة بالسؤال، ثم يتم إدخال النتائج المناسبة في الـContext.
لذلك يمكن النظر إلى:
Memory Retrieval
و
RAG Retrieval
على أنهما آليتان مختلفتان يمكنهما كلاهما إنتاج معلومات يتم وضعها في الـContext.
كيف تفكر في النظام بالكامل؟
كمبرمج مبتدئ في Agentic Engineering، لا تبدأ بالتفكير:
أين أضع الـMemory؟
أو:
أين أضع الـContext؟
ابدأ بالسؤال:
ما الذي يحتاج الـAgent إلى معرفته الآن؟
هذه المعلومات هي Context.
ثم اسأل:
ما المعلومات التي أريد أن يحتفظ بها النظام لكي يستطيع استخدامها مستقبلاً؟
هذه هي Memory.
ثم:
كيف سأسترجع من الـMemory المعلومات المناسبة للمهمة الحالية؟
هذه هي Memory Retrieval.
ثم:
كيف سأقدم المعلومات المسترجعة إلى الـAgent؟
هنا تدخل في Context Engineering.
Declarative مقابل Code-Driven
في النهاية، يمكن تلخيص الاختلاف بهذه الطريقة:
Declarative Agent
أنت تصف للـHarness:
ما الذي يجب أن يعرفه الـAgent، وما القواعد التي يجب أن يتبعها، وما الـSkills التي يمكنه استخدامها.
وتستخدم Markdown وملفات المشروع كوسيلة للتعبير عن هذه الأشياء.
الـHarness هو الذي يتولى جزءاً كبيراً من orchestration وتحضير البيئة المناسبة للـAgent.
Code-Driven Agent
أنت تصف كل ذلك برمجياً.
تحدد الـSystem Prompt، والـRuntime Context، والـState، والـTools، والـMemory، وآلية الاسترجاع، وكيفية دمج كل ذلك أثناء تنفيذ الـAgent.
وهذا هو السبب في أن LangChain/LangGraph يعطيك مرونة كبيرة جداً، لكنه في المقابل يتطلب منك فهماً أكبر للـarchitecture.
الخلاصة
هناك أربع أفكار يجب أن تبقى واضحة في ذهنك:
Context:
المعلومات التي يحتاجها الـAgent أثناء المهمة الحالية.
Memory:
المعلومات التي يحتفظ بها النظام لكي يستخدمها في المستقبل.
Retrieval:
العملية التي تستخرج المعلومات المناسبة من الـMemory أو من مصادر أخرى.
Context Engineering:
عملية تحديد المعلومات التي يجب تقديمها للـAgent، ومتى وكيف.
أما الفرق بين الطريقتين:
Declarative Agent:
تصف الـAgent من خلال Markdown والـHarness يتولى جزءاً كبيراً من التنفيذ.
Code-Driven Agent:
تبني الـAgent وتتحكم في الـContext والـMemory والـTools والـOrchestration من خلال الكود، مثل Python مع LangChain/LangGraph.
وأهم جملة في الموضوع كله هي:
الـMemory تحفظ، والـRetrieval يسترجع، والـContext يزوّد الـAgent بما يحتاجه الآن.
وهذه الجملة تنطبق سواء كان الـAgent مبنياً من خلال Markdown + Harness أو من خلال Python + LangChain/LangGraph.