diff --git a/rag/RAG_LOGIC_SIMPLE.md b/rag/RAG_LOGIC_SIMPLE.md new file mode 100644 index 0000000..a1155c5 --- /dev/null +++ b/rag/RAG_LOGIC_SIMPLE.md @@ -0,0 +1,527 @@ +# توضیح خیلی ساده منطق RAG در پروژه + +این فایل قرار است خیلی ساده بگوید RAG در این پروژه چطور کار می‌کند. + +## اول: RAG یعنی چه؟ + +RAG یعنی: + +1. سوال کاربر را می‌گیریم +2. متن‌های مرتبط را از حافظه دانشی پیدا می‌کنیم +3. آن متن‌ها را کنار سوال می‌گذاریم +4. بعد از مدل زبانی می‌خواهیم جواب بدهد + +یعنی مدل فقط از حافظه خودش جواب نمی‌دهد؛ +قبل از جواب دادن، اطلاعات مرتبط پروژه را هم می‌بیند. + +--- + +## نقش فایل `rag/apps.py` + +فایل `rag/apps.py` فقط اپ Django مربوط به RAG را ثبت می‌کند. + +کار اصلی‌اش این است: + +- اسم اپ را مشخص می‌کند: `rag` +- نام نمایشی اپ را مشخص می‌کند + +پس: + +- `rag/apps.py` منطق اصلی RAG را پیاده‌سازی نمی‌کند +- فقط می‌گوید این اپ در پروژه وجود دارد + +منطق اصلی RAG بیشتر در این فایل‌هاست: + +- `rag/views.py` +- `rag/chat.py` +- `rag/retrieve.py` +- `rag/ingest.py` +- `rag/embedding.py` +- `rag/vector_store.py` +- `rag/user_data.py` +- `rag/config.py` + +--- + +## تصویر خیلی ساده از کل جریان + +RAG در این پروژه دو بخش اصلی دارد: + +### 1) آماده‌سازی دانش + +در این بخش سیستم اطلاعات را جمع می‌کند و داخل دیتابیس برداری ذخیره می‌کند. + +مراحل: + +1. فایل‌های دانش را می‌خواند +2. متن‌ها را خرد می‌کند +3. هر تکه را تبدیل به embedding می‌کند +4. embeddingها را داخل Qdrant ذخیره می‌کند + +این کار بیشتر در `rag/ingest.py` انجام می‌شود. + +### 2) جواب دادن به سوال کاربر + +در این بخش وقتی کاربر سوال می‌پرسد: + +1. سوال embedding می‌شود +2. متن‌های نزدیک و مرتبط پیدا می‌شوند +3. داده‌های کاربر هم اضافه می‌شود +4. همه این‌ها به مدل زبانی داده می‌شود +5. مدل جواب را به صورت 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_uuid` +- `kb_name` + +این metadata خیلی مهم است؛ +چون کمک می‌کند بعدا فقط داده‌های مرتبط برگردند. + +--- + +## دستور ورود اطلاعات + +### فایل: `rag/management/commands/rag_ingest.py` + +این فایل یک command جنگو دارد که ingestion را اجرا می‌کند. + +یعنی اگر این دستور اجرا شود: + +```bash +python manage.py rag_ingest +``` + +سیستم: + +- منابع را می‌خواند +- chunk می‌کند +- embedding می‌سازد +- داخل Qdrant ذخیره می‌کند + +--- + +## بخش دوم: وقتی کاربر سوال می‌پرسد چه می‌شود؟ + +### ورودی API + +### فایل: `rag/views.py` + +در این فایل endpoint چت وجود دارد. + +کارش این است که از کاربر این اطلاعات را بگیرد: + +- `service_id` +- `query` +- `user_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 از چند بخش ساخته می‌شود: + +1. داده فعلی خاک کاربر +2. داده هواشناسی کاربر +3. متن‌های مرتبط پیدا شده از 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()` کار اصلی بازیابی را انجام می‌دهد. + +مراحلش ساده است: + +1. سوال کاربر embedding می‌شود +2. یک جستجوی شباهت در Qdrant انجام می‌شود +3. فقط متن‌های مجاز برگردانده می‌شوند + +--- + +## چرا گفتیم "متن‌های مجاز"؟ + +چون این پروژه داده کاربر دارد و نباید اطلاعات یک کاربر به کاربر دیگر برسد. + +برای همین موقع جستجو فیلتر گذاشته می‌شود. + +فیلترها معمولا این‌ها هستند: + +- `sensor_uuid` +- `kb_name` + +یعنی سیستم فقط این‌ها را برمی‌گرداند: + +- داده‌های عمومی (`__global__`) +- داده‌های همان کاربر +- داده‌های همان knowledge base + +پس این بخش برای امنیت و جداسازی اطلاعات خیلی مهم است. + +--- + +## جستجو در Qdrant چطور انجام می‌شود؟ + +### فایل: `rag/vector_store.py` + +تابع `search()` در این فایل: + +- query vector را می‌گیرد +- فیلترها را می‌سازد +- از Qdrant نتیجه می‌گیرد + +بعد نتیجه‌ها را به شکل ساده برمی‌گرداند: + +- `id` +- `score` +- `text` +- `metadata` + +`score` یعنی میزان شباهت. +هرچه بیشتر باشد، یعنی متن به سوال نزدیک‌تر است. + +--- + +## بعد از بازیابی چه می‌شود؟ + +### دوباره در `rag/chat.py` + +بعد از این که متن‌های مرتبط پیدا شدند: + +- متن‌های مرجع جمع می‌شوند +- داده کاربر هم کنار آن‌ها قرار می‌گیرد +- tone و system prompt هم اضافه می‌شود + +در آخر یک پیام system ساخته می‌شود که به مدل می‌گوید: + +- از داده‌های خاک استفاده کن +- از متن‌های مرجع استفاده کن +- با زبان کاربر جواب بده + +--- + +## تولید جواب نهایی + +### تابع: `chat_rag_stream()` + +این تابع: + +1. تنظیمات سرویس را می‌خواند +2. context را می‌سازد +3. پیام system و user را آماده می‌کند +4. به مدل زبانی درخواست می‌فرستد +5. جواب را به صورت stream برمی‌گرداند + +پس جواب نهایی فقط از خود مدل نیست؛ +بلکه از ترکیب این‌ها ساخته می‌شود: + +- سوال کاربر +- داده‌های فعلی کاربر +- متن‌های مرجع RAG +- لحن و دستور سیستم + +--- + +## tone چیست؟ + +tone یعنی لحن پاسخ. + +مثلا سیستم می‌تواند مشخص کند: + +- رسمی جواب بده +- ساده جواب بده +- تخصصی جواب بده + +فایل‌های tone از روی knowledge base یا service خوانده می‌شوند. + +پس tone روی سبک جواب اثر دارد، +نه روی اصل جستجو. + +--- + +## نقش `rag/config.py` + +این فایل تنظیمات را بارگذاری می‌کند. + +مثلا: + +- مدل embedding چیست +- Qdrant کجاست +- اندازه vector چقدر است +- chunking چگونه باشد +- سرویس‌ها چه هستند +- هر سرویس از کدام knowledge base استفاده کند + +یعنی این فایل مغز تنظیمات سیستم است. + +--- + +## خلاصه خیلی ساده کل مسیر + +اگر بخواهیم خیلی خلاصه بگوییم: + +### مرحله آماده‌سازی + +1. فایل‌ها و داده‌های کاربر خوانده می‌شوند +2. متن‌ها chunk می‌شوند +3. embedding ساخته می‌شود +4. داخل Qdrant ذخیره می‌شوند + +### مرحله پاسخ‌گویی + +1. کاربر سوال می‌پرسد +2. سوال embedding می‌شود +3. متن‌های مشابه پیدا می‌شوند +4. داده خاک و هواشناسی کاربر هم اضافه می‌شود +5. همه این‌ها به LLM داده می‌شود +6. LLM جواب نهایی را می‌سازد + +--- + +## فرق این پروژه با یک چت ساده + +اگر چت ساده بود: + +- مدل فقط با دانسته‌های خودش جواب می‌داد + +ولی اینجا: + +- مدل به داده‌های واقعی پروژه دسترسی دارد +- داده‌های همان کاربر را می‌بیند +- از متن‌های مرجع واقعی استفاده می‌کند + +پس جواب‌ها: + +- دقیق‌تر می‌شوند +- شخصی‌تر می‌شوند +- به داده‌های واقعی نزدیک‌تر می‌شوند + +--- + +## فایل‌ها را خیلی ساده به خاطر بسپار + +- `rag/apps.py` -> فقط ثبت اپ +- `rag/views.py` -> گرفتن درخواست کاربر +- `rag/chat.py` -> ساخت context و گرفتن جواب از مدل +- `rag/retrieve.py` -> جستجوی متن مرتبط +- `rag/ingest.py` -> وارد کردن دانش به سیستم +- `rag/embedding.py` -> تبدیل متن به embedding +- `rag/vector_store.py` -> ذخیره و جستجو در Qdrant +- `rag/user_data.py` -> ساخت متن از داده‌های کاربر +- `rag/config.py` -> تنظیمات کل RAG + +--- + +## یک مثال خیلی ساده + +فرض کن کاربر بپرسد: + +`آیا خاک من برای آبیاری مناسب است؟` + +سیستم این کارها را می‌کند: + +1. سوال را می‌گیرد +2. می‌فهمد باید از سرویس یا دانش آبیاری استفاده کند +3. داده خاک همان کاربر را از دیتابیس می‌گیرد +4. داده هواشناسی را هم می‌گیرد +5. متن‌های مرتبط آبیاری را از Qdrant پیدا می‌کند +6. همه را به مدل می‌دهد +7. مدل جواب می‌دهد + +پس جواب نهایی فقط یک حدس عمومی نیست؛ +بلکه بر اساس: + +- اطلاعات خاک +- اطلاعات هوا +- متن‌های مرجع آبیاری + +ساخته می‌شود. + +--- + +## نتیجه نهایی + +منطق RAG این پروژه به زبان خیلی ساده این است: + +- اول دانش را آماده می‌کند +- بعد موقع سوال، دانش مرتبط را پیدا می‌کند +- داده‌های واقعی کاربر را هم اضافه می‌کند +- و در آخر از مدل می‌خواهد با این اطلاعات جواب بدهد + +و یادت باشد: + +- `rag/apps.py` فقط فایل ثبت اپ است +- منطق واقعی RAG در فایل‌های `chat`, `retrieve`, `ingest`, `vector_store`, `user_data` و `views` قرار دارد +