أجرى وكيل الذكاء الاصطناعي (AI agent) الخاص بك للتو محادثة مدتها 30 دقيقة مع مستخدم. ناقشا متطلبات المشروع، وتبادلا التفضيلات، واتخذا القرارات. ثم يكتب المستخدم /new لبدء جلسة جديدة.
يحاول الوكيل دمج تلك المحادثة في الذاكرة طويلة المدى. تفشل مكالمة LLM. بسبب Rate limit أو Timeout. أو يعيد النموذج نصاً بدلاً من استدعاء الأداة (tool) المطلوبة.
تختفي الذاكرة. ثلاثون دقيقة من السياق، تتبخر.
يحدث هذا أكثر مما تعتقد. لقد تتبعنا ذلك عبر مثيلات LemonClaw الخاصة بنا: كان لعملية دمج الذاكرة معدل فشل يقارب 15% في أي نموذج واحد. بالنسبة لميزة يُفترض أن تكون بنية تحتية غير مرئية، فإن هذا أمر غير مقبول.
إذا كنت تبني واجهة المنتج المحيطة بدلاً من مجرد نظام الذاكرة الفرعي، فاقرن هذه الصفحة بـ دليل chatbot بمفتاح واحد و دليل LemonClaw المستضاف ذاتياً. متانة الذاكرة تهم فقط عندما يعيش الوكيل بالفعل داخل تطبيق قابل للاستخدام.
كيف تتعامل الأطر الأخرى مع هذا (إنها لا تفعل)
تعامل معظم أطر عمل وكلاء الذكاء الاصطناعي دمج الذاكرة كمكالمة LLM بسيطة. إذا نجحت، فهذا رائع. وإذا لم تنجح، تضيع الذاكرة.
يستخدم الإطار السابق لـ LemonClaw نفس النموذج للدمج كما هو الحال في المحادثة. مكالمة Claude Sonnet تكلف 0.003 دولار وتستغرق أكثر من 8 ثوانٍ، فقط لتلخيص دردشة لن يراها المستخدم أبداً. عندما تفشل تلك المكالمة (Rate limit، Timeout، خطأ في النموذج)، يسجل الإطار تحذيراً ويستمر. سياق المستخدم قد ضاع.
إطار عمل nanobot، وهو إطار عمل شائع آخر، لديه نفس البنية. نموذج واحد، محاولة واحدة، ولا يوجد Fallback. وظيفة الدمج لا تحتوي حتى على مهلة انتظار (timeout). استجابة بطيئة من المصدر (أخطاء Cloudflare 524 شائعة) تعطل الجلسة بأكملها حتى ينقطع الاتصال.
لا يفصل أي من الإطارين عملية الدمج عن النموذج الرئيسي. ولا يملك أي منهما منطق Fallback لعمليات الذاكرة. ولا يميز أي منهما بين "فشل مكالمة API" و "نجاح مكالمة API ولكن النموذج لم يفعل ما طلبناه".
هذه ليست حالات نادرة. مع معدلات فشل تصل إلى 15% في أي نموذج واحد، فإن إطار العمل الذي يقوم بـ 100 عملية دمج يومياً يفقد الذاكرة في 15 منها. على مدار أسبوع، يعني ذلك 105 محادثة ينسى فيها الوكيل كل شيء.
المشكلة أعمق من منطق إعادة المحاولة (Retry Logic)
الإصلاح البديهي هو إعادة المحاولة مع التراجع الأسي (exponential backoff). كان لدينا ذلك. وهو يعالج أخطاء HTTP العابرة بشكل جيد:
# Retry loop: 1s → 2s → 4s backoff
for attempt in range(3):
try:
response = await acompletion(**kwargs)
return await self._collect_stream(response)
except (RateLimitError, APIConnectionError) as e:
await asyncio.sleep(RETRY_DELAYS[attempt])
هذا يلتقط أخطاء 429 واضطرابات الشبكة. لكن هناك وضعين للفشل يتسللان من خلاله:
وضع الفشل 1: النموذج لا يستطيع القيام بـ tool calling. بعض النماذج، خاصة الصغيرة منها التي تعمل على محركات استدلال سريعة، تفشل أحياناً في إنشاء استدعاءات دوال صالحة في المطالبات المعقدة. تعيد API رمز 200 مع خطأ ServiceUnavailableError مغلف داخل MidStreamFallbackError. يرى منطق إعادة المحاولة الخاص بك استثناءً، ويعيد محاولة نفس النموذج، ويحصل على نفس الخطأ.
وضع الفشل 2: النموذج "ينجح" ولكنه لا يستدعي الأداة. يعيد LLM استجابة صالحة تماماً. HTTP 200. لا توجد أخطاء. ولكن بدلاً من استدعاء save_memory ببيانات منظمة، يكتب ملخصاً نصياً عادياً. يعتبر محرك إعادة المحاولة الخاص بك هذا نجاحاً. تتحقق وظيفة الدمج من استدعاءات الأدوات، فلا تجد شيئاً، وتستسلم.
وضع الفشل الثاني هو الأكثر خطورة. تعتقد طبقة النقل أن كل شيء سار على ما يرام، بينما تعرف طبقة الأعمال أنه لم ينجح. لا يوجد قدر من إعادات المحاولة على مستوى HTTP سيصلح نموذجاً لا يفهم مخطط الأداة (tool schema) الخاص بك.
بنية Fallback ثنائية الطبقة
لقد حللنا ذلك من خلال حلقتي Fallback مستقلتين تعملان على مستويات مختلفة:
المستخدم يرسل /new
│
▼
consolidate() ─── Business Layer Fallback
│ "هل استدعى النموذج save_memory؟"
│ لا ← جرب النموذج التالي في السلسلة
│
▼
_chat_with_retry() ─── Transport Layer Fallback
│ أخطاء HTTP ← exponential backoff
│ استنفاد المحاولات ← تتبع سلسلة fallback
│
▼
سلسلة fallback في MODEL_MAP:
llama-3.3-70b ─$0.59/M─→ qwen3-32b ─$0.29/M─→ llama-4-scout ─$0.11/M─→ gpt-4.1-mini ─→ claude-haiku
(394 TPS) (662 TPS) (594 TPS) (موثوق) (الملاذ الأخير)
تتعامل الطبقة 1 مع إخفاقات النقل. وتتعامل الطبقة 2 مع إخفاقات منطق الأعمال. تتم مشاركة سلسلة Fallback بين الطبقتين، ويتم تعريفها مرة واحدة في كتالوج مركزي.
هذا نهج مختلف تماماً عن إعادة محاولة نفس النموذج. عندما يفشل نموذج في استدعاء أداة، نادراً ما يفيد إعادة محاولته بنفس المطالبة. لكن الانتقال إلى نموذج مختلف بأوزان مختلفة وسلوك استدعاء أدوات مختلف يفيد.
كتالوج النماذج: مصدر واحد للحقيقة
كل نموذج في كتالوجنا يحتوي على حقل fallback اختياري يشير إلى النموذج التالي الذي يجب تجربته:
@dataclass(frozen=True)
class ModelEntry:
id: str
label: str
tier: str
description: str
fallback: str | None = None
hidden: bool = False # مخفي من قائمة /model التي يراها المستخدم
MODEL_CATALOG = [
# النماذج المرئية للمستخدم (16 نموذجاً يمكن للمستخدمين التبديل بينها)
ModelEntry("claude-sonnet-4-6", "Claude Sonnet 4.6", "standard",
"Recommended", fallback="claude-sonnet-4-5"),
ModelEntry("gpt-4.1-mini", "GPT-4.1 Mini", "economy",
"Stable tool calling", fallback="claude-haiku-4-5"),
# نماذج الدمج المخفية (للاستخدام الداخلي فقط)
ModelEntry("llama-3.3-70b-versatile", "Llama 3.3 70B (Groq)", "economy",
"394 TPS", fallback="qwen3-32b", hidden=True),
ModelEntry("qwen3-32b", "Qwen3 32B (Groq)", "economy",
"662 TPS", fallback="llama-4-scout-17b-16e-instruct", hidden=True),
# ...
]
تبقي علامة hidden=True النماذج الداخلية بعيدة عن أمر /model الذي يواجهه المستخدم بينما تظل مشاركة في سلاسل Fallback. يرى المستخدمون 16 نموذجاً يمكنهم التبديل بينها، بينما يستخدم النظام 19 نموذجاً. النماذج الثلاثة المخفية موجودة فقط للمهام الخلفية مثل دمج الذاكرة، حيث تهم السرعة والتكلفة أكثر من جودة المحادثة.
هذا الكتالوج هو المصدر الوحيد للحقيقة لجميع عمليات توجيه النماذج. إضافة نموذج جديد إلى سلسلة Fallback يعني إضافة سطر واحد. لا توجد ملفات تكوين للمزامنة، ولا متغيرات بيئة للتحديث، ولا نصوص برمجية للنشر للتعديل.
طبقة النقل: Fallback متسلسل مع اكتشاف الحلقات
يقوم محرك إعادة المحاولة بتتبع سلسلة Fallback باستخدام مجموعة "visited" لمنع الحلقات اللانهائية:
async def _chat_with_retry(self, kwargs, original_model):
# المرحلة 1: Exponential backoff على النموذج الأساسي
for attempt in range(3):
try:
response = await acompletion(**kwargs)
return await self._collect_stream(response)
except (RateLimitError, APIConnectionError, APIError) as e:
await asyncio.sleep(RETRY_DELAYS[attempt])
except AuthenticationError:
return LLMResponse(content="API key invalid.", finish_reason="error")
# المرحلة 2: تتبع سلسلة fallback
visited = {original_model}
current = original_model
while True:
entry = MODEL_MAP.get(current)
if not entry or not entry.fallback or entry.fallback in visited:
break
current = entry.fallback
visited.add(current)
# تحديد البوابة الصحيحة لهذا النموذج
gw = self._resolve_gateway_for_model(current)
resolved = self._resolve_model(current, gateway=gw)
fb_kwargs = {**kwargs, "model": resolved}
# إصلاح api_base لبروتوكول النموذج المستهدف
if gw and gw.default_api_base:
fb_kwargs["api_base"] = gw.default_api_base
try:
response = await acompletion(**fb_kwargs)
return await self._collect_stream(response)
except Exception:
continue # جرب التالي في السلسلة
return LLMResponse(content="Service unavailable.", finish_reason="error")
مجموعة visited بالغة الأهمية. بدونها، سلسلة مثل A→B→A ستدخل في حلقة إلى الأبد. معها، يحاول المحرك كل نموذج مرة واحدة بالضبط.
دقة البوابة (Gateway resolution) تهم أيضاً. تحتاج النماذج المختلفة إلى تنسيقات API مختلفة. يتم توجيه نماذج Claude عبر بوابة بتنسيق Anthropic (بدون لاحقة /v1). يتم توجيه نماذج GPT عبر بوابة متوافقة مع OpenAI (مع /v1). تستخدم نماذج Groq نقطة نهاية أخرى. يقوم محرك Fallback بتحديد البوابة الصحيحة لكل نموذج في السلسلة، مما يمنع عدم تطابق البروتوكول مثل إرسال طلبات Anthropic إلى نقطة نهاية OpenAI.
هذا تفصيل تتجاهله معظم أطر العمل تماماً. يفترضون أن جميع النماذج تتحدث نفس البروتوكول. في بيئة الإنتاج، مع 19 نموذجاً عبر 4 تنسيقات API مختلفة، ينهار هذا الافتراض فوراً.
طبقة الأعمال: التحقق من استدعاء الأدوات
تضيف وظيفة الدمج حلقة Fallback خاصة بها في الأعلى:
async def consolidate(self, session, provider, model, **kwargs):
visited = set()
current_model = model
while current_model and current_model not in visited and len(visited) <= 3:
visited.add(current_model)
response = await asyncio.wait_for(
provider.chat(messages=messages, tools=SAVE_MEMORY_TOOL, model=current_model),
timeout=30,
)
if response.has_tool_calls:
# نجاح: استخراج وحفظ الذاكرة
args = response.tool_calls[0].arguments
self.write_long_term(args["memory_update"])
self.append_history(args["history_entry"])
return True
# النموذج لم يستدعِ الأداة — جرب التالي في السلسلة
entry = MODEL_MAP.get(current_model)
next_model = entry.fallback if entry else None
if next_model and next_model not in visited:
current_model = next_model
continue
return False # لا مزيد من fallbacks
return False
هذا يلتقط الحالة التي تعيد فيها _chat_with_retry استجابة ناجحة (HTTP 200، محتوى صالح) ولكن النموذج لم يستخدم الأداة. تتحقق وظيفة الدمج من has_tool_calls، وإذا كانت مفقودة، تنتقل إلى النموذج التالي في السلسلة.
غلاف مهلة الانتظار (asyncio.wait_for) يؤدي أيضاً إلى تشغيل Fallback. إذا استغرق النموذج أكثر من 30 ثانية (شائع مع أخطاء Cloudflare 524 في المصادر البطيئة)، تلتقط الوظيفة TimeoutError وتجرب النموذج التالي بدلاً من حظر جلسة المستخدم إلى أجل غير مسمى.
لماذا Groq لدمج الذاكرة
دمج الذاكرة هو مهمة خلفية. لا يرى المستخدم المخرجات. يحتاجون فقط إلى أن تعمل. وهذا يجعلها مرشحاً مثالياً للنماذج السريعة والرخيصة.
تستخدم معظم أطر العمل نفس النموذج الباهظ لكل شيء. إذا كنت تستخدم Claude Sonnet للمحادثة، فأنت تستخدمه أيضاً لدمج الذاكرة. هذا يكلف 3 دولارات لكل مليون token مدخل وأكثر من 8 ثوانٍ لكل عملية دمج، لمهمة تنتج مخرجات لا يقرأها أي إنسان أبداً.
لقد فصلنا عملية الدمج عن نموذج المحادثة تماماً. تستخدم المحادثة أي نموذج يختاره المستخدم. بينما يستخدم الدمج سلسلة مخصصة من النماذج المستضافة على Groq:
| النموذج | السرعة | تكلفة المدخلات | تكلفة المخرجات |
|---|---|---|---|
| llama-3.3-70b-versatile | 394 TPS | $0.59/M | $0.79/M |
| qwen3-32b | 662 TPS | $0.29/M | $0.59/M |
| llama-4-scout-17b-16e | 594 TPS | $0.11/M | $0.34/M |
| gpt-4.1-mini (سابقاً) | ~150 TPS | $0.40/M | $1.60/M |
يقوم النموذج الأساسي (llama-3.3-70b) بدمج جلسة مكونة من 60 رسالة في حوالي 5 ثوانٍ. كان الافتراضي السابق (gpt-4.1-mini) يستغرق أكثر من 8 ثوانٍ. انخفضت التكلفة لكل عملية دمج من ~0.003 دولار إلى ~0.001 دولار.
المقايضة: نماذج Groq لديها استدعاء أدوات أقل موثوقية في المطالبات المعقدة. وهذا هو بالضبط سبب وجود Fallback ثنائي الطبقة. عندما يفشل llama-3.3-70b في استدعاء الأداة، يتولى qwen3-32b المهمة. وإذا فشل ذلك أيضاً، يحاول llama-4-scout. وإذا فشلت جميع نماذج Groq الثلاثة، يتعامل gpt-4.1-mini مع الأمر بموثوقية استدعاء أدوات تقارب 100%.
في بيئة الإنتاج، نرى النموذج الأساسي ينجح في حوالي 85% من الحالات. تصل السلسلة إلى gpt-4.1-mini في أقل من 2% من عمليات الدمج. معدل الفشل الإجمالي: صفر فعلياً.
نتائج الإنتاج
لقد نشرنا هذا في مثيلين من LemonClaw واختبرناه بمحادثات Telegram حقيقية.
النشر الأول (Fallback أحادي الطبقة فقط):
Memory consolidation (archive_all): 56 messages
llama-3.3-70b-versatile → "Failed to call a function"
Falling back → qwen3-32b
qwen3-32b: LLM did not call save_memory, skipping
→ "Memory archival failed, session not cleared."
التقطت طبقة النقل الفشل الأول وتراجعت. لكن qwen3-32b أعاد نصاً دون استدعاء الأداة. لم يتمكن Fallback أحادي الطبقة من التعامل مع هذا. هذا هو السيناريو الدقيق الذي كانت ستفقد فيه كل أطر العمل الأخرى الذاكرة بصمت.
النشر الثاني (Fallback ثنائي الطبقة):
Memory consolidation (archive_all): 60 messages
model=llama-3.3-70b-versatile → success
Memory consolidation done: 60 messages remaining
نفس النموذج، نفس حجم الرسائل. هذه المرة نجح من المحاولة الأولى. الطبيعة المتقطعة لفشل استدعاء الأدوات هي بالضبط سبب حاجتك إلى سلسلة Fallback بدلاً من نموذج احتياطي واحد.
عندما يفشل النموذج الأساسي، تلتقطه السلسلة:
llama-3.3-70b → tool call failed
→ consolidate() fallback → qwen3-32b
→ qwen3-32b didn't call tool
→ consolidate() fallback → llama-4-scout
→ llama-4-scout didn't call tool
→ consolidate() fallback → gpt-4.1-mini
→ gpt-4.1-mini called save_memory ✓
Memory consolidation done
تمت تجربة أربعة نماذج، وحُفظت الذاكرة. يرى المستخدم "بدأت جلسة جديدة" وليس لديه أدنى فكرة عن حدوث أي من هذا.
فجوة البنية التحتية
نظام ذاكرة LemonClaw مقابل البدائل، ميزة بميزة:
| القدرة | إطار عمل وكيل AI تقليدي | LemonClaw |
|---|---|---|
| نموذج الدمج | نفس نموذج المحادثة (باهظ، بطيء) | سلسلة نماذج مستقلة، مسرعة بـ Groq |
| التعامل مع الفشل | تسجيل تحذير، فقدان الذاكرة | Fallback ثنائي الطبقة، بعمق 5 نماذج |
| Fallback النقل | إعادة محاولة نفس النموذج 3 مرات | Fallback متسلسل عبر نماذج مختلفة |
| Fallback منطق الأعمال | لا يوجد | التحقق من استدعاء الأدوات + تبديل النماذج |
| حماية Timeout | لا يوجد (Cloudflare 524 يعطل الجلسة) | asyncio.wait_for(timeout=30) + fallback |
| تقليص الجلسة | لا يوجد (السياق ينمو للأبد) | تقليص الرسائل القديمة بعد الدمج |
| البحث في التاريخ | لا يوجد | نافذة HISTORY.md متحركة، قابلة للبحث بـ grep |
| النماذج الداخلية | غير مدعومة | hidden=True للنماذج الخاصة بالنظام فقط |
| منع الحلقات | غير مطلوب (لا توجد سلاسل) | مجموعة visited تمنع حلقات A→B→A |
| دقة البوابة | افتراض تنسيق API واحد | بوابة لكل نموذج مع اكتشاف البروتوكول |
كل صف في هذا الجدول يمثل فشلاً في الإنتاج إما جربناه بأنفسنا أو لاحظناه في متتبعات المشكلات الخاصة بأطر العمل الأخرى. الـ Fallback ثنائي الطبقة، وكتالوج النماذج المخفية، ودقة البوابة لكل نموذج، والـ Fallback الناجم عن المهلة: لا يوجد أي من هذه في nanobot أو أي إطار عمل وكلاء مفتوح المصدر آخر قمنا بفحصه.
ما تعلمناه
"نجاح الطلب" ليس "نجاح المهمة". تعمل محركات إعادة المحاولة العامة على مستوى HTTP. لا يمكنهم معرفة أن استجابة 200 مع JSON صالح هي في الواقع فشل لأن النموذج لم يستخدم الأداة التي طلبتها. تحتاج العمليات الحساسة للأعمال إلى معايير نجاح خاصة بها ومنطق Fallback خاص بها.
تفشل النماذج الصغيرة بشكل مختلف عن النماذج الكبيرة. النماذج الكبيرة (GPT-4.1، Claude Sonnet) تستدعي الأدوات دائماً تقريباً عند طلبها. النماذج الصغيرة على محركات الاستدلال السريعة تنشئ أحياناً استجابات تبدو صالحة ولكنها تتجاهل مخطط الأداة تماماً. هذا ليس خطأ يمكنك إصلاحه بهندسة المطالبات (prompt engineering). إنها فجوة في القدرات تتطلب تخفيفاً معمارياً.
اختبر ببيانات الإنتاج، وليس ببيانات اصطناعية. نجح اختبارنا الأولي بـ 6 رسائل اصطناعية في كل نموذج. بينما فشلت جلسة حقيقية مكونة من 60 رسالة مع تاريخ استدعاء الأدوات، والطوابع الزمنية، واللغات المختلطة في اثنين من نماذج Groq الثلاثة. تعقيد البيانات الحقيقية يكشف عن أوضاع فشل لن تظهرها بيانات الاختبار النظيفة أبداً.
هذا هو السبب أيضاً في أن دليل تحديد معدل AI API مهم هنا. نظام الذاكرة لا يحتاج فقط إلى "نموذج أفضل". إنه يحتاج إلى سياسة نقل، وفحص نجاح منطق الأعمال، وسلم Fallback لا ينهار تحت فشل المزود العادي.
LemonClaw هو إطار عمل وكيل ذكاء اصطناعي مفتوح المصدر مع توجيه مدمج متعدد النماذج، وذاكرة مستمرة، وأكثر من 10 تكاملات مع منصات الدردشة. نظام Fallback ثنائي الطبقة بالكامل الموصوف هنا متاح في الإصدار مفتوح المصدر. قم بتشغيله على خادمك الخاص: github.com/hedging8563/lemonclaw
هل تحتاج إلى أكثر من 300 نموذج ذكاء اصطناعي عبر مفتاح API واحد؟ يوفر lemondata.cc وصولاً موحداً إلى OpenAI و Anthropic و Google و DeepSeek و Groq والمزيد.
