7 دقيقة قراءة#llm

بناء روبوت محادثة بسيط باستخدام LangGraph: دليل مناسب للمبتدئين

بناء روبوت محادثة بسيط باستخدام LangGraph: دليل مناسب للمبتدئين

مقدمة

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

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

LangGraph يحل هذه المشكلة من خلال السماح لنا بنمذجة تطبيق الذكاء الاصطناعي كرسم بياني. بدلاً من التحكم يدويًا في كل خطوة من المحادثة، نحدد مجموعة من العقد التي تقوم بتنفيذ العمل، وحواف تحدد كيفية تدفق التنفيذ بين تلك العقد، وحالة مشتركة تحمل المعلومات عبر الرسم البياني.

في هذه المقالة، سنقوم ببناء روبوت محادثة بسيط من الصفر مع تعلم المفاهيم الأساسية التي تجعل LangGraph يعمل.

في النهاية، لن تفهم فقط كيفية بناء روبوت محادثة، ولكن أيضًا سبب تصميم LangGraph بالطريقة التي هي عليها.


المتطلبات الأساسية

قبل البدء، تأكد من توفر:

  • Python 3.10 أو أحدث
  • المعرفة الأساسية بوظائف وفئات لغة Python
  • مزود لنموذج لغوي كبير (OpenAI، Ollama، Anthropic، إلخ.)
  • تم تثبيت LangChain و LangGraph

سنستخدم Ollama خلال هذا البرنامج التعليمي، لكن البنية العامة متطابقة مع محركات الاستدلال الأخرى.


فهم المفاهيم الأساسية الثلاثة

قبل كتابة أي كود، من المهم فهم اللبنات الأساسية الثلاث التي تتكون منها كل تطبيق LangGraph.

الحالة

الحالة هي الذاكرة المشتركة للرسم البياني.

كل عقدة تستقبل الحالة الحالية، تقوم ببعض الأعمال، ثم تُعيد تحديثًا لتلك الحالة.

على عكس برامج Python التقليدية حيث تقوم الدوال بتعديل الكائنات مباشرةً، تقوم عقد LangGraph بإرجاع التغييرات التي تريد إجراؤها فقط. ثم يقوم LangGraph بدمج تلك التغييرات في الحالة المشتركة.

يمكنك التفكير في الحالة كدفتر ملاحظات يُسمح لكل عقدة بالقراءة منه. بدلاً من محو الدفتر، تقوم كل عقدة ببساطة بكتابة معلومات جديدة فيه.

بالنسبة لروبوت المحادثة، تحتوي الحالة عادةً على سجل المحادثة.


العقد

العقدة هي مجرد دالة في بايثون.

مهمته هي تنفيذ مهمة محددة واحدة.

بعض الأمثلة تشمل:

  • طلب استجابة من نموذج لغة كبيرة (LLM).
  • استدعاء أداة خارجية.
  • البحث في قاعدة بيانات.
  • استرجاع المستندات من مخزن المتجهات.
  • تلخيص الرسائل السابقة.

كل عقدة تتبع نفس الفكرة الأساسية:

  1. قراءة الحالة الحالية.
  2. قم بإنجاز بعض الأعمال.
  3. قم بإرجاع تحديث للحالة.

هذه الواجهة البسيطة تجعل العقد سهلة الفهم وإعادة الاستخدام.


الحواف

تحدد الحواف كيفية انتقال التنفيذ عبر الرسم البياني.

هناك نوعان من الحواف.

الحافة العادية تنقل التنفيذ دائمًا إلى العقدة التالية.

على سبيل المثال:

البداية → روبوت المحادثة → النهاية

الحافة الشرطية تسمح للرسم البياني باتخاذ قرار.

على سبيل المثال، بعد أن يُنشئ روبوت المحادثة ردًا، يمكن للرسم البياني أن يقرر:

  • انهاء المحادثة.
  • استدعاء أداة.
  • اطلب من نموذج آخر.
  • استمر في المعالجة.

هذه القدرة على اتخاذ القرارات هي ما يمكّن LangGraph من بناء سير عمل معقدة للذكاء الاصطناعي مع الحفاظ على تنظيم الكود.


تنفيذ أول روبوت محادثة لدينا

حان الوقت الآن لتحويل المفاهيم من القسم السابق إلى كود عملي.

على الرغم من أن البرنامج لا يتجاوز 40 سطرًا، إلا أنه يحتوي على كل مكون أساسي لتطبيق LangGraph:

  • حالة تخزن المعلومات المشتركة عبر الرسم البياني.
  • عقدة تقوم بتنفيذ الأعمال.
  • رسم بياني يربط العقد معًا.
  • مدقق يتذكر المحادثات.
  • حلقة تنفيذية تقوم بإرسال رسائل المستخدم إلى الرسم البياني.

لنفحص كل جزء واحدًا تلو الآخر.


الخطوة الأولى: تحديد حالة الرسم البياني

أول شيء يحتاجه كل تطبيق LangGraph هو حالة.


python
from typing import Annotated 
from typing_extensions import TypedDict 
from langchain_core.messages import BaseMessage 
from langgraph.graph.message import add_messages 
class State(TypedDict): 
  messages: Annotated[list[BaseMessage], add_messages] 

الحالة هي الذاكرة المشتركة للرسم البياني.

كل عقدة تتلقى الحالة الحالية كمدخل وتعيد التغييرات التي يجب دمجها مرة أخرى فيها.

في روبوت المحادثة الخاص بنا، تحتوي الحالة على حقل واحد فقط:

رسائل

والذي يقوم بتخزين المحادثة بأكملها.

لاحظ أن الحقل مغلف داخل Annotated.

python
Annotated[list[BaseMessage], add_messages] 

هذا أحد أهم الأسطر في البرنامج بأكمله.

عادةً، عندما تُعيد عقدة قيمة لحقل ما، يقوم LangGraph باستبدال القيمة السابقة. على سبيل المثال، إذا أعادت عقدة ما:

python
{"messages": [response]} 

المحادثة القديمة ستختفي.

تغير دالة add_messages هذا السلوك. بدلاً من استبدال القائمة، يقوم LangGraph بإلحاق الرسائل الجديدة بالمحادثة الحالية.

بدون add_messages، سينسى روبوت المحادثة كل شيء بعد كل دورة محادثة.


الخطوة الثانية: إنشاء نموذج اللغة

بعد ذلك، نقوم بإنشاء نموذج اللغة.

python
from langchain.chat_models import init_chat_model 
llm = init_chat_model( "llama3.2:1b", model_provider="ollama", )

تقوم الدالة init_chat_model() بإنشاء نموذج محادثة يعرف LangChain كيفية التواصل معه.

على الرغم من أننا نستخدم Ollama في هذا البرنامج التعليمي، فإن بقية الأكواد ستبقى متطابقة تقريبًا إذا قمت بالتبديل إلى OpenAI أو Anthropic أو أي مزود آخر مدعوم. إحدى مزايا LangChain هي أنه يوفر واجهة مشتركة للعديد من نماذج اللغة المختلفة.


الخطوة الثالثة: كتابة عقدة Chatbot

الآن يمكننا إنشاء عقدتنا الأولى.

python
def chatbot(state: State): 
  response = llm.invoke(state["messages"]) 
return { "messages": [response] }

تذكر أن العقدة هي مجرد دالة في لغة Python.

يتلقى الحالة الحالية كمدخل.

python
state["messages"] 

يحتوي على المحادثة الكاملة حتى هذه اللحظة.

ترسل العقدة تلك الرسائل إلى نموذج اللغة.

python
response = llm.invoke(state["messages"])

النموذج يولد ردًا، والذي يتم إرجاعه كـ AIMessage.

أخيرًا، تُعيد العقدة:

python
{ "messages": [response] } 

لاحظ أن العقدة لا تقوم بتعديل الحالة الحالية مباشرة.

بدلاً من ذلك، فإنه يُعيد فقط المعلومات الجديدة التي يرغب في إضافتها.

LangGraph مسؤول عن دمج هذا التحديث في الحالة المشتركة.

لأننا قمنا بتكوين حقل الرسائل باستخدام add_messages، يتم إلحاق استجابة الذكاء الاصطناعي الجديدة بالمحادثة بدلاً من استبدالها.

هذا الفصل بين قراءة الحالة وإرجاع التحديثات هو أحد المبادئ الأساسية لتصميم LangGraph.


الخطوة 4: بناء الرسم البياني

الآن بعد أن أصبح لدينا عقدة، يمكننا بناء الرسم البياني نفسه.

python
builder = StateGraph(State) 
builder.add_node("chatbot", chatbot) 
builder.add_edge(START, "chatbot") 
builder.add_edge("chatbot", END) 

السطر الأول ينشئ رسمًا بيانيًا تُحدَّد حالته المشتركة بواسطة فئة State الخاصة بنا.

python
builder = StateGraph(State)

بعد ذلك، نقوم بتسجيل وظيفة الدردشة الآلية كعقدة.

python
builder.add_node("chatbot", chatbot) 

الوسيط الأول هو اسم العقدة داخل الرسم البياني، بينما الوسيط الثاني هو دالة Python التي يجب تنفيذها.

أخيرًا، نقوم بتوصيل العقد معًا:

بداية ← روبوت محادثة ← نهاية

بيانياً، يبدو سير العمل كالتالي:

Article Media

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


الخطوة 5: إضافة الذاكرة

بعد ذلك، نضيف الذاكرة إلى روبوت المحادثة الخاص بنا.

python
from langgraph.checkpoint.memory import InMemorySaver 
checkpointer = InMemorySaver() 
graph = builder.compile( checkpointer=checkpointer) 

بدون نقطة فحص، سيتم التعامل مع كل استدعاء للرسم البياني على أنه محادثة جديدة تمامًا.

يقوم المدقق بتخزين حالة الرسم البياني بعد كل تنفيذ واستعادتها في المرة التالية التي تستمر فيها نفس المحادثة.

في هذا المثال، نستخدم InMemorySaver، الذي يحتفظ بكل شيء في ذاكرة البرنامج.

هذا مثالي للتعلم والاختبار، ولكن لأن البيانات مخزنة فقط في ذاكرة الوصول العشوائي (RAM)، فإن جميع المحادثات تُفقد عند إنهاء البرنامج.

بالنسبة للتطبيقات الإنتاجية، يدعم LangGraph أيضًا نقاط التفتيش المستدامة المدعومة بقواعد بيانات مثل PostgreSQL أو SQLite.


الخطوة 6: تحديد محادثة

نظرًا لأن أداة حفظ النقاط يمكنها تخزين محادثات متعددة، يحتاج LangGraph إلى طريقة لمعرفة أي منها يجب تحميله.

هذا هو الغرض من كائن التكوين.

python
config = { "configurable": { "thread_id": "thread-1" } } 

thread_id يعمل كمُعرِّف فريد للمحادثة.

عند استدعاء الرسم البياني بنفس thread_id، يقوم LangGraph باستعادة الحالة المحفوظة مسبقًا ومتابعة المحادثة من حيث توقفت.

إذا تم استخدام thread_id مختلف، يبدأ LangGraph محادثة جديدة تمامًا.

يمكنك اعتبار thread_id بمثابة معرف جلسة الدردشة.


الخطوة 7: تشغيل الرسم البياني

أخيرًا، ننشئ حلقة محادثة بسيطة.

python
while True:
    user_input = input("You: ")

    if user_input.lower() in {"quit", "exit"}:
        break

    result = graph.invoke(
        {
            "messages": [{"role": "user","content": user_input,}],
        },
        config=config
    )

    print("AI:", result["messages"][-1].content)

كل تكرار يقوم بالخطوات التالية:

  1. اقرأ مدخلات المستخدم.
  2. قم بتغليفه في كائن رسالة.
  3. استدعاء الرسم البياني.
  4. استرجع المحادثة السابقة باستخدام thread_id.
  5. نفِّذ الرسم البياني (START → chatbot → END).
  6. حفظ الحالة المحدثة.
  7. إرجاع الحالة النهائية.
  8. اطبع استجابة النموذج.

لاحظ أننا نمرر فقط رسالة المستخدم الجديدة إلى graph.invoke(). نحن لا نعيد إرسال سجل المحادثة بالكامل يدويًا. يقوم المدقق تلقائيًا باستعادة الرسائل السابقة قبل تشغيل الرسم البياني، وبعد التنفيذ يحفظ الحالة المحدثة مرة أخرى.

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

Hiwa AI Logo
هـيـوا للذكاء الاصطناعي

تطوير متخصص لأنظمة الذكاء الاصطناعي المستقلة والعقد الموزعة عالية الاعتمادية للمؤسسات الدولية.

منصة متقدمة للذكاء الاصطناعي والوكلاء الأذكياء
التواصل الرقمي:

المنصة

  • حول هيوا
  • الوظائف
  • المدونة

معلومات الاتصال

طهران، طريق ستاري السريع، شارع مخبري، قبل شارع شاهين، رقم 147، الطابق الثاني، الوحدة 3
© 2026 هـيـوا للذكاء الاصطناعي. جميع الحقوق المادية والمعنوية محفوظة.
سياسة الخصوصيةسياسة ملفات تعريف الارتباطإعدادات ملفات تعريف الارتباطشروط الاستخدامالإشعار القانوني
لديك سؤال؟ اسأل هيوا!