تحظى أدلة المبتدئين المعنونة بـ “كيف تبني أول وكيل ذكاء اصطناعي” باهتمام متواصل. والأدلة الجيدة منها تقسّم الوكيل عادةً إلى أربعة أجزاء: دماغ نموذج اللغة الكبير المسؤول عن الاستدلال، والذاكرة التي تحفظ الحالة، والأدوات التي تتفاعل مع العالم الخارجي، وحلقة الوكيل التي تربط الثلاثة معاً في تكرار. ويصاحب ذلك نمط ReAct - التناوب بين الاستدلال والتصرف - باعتباره المعيار الفعلي. كل ذلك صحيح. لكن عند تشغيل الوكلاء فعلياً في الإنتاج، يكون الجزء الذي يتعطل مختلفاً. إنه ضوابط الحماية التي تقرر متى توقف الحلقة. يشغّل هذا المقال حلقة وكيل دنيا مع ضوابط حماية بلغة Python الصرفة دون استدعاء أي نموذج لغوي خارجي، ويوضح الفارق بأرقام حقيقية.

نظرة عامة

حلقة الوكيل في جوهرها حلقة while. تراقب الحالة، وتقرر الإجراء التالي، وتنفّذ أداة، ثم تراقب النتيجة من جديد. في المسار السعيد الذي تعرضه مواد المبتدئين، تدور هذه الحلقة بضع مرات وتنتج إجابة وتنتهي. المشكلة هي المسار غير السعيد. في العمليات الحقيقية، يحدث كثيراً أن يستدعي النموذج الأداة ذاتها إلى ما لا نهاية، أو يتعلق بمهمة لا تنتهي، أو يظل طلب واحد يشغل وحدة معالجة الرسوميات GPU دون أن يُفرج عنها. ضوابط الحماية هي الآلية التي تحجب هذا الانفلات على مستوى الكود.

تشغّل ThakiCloud وكلاء ومهام دفعية لعملاء متعددين على مجموعة GPU واحدة في بيئة متعددة المستأجرين. في هذا السياق، تُعدّ ضوابط الحماية شرطاً مسبقاً لا خياراً. لا يمكن السماح لحلقة منفلتة من مستأجر واحد بتعطيل المجموعة بأكملها. لهذا يصبح السؤال “كيف توقف حلقة الوكيل” أهم من الناحية التشغيلية من السؤال “كيف تبني وكيلاً”. يشارك هذا المقال نتائج تطبيق آلية الإيقاف في أصغر صورة لها وتشغيلها مباشرة.

ما هذه التقنية

هيكل حلقة ReAct بسيط. تنظر السياسة إلى الحالة الراهنة وتقرر ما ستفعله بعد ذلك. إن طالبت باستدعاء أداة، تعمل الأداة وتنتج ملاحظة. وإن طالبت بالانتهاء، تُعاد الإجابة. في الوكيل الحقيقي تكون السياسة نموذج لغة كبير LLM، لكن بنية التحكم في الحلقة ذاتها مستقلة عن النموذج. لهذا استُعيض في هذه التجربة عن السياسة بمحاكٍ يعمل بقواعد ثابتة - لمراقبة مستوى التحكم في الحلقة لا جودة النموذج - مما يجعل النتائج قابلة للتكرار الكامل.

تُضيف ضوابط الحماية ثلاثة شروط إيقاف إلى هذه الحلقة. حد الخطوات (max_steps) يُجبر الحلقة على التوقف بعد عدد محدد من التكرارات. ميزانية الوقت (wall_budget) تقيّد وقت الساعة الجدارية لكل مهمة. كشف التكرار (repeat_guard) يقطع الحلقة حين تتكرر الإجراء ذاته، مما يشير إلى فخ تكرار. تنتهي كل مهمة بسبب إنهاء واحد بالضبط من بين: finished أو max_steps أو wall_budget أو repeat_guard أو no_action.

حلقة الوكيل مع ضوابط الحماية: بعد قرار السياسة، يجب على الحلقة اجتياز حد الخطوات وميزانية الوقت وكشف التكرار قبل تنفيذ أي أداة. وإذا أُطلق أي ضابط حماية، توقف الحلقة بسبب إنهاء صريح

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

الإعداد والتكامل

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

@dataclass
class Guards:
    max_steps: int = 6
    wall_budget_s: float = 2.0
    repeat_limit: int = 2

def run_task(task: str, g: Guards) -> Trace:
    t0 = time.perf_counter()
    tr = Trace(task=task)
    repeats: dict[str, int] = {}
    while True:
        if tr.steps >= g.max_steps:
            tr.terminal = "max_steps"; break
        if (time.perf_counter() - t0) > g.wall_budget_s:
            tr.terminal = "wall_budget"; break
        act = policy(task, tr.scratch)
        if "final" in act:
            tr.answer = act["final"]
            tr.terminal = "finished" if act["final"] is not None else "no_action"
            break
        sig = f"{act['tool']}:{act['input']}"
        repeats[sig] = repeats.get(sig, 0) + 1
        if repeats[sig] > g.repeat_limit:
            tr.terminal = "repeat_guard"; break
        obs = TOOLS[act["tool"]](act["input"])
        tr.scratch.append({"tool": act["tool"], "input": act["input"], "obs": obs})
        tr.steps += 1
    tr.latency_ms = round((time.perf_counter() - t0) * 1000, 3)
    return tr

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

.venv/bin/python scripts/experiments/minimal-guarded-agent-loop/agent_loop.py

تضمّن مجموعة المهام أربع مهام تكتمل بصورة طبيعية، إلى جانب مهمة فخ تكرار مصمّمة عمداً لتكرار الاستعلام ذاته إلى الأبد. ما إذا كانت مهمة الفخ تُوقفها آلية كشف التكرار هو التحقق المحوري لهذه التجربة.

نتائج التجربة الفعلية

فيما يلي النتائج الحقيقية لتشغيل خمس مهام. ضُبطت ضوابط الحماية على: حد خطوات 6، وميزانية وقت 2.0 ثانية، وحد تكرار 2.

{
  "n_tasks": 5,
  "by_terminal": { "finished": 4, "repeat_guard": 1 },
  "total_latency_ms": 0.115,
  "total_steps": 7
}

المحور الرئيسي هو توزيع أسباب الإنهاء. أربع مهام انتهت بصورة طبيعية، ومهمة واحدة أوقفها كاشف التكرار. مهمة “loop forever please” المزروعة عمداً واصلت تكرار الاستعلام ذاته حتى أوقفها كشف التكرار عند الخطوة الثانية بالضبط. بمجرد أن تجاوز الإجراء ذاته الحد المسموح به، قُطعت الحلقة. بدون ضوابط الحماية، ما كانت هذه المهمة لتنتهي أبداً، مع إصرار السياسة على الإجراء ذاته إلى الأبد.

عدد خطوات الحلقة لكل مهمة وتوزيع أسباب الإنهاء: أربع مهام تنتهي بصورة طبيعية في 1 إلى 2 خطوة، ومهمة فخ التكرار الوحيدة تتوقف عبر كشف التكرار

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

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

التطبيق على منصة ThakiCloud للذكاء الاصطناعي وتعلم الآلة على Kubernetes

قد تبدو هذه الحلقة الدنيا مجرد تمرين، لكن المبادئ التي تجسّدها هي ذاتها جوهر تشغيل وكلاء الإنتاج. المبدأ هو أن الإيقاف مسؤولية البنية التحتية لا النموذج. في حزمة عمليات ThakiCloud، يتجلى هذا المبدأ على مستويين.

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

وتأتي قابلية التدقيق بصورة طبيعية. في هذه التجربة، أبقت كل مهمة سجلاً بسبب الإنهاء بصريح العبارة. ما إذا انتهت طبيعياً، أو أوقفها كشف التكرار، أو تجاوزت الوقت يُسجَّل بصورة هيكلية. مدّ هذا النمط للإنتاج يعني أن كل إجراء وسبب إنهاء من وكيل يُدوَّن في سجلات، ويمكن تتبع من أوقف ماذا ومتى ولماذا. في البيئات التي تفترض النشر المحلي والسيادي، تُعدّ هذه القابلية للتتبع شرطاً مسبقاً للتبني من قِبل القطاع العام أو عملاء الصناعات المنظَّمة. النظام الذي لا يستطيع شرح ما فعله وكلاؤه غير قابل للنشر بحكم تعريفه.

خلاصة القول: أهم ما ينبغي تعلّمه عند بناء أول وكيل ليس كيفية توصيل الأدوات، بل كيفية إيقاف الحلقة. ضوابط الحماية ليست ميزة أمان تُضاف لاحقاً بل يجب أن تكون جزءاً من الحلقة منذ البداية. ووضع هذه الضوابط على مستوى التطبيق والبنية التحتية معاً هو الطريقة الآمنة لتشغيل الوكلاء على منصة GPU متعددة المستأجرين.

القيود والاعتراضات

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

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

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

المصادر