Files
Ai/docs/yield_harvest_pcse_rag_api_plan.md
2026-04-29 23:54:30 +03:30

747 lines
20 KiB
Markdown

# راهنمای پیاده‌سازی API صفحه Yield & Harvest با PCSE و RAG
این فایل برای تیم بک‌اند نوشته شده تا صفحه `yield-harvest` را با تکیه بر:
- مستند `psce_doc.txt` پروژه
- سرویس‌های موجود در `crop_simulation/`
- معماری فعلی RAG در `rag/`
به شکل قابل اتکا پیاده‌سازی کند.
نکته: فایل `psce_doc.txt` در عمل مستند PCSE است و در این سند هم با عنوان PCSE به آن اشاره می‌شود.
---
## جمع‌بندی سریع
برای این صفحه، بهترین معماری این است:
1. عددها، تاریخ‌ها، درصدها و سری‌های نمودار از PCSE و داده‌های مزرعه ساخته شوند.
2. RAG فقط برای متن‌های توضیحی، خلاصه‌سازی، و wording کاربرپسند استفاده شود.
3. RAG اجازه نداشته باشد عدد جدید، تاریخ جدید، یا KPI جدید اختراع کند.
4. یک endpoint خلاصه برای فرانت برگردانده شود:
`GET /api/yield-harvest/summary/?farm_uuid=<uuid>`
اگر لازم شد از نظر convention داخلی پروژه همه‌چیز داخل `crop_simulation` بماند، می‌توانید معادل زیر را هم نگه دارید:
`GET /api/crop-simulation/yield-harvest-summary/?farm_uuid=<uuid>`
برای فرانت فعلی، مدل summary بهتر از چند endpoint پراکنده است.
---
## چیزی که همین الان در پروژه دارید
### لایه PCSE / شبیه‌سازی
الان پروژه این اجزا را دارد:
- `crop_simulation/services.py`
- `crop_simulation/growth_simulation.py`
- `crop_simulation/harvest_prediction.py`
- `crop_simulation/yield_prediction.py`
و همین حالا از PCSE این خروجی‌ها را می‌سازید:
- `yield` از `TWSO`
- `biomass` از `TAGP`
- `leaf_area_index` از `LAI`
- `development_stage` از `DVS`
- `soil_moisture` از `SM`
این دقیقاً با چیزی که در `psce_doc.txt` آمده هم‌راستا است: PCSE برای state/rate variables و خروجی روزانه مناسب است و برای ساخت KPI، trend و harvest timing گزینه خوبی است.
### لایه RAG
الان پروژه الگوی خوبی برای سرویس‌های ترکیبی deterministic + RAG دارد:
- `rag/services/irrigation.py`
- `rag/services/fertilization.py`
- `rag/chat.py`
- `config/rag_config.yaml`
الگوی درست در این پروژه این است:
- اول عددها و تصمیم‌های پایه از منطق deterministic ساخته می‌شوند
- بعد RAG فقط متن نهایی را polish می‌کند
- در صورت خراب شدن خروجی LLM، fallback ساختاریافته دارید
برای `yield-harvest` هم باید دقیقاً همین الگو تکرار شود.
---
## اصل طراحی مهم
### چه چیزی باید deterministic باشد
این فیلدها نباید از RAG بیایند:
- `daysUntil`
- `readiness`
- `share`
- `series[].data`
- `averageReadiness`
- `predicted yield`
- `harvest date`
- هر عددی که در progress bar، chart، KPI یا sorting استفاده می‌شود
### چه چیزی می‌تواند از RAG بیاید
این فیلدها مناسب RAG هستند:
- `season_highlights_card.subtitle`
- `season_highlights_card.spotlight.caption`
- `harvest_prediction_card.description`
- `harvest_operations_card.summary`
- `steps[].note`
- badgeها و labelهای توصیفی کوتاه
### قانون طلایی
RAG باید فقط روی context قطعی زیر کار کند:
- farm details
- خروجی‌های PCSE
- داده‌های آب‌وهوا
- داده‌های سنسور
- در صورت وجود: داده کیفیت، آفات، اقتصاد، بازار
و prompt آن باید صریح بگوید:
- عدد جدید نساز
- فقط از مقادیر داده‌شده استفاده کن
- اگر داده کافی نیست، کمبود را بگو
- خروجی را در JSON معتبر برگردان
---
## پیشنهاد معماری برای این صفحه
بهترین راه این است که یک orchestrator service جدید بسازید:
- `crop_simulation/yield_harvest_summary.py`
و داخل آن چند builder کوچک داشته باشید:
- `_build_yield_prediction_block()`
- `_build_harvest_prediction_block()`
- `_build_yield_prediction_chart_block()`
- `_build_harvest_readiness_zones_block()`
- `_build_yield_quality_bands_block()`
- `_build_harvest_operations_block()`
- `_build_season_highlights_block()`
و یک facade نهایی:
- `YieldHarvestSummaryService.get_summary(farm_uuid, season_year=None, crop_name=None)`
این service باید:
1. داده مزرعه را از `farm_data.services.get_farm_details()` بگیرد.
2. خروجی شبیه‌سازی را از `CurrentFarmChartSimulator` و سرویس‌های فعلی بگیرد.
3. بلوک‌های deterministic را بسازد.
4. اگر RAG فعال بود، متن‌های narrative را enrich کند.
5. یک payload نهایی برای فرانت برگرداند.
---
## Mapping پیشنهادی هر کارت به منبع داده
| بلوک | منبع اصلی | وضعیت امکان پیاده‌سازی |
|---|---|---|
| `yield_prediction` | `crop_simulation/yield_prediction.py` + chart metrics | قابل پیاده‌سازی همین الآن |
| `harvest_prediction_card` | `crop_simulation/harvest_prediction.py` | قابل پیاده‌سازی همین الآن |
| `yield_prediction_chart` | `CurrentFarmChartSimulator` + historical baseline | نیمه‌آماده، نیاز به تصمیم درباره سری مقایسه‌ای |
| `season_highlights_card` | aggregate از بقیه بلوک‌ها + RAG | قابل پیاده‌سازی اگر بقیه بلوک‌ها حاضر باشند |
| `harvest_readiness_zones` | داده قطعه/زون + PCSE per zone | فعلاً gap داده‌ای دارد |
| `yield_quality_bands` | quality model / grading rules / lab data | فعلاً gap داده‌ای دارد |
| `harvest_operations_card` | rules + optimizer + RAG | قابل پیاده‌سازی به‌صورت اولیه |
---
## نکته مهم: همه بلوک‌ها را PCSE به‌تنهایی تولید نمی‌کند
PCSE برای این بخش‌ها خیلی مناسب است:
- زمان برداشت
- روند رشد
- عملکرد پیش‌بینی‌شده
- stage / maturity / readiness proxy
- trend chart
اما PCSE به‌صورت پیش‌فرض برای این‌ها کافی نیست:
- `بریکس`
- `گرید ممتاز / درجه یک / فرآوری`
- `پتانسیل صادرات`
- `قیمت فروش`
- `premium`
- readiness per block وقتی مدل block-level ندارید
پس برای صفحه کامل، باید سه لایه را از هم جدا ببینید:
1. `PCSE layer`: عددهای زیستی و رشد
2. `Rules/Aggregation layer`: تبدیل خروجی PCSE به KPIهای محصولی
3. `RAG layer`: توضیح، جمع‌بندی، و متن قابل نمایش
---
## طراحی endpoint پیشنهادی
### Route
پیشنهاد اصلی:
- `GET /api/yield-harvest/summary/?farm_uuid=<uuid>&season_year=1404&crop_name=wheat`
### Query params
- `farm_uuid`: اجباری
- `season_year`: اختیاری
- `crop_name`: اختیاری
- `include_narrative`: اختیاری، پیش‌فرض `true`
### چرا `include_narrative` خوب است
چون اگر RAG کند یا موقتاً غیرفعال باشد، باز هم فرانت می‌تواند با داده deterministic رندر شود.
---
## ساختار پیشنهادی response
همان envelope فعلی پروژه مناسب است:
```json
{
"code": 200,
"msg": "success",
"data": {
"farm_uuid": "11111111-1111-1111-1111-111111111111",
"season_highlights_card": {},
"yield_prediction": {},
"harvest_prediction_card": {},
"harvest_readiness_zones": {},
"yield_quality_bands": {},
"harvest_operations_card": {},
"yield_prediction_chart": {}
}
}
```
---
## پیشنهاد فنی برای ساخت هر بلوک
## 1) `yield_prediction`
### منبع
- `YieldPredictionService`
- یا مستقیم `CurrentFarmChartSimulator.simulate()`
### منطق پیشنهادی
- `predicted yield` از `TWSO`
- `harvest readiness` از `DVS` و فاصله تا maturity
- `quality score` فعلاً rule-based، نه RAG-based
- `loss risk` از ترکیب moisture/weather/pest signals اگر دارید، وگرنه با fallback ساده
### توصیه
اگر الآن فقط داده قطعی می‌خواهید:
- KPI اول را دقیق بسازید
- KPIهای دوم تا چهارم را با rules ساده و شفاف بسازید
- آن‌ها را به عنوان `estimated` در کد داخلی mark کنید
---
## 2) `harvest_prediction_card`
### منبع
- `crop_simulation/harvest_prediction.py`
### وضعیت
این بلوک تقریباً آماده است.
### توصیه
- `dateFormatted` را از serializer-ready formatter بگیرید
- `daysUntil` حتماً `number` بماند
- متن `description` اگر خواستید با RAG بهتر شود، version deterministic را هم نگه دارید
یعنی بهتر است این دو فیلد را داشته باشید:
- `description`
- `descriptionSource = "deterministic" | "rag"`
این source flag برای debugging خیلی کمک می‌کند.
---
## 3) `yield_prediction_chart`
### واقعیت فعلی
خروجی chart فعلی شما در `CurrentFarmChartSimulator` بیشتر این‌ها را می‌دهد:
- leaf count estimate
- biomass
- storage organ weight
- lai
- soil moisture
اما payload فرانت `yield-harvest` در سند شما نمودار `سال قبل / سال جاری` می‌خواهد.
### نتیجه
این بخش هنوز one-to-one با کد فعلی آماده نیست.
### راه درست
یکی از این دو مسیر را انتخاب کنید:
#### مسیر A - سریع‌تر
همان chart فعلی را به contract فرانت نزدیک کنید و فعلاً به‌جای `سال قبل/سال جاری` از:
- `عملکرد تجمعی پیش‌بینی‌شده`
- `بیوماس`
استفاده کنید.
#### مسیر B - محصولی‌تر
دو سری واقعی تولید کنید:
- `سال جاری`: از simulation جاری
- `سال قبل`: از historical scenario یا historical harvest data
اگر داده سال قبل ندارید، این سری را fake نکنید.
### توصیه نهایی
برای production بهتر است تا وقتی historical source ندارید، label سری‌ها را صادقانه تغییر دهید.
---
## 4) `harvest_readiness_zones`
### بزرگ‌ترین gap فعلی
مدل داده فعلی شما عمدتاً farm-level است:
- `SensorData`
- `center_location`
- `farm_details`
اما این کارت block-level data می‌خواهد:
- `A1`
- `A2`
- cultivar per block
- readiness per block
### نتیجه
بدون model یا source جدید برای block/zone، این کارت را نباید fake کنید.
### راه درست
یا باید یکی از این‌ها را اضافه کنید:
1. مدل `FarmBlock` یا `FarmZone`
2. چند sensor/polygon برای هر مزرعه
3. block metadata در JSON مزرعه
### پیاده‌سازی پیشنهادی
برای هر block:
1. weather/location را resolve کنید
2. crop parameters block-specific بسازید
3. یک simulation جدا اجرا کنید
4. `DVS`, `TWSO`, `SM`, `maturity date` را بگیرید
5. readiness را از rule زیر بسازید
مثال rule:
```text
readiness = clamp((current_dvs / 2.0) * 100, 0, 100)
```
یا:
```text
readiness = clamp(100 - days_until_harvest * 4, 0, 100)
```
بهتر است این rule داخل code comment شفاف توضیح داده شود.
---
## 5) `yield_quality_bands`
### نکته مهم
PCSE به‌صورت پیش‌فرض grade یا brix تولید نمی‌کند.
پس این کارت را باید از یکی از این منابع ساخت:
1. داده آزمایشگاهی
2. rule engine بر اساس moisture + disease risk + maturity + crop profile
3. مدل quality جدا
### چیزی که نباید انجام شود
این‌که RAG خودش بگوید:
- 46% گرید ممتاز
- 34% گرید یک
بدون منطق deterministic
این کار برای dashboard اشتباه است.
### پیشنهاد عملی
فاز اول:
- اگر quality data ندارید، این کارت را با flag `unavailable` برگردانید
- یا bands را از rule-based scoring بسازید و در backend صریح mark کنید که estimated هستند
مثلاً:
- `quality_score >= 85 -> premium`
- `70..84 -> grade_1`
- `< 70 -> processing`
اما این rule باید crop-specific باشد، نه universal.
---
## 6) `harvest_operations_card`
### بهترین جا برای ترکیب deterministic + RAG
این کارت candidate خیلی خوبی برای RAG است، چون:
- order و timing می‌تواند از rules و simulation بیاید
- متن summary و noteها می‌تواند از RAG بیاید
### طراحی پیشنهادی
ابتدا backend یک payload قطعی بسازد:
```json
{
"recommended_shift_count": 2,
"sorting_capacity_ton_per_day": 15,
"required_workers": 12,
"max_transfer_hours": 6,
"priority_blocks": ["A1", "A2"],
"reasoning": [
"A1 readiness بالاتر دارد",
"moisture در محدوده مناسب است"
]
}
```
بعد این payload را به RAG بدهید تا فقط این‌ها را تولید کند:
- `summary`
- `steps[].note`
- `steps[].status`
و حتی‌المقدور:
- `outputs[]` را deterministic نگه دارید
---
## 7) `season_highlights_card`
### بهترین روش
این کارت را از بقیه بلوک‌ها derive کنید، نه از یک منبع مستقل.
یعنی:
- `seasonLabel` از ورودی season
- `badges` از readiness/quality/risk
- `spotlight.value` از harvest window یا best sale window
- `metrics` از yield, grade, revenue estimate
### نکته
اگر هنوز economy data ندارید، فیلدهایی مثل:
- `درآمد هدف`
- `پنجره طلایی فروش`
نباید با RAG اختراع شوند.
یا باید:
- حذف شوند
- یا با `null`
- یا با fallback business rule
برگردند.
---
## پیشنهاد برای RAG service جدید
مثل `irrigation` و `fertilization` یک سرویس جدید اضافه کنید:
- `rag/services/yield_harvest.py`
و در `config/rag_config.yaml` هم service جدید تعریف کنید:
- `yield_harvest`
### نقش این سرویس
این سرویس نباید خودش KPI بسازد.
فقط باید:
- summary بنویسد
- subtitle بسازد
- operation notes تولید کند
- badge text را human-friendly کند
### ورودی پیشنهادی به RAG
```json
{
"farm_uuid": "...",
"plant_name": "...",
"deterministic_metrics": {
"predicted_yield_tons": 42.8,
"days_until_harvest": 18,
"readiness_avg": 84,
"quality_score": 91,
"loss_risk_percent": 6.5
},
"operations": {
"shift_count": 2,
"required_workers": 12,
"max_transfer_hours": 6
}
}
```
### خروجی پیشنهادی از RAG
فقط این بخش‌ها:
```json
{
"season_highlights_card": {
"subtitle": "...",
"spotlight": {
"caption": "..."
},
"badges": ["...", "..."]
},
"harvest_prediction_card": {
"description": "..."
},
"harvest_operations_card": {
"summary": "...",
"steps": [
{
"title": "...",
"note": "...",
"status": "..."
}
]
}
}
```
### Rule مهم
اگر JSON RAG خراب بود:
- fallback deterministic برگردان
- endpoint fail نکند
---
## فایل‌هایی که پیشنهاد می‌شود تغییر کنند
### در `crop_simulation/`
- `crop_simulation/apps.py`
- اضافه کردن getter برای summary service
- `crop_simulation/serializers.py`
- serializer درخواست و پاسخ summary
- `crop_simulation/views.py`
- view جدید برای summary
- `crop_simulation/urls.py`
- route جدید
- `crop_simulation/yield_harvest_summary.py`
- orchestrator اصلی
### در `Schemas/`
- `Schemas/crop_simulation_yield_harvest_summary.py`
- contract برای مستندسازی route
- `Schemas/__init__.py`
- register کردن contract جدید
### در `rag/`
- `rag/services/yield_harvest.py`
- narrative enrichment
### در config
- `config/rag_config.yaml`
- service جدید `yield_harvest`
- `config/tones/yield_harvest_tone.txt`
- tone مخصوص summary صفحه
- در صورت نیاز:
- `config/knowledge_base/yield_harvest/`
---
## ترتیب پیشنهادی پیاده‌سازی
### فاز 1 - سریع و قابل اتکا
فقط این بلوک‌ها را واقعی کنید:
- `yield_prediction`
- `harvest_prediction_card`
- `yield_prediction_chart`
- `harvest_operations_card` با rules ساده
و برای بقیه اگر داده ندارید:
- `null`
- یا `available: false`
برگردانید.
### فاز 2 - RAG narrative
به summary و operation notes متن کاربرپسند اضافه کنید.
### فاز 3 - block-level readiness
بعد از اضافه شدن مدل zone/block، `harvest_readiness_zones` را واقعی کنید.
### فاز 4 - quality/economy
بعد از اضافه شدن منبع quality یا market:
- `yield_quality_bands`
- revenue
- sale window
را کامل کنید.
---
## توصیه مهم درباره contract
اگر بعضی بلوک‌ها هنوز data source واقعی ندارند، بهتر است از همین حالا response را این‌طور طراحی کنید:
```json
{
"harvest_readiness_zones": {
"available": false,
"reason": "block_level_data_missing",
"averageReadiness": null,
"blocks": []
}
}
```
این بهتر از mock پنهان است، چون:
- فرانت می‌فهمد چرا کارت کامل نیست
- QA راحت‌تر تست می‌کند
- بعداً migration ساده‌تر می‌شود
---
## ریسک‌های اصلی
### 1. استفاده از RAG برای عددسازی
بزرگ‌ترین خطر این صفحه همین است. RAG فقط برای narrative مناسب است.
### 2. نبود داده block-level
`harvest_readiness_zones` بدون مدل block عملاً دقیق نمی‌شود.
### 3. نبود quality source
`yield_quality_bands` بدون مدل کیفیت یا rule engine crop-specific قابل اتکا نیست.
### 4. ناهماهنگی chart contract
chart فعلی backend دقیقاً همان chart مورد انتظار فرانت نیست.
---
## پیشنهاد نهایی من
اگر بخواهم برای همین repo کم‌ریسک‌ترین مسیر را انتخاب کنم:
1. یک summary service در `crop_simulation` بسازید.
2. `yield_prediction` و `harvest_prediction_card` را از سرویس‌های فعلی reuse کنید.
3. `yield_prediction_chart` را فعلاً با داده واقعی current simulation برگردانید، نه مقایسه fake سال قبل.
4. `harvest_operations_card` را با rules deterministic + optional RAG summary بسازید.
5. `season_highlights_card` را از همین بلوک‌ها aggregate کنید.
6. `harvest_readiness_zones` و `yield_quality_bands` را فقط وقتی source واقعی دارید production کنید.
این مسیر با معماری فعلی پروژه، با `psce_doc.txt`، و با pattern موجود RAG بیشترین سازگاری را دارد.
---
## یک pseudo flow پیشنهادی
```text
GET /api/yield-harvest/summary/?farm_uuid=...
->
load farm details
->
run/reuse PCSE simulation outputs
->
build deterministic blocks
->
optionally call RAG for narrative fields only
->
merge response
->
return code/msg/data
```
---
## نتیجه
برای این صفحه:
- PCSE باید موتور عددها باشد
- rules باید موتور KPIهای محصولی باشد
- RAG باید موتور متن و explanation باشد
اگر این مرزبندی رعایت شود، هم dashboard قابل اعتماد می‌شود، هم توسعه بعدی آن تمیز و قابل نگهداری می‌ماند.