انتقل إلى المحتوى الرئيسي

الوحدة 8 — الوكلاء: حلقة الاستدلال والفعل

الوكيل هو حلقة تحكّم تسمح للنموذج بتكرار «فكِّر ثمّ افعل» حتّى يبلغ الجواب. في الوحدة 7 كتبنا الحلقة يدويًّا. في هذه الوحدة نُنظّمها بأدوات مخصّصة، ثمّ نرفع مستوى التحكّم إلى LangGraph حين تصبح البنية أعقد.

حلقة ReAct: الفكرة الأصليّة

اقترحت ورقة ReAct (Reasoning + Acting، ياو وآخرون، 2022) نمطًا بسيطًا: يتناوب النموذج بين الفكرة («أحتاج للتحقّق من سقف الشهر») والفعل («استدعاء plafond_restant»)، ثمّ يقرأ الملاحظة (النتيجة)، ويُكرّر حتّى يجيب.

مع دعم استدعاء الأدوات الأصليّ في النماذج الحديثة، ذاب هذا النمط في الآلية نفسها: النموذج ينتج إمّا نصًّا نهائيًّا، إمّا استدعاء أداة. الحلقة تستمرّ حتّى ينتفي استدعاء الأداة.

create_react_agent من LangGraph

LangChain اليوم يوصي باستعمال LangGraph لبناء الوكلاء. الفئة create_react_agent تُنشئ وكيلًا مُعياريًّا يعمل بأربعة أسطر:

from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

modele = ChatOpenAI(model="gpt-4o-mini", temperature=0)
outils = [convertir_devise, outil_plafond, ajouter_ligne_tableur]
agent = create_react_agent(modele, outils)

for event in agent.stream(
{"messages": [("user", "أضف عشاءً بـ80 دولارًا بتاريخ 3 مارس، فئة عشاء عمل.")]},
stream_mode="values",
):
event["messages"][-1].pretty_print()

هذا الوكيل يستدعي convertir_devise (80 دولار = 73.6 يورو)، ثم plafond_restant (للتحقّق)، ثم ajouter_ligne_tableur، ثم يُنهي بجواب طبيعيّ. كلّه بلا خطوة برمجيّة إضافيّة.

لماذا LangGraph بدل الوكيل الكلاسيكيّ

الوكيل الكلاسيكيّ من langchain.agents (الجيل السابق) كان صندوقًا أسود: صعوبة في تعديل السلوك، صعوبة في المراقبة، ومشاكل في التوازي. LangGraph يحلّ هذه المشاكل بمقاربة مختلفة: رسم بيانيّ صريح من العُقَد والأقواس.

كلّ عقدة دالّة بايثونيّة، وكلّ قوس شرط انتقال. هذه البنية تعطي:

  • وضوحًا: نرى الرسم في اللوحة بيانيًّا (LangSmith يعرضه).
  • تدخّلات معلَنة: يمكن إدخال إنسان في نقطة محدّدة من الرسم.
  • حالة مُهيكلة: يُعرَّف نوع الحالة بـTypedDict، وتُحدَّث كلّ عقدة الحقول التي تعنيها.
  • إعادة التشغيل: يُمكن إعادة تنفيذ من عقدة معيّنة، مفيد للتنقيح.

حدود التكرار: الحاجز الأوّل

الفخّ الأشهر: الوكيل يدخل حلقة لانهائيّة. سبب شائع: أداة تفشل صامتة، فيُعيد النموذج استدعاءها لعلّها تنجح، وهكذا. LangGraph يُعرِّف recursion_limit:

agent.invoke({"messages": [...]}, {"recursion_limit": 15})

الحدّ الافتراضيّ 25. تجاوزه يرفع GraphRecursionError. في الإنتاج، نُطبّق دائمًا حدًّا صريحًا أدنى (10–15) ونُسجّل حالات التجاوز؛ فهي إشارة إلى أداة مكسورة أو تعليمة غامضة، لا إلى مسألة يجب فيها زيادة السقف.

الإنسان في الحلقة

بعض الأفعال لا تُنفَّذ بدون تأكيد بشريّ: تعديل قاعدة بيانات، إرسال بريد، تحويل مبلغ. LangGraph يوفّر interrupt_before لإيقاف الرسم قبل عقدة معيّنة، وانتظار قرار:

from langgraph.checkpoint.memory import MemorySaver

agent = create_react_agent(modele, outils, checkpointer=MemorySaver(),
interrupt_before=["tools"])

النقاط الحاسمة: نُخزّن الحالة عبر checkpointer، ونستأنف عبر Command(resume=...) بعد قرار المستخدم. هذا يبني تجربة استخدام آمنة: يقترح المساعد إضافة السطر، يعرض الوسائط، ينتظر «تأكيد».

الوحدة 30 من المسار (وليست جزءًا من هذه الدورة) تُفصّل هذا النمط.

البنية الأعقد: تفريع صريح

مساعد يواجه أنواعًا مختلفة من الطلبات (سؤال سياسة، حساب سقف، إدخال طلب) قد يحتاج تفريعًا صريحًا بدل ترك القرار كليًّا للنموذج. LangGraph يسمح بذلك:

from langgraph.graph import StateGraph, END

def classifier(state):
dernier = state["messages"][-1].content
return "rag" if "سياسة" in dernier else "outil"

graphe = StateGraph(EtatMessages)
graphe.add_node("rag", noeud_rag)
graphe.add_node("outil", noeud_outil)
graphe.add_conditional_edges("start", classifier, {"rag": "rag", "outil": "outil"})
graphe.add_edge("rag", END)
graphe.add_edge("outil", END)

هذه بنية «موجّه» (router): مسار مختصر للأسئلة التي لا تحتاج وكيلًا كاملًا، ووكيل كامل للأسئلة المعقّدة. قاعدة: الوكيل ليس دائمًا الجواب؛ سلسلة موجَّهة أسرع وأرخص وأدقّ للأسئلة البسيطة.

الفخّ: الوكيل الذي يتراكم عليه

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

علامات إنذار:

  • انتقاء أداة خاطئة على أسئلة كانت تعمل.
  • استدعاءات متكرّرة لأداة واحدة بوسائط قريبة.
  • مسارات تنتهي عند recursion_limit.

علاج: مراجعة التعليمة بعد كلّ إضافة أداة، وقاعدة «أداة لكلّ مسار»، وتقييم منهجيّ (الوحدة 9).

الخيط الأحمر

مساعد النفقات الآن يمتلك وكيلًا مبنيًّا بـcreate_react_agent بحدّ تكرار 12، ونقطة توقّف قبل ajouter_ligne_tableur لتأكيد المستخدم. يستقبل «أضِف عشاءً بـ80 دولارًا…»، يُحوّل، يتحقّق من السقف، يعرض ملخّصًا، ينتظر التأكيد، ثمّ يُدخل السطر. سيصير المشروع النهائيّ في الوحدة 10.

قاعدة قرار

سؤال-جواب مباشر: سلسلة LCEL. سؤالان متتابعان مستقلاّن: سلسلة موجَّهة. سلسلة إجراءات مترابطة قد تحتاج إعادة محاولة: وكيل. عمليّة حسّاسة على قاعدة بيانات: وكيل مع إنسان في الحلقة.

الخلاصة

  • الوكيل حلقة تحكّم؛ create_react_agent من LangGraph التنفيذ الحديث المُوصى به.
  • LangGraph يوفّر رسمًا صريحًا وحالة مُهيكلة ونقاط توقّف وإعادة تشغيل، ما تفتقده الوكلاء الكلاسيكيّون.
  • recursion_limit حاجز إلزاميّ في الإنتاج؛ تجاوزه إشارة إلى مسألة عميقة لا يُداويها رفع السقف.
  • «الإنسان في الحلقة» عبر interrupt_before نمط أمان معياريّ للأفعال ذات الأثر.