UPDATE
This commit is contained in:
@@ -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` قرار دارد
|
||||
|
||||
Reference in New Issue
Block a user