25 KiB
سیاست منبع داده و تجمیع کلاستر برای APIهای AI
این سند مشخص میکند هر API از کجا داده میگیرد، آیا الان خروجی آن بر اساس میانگین داده سنسور کلاسترها و میانگین داده ماهوارهای کلاسترهای location_data هست یا نه، و برای یکپارچهسازی چه policyای باید رعایت شود.
این سند بر اساس کد فعلی پروژه نوشته شده و مخصوص APIهای زیر است:
POST /api/rag/chat/POST /api/soile/anomaly-detection/POST /api/soile/health-summary/POST /api/soile/moisture-heatmap/POST /api/weather/farm-card/POST /api/weather/water-need-prediction/POST /api/pest-disease/detect/POST /api/pest-disease/risk/POST /api/irrigation/plan-from-text/POST /api/irrigation/recommend/POST /api/farm-data/parameters/POST /api/fertilization/plan-from-text/POST /api/fertilization/recommend/POST /api/crop-simulation/current-farm-chart/POST /api/crop-simulation/growth/GET /api/crop-simulation/growth/{task_id}/status/POST /api/crop-simulation/harvest-prediction/GET /api/crop-simulation/yield-harvest-summary/POST /api/crop-simulation/yield-prediction/POST /api/economy/overview/POST /api/farm-alerts/tracker/
1) قانون هدف کسبوکاری
قانون مطلوبی که باید برای محاسبههای عمومی AI رعایت شود این است:
- برای محاسبههای عمومی AI مثل
RAG،crop_simulation،irrigation،fertilization،farm_alertsو سرویسهای تحلیلی خاک، مبنای داده بایدمیانگین داده سنسورهای کلاسترهاومیانگین داده ماهوارهای کلاسترهای location_dataباشد. - این تجمیع باید در سطح
بلوکهای بزرگ کشاورزانجام شود؛ یعنی اول هر block اصلی جداگانه محاسبه شود، بعد در صورت نیاز یک خلاصه کل مزرعه از روی blockهای اصلی ساخته شود. - اگر کشاورز هنوز block تعریف نکرده باشد، حالت پیشفرض دامنه باید این باشد:
1 بلوک بزرگبرای کل مزرعه1 بلوک کوچکداخل همان بلوک بزرگ
- هر API که فقط
farm_uuidمیگیرد و رفتار عمومی مزرعه را تحلیل میکند، باید از snapshot تجمیعشدهی مبتنی بر block/sub-block استفاده کند، نه از یک سنسور خام یا یک location خام.
2) وضعیت فعلی مدل داده
2.1) لایه مزرعه
رکورد canonical مزرعه در farm_data.SensorData نگهداری میشود:
- شناسه اصلی:
farm_uuid - اتصال مکانی:
center_location -> location_data.SoilLocation - سنسورها:
sensor_payload - آبوهوا:
weather_forecast - گیاه:
plant_assignmentsوplant_snapshots - روش آبیاری:
irrigation_method
2.2) لایه مکانی
رکورد canonical مکانی در location_data.SoilLocation است:
farm_boundaryinput_block_countblock_layoutblock_subdivisionsremote_sensing_runs
2.3) لایه کلاستر و سنجش از دور
در location_data عملاً دو سطح تجمیع وجود دارد:
block= بلوک اصلی که کشاورز تعریف کردهsub-block / cluster= بخشهای کوچکتر داخل هر block
منطق فعلی تجمیع در location_data/satellite_snapshot.py پیاده شده است:
build_block_sensor_summary(...)- داده سنسورهای منتسب به sub-blockها را جمع میکند
- ابتدا برای هر sub-block میانگین میسازد
- سپس از روی sub-blockها میانگین block را میسازد
summarize_block_satellite_metrics(...)- دادههای grid/cell ماهوارهای را برای cluster blockها خلاصه میکند
- سپس میانگین block را میسازد
build_location_block_satellite_snapshots(...)- برای هر block اصلی یک snapshot میسازد
build_farmer_block_aggregated_snapshot(...)- از روی blockهای اصلی یک خلاصه کل مزرعه میسازد
پس زیرساخت فنی برای policy موردنظر تا حد زیادی در پروژه وجود دارد.
3) رفتار پیشفرض blockها
رفتار فعلی در کد
تابع build_block_layout() در location_data/models.py وقتی blockی داده نشود، این رفتار را دارد:
input_block_count = 1- فقط
1 بلوک اصلیباblock-1ساخته میشود sub_blocks = []
یعنی الان بخش دوم rule شما کامل اعمال نشده، چون:
1 بلوک بزرگوجود دارد- ولی
1 بلوک کوچک داخل آنبهصورت default ساخته نمیشود
رفتار مطلوب پیشنهادی
برای سازگاری با خواسته شما، policy پیشنهادی این است:
- اگر هیچ block و هیچ subdivisionی تعریف نشده بود:
block_layout.blocks = [block-1]- داخل
block-1.sub_blocksیک sub-block پیشفرض ساخته شود
- این sub-block پیشفرض میتواند چیزی شبیه این داشته باشد:
{
"sub_block_code": "block-1-sub-1",
"cluster_label": 0,
"source": "default",
"boundary": {},
"cluster_uuid": null
}
این policy باعث میشود تمام APIهای downstream همیشه حداقل یک سطح sub-block داشته باشند و منطق aggregation یکنواخت بماند.
4) منبع canonical پیشنهادی برای همه APIهای AI
برای APIهای عمومی AI، منبع canonical باید این ترتیب باشد:
4.1) سنسورها
منبع اصلی:
farm_data.SensorData.sensor_payload
اما نه به صورت خام. باید از مسیر زیر مصرف شود:
- assign سنسورها به
cluster/sub-block - میانگینگیری در سطح sub-block
- میانگینگیری مجدد در سطح block اصلی
- در صورت نیاز میانگینگیری در سطح کل مزرعه
4.2) ماهواره و remote sensing
منبع اصلی:
location_data.RemoteSensingRunlocation_data.AnalysisGridObservationlocation_data.RemoteSensingSubdivisionResultlocation_data.RemoteSensingClusterBlocklocation_data.RemoteSensingClusterAssignment
و باز هم باید از مسیر زیر مصرف شود:
- میانگین متریک هر cluster/sub-block
- میانگین متریک هر block اصلی
- در صورت نیاز میانگین کل مزرعه
4.3) آبوهوا
منبع اصلی آبوهوا فعلاً cluster-based نیست و از اینجا میآید:
farm.weather_forecast- یا آخرین
center_location.weather_forecasts
یعنی weather فعلاً location-center based است، نه cluster based.
4.4) source of truth نهایی برای APIهای عمومی
برای APIهایی که farm_uuid میگیرند، بهتر است source of truth نهایی یکی از این دو باشد:
get_farm_details(farm_uuid)بعد از ارتقا به policy جدید- یا یک service جدید مثل
build_ai_farm_snapshot(farm_uuid)
این snapshot باید شامل این بخشها باشد:
farm_level_aggregated_metricsblock_level_metricssub_block_level_metricsweatherplantsirrigation_methodsource_metadata
5) وضعیت فعلی هر API
در این بخش برای هر API مشخص شده:
- آیا الان مبتنی بر میانگین سنسور کلاسترها و میانگین ماهوارهای کلاسترها هست یا نه
- اگر نیست، الان داده را از کجا میگیرد
- وضعیت انطباق آن با policy جدید
5.1) RAG
POST /api/rag/chat/
وضعیت فعلی: نیمهمنطبق
منبع داده فعلی:
- متن خاک کاربر در
rag/user_data.py -> build_user_soil_text() - از
SensorDataوcenter_locationمیخواند - از
build_farmer_block_aggregated_snapshot(...)استفاده میکند - از
build_location_block_satellite_snapshots(...)هم برای blockهای اصلی استفاده میکند
نتیجه:
- برای summary کلی مزرعه، از aggregation مبتنی بر block استفاده میکند
- برای satellite و sensor summary تا حدی با policy شما سازگار است
- اما RAG chat هنوز یک contract رسمی و واحد برای
cluster mean onlyندارد و متن embed شده ممکن است ترکیبی از دادههای سطح farm و block باشد
نیاز به اصلاح:
- canonical snapshot باید صریحاً از
block meanوsub-block meanساخته شود - prompt/context باید روشن بگوید که اعداد از
cluster averagesآمدهاند
POST /api/soile/anomaly-detection/
وضعیت فعلی: غیرمنطبق مستقیم، منطبق غیرمستقیم
منبع داده فعلی:
- anomaly payload از request میآید
- اطلاعات مزرعه از
farm_data.services.get_farm_details() - سپس به
rag/services/soil_anomaly.pyداده میشود
نتیجه:
- خود anomaly ممکن است از هر منبعی آمده باشد و API آن را enforce نمیکند
- اما farm context از
get_farm_details()میآید که فعلاًlatest_satellite + sensor_payloadرا ترکیب میکند get_farm_details()هنوز خلاصه soil را ازbuild_location_satellite_snapshot(center_location)میگیرد، نه ازbuild_farmer_block_aggregated_snapshot()
نیاز به اصلاح:
get_farm_details()باید خلاصه soil اصلی را ازfarmer-level aggregated snapshotبگیرد- anomaly input هم اگر داخلی تولید میشود، باید بر پایه cluster mean باشد
5.2) Soile
POST /api/soile/health-summary/
وضعیت فعلی: احتمالاً نیمهمنطبق
منبع داده فعلی:
- از
farm_data.context.load_farm_context()و سرویسهای soil استفاده میکند load_farm_context()ازbuild_location_block_satellite_snapshots(location)استفاده میکند- بخشی از context block-based است
اما:
- اگر در summary نهایی از metrics خام سنسور یا latest weather/location استفاده شود، خروجی کاملاً cluster-mean-only نیست
نیاز به اصلاح:
- health summary باید صریحاً از
block_levelوfarm_levelaggregated metrics استفاده کند - هیچ metric خام سنسور بدون عبور از منطق sub-block mean وارد پاسخ نشود
POST /api/soile/moisture-heatmap/
وضعیت فعلی: منطبق نیست
منبع داده فعلی:
- heatmap ذاتاً spatial است و معمولاً از grid/cell یا location-level moisture data ساخته میشود
- برای heatmap، میانگینگیری کامل روی clusterها کافی نیست چون heatmap نیاز به توزیع مکانی دارد
نتیجه:
- این API نباید به خروجی تکعددی farm average تقلیل داده شود
- بلکه باید داده خام grid/cell یا cluster-level map را نگه دارد
policy صحیح:
- برای کارت summary یا average moisture بله، از cluster mean استفاده شود
- اما برای heatmap خودِ خروجی باید
cluster mapیاgrid mapباشد، نه صرفاً میانگین کل مزرعه
5.3) Weather
POST /api/weather/farm-card/
وضعیت فعلی: غیرمنطبق
منبع داده فعلی:
- از
weather_forecastمرتبط باcenter_location - یا آخرین forecast همان location
نتیجه:
- weather فعلاً بر اساس clusterهای
location_dataنیست - چون مدل weather cluster-based ندارد
نیاز به اصلاح:
- اگر قرار است cluster-based شود، باید weather در سطح block/sub-block تعریف شود
- در غیر این صورت، این API باید در سند بهعنوان
location-centered weatherثبت شود
POST /api/weather/water-need-prediction/
وضعیت فعلی: نیمهمنطبق
منبع داده فعلی:
- در
rag/services/water_need_prediction.pyازget_farm_details(farm_uuid)استفاده میشود - همچنین از weather forecast مزرعه استفاده میکند
نتیجه:
- بخش خاک/سنسور میتواند از snapshot مزرعه بیاید
- اما چون
get_farm_details()هنوز fully farmer-block-aggregated نیست، خروجی کامل منطبق نیست - بخش weather هم location-level است
نیاز به اصلاح:
- خاک و ماهواره از farmer aggregated snapshot
- weather تا زمان توسعه مدل cluster-weather، بهصورت location-level باقی بماند ولی source آن شفاف اعلام شود
5.4) Pest & Disease
POST /api/pest-disease/detect/
وضعیت فعلی: غیرمنطبق مفهومی
منبع داده فعلی:
- ورودی اصلی: تصویر
- context کمکی:
farm_uuidو داده مزرعه ازget_farm_details()
نتیجه:
- هسته این API image-based است، نه cluster average based
- context مزرعه میتواند cluster-based شود، اما خروجی نهایی وابسته به تصویر است
policy صحیح:
- context مزرعه برای کمک به تشخیص از snapshot تجمیعی بیاید
- اما این API ذاتاً APIِ میانگینمحور نیست
POST /api/pest-disease/risk/
وضعیت فعلی: نیمهمنطبق
منبع داده فعلی:
rag/services/pest_disease.py- اطلاعات مزرعه از
get_farm_details() - داده RAG و پایگاه دانش تخصصی
نتیجه:
- risk API باید از context مزرعه استفاده کند
- اگر
get_farm_details()اصلاح شود، این API هم خودبهخود نزدیک به policy مطلوب میشود
5.5) Irrigation
POST /api/irrigation/plan-from-text/
وضعیت فعلی: غیرمنطبق ذاتی
منبع داده فعلی:
- ورودی اصلی: متن آزاد
- مدل parser متنی
نتیجه:
- این API parser است، نه تحلیل agronomic مبتنی بر sensor/satellite
- بنابراین لازم نیست خروجیاش بر پایه cluster average باشد
policy صحیح:
- فقط اگر farm context کمکی به parser اضافه شود، آن context باید از snapshot تجمیعی بیاید
POST /api/irrigation/recommend/
وضعیت فعلی: نیمهمنطبق
منبع داده فعلی:
- از farm context و سرویس RAG irrigation استفاده میکند
- بخشی از سنسور را ممکن است مستقیماً از
sensor.sensor_payloadبخواند
نتیجه:
- اگر بعضی metricها مستقیم از payload خام خوانده شوند، با policy شما ناسازگار است
نیاز به اصلاح:
- recommendation فقط باید از aggregated block/sub-block metrics تغذیه شود
- fallback مستقیم به اولین سنسور یا payload خام باید حذف یا محدود شود
5.6) Farm Parameters
POST /api/farm-data/parameters/
وضعیت فعلی: خارج از دامنه این policy
منبع داده فعلی:
- این API داده را ایجاد/ویرایش میکند
farm_boundaryرا میگیردcenter_locationرا resolve میکندsensor_payloadرا ذخیره میکند- weather/location sync را trigger میکند
نتیجه:
- این API تولیدکننده داده است، نه consumer تحلیلی
- بنابراین قرار نیست خروجی analytic آن بر پایه cluster mean باشد
اما نقش مهم:
- باید sensorها را طوری ذخیره کند که assignment به
cluster/sub-blockممکن باشد - اگر cluster_uuid یا sub_block_code در payload نیاید، aggregation دقیق محدود میشود
5.7) Fertilization
POST /api/fertilization/plan-from-text/
وضعیت فعلی: غیرمنطبق ذاتی
منبع داده فعلی:
- parser متن آزاد
نتیجه:
- مانند irrigation text parser، این API ماهیتاً cluster-average consumer نیست
POST /api/fertilization/recommend/
وضعیت فعلی: نیمهمنطبق
منبع داده فعلی:
- context مزرعه و RAG fertilization
- معمولاً از
get_farm_details()و contextهای وابسته استفاده میکند
نتیجه:
- با اصلاح منبع canonical مزرعه، این API هم میتواند کاملاً منطبق شود
5.8) Crop Simulation
POST /api/crop-simulation/current-farm-chart/
POST /api/crop-simulation/growth/
POST /api/crop-simulation/harvest-prediction/
GET /api/crop-simulation/yield-harvest-summary/
POST /api/crop-simulation/yield-prediction/
وضعیت فعلی: غیرمنطبق تا نیمهمنطبق
منبع داده فعلی:
- سرویسهای
crop_simulation/services.py - بخشی از دادهها از farm context و بخشی از سنسور یا weather فعلی میآیند
- در بعضی helperها متریکها ممکن است مستقیماً از
sensor_payloadیا propertyهای سنسور resolve شوند
نتیجه:
- با rule شما که گفته بودی برای
crop_simulationباید از داده کل بلوکهای بزرگ استفاده شود، وضعیت فعلی هنوز کامل نیست - چون منبع canonical شبیهسازی هنوز بهصورت صریح farmer-block aggregation enforced نشده
نیاز به اصلاح:
- ورودی تمام simulation endpointها باید از farm aggregated snapshot بیاید
- یعنی متریکهای soil moisture, temperature, ndvi, ndwi, slope, nitrogen, phosphorus, potassium از
cluster mean -> block mean -> farm meanساخته شوند - weather فعلاً جداگانه location-level میماند مگر بعداً block-weather اضافه شود
GET /api/crop-simulation/growth/{task_id}/status/
وضعیت فعلی: وابسته به منبع run اولیه
نتیجه:
- این endpoint فقط status/result job را برمیگرداند
- اگر
growthهنگام شروع از داده غیرمنطبق استفاده کرده باشد، status endpoint هم همان خروجی را reflect میکند
5.9) Economy
POST /api/economy/overview/
وضعیت فعلی: منطبق نیست و حتی منبع واقعی ندارد
منبع داده فعلی:
economy/services.py- پیام صریح دارد که منبع واقعی تنظیم نشده است
نتیجه:
- این API فعلاً نه cluster-based است و نه حتی data-backed
نیاز به اصلاح:
- اگر قرار است فعال شود، باید از snapshot مزرعه + هزینهها + yield prediction + irrigation/fertilization plan استفاده کند
5.10) Farm Alerts
POST /api/farm-alerts/tracker/
وضعیت فعلی: نیمهمنطبق
منبع داده فعلی:
farm_alerts/services.py- از
load_farm_context(farm_uuid)وget_farm_details(farm_uuid)استفاده میکند
نتیجه:
- چون farm context بخشی از snapshotهای block-based را میخواند، تا حدی با policy سازگار است
- اما اگر context نهایی هنوز metric خام یا latest non-aggregated را ترجیح بدهد، کامل منطبق نیست
نیاز به اصلاح:
- همه alert ruleها باید روی block/farm aggregated metrics سوار شوند
- در صورت نیاز، هشدارهای spatial باید روی cluster-level breakdown هم نمایش داده شوند
6) جمعبندی سریع انطباق APIها
APIهایی که ماهیتاً باید cluster-aggregated باشند
اینها باید به policy جدید مهاجرت کنند:
POST /api/rag/chat/POST /api/soile/anomaly-detection/POST /api/soile/health-summary/POST /api/weather/water-need-prediction/POST /api/pest-disease/risk/POST /api/irrigation/recommend/POST /api/fertilization/recommend/POST /api/crop-simulation/current-farm-chart/POST /api/crop-simulation/growth/POST /api/crop-simulation/harvest-prediction/GET /api/crop-simulation/yield-harvest-summary/POST /api/crop-simulation/yield-prediction/POST /api/farm-alerts/tracker/
APIهایی که ماهیتاً parser/input/image/weather هستند و کامل cluster-based نیستند
POST /api/pest-disease/detect/-> image-firstPOST /api/irrigation/plan-from-text/-> text parserPOST /api/fertilization/plan-from-text/-> text parserPOST /api/farm-data/parameters/-> data ingestion/upsertPOST /api/weather/farm-card/-> location-centered weatherPOST /api/economy/overview/-> فعلاً منبع واقعی ندارد
APIهایی که spatial map هستند و نباید صرفاً average شوند
POST /api/soile/moisture-heatmap/
این API باید cluster/grid-aware بماند، نه فقط average-based.
7) مهمترین mismatch فعلی در کد
مهمترین mismatch فعلی این است که farm_data.services.get_farm_details() برای soil.resolved_metrics این کار را میکند:
latest_satellite = build_location_satellite_snapshot(center_location)- سپس
latest_satellite.resolved_metricsرا به عنوان soil_metrics میگیرد
این یعنی:
- خلاصه اصلی soil بر اساس یک snapshot location/block واحد ساخته میشود
- نه بر اساس
build_farmer_block_aggregated_snapshot(center_location, sensor_payload=...)
در حالی که برای policy موردنظر شما بهتر است این کار انجام شود:
farm_level_snapshot = build_farmer_block_aggregated_snapshot(...)soil.resolved_metrics = farm_level_snapshot.resolved_metricssoil.satellite_snapshots = block-level snapshots- در صورت نیاز
sub_block snapshotsهم در context بمانند
8) پیشنهاد ساختار استاندارد پاسخ داده برای AI
برای همه سرویسهای AI بهتر است یک snapshot واحد با این ساختار وجود داشته باشد:
{
"farm_uuid": "...",
"aggregation_policy": {
"sensor": "cluster_mean_then_block_mean_then_farm_mean",
"satellite": "cluster_mean_then_block_mean_then_farm_mean",
"weather": "center_location_latest_forecast",
"default_block_policy": "1_main_block + 1_default_sub_block_when_missing"
},
"farm_metrics": {},
"block_metrics": [],
"sub_block_metrics": [],
"weather": {},
"plants": [],
"irrigation_method": {}
}
مزیت این طراحی:
- همه APIها source of truth یکسان دارند
- اختلاف بین RAG، crop simulation، irrigation و alerts کم میشود
- تستپذیری سادهتر میشود
9) نتیجه نهایی
الان کدام APIها دقیقاً مطابق خواسته شما نیستند؟
تقریباً همه APIهای تحلیلی هنوز کاملاً مطابق policy شما نیستند، چون منبع canonical یکپارچهای که صریحاً بر پایه cluster mean sensor + cluster mean satellite باشد هنوز همهجا enforce نشده است.
بیشترین فاصله با policy مطلوب در این بخشهاست:
crop_simulationirrigation/recommendfertilization/recommendweather/farm-cardeconomy/overview- بخشی از
soileوfarm_alerts
الان کدام APIها از همین حالا تا حدی نزدیک هستند؟
rag/chatfarm_alerts/trackersoile/health-summarypest-disease/risk
چون بهصورت مستقیم یا غیرمستقیم از snapshotهای block-based و get_farm_details() استفاده میکنند.
الان کدام APIها ماهیتاً نباید صرفاً average-based شوند؟
soile/moisture-heatmappest-disease/detect- parserهای
plan-from-text
10) پیشنهاد اجرای فنی در کد
ترتیب پیشنهادی برای پیادهسازی:
get_farm_details()را بهfarmer aggregated snapshotمهاجرت بده.- یک service جدید مثل
build_ai_farm_snapshot()بساز. - default block policy را به
1 main block + 1 default sub-blockارتقا بده. - همه APIهای تحلیلی را وادار کن فقط از snapshot جدید بخوانند.
- برای APIهای spatial مثل heatmap، علاوه بر average summary، خروجی cluster/grid breakdown نگه دار.