مقدمة
في المقال السابق، قمنا ببناء أول روبوت محادثة باستخدام LangGraph. كان الرسم البياني بسيطًا عن قصد:
ابدأ → روبوت المحادثة → انتهى
كل رسالة اتبعت المسار نفسه تمامًا. بغض النظر عما طلبه المستخدم، كانت الدردشة الآلية ترسل المحادثة مباشرة إلى نموذج اللغة. بينما يعد هذا نقطة بداية رائعة، نادرًا ما تتصرف تطبيقات الذكاء الاصطناعي في العالم الحقيقي بهذه الطريقة. تخيل أننا نبني دردشة آلية لـ §L0§Hiwa AI§/L0§.
بعض الأسئلة متعلقة بالشركة:
- ما هي الخدمات التي تقدمها Hiwa AI؟
- أين يقع مقر Hiwa AI؟
- كيف يمكنني الاتصال بـ Hiwa AI؟
أسئلة أخرى لا علاقة لها بالشركة:
- من فاز بكأس العالم؟
- قل لي نكتة.
- ما هو الطقس اليوم؟
من الناحية المثالية، يجب أن يتعرف روبوت المحادثة لدينا على نية المستخدم قبل اتخاذ قرار بشأن الخطوة التالية.
في هذه المقالة، سنقوم بتوسيع وظائف روبوت الدردشة الخاص بنا باستخدام مفهومين مهمين من LangGraph:
- تصنيف النية - تحديد ما يسأل عنه المستخدم.
- التوجيه الشرطي — اختيار مسار تنفيذ مختلف بناءً على تلك النية.
على الرغم من أننا سنحافظ على الرسم البياني صغيرًا نسبيًا، إلا أن هذين المفهومين هما أساس العديد من أنظمة الذكاء الاصطناعي المستخدمة في الإنتاج.

فهم تصنيف النوايا
تصنيف النية هو عملية تحديد ما يحاول المستخدم تحقيقه. بدلاً من توليد إجابة على الفور، يقوم روبوت المحادثة أولاً بتحليل رسالة المستخدم ويربطها بفئة معينة. بالنسبة لروبوت المحادثة الخاص بنا، سنستخدم فئتين فقط:
- أسئلة ذات صلة – حول Hiwa AI
- غير مرتبط – كل شيء آخر.
على سبيل المثال:
سؤال، نية
- ما هي المنتجات التي تقدمها Hiwa AI؟: ذات صلة،
- أين يقع مقر Hiwa AI؟: ذات صلة،START → روبوت محادثة → END
- أخبرني نكتة.
- من اخترع لغة بايثون؟: غير مرتبط
بدلاً من محاولة الإجابة على كل سؤال، يقوم روبوت المحادثة الخاص بنا أولاً بتحديد الفئة التي ينتمي إليها السؤال. هذه الخطوة الإضافية تسمح للرسم البياني باتخاذ قرارات أكثر ذكاءً لاحقاً.
فهم التوجيه الشرطي
في المقال السابق، كان التنفيذ دائمًا يتبع المسار نفسه. لم يكن هناك اتخاذ قرار. التوجيه الشرطي يغير هذا. بدلًا من تنفيذ العقدة التالية دائمًا، يمكن لـ LangGraph فحص الحالة الحالية وتحديد المكان الذي يجب أن يستمر فيه التنفيذ.
يبدو الرسم البياني الجديد الخاص بنا هكذا:

لاحظ أن هناك الآن مسارين محتملين للتنفيذ. المسار الذي يتبعه الرسم البياني يعتمد كليًا على نتيجة تصنيف النية.
الخطوة 1: توسيع الحالة
كان أول روبوت محادثة لدينا يحتاج فقط إلى تذكر سجل المحادثة. الآن نحتاج أيضًا إلى تذكر نية المستخدم.
from typing import Literal
from langgraph.graph import MessagesState
class State(MessagesState):
user_intent: Literal["related", "unrelated"]بدلاً من إنشاء حالة جديدة تمامًا، نرث من MessagesState. تحتوي MessagesState بالفعل على كل ما يلزم لتخزين سجل المحادثة. نقوم ببساطة بتمديدها بحقل آخر يُسمى user_intent. لاحقًا، سيستخدم الرسم البياني لدينا هذه القيمة لتحديد العقدة التي يجب تنفيذها بعد ذلك.
الخطوة الثانية: تحديد استجابة منظمة
يحتاج نموذج اللغة إلى تصنيف رسالة المستخدم. بدلاً من طلب إرجاع النموذج لنص عادي، سنطلب منه إرجاع كائن منظم.
from typing import Literal
from pydantic import BaseModel
class UserIntent(BaseModel):
user_intent: Literal["related", "unrelated"]
reasoning: strبعد ذلك، نطلب من نموذج اللغة أن يعيد دائمًا هذه البنية.
structured_llm = llm.with_structured_output(UserIntent)الآن، بدلاً من إنشاء شيء مثل هذا:
أعتقد أن هذا السؤال مرتبط بـ Hiwa AI لأن...
يعيد النموذج كائنًا مثل:
UserIntent(
user_intent="related",
reasoning="The user is asking about the company's services."
)هذا النهج أسهل بكثير في التعامل معه لأن تطبيقنا يتلقى بيانات منظمة بدلاً من نص حر.
الخطوة 3: إنشاء عقدة تصنيف النوايا
الآن يمكننا إنشاء العقدة الأولى لدينا.
from langchain_core.messages import SystemMessage
INTENT_SYSTEM = """ Determine whether the user's question is related to Hiwa AI. Return: - related - unrelated """العقدة نفسها صغيرة جدًا.
def find_out_intent(state: State):
result = structured_llm.invoke(
[SystemMessage(content=INTENT_SYSTEM)] + state["messages"]
)
return { "user_intent": result.user_intent }يستقبل العقدة سجل المحادثة. تطلب من نموذج اللغة تصنيف أحدث رسالة من المستخدم. أخيرًا، تخزن التصنيف داخل حالة الرسم البياني. لاحظ أن هذه العقدة لا تجيب على سؤال المستخدم. مسؤوليتها الوحيدة هي تحديد نية المستخدم. الحفاظ على تركيز كل عقدة على مهمة واحدة يجعل الرسم البياني أسهل في الفهم والصيانة.
الخطوة 4: اتخاذ القرار
الآن بعد أن فهم الرسم البياني نية المستخدم، يمكنه تحديد الخطوة التالية. يتم اتخاذ هذا القرار بواسطة دالة Python عادية.
from typing import Literal
from langgraph.graph import END
def should_continue( state: State,) -> Literal["chatbot", END]:
if state["user_intent"] == "related":
return "chatbot"
return ENDإذا كان السؤال متعلقًا بـ Hiwa AI، يستمر الرسم البياني إلى عقدة الدردشة الآلية. وإلا، ينتهي التنفيذ فورًا. تُسمى هذه الوظيفة بوظيفة التوجيه لأن وظيفتها الوحيدة هي تحديد العقدة التي يجب تشغيلها بعد ذلك.
الخطوة 5: إنشاء عقدة Chatbot
عقدة الدردشة الآلية لدينا تكاد تكون مطابقة لتلك الموجودة في المقالة السابقة.
def chatbot(state: State):
response = llm.invoke(state["messages"])
return {"messages": [response]}الفرق الوحيد هو أن هذه العقدة لم تعد تُنفذ لكل رسالة مستخدم. فهي تعمل فقط إذا قررت وظيفة التوجيه أن السؤال مرتبط بـ Hiwa AI.
الخطوة 6: بناء الرسم البياني
أخيرًا، نقوم بتوصيل كل شيء معًا.
from langgraph.graph import StateGraph, START, END
builder = StateGraph(State)
builder.add_node("find_out_intent", find_out_intent)
builder.add_node("chatbot", chatbot)
builder.add_edge(START, "find_out_intent")
builder.add_conditional_edges("find_out_intent", should_continue, ["chatbot", END])
builder.add_edge("chatbot", END)
graph = builder.compile()يبدو معظم هذا الكود مألوفًا من المقال السابق.
المفهوم الجديد الوحيد هو:
from langgraph.graph import StateGraph, START, END
builder = StateGraph(State)
builder.add_node("find_out_intent", find_out_intent)
builder.add_node("chatbot", chatbot)
builder.add_edge(START, "find_out_intent")
builder.add_conditional_edges(
"find_out_intent",
should_continue,
["chatbot", END]
)
builder.add_edge("chatbot", END)
graph = builder.compile()
def chatbot(state: State):
response = llm.invoke(state["messages"])
return {"messages": [response]}الفرق الوحيد هو أن هذه العقدة لم تعد تُنفذ لكل رسالة مستخدم. فهي تعمل فقط إذا قررت وظيفة التوجيه أن السؤال مرتبط بـ Hiwa AI.
الخطوة 6: بناء الرسم البياني
أخيرًا، نقوم بتوصيل كل شيء معًا.
from langgraph.graph import StateGraph, START, END
builder = StateGraph(State)
builder.add_node("find_out_intent", find_out_intent)
builder.add_node("chatbot", chatbot)
builder.add_edge(START, "find_out_intent")
builder.add_conditional_edges("find_out_intent", should_continue, ["chatbot", END])
builder.add_edge("chatbot", END)
graph = builder.compile()معظم هذا الكود يجب أن يبدو مألوفًا من المقال السابق. المفهوم الجديد الوحيد هو:
builder.add_conditional_edges( "find_out_intent", should_continue, ["chatbot", END])بدلاً من الاتصال المباشر الدائم بين عقدة وأخرى، نطلب من LangGraph تنفيذ الدالة should_continue(). القيمة التي تُرجعها هذه الدالة تحدد الحافة التي يتبعها الرسم البياني.
هذه إحدى الميزات التي تجعل §L0§LangGraph§/L0§ قوية جدًا. بدلاً من كتابة عبارات if المتداخلة عبر تطبيقك، يمكنك نمذجة عملية اتخاذ القرار مباشرة كرسم بياني.
مع نمو تطبيقك، يمكنك ببساطة إضافة المزيد من العقد والمزيد من منطق التوجيه مع الحفاظ على كل مكون صغيرًا ومركّزًا.
ماذا بعد؟
يمكن لروبوت الدردشة الخاص بنا الآن اتخاذ القرارات قبل إنشاء الرد. ومع ذلك، لا يزال لديه قيد رئيسي واحد.
حتى عندما يكون السؤال متعلقًا بـ Hiwa AI، فإن نموذج اللغة لا يملك أي معرفة بموقع الشركة.
في المقال التالي، سنحل هذه المشكلة من خلال تقديم تقنية "التوليد المعزز بالاسترجاع" (RAG). سنقوم ببناء قاعدة معرفية من موقع §L0§Hiwa AI§/L0§، واسترداد المعلومات الأكثر صلة لكل سؤال، وتوفير هذا السياق لنموذج اللغة قبل أن يقوم بتوليد استجابته.

