مقدمه
در مقاله قبلی، ما اولین چتبات خود را با استفاده از LangGraph ساختیم. گراف بهصورت عمدی ساده طراحی شده بود:
شروع → چتبات → پایان
هر پیام دقیقاً همان مسیر را دنبال میکرد. بدون توجه به اینکه کاربر چه چیزی پرسیده بود، چتبات همیشه مکالمه را مستقیماً به مدل زبانی ارسال میکرد. هرچند این نقطه شروع خوبی است، اما کاربردهای واقعی هوش مصنوعی به ندرت به این شکل عمل میکنند. تصور کنید که در حال ساخت یک چتبات برای Hiwa AI هستیم.
برخی از سوالات مرتبط با شرکت هستند:
- Hiwa AI چه خدماتی ارائه میدهد؟
- Hiwa AI در کجا واقع شده است؟
- چگونه میتوانم با §L0§Hiwa AI§/L0§ تماس بگیرم؟
سوالات دیگر هیچ ارتباطی با شرکت ندارند:
- چه کسی جام جهانی را برد؟
- یک جوک بگو.
- امروز هوا چطوره؟
بهطور ایدهآل، چتبات ما باید قصد کاربر را قبل از تصمیمگیری در مورد اقدام بعدی تشخیص دهد.
در این مقاله، دو مفهوم مهم LangGraph را به چتبات خود اضافه خواهیم کرد:
- طبقهبندی قصد — تعیین اینکه کاربر در مورد چه چیزی سوال میکند.
- مسیریابی شرطی — انتخاب مسیر اجرایی متفاوت بر اساس آن قصد.
اگرچه گراف را نسبتاً کوچک نگه خواهیم داشت، این دو مفهوم پایهی بسیاری از سیستمهای هوش مصنوعی تولیدی هستند.

درک طبقهبندی قصد
طبقهبندی قصد فرآیند شناسایی هدف کاربر است. به جای تولید فوری پاسخ، چتبات ابتدا پیام کاربر را تحلیل کرده و آن را به یک دسته اختصاص میدهد. برای چتبات ما تنها از دو دسته استفاده خواهیم کرد:
- مربوط – سوالات درباره §L0§هایوا AI§/L0§.
- نامرتبط – هر چیز دیگر.
به عنوان مثال:
سوال، قصد
- Hiwa AI چه محصولاتی ارائه میدهد؟: مرتبط،
- Hiwa AI در کجا واقع شده است؟: مرتبط،START → چتبات → END
- یک جوک بگو: بیربط
- چه کسی پایتون را اختراع کرد؟: نامربوط
به جای تلاش برای پاسخگویی به هر سوال، چتبات ما ابتدا تصمیم میگیرد که سوال در کدام دسته قرار میگیرد. این مرحله اضافی به گراف اجازه میدهد تا بعداً تصمیمات هوشمندانهتری بگیرد.
درک مسیریابی شرطی
در مقاله قبلی، اجرا همیشه از مسیر یکسانی پیروی میکرد. هیچ تصمیمگیری وجود نداشت. مسیریابی شرطی این را تغییر میدهد. به جای اینکه همیشه گره بعدی اجرا شود، LangGraph میتواند وضعیت فعلی را بررسی کند و تصمیم بگیرد که اجرا از کجا ادامه یابد.
گراف جدید ما به این شکل است:

توجه کنید که اکنون دو مسیر اجرای ممکن وجود دارد. مسیری که گراف دنبال میکند کاملاً به نتیجه طبقهبندی intent بستگی دارد.
مرحله ۱: گسترش وضعیت
چتبات اول ما فقط نیاز داشت تاریخچه مکالمه را به خاطر بسپارد. حالا باید قصد کاربر را نیز به خاطر بسپاریم.
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)اکنون، به جای تولید چیزی شبیه به این:
فکر میکنم این سوال مربوط به هوش مصنوعی هیوا است چون...
مدل یک شیء مانند زیر برمیگردد:
UserIntent(
user_intent="related",
reasoning="The user is asking about the company's services."
)این روش کار کردن با آن بسیار آسانتر است زیرا برنامهی ما دادههای ساختاریافته دریافت میکند به جای متن آزاد.
مرحله ۳: ایجاد گره طبقهبندی قصد
اکنون میتوانیم اولین گره خود را ایجاد کنیم.
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 }گره تاریخچه مکالمه را دریافت میکند. سپس از مدل زبانی میخواهد که آخرین پیام کاربر را دستهبندی کند. در نهایت، این دستهبندی را در وضعیت گراف ذخیره میکند. توجه داشته باشید که این گره به سوال کاربر پاسخ نمیدهد. تنها مسئولیت آن تعیین قصد کاربر است. تمرکز هر گره بر یک وظیفه واحد، درک و نگهداری گراف را آسانتر میسازد.
مرحله ۴: اتخاذ تصمیم
اکنون که گراف از قصد کاربر آگاه است، میتواند تصمیم بگیرد که چه کاری انجام دهد. این تصمیم توسط یک تابع معمولی پایتون گرفته میشود.
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اگر سوال مربوط به هوش مصنوعی هیوا باشد، گراف به گره چتبات ادامه مییابد. در غیر این صورت، اجرا بلافاصله پایان مییابد. این تابع به عنوان تابع مسیریابی شناخته میشود زیرا تنها وظیفه آن تصمیمگیری درباره این است که کدام گره باید بعدی اجرا شود.
مرحله 5: ایجاد نود چتبات
گره چتبات ما تقریباً مشابه گره ای است که در مقاله قبلی بررسی شد.
def chatbot(state: State):
response = llm.invoke(state["messages"])
return {"messages": [response]}تنها تفاوت این است که این نود دیگر برای هر پیام کاربر اجرا نمیشود. فقط در صورتی اجرا میشود که تابع روتینگ تشخیص دهد سوال مرتبط با §L0§هایوا هوش مصنوعی§/L0§ است.
مرحله ۶: ساخت گراف
در نهایت، همه چیز را به هم متصل میکنیم.
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 است.
مرحله ۶: ساخت گراف
در نهایت، همه چیز را به هم متصل میکنیم.
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() را اجرا کند. هر مقداری که این تابع برگرداند، تعیین میکند که گراف از کدام یال پیروی کند.
این یکی از ویژگیهایی است که LangGraph را بسیار قدرتمند میسازد. به جای نوشتن دستورات شرطی تو در تو در سراسر برنامهتان، میتوانید فرآیند تصمیمگیری خود را مستقیماً به صورت یک گراف مدل کنید.
با گسترش برنامهی شما، به سادگی میتوانید گرههای بیشتر و منطق مسیریابی بیشتری اضافه کنید، در حالی که هر مؤلفه را کوچک و متمرکز نگه میدارید.
چه بعدی؟
چتبات ما اکنون میتواند قبل از تولید پاسخ تصمیمگیری کند. با این حال، هنوز یک محدودیت عمده دارد.
حتی زمانی که سوال مرتبط با Hiwa AI باشد، مدل زبانی هیچ دانشی از وبسایت این شرکت ندارد.
در مقاله بعدی، این مشکل را با معرفی تولید تقویتشده با بازیابی (RAG) حل خواهیم کرد. یک پایگاه دانش از وبسایت §L0§Hiwa AI§/L0§ ایجاد میکنیم، مرتبطترین اطلاعات را برای هر سوال بازیابی کرده و آن زمینه را قبل از تولید پاسخ توسط مدل زبانی ارائه خواهیم داد.

