بلا حلقة، لا وكيل
يمكن تلخيص سر Claude Code في سطر واحد: while stop_reason == "tool_use"
ما الذي يفعله الـ agent فعلياً؟
حين تشغّل Claude Code في الطرفية وتطلب منه «جمع كل تعليقات TODO في قائمة»، تراه يقرر بنفسه: يبدأ بـ grep، ثم يقرأ عدة ملفات بـ cat، ثم يُخرج Markdown. النموذج لا ينفذ الكود بنفسه — بل يطلب تنفيذه فحسب. ما يجعله يبدو «لديه يدان وقدمان» هو ذلك الكود الرابط المؤلف من نحو 30 سطراً يحيط به.
هذا الدرس يُفكك ذلك الكود الرابط ويُوضحه. يُسمى agent loop (حلقة الوكيل)، وبنيته هي:
while response.stop_reason == "tool_use": response = LLM(messages, tools) # 1. ask the model execute_tools(response.tool_calls) # 2. run what it asked for messages.append(tool_results) # 3. feed results back
هذا كل شيء. Claude Code في بيئة الإنتاج يُضيف فوق هذا صلاحيات وhooks وsub-agents وعزل worktree وضغط الذاكرة — لكن النواة لا تزال هذه الأسطر الأربعة.
الحدس الأساسي: كل استجابة من النموذج إما «أريد استدعاء أداة» أو «انتهيت». طالما في الحالة الأولى تستمر الحلقة؛ حين تدخل الحالة الثانية تخرج الحلقة. المعيار هو حقل stop_reason في الاستجابة.
شاهد messages[] تنمو خطوة بخطوة
الحلقة التالية تحاكي مهمة: «ما الملفات في الدليل الحالي؟ ثم اقرأ package.json». اضغط Step، كل ضغطة تقدّمك خطوة واحدة في الحلقة. يسار: فقاعة المحادثة التي يراها الإنسان، يمين: مصفوفة messages[] الفعلية المُمررة للنموذج — راقب كيف تنمو.
يجب إعادة نتائج الأدوات إلى سجل الرسائل
أكثر خطأ يرتكبه المبتدئون هو اعتبار «تنفيذ الأداة» مجرد تأثير جانبي — نُنفذ وننتهي. لكن النموذج في الجولة التالية لا يرى إلا messages[]، وكل ما ليس فيها لا يعلم أنه حدث. بدون خطوة append، تنهار الحلقة بأكملها.
الأخطاء ليست كلها متشابهة. نوعان شائعان:
- نسيان append: النموذج لن يرى النتيجة في الجولة التالية، فسيُكرر طلب الأداة نفسها — وينتج عن ذلك حلقة لا نهائية.
- append مع فقدان
tool_use_id: Anthropic API ستُعيد خطأ مباشراًtool_result must have tool_use_id، وستنهار الحلقة عند خطوة استدعاء API.
المهمة ذاتها: «عدّ ملفات Python في المشروع». شغّل النسختين جنباً إلى جنب وشاهد الفارق في النتيجة.
فهم stop_reason
كل استجابة من النموذج تحمل stop_reason. قرار الاستمرار أو الخروج يعتمد على هذا الحقل:
tool_use— النموذج يريد استدعاء أداة، استمر في الحلقة.end_turn— النموذج أنهى ما يريد قوله، اخرج من الحلقة.max_tokens— الإنتاج بلغ حد الـ token فاقتُطع، اخرج من الحلقة (عالجه عادةً كاستثناء ونبّه المستخدم بعدم اكتمال الإخراج).stop_sequence— صادف تسلسل إيقاف مخصصاً، اخرج من الحلقة.
الخطأ الشائع هو الكتابة كـ «استمر طالما لم يكن tool_use»، أو تجاهل max_tokens ومعاملتها كـ end_turn عادية.
جرّبه محلياً
استنسخ shareAI-lab/learn-claude-code محلياً:
git clone https://github.com/shareAI-lab/learn-claude-code cd learn-claude-code pip install -r requirements.txt cp .env.example .env # fill in ANTHROPIC_API_KEY python agents/s01_agent_loop.py
ثم اطلب منه شيئاً حقيقياً: ساعدني في عدّ ملفات .py في هذا المستودع. ستراه يُرسل ls -R، يرى الإخراج، يُرسل find . -name "*.py" | wc -l، ثم يُعطيك الإجابة. العملية برمتها هي هذه الحلقة تدور.