15 KiB
توضیح خیلی ساده منطق RAG در پروژه
این فایل قرار است خیلی ساده بگوید RAG در این پروژه چطور کار میکند.
اول: RAG یعنی چه؟
RAG یعنی:
- سوال کاربر را میگیریم
- متنهای مرتبط را از حافظه دانشی پیدا میکنیم
- آن متنها را کنار سوال میگذاریم
- بعد از مدل زبانی میخواهیم جواب بدهد
یعنی مدل فقط از حافظه خودش جواب نمیدهد؛ قبل از جواب دادن، اطلاعات مرتبط پروژه را هم میبیند.
نقش فایل rag/apps.py
فایل rag/apps.py فقط اپ Django مربوط به RAG را ثبت میکند.
کار اصلیاش این است:
- اسم اپ را مشخص میکند:
rag - نام نمایشی اپ را مشخص میکند
پس:
rag/apps.pyمنطق اصلی RAG را پیادهسازی نمیکند- فقط میگوید این اپ در پروژه وجود دارد
منطق اصلی RAG بیشتر در این فایلهاست:
rag/views.pyrag/chat.pyrag/retrieve.pyrag/ingest.pyrag/embedding.pyrag/vector_store.pyrag/user_data.pyrag/config.py
تصویر خیلی ساده از کل جریان
RAG در این پروژه دو بخش اصلی دارد:
1) آمادهسازی دانش
در این بخش سیستم اطلاعات را جمع میکند و داخل دیتابیس برداری ذخیره میکند.
مراحل:
- فایلهای دانش را میخواند
- متنها را خرد میکند
- هر تکه را تبدیل به embedding میکند
- embeddingها را داخل Qdrant ذخیره میکند
این کار بیشتر در rag/ingest.py انجام میشود.
2) جواب دادن به سوال کاربر
در این بخش وقتی کاربر سوال میپرسد:
- سوال embedding میشود
- متنهای نزدیک و مرتبط پیدا میشوند
- دادههای کاربر هم اضافه میشود
- همه اینها به مدل زبانی داده میشود
- مدل جواب را به صورت stream برمیگرداند
این کار بیشتر در rag/chat.py و rag/retrieve.py انجام میشود.
بخش اول: سیستم چطور دانش را آماده میکند؟
فایل اصلی: rag/ingest.py
این فایل کارش این است که اطلاعات را وارد سیستم RAG کند.
از کجا اطلاعات میآید؟
سیستم این منابع را میخواند:
- فایلهای پایگاه دانش
- فایل لحن یا tone
- دادههای خاک هر کاربر
- دادههای هواشناسی هر کاربر
پایگاه دانش یعنی چه؟
پایگاه دانش یعنی متنهایی که پروژه از قبل دارد.
مثلا:
- اطلاعات عمومی چت
- اطلاعات آبیاری
- اطلاعات کودهی
در تنظیمات، برای هر بخش یک knowledge base تعریف شده است.
مرحله 1: خواندن منابع
تابع load_sources() در rag/ingest.py منابع را جمع میکند.
خروجی این تابع تقریبا این شکلی است:
- شناسه منبع
- متن منبع
- شناسه سنسور یا کاربر
- نام پایگاه دانش
نکته مهم:
- دادههای عمومی با
__global__ذخیره میشوند - دادههای شخصی هر کاربر با
sensor_uuidخودش ذخیره میشوند - دادههای کاربری معمولا با
__all__درkb_nameعلامت میخورند
این کار باعث میشود بعدا سیستم بداند هر متن برای چه کسی یا چه بخشی بوده است.
مرحله 2: خرد کردن متن
فایل: rag/chunker.py
متنهای طولانی مستقیم وارد جستجو نمیشوند. اول آنها را به تکههای کوچکتر تبدیل میکنیم.
چرا؟
چون:
- جستجو دقیقتر میشود
- embedding بهتر میشود
- مدل فقط بخشهای لازم را میبیند
مثلا یک فایل بلند به چند chunk تبدیل میشود.
مرحله 3: ساخت embedding
فایل: rag/embedding.py
هر chunk متنی به یک لیست عددی تبدیل میشود. به این لیست عددی میگوییم embedding.
خیلی ساده:
- متن شبیه به هم -> embedding شبیه به هم
- متن متفاوت -> embedding متفاوت
پس بعدا اگر کاربر سوالی شبیه یک متن بپرسد، سیستم میتواند آن متن را پیدا کند.
مرحله 4: ذخیره در Qdrant
فایل: rag/vector_store.py
بعد از ساخت embedding، دادهها داخل Qdrant ذخیره میشوند.
Qdrant در این پروژه نقش حافظه برداری را دارد.
برای هر chunk این چیزها ذخیره میشود:
- خود متن
- embedding
- منبع متن
- شماره chunk
sensor_uuidkb_name
این metadata خیلی مهم است؛ چون کمک میکند بعدا فقط دادههای مرتبط برگردند.
دستور ورود اطلاعات
فایل: rag/management/commands/rag_ingest.py
این فایل یک command جنگو دارد که ingestion را اجرا میکند.
یعنی اگر این دستور اجرا شود:
python manage.py rag_ingest
سیستم:
- منابع را میخواند
- chunk میکند
- embedding میسازد
- داخل Qdrant ذخیره میکند
بخش دوم: وقتی کاربر سوال میپرسد چه میشود؟
ورودی API
فایل: rag/views.py
در این فایل endpoint چت وجود دارد.
کارش این است که از کاربر این اطلاعات را بگیرد:
service_idqueryuser_idیاsensor_uuid
بعد چند بررسی انجام میشود:
- آیا سوال خالی نیست؟
- آیا
service_idمعتبر است؟ - اگر سرویس نیاز به داده کاربر دارد، آیا
user_idداده شده؟
اگر همه چیز درست باشد،
در نهایت chat_rag_stream() صدا زده میشود.
service_id چرا مهم است؟
چون سیستم چند نوع سرویس دارد.
مثلا:
- سرویس چت عمومی
- سرویس آبیاری
- سرویس کودهی
هر سرویس میتواند اینها را مشخص کند:
- از کدام knowledge base استفاده شود
- از چه مدل زبانی استفاده شود
- آیا دادههای شخصی کاربر لازم است یا نه
- چه tone یا system prompt استفاده شود
این تنظیمات در rag/config.py و فایل config/rag_config.yaml مدیریت میشوند.
ساخت context
فایل اصلی: rag/chat.py
مهمترین بخش پاسخگویی همینجاست.
تابع مهم: build_rag_context()
این تابع یک context برای مدل میسازد.
این context از چند بخش ساخته میشود:
- داده فعلی خاک کاربر
- داده هواشناسی کاربر
- متنهای مرتبط پیدا شده از RAG
یعنی مدل فقط سوال را نمیبیند؛ بلکه این اطلاعات کمکی را هم میبیند.
داده خاک و هواشناسی کاربر از کجا میآید؟
فایل: rag/user_data.py
این فایل اطلاعات کاربر را از دیتابیس پروژه میسازد.
دو تابع مهم:
build_user_soil_text(sensor_uuid)build_user_weather_text(sensor_uuid)
کار این توابع:
- دادههای مدلهای پروژه را میخوانند
- آنها را به متن ساده تبدیل میکنند
چرا به متن؟
چون سیستم RAG در نهایت با متن کار میکند.
پس حتی دادههای دیتابیس هم به متن تبدیل میشوند تا:
- embed شوند
- یا مستقیم داخل context قرار بگیرند
پیدا کردن متنهای مرتبط
فایل: rag/retrieve.py
در اینجا تابع search_with_query() کار اصلی بازیابی را انجام میدهد.
مراحلش ساده است:
- سوال کاربر embedding میشود
- یک جستجوی شباهت در Qdrant انجام میشود
- فقط متنهای مجاز برگردانده میشوند
چرا گفتیم "متنهای مجاز"؟
چون این پروژه داده کاربر دارد و نباید اطلاعات یک کاربر به کاربر دیگر برسد.
برای همین موقع جستجو فیلتر گذاشته میشود.
فیلترها معمولا اینها هستند:
sensor_uuidkb_name
یعنی سیستم فقط اینها را برمیگرداند:
- دادههای عمومی (
__global__) - دادههای همان کاربر
- دادههای همان knowledge base
پس این بخش برای امنیت و جداسازی اطلاعات خیلی مهم است.
جستجو در Qdrant چطور انجام میشود؟
فایل: rag/vector_store.py
تابع search() در این فایل:
- query vector را میگیرد
- فیلترها را میسازد
- از Qdrant نتیجه میگیرد
بعد نتیجهها را به شکل ساده برمیگرداند:
idscoretextmetadata
score یعنی میزان شباهت.
هرچه بیشتر باشد، یعنی متن به سوال نزدیکتر است.
بعد از بازیابی چه میشود؟
دوباره در rag/chat.py
بعد از این که متنهای مرتبط پیدا شدند:
- متنهای مرجع جمع میشوند
- داده کاربر هم کنار آنها قرار میگیرد
- tone و system prompt هم اضافه میشود
در آخر یک پیام system ساخته میشود که به مدل میگوید:
- از دادههای خاک استفاده کن
- از متنهای مرجع استفاده کن
- با زبان کاربر جواب بده
تولید جواب نهایی
تابع: chat_rag_stream()
این تابع:
- تنظیمات سرویس را میخواند
- context را میسازد
- پیام system و user را آماده میکند
- به مدل زبانی درخواست میفرستد
- جواب را به صورت stream برمیگرداند
پس جواب نهایی فقط از خود مدل نیست؛ بلکه از ترکیب اینها ساخته میشود:
- سوال کاربر
- دادههای فعلی کاربر
- متنهای مرجع RAG
- لحن و دستور سیستم
tone چیست؟
tone یعنی لحن پاسخ.
مثلا سیستم میتواند مشخص کند:
- رسمی جواب بده
- ساده جواب بده
- تخصصی جواب بده
فایلهای tone از روی knowledge base یا service خوانده میشوند.
پس tone روی سبک جواب اثر دارد، نه روی اصل جستجو.
نقش rag/config.py
این فایل تنظیمات را بارگذاری میکند.
مثلا:
- مدل embedding چیست
- Qdrant کجاست
- اندازه vector چقدر است
- chunking چگونه باشد
- سرویسها چه هستند
- هر سرویس از کدام knowledge base استفاده کند
یعنی این فایل مغز تنظیمات سیستم است.
خلاصه خیلی ساده کل مسیر
اگر بخواهیم خیلی خلاصه بگوییم:
مرحله آمادهسازی
- فایلها و دادههای کاربر خوانده میشوند
- متنها chunk میشوند
- embedding ساخته میشود
- داخل Qdrant ذخیره میشوند
مرحله پاسخگویی
- کاربر سوال میپرسد
- سوال embedding میشود
- متنهای مشابه پیدا میشوند
- داده خاک و هواشناسی کاربر هم اضافه میشود
- همه اینها به LLM داده میشود
- LLM جواب نهایی را میسازد
فرق این پروژه با یک چت ساده
اگر چت ساده بود:
- مدل فقط با دانستههای خودش جواب میداد
ولی اینجا:
- مدل به دادههای واقعی پروژه دسترسی دارد
- دادههای همان کاربر را میبیند
- از متنهای مرجع واقعی استفاده میکند
پس جوابها:
- دقیقتر میشوند
- شخصیتر میشوند
- به دادههای واقعی نزدیکتر میشوند
فایلها را خیلی ساده به خاطر بسپار
rag/apps.py-> فقط ثبت اپrag/views.py-> گرفتن درخواست کاربرrag/chat.py-> ساخت context و گرفتن جواب از مدلrag/retrieve.py-> جستجوی متن مرتبطrag/ingest.py-> وارد کردن دانش به سیستمrag/embedding.py-> تبدیل متن به embeddingrag/vector_store.py-> ذخیره و جستجو در Qdrantrag/user_data.py-> ساخت متن از دادههای کاربرrag/config.py-> تنظیمات کل RAG
یک مثال خیلی ساده
فرض کن کاربر بپرسد:
آیا خاک من برای آبیاری مناسب است؟
سیستم این کارها را میکند:
- سوال را میگیرد
- میفهمد باید از سرویس یا دانش آبیاری استفاده کند
- داده خاک همان کاربر را از دیتابیس میگیرد
- داده هواشناسی را هم میگیرد
- متنهای مرتبط آبیاری را از Qdrant پیدا میکند
- همه را به مدل میدهد
- مدل جواب میدهد
پس جواب نهایی فقط یک حدس عمومی نیست؛ بلکه بر اساس:
- اطلاعات خاک
- اطلاعات هوا
- متنهای مرجع آبیاری
ساخته میشود.
نتیجه نهایی
منطق RAG این پروژه به زبان خیلی ساده این است:
- اول دانش را آماده میکند
- بعد موقع سوال، دانش مرتبط را پیدا میکند
- دادههای واقعی کاربر را هم اضافه میکند
- و در آخر از مدل میخواهد با این اطلاعات جواب بدهد
و یادت باشد:
rag/apps.pyفقط فایل ثبت اپ است- منطق واقعی RAG در فایلهای
chat,retrieve,ingest,vector_store,user_dataوviewsقرار دارد