چرا RAG در مکالمهها شکست میخورد؟ معرفی Conversation-aware Retrieval
تصور کن یک چتبات داخلی برای تیم پشتیبانی یا یک دستیار فنی داری که به مستندات شرکت وصل است. کاربر یک سؤال مشخص میپرسد، جواب

تصور کن یک چتبات داخلی برای تیم پشتیبانی یا یک دستیار فنی داری که به مستندات شرکت وصل است. کاربر یک سؤال مشخص میپرسد، جواب

تصور کن یک چتبات داخلی برای تیم پشتیبانی یا یک دستیار فنی داری که به مستندات شرکت وصل است. کاربر یک سؤال مشخص میپرسد، جواب میگیرد، و بعد مثل خیلی از مکالمههای واقعی سؤال بعدی را نصفهنیمه میپرسد:
«اینش چطور بود؟»
«همون مورد قبلی رو میگم…»
«برای این سناریو هم جواب میده؟»
اینجا دقیقاً همان جایی است که خیلی از سیستمهای RAG ساده به مشکل میخورند؛ نه بهخاطر اینکه «اطلاعات ندارند»، بلکه چون نمیفهمند ضمیرها و ارجاعها به چه چیزی اشاره میکنند.
فرض کن کاربر قبلاً دربارهی سیاست بازگشت وجه (Refund Policy) سؤال پرسیده و حالا ادامه میدهد:
گفتوگو:
این «اینش» برای انسان واضح است: منظورش همان شرایط بازگشت وجه است.
اما اگر سیستم فقط پیام آخر را ببیند، ممکن است دنبال «خرید سازمانی» بگردد و سندهای کاملاً دیگری را بالا بیاورد.
در بسیاری از پیادهسازیهای RAG، مرحلهی جستجو (retrieval) بر اساس آخرین پیام انجام میشود. نتیجه؟
و این یعنی تجربهای که کاربر حس میکند:
«انگار طرف حرفم رو نفهمید.»
RAG کلاسیک معمولاً اینطور کار میکند:
آخرین سؤال کاربر👈🏻 جستجو در اسناد 👈🏻 چند تکه متن 👈🏻 تولید پاسخ
این جریان برای سؤالهای مستقل (single-shot) خوب است، اما در مکالمههای واقعی سه جای اصلی گیر میکند:
کاربر اغلب سؤال دوم/سوم را کامل نمیپرسد. RAG سنتی هم چون فقط آخرین پیام را query میکند، مسیر را اشتباه میرود.
کلماتی مثل «این»، «اون»، «همون»، «مثل قبلی»، «برای این مورد» بدون تاریخچه، معنای دقیقی ندارند.
اطلاعات مهم مکالمه معمولاً در پیامهای قبلی گفته میشود:
اگر اینها وارد retrieval نشوند، حتی مدل زبانی قوی هم با context غلط، خروجی غلط میدهد.
| User Message | What system sees (در RAG ساده) | Problem |
|---|---|---|
| «اینش چطور بود؟» | اینش چطور بود؟ |
«این» به چی اشاره میکنه؟ سیستم نمیفهمه. |
| «برای همون مورد قبلی هم جواب میده؟» | مورد قبلی + جواب میده |
بدون دانستن «مورد قبلی»، retrieval شانسی میشود. |
| «پس تو نسخه جدید چی تغییر کرده؟» | نسخه جدید + تغییر |
کدوم محصول/کدوم نسخه؟ کانتکست قبلی حذف شده. |
| «همون policy رو برای سازمانی هم داریم؟» | policy + سازمانی |
سیستم ممکنه policyهای HR یا چیز دیگری را بیاورد. |
| «اگه همون خطا رو دیدم چی؟» | همون خطا |
بدون لاگ/اسم خطا، جستجو بیهدف میشود. |
RAG سنتی از نظر «دانش» مشکل ندارد؛ مشکلش این است که در مکالمه، سؤالِ درست برای جستجو را نمیسازد. و همین دقیقاً مقدمهای است برای اینکه بفهمیم چرا به Conversation-aware Retrieval نیاز داریم.
تا اینجا دیدیم Conversation-aware Retrieval چرا لازم است، اما سؤال مهمتر این است:
این سیستم دقیقاً چه کاری انجام میدهد که RAG معمولی انجام نمیدهد؟
پاسخ کوتاه این است که Conversation-aware Retrieval قبل از جستجو، کمی «فکر» میکند.
نه به این معنی که جواب میسازد، بلکه سعی میکند بفهمد اگر این مکالمه را یک انسان میخواند، دنبال چه چیزی میگشت.
برای درک بهتر، بیایید مسیر را قدمبهقدم جلو برویم.
اولین کاری که سیستم انجام میدهد، نگاه کردن به کل مکالمه است، نه فقط آخرین پیام. در مکالمههای واقعی، اطلاعات مهم معمولاً پراکندهاند: کاربر یک چیز را در جملهی اول میگوید، محدودیت را در جملهی دوم اضافه میکند و سؤال اصلی را در جملهی سوم میپرسد.
مثلاً این گفتوگو را در نظر بگیر:
«ما روی پلن Enterprise هستیم»
«برای API محدودیت داریم»
«این برای همه endpointها اعمال میشه؟»
اگر این مکالمه را یک انسان بخواند، خیلی راحت متوجه میشود که سؤال اصلی دربارهی دامنهی محدودیت API در پلن Enterprise است. اما برای سیستم، این فهم باید بهصورت صریح ساخته شود.
در این مرحله، Conversation-aware Retrieval سعی میکند یک تصویر ذهنی بسازد:
این مرحله شبیه کاری است که خود ما ناخودآگاه انجام میدهیم: «آها، منظورش اینه.»
بعد از اینکه سیستم «منظور» مکالمه را فهمید، هنوز آمادهی جستجو نیست. چرا؟
چون سؤالی که کاربر پرسیده، معمولاً برای جستجو مناسب نیست.
جملههایی مثل «اینش چطور بود؟» یا «برای همون مورد قبلی چی؟» برای انسان واضحاند، اما برای موتور جستجو کاملاً بیمعنیاند. اینجاست که مرحلهی بازنویسی وارد میشود.
در این مرحله، سیستم سؤالی میسازد که:
مثلاً بهجای:
«این برای همه endpointها اعمال میشه؟»
سیستم این را میسازد:
«API rate limits in Enterprise plan and whether they apply to all endpoints»
نکتهی مهم اینجاست که این سؤال را کاربر نگفته، اما دقیقاً همان چیزی است که منظورش بوده.
وقتی سؤال درست ساخته شد، تازه وارد مرحلهای میشویم که RAG سنتی از همانجا شروع میکند: جستجو در اسناد.
اما تفاوت بزرگ اینجاست که حالا موتور جستجو با یک query شفاف و دقیق طرف است.
در نتیجه:
دسترسی پیدا میکند.
به بیان ساده، Conversation-aware Retrieval کاری میکند که retrieval با حدس و گمان جلو نرود، بلکه با نیت مشخص انجام شود.
اگر بخواهیم کل این مسیر را در یک نگاه ببینیم، میشود اینطور تصورش کرد:
Chat History
↓
(فهم مکالمه و نیت کاربر)
↓
تبدیل به یک سؤال دقیق و مستقل
↓
جستجو در اسناد مرتبط
این «فهم مکالمه» و «تبدیل سؤال» همان چیزی است که در RAG ساده وجود ندارد و دقیقاً همان جایی است که Conversation-aware Retrieval ارزش خودش را نشان میدهد.
Conversation-aware Retrieval تلاش نمیکند جواب بهتری بسازد؛
تلاش میکند سؤال بهتری برای جستجو بسازد.
و وقتی سؤال درست باشد،
بقیهی سیستم (Retriever و LLM) معمولاً کارشان را درست انجام میدهند.

Conversation-aware Retrieval یک ایدهی واحد نیست که فقط یک راه پیادهسازی داشته باشد. در عمل، تیمها بسته به پیچیدگی محصول، حجم داده و حساسیت پاسخها، از روشهای مختلفی استفاده میکنند. بیایید سه رویکرد رایج را از ساده تا حرفهای بررسی کنیم.
در سادهترین حالت، بعضی سیستمها تلاش میکنند با چسباندن چند پیام آخر مکالمه به هم، مشکل کانتکست را حل کنند. یعنی بهجای اینکه فقط آخرین پیام کاربر را برای جستجو بفرستند، مثلاً ۳ یا ۵ پیام آخر را کنار هم میگذارند و همان را query میکنند.
در نگاه اول، این کار منطقی به نظر میرسد؛ بالاخره اطلاعات بیشتری وارد جستجو شده. اما در عمل، این روش خیلی زود به مشکل میخورد. مکالمهها پر از جملههای محاورهای، تکراری و حتی بیربط هستند و موتور جستجو نمیداند کدام بخش مهمتر است.
مزیت اصلی این روش سادگی آن است. پیادهسازی سریع است و نیاز به مدل اضافه یا طراحی پیچیده ندارد.
اما محدودیت بزرگش نویز بالاست؛ هم context window مدل هدر میرود، هم retrieval نتایج شلختهتری برمیگرداند.
این روش معمولاً فقط برای نمونههای اولیه (PoC) یا پروژههای خیلی کوچک جواب میدهد.
این روش، رایجترین و عملیترین انتخاب در سیستمهای production است. ایده ساده است:
قبل از اینکه جستجو انجام شود، یک LLM کل مکالمه را میخواند و آن را به یک سؤال مستقل، شفاف و قابل جستجو تبدیل میکند.
در این رویکرد، سیستم بهجای اینکه مکالمهی خام را وارد retrieval کند، از LLM میخواهد «منظور کاربر را در قالب یک query رسمی و دقیق» بنویسد. نتیجه معمولاً چیزی است که اگر یک انسان میخواست در مستندات جستجو کند، دقیقاً همان را مینوشت.
مزیت اصلی این روش این است که نویز را بهشدت کاهش میدهد و retrieval را هدفمند میکند. همچنین با مکالمههای طولانی هم خوب کنار میآید، چون خروجی نهایی فقط یک query تمیز است.
محدودیتش این است که به کیفیت prompt و مدل وابسته است و یک لایهی پردازش اضافی به سیستم اضافه میکند.
با این حال، در بیشتر محصولات واقعی، این روش بهترین توازن بین کیفیت و پیچیدگی را دارد.
در سیستمهای پیچیدهتر، بهخصوص جاهایی که مکالمه طولانی است یا تصمیمها در چند مرحله گرفته میشوند، از خلاصهسازی مکالمه استفاده میشود. در این روش، سیستم یک خلاصهی ساختیافته از مکالمه میسازد و آن را بهروز نگه میدارد.
بهجای اینکه هر بار کل تاریخچه بررسی شود، یک خلاصهی زنده وجود دارد که شامل موضوع، محدودیتها و هدف کاربر است. این خلاصه بعداً برای بازنویسی query یا حتی برای تولید پاسخ استفاده میشود.
مزیت این روش مقیاسپذیری و نظم بالای آن است. برای agentهای چندمرحلهای یا copilotهای پیشرفته، این رویکرد بسیار مؤثر است.
محدودیتش پیچیدگی پیادهسازی و نیاز به طراحی دقیق است؛ اگر خلاصه بد ساخته شود، کل سیستم گمراه میشود.
یکی از رایجترین سوءتفاهمها این است که Conversation-aware Retrieval با Memory یکی گرفته میشود. در حالی که این دو، نقشهای کاملاً متفاوتی دارند.
Conversation-aware Retrieval تمرکزش روی درست جستجو کردن است، در حالی که Memory تمرکزش روی یادآوری اطلاعات در طول زمان است.
برای شفاف شدن تفاوت، جدول زیر خیلی کمک میکند:
| Concept | Scope | Purpose |
|---|---|---|
| Conversation-aware Retrieval | همان مکالمهی فعلی | ساخت query درست برای جستجو |
| Short-term Memory | طول یک session | حفظ فرضها و تنظیمات مکالمه |
| Long-term Memory | چندین session | نگهداشت ترجیحات و اطلاعات پایدار کاربر |
به زبان ساده:
Conversation-aware Retrieval میپرسد «الان دقیقاً چی رو باید سرچ کنم؟»
Memory میپرسد «این کاربر یا این سیستم قبلاً چی گفته یا چی ترجیح میده؟»
دانستن اینکه کجا نباید از این تکنیک استفاده کرد، به اندازهی دانستن کاربردش مهم است.
Conversation-aware Retrieval معمولاً لازم است وقتی:
در مقابل، معمولاً لازم نیست وقتی:
استفادهی بیدلیل از Conversation-aware Retrieval فقط سیستم را پیچیدهتر میکند، بدون اینکه ارزش واقعی اضافه کند.
تجربهی عملی نشان میدهد بعضی اشتباهها بارها و بارها تکرار میشوند.
یکی از رایجترین اشتباهها این است که کل تاریخچهی مکالمه بدون فیلتر وارد retrieval میشود. این کار معمولاً باعث افزایش نویز و کاهش دقت میشود، نه برعکس.
اشتباه رایج بعدی، نادیده گرفتن query rewriting است. بعضی تیمها فکر میکنند vector search بهتنهایی کافی است، در حالی که بدون سؤال درست، بهترین embedding هم خروجی ضعیفی میدهد.
و در نهایت، استفادهی بیشازحد از Memory. Memory قرار نیست جای retrieval یا query rewriting را بگیرد. وقتی همهچیز را به memory بسپارید، سیستم بهجای «دقیق شدن»، «سنگین و غیرقابلپیشبینی» میشود.
در نهایت، اگر بخواهیم کل بحث را در چند خط جمع کنیم:
Conversation-aware Retrieval قرار نیست جادو کند؛
قرار است کاری را انجام دهد که انسانها همیشه انجام میدهند:
اول بفهمند، بعد بگردند.