第2260篇:农业AI工程——病虫害识别和农业决策支持系统
第2260篇:农业AI工程——病虫害识别和农业决策支持系统
适读人群:农业科技工程师、Java后端开发者、农业数字化技术团队 | 阅读时长:约15分钟 | 核心价值:从农业真实痛点出发,实现病虫害图像识别、气象数据融合和智能农业决策支持的完整工程方案
我在华南某省级农业科技平台项目中工作过一段时间。那时刚好碰上一场稻飞虱爆发,几个县的水稻在一周内出现大面积减产风险。
当地农业局的应对方式:打电话通知村里的农技员,农技员骑摩托车去田间,拍照,再发给专家,专家看完回复建议,最快也要两三天。等指导意见到了,有的田块已经从"轻度"变成"重度"了。
一位老农技员和我说:"你说这手机照片能认出是什么虫子,然后告诉我怎么打药,那要多好啊。"
这句话我记了好几年。后来做了相关系统,才真正理解其中的工程复杂度——农业AI不只是图像识别,它需要把病虫害识别、气象数据、土壤数据、作物生长周期、农药配伍知识全部融合在一起,才能给出有实用价值的决策建议。
农业AI系统架构
病虫害图像识别
图像识别服务
@Service
public class CropDiseaseRecognitionService {
@Autowired
private ModelInferenceClient inferenceClient;
@Autowired
private OpenAIClient openAIClient;
@Autowired
private CropKnowledgeRepository knowledgeRepository;
/**
* 病虫害识别——双模式:本地模型+LLM视觉辅助
*/
public DiseaseRecognitionResult recognize(MultipartFile imageFile,
String cropType,
String growthStage) {
byte[] imageBytes = imageFile.getBytes();
// 1. 本地轻量模型快速识别(<200ms)
LocalModelResult localResult = inferenceClient.classify(
imageBytes,
InferenceRequest.builder()
.modelName("crop-disease-classifier-v3")
.topK(5)
.build()
);
// 2. 如果置信度高,直接返回
if (localResult.getTopResult().getConfidence() > 0.90) {
return buildResult(localResult.getTopResult(), cropType, growthStage);
}
// 3. 置信度不够,用GPT-4V辅助分析
DiseaseRecognitionResult visionResult = visionModelAnalysis(
imageBytes, cropType, growthStage, localResult
);
// 4. 融合两个模型结果
return mergeResults(localResult, visionResult);
}
/**
* 使用GPT-4V进行视觉分析——处理复杂病害和低置信度场景
*/
private DiseaseRecognitionResult visionModelAnalysis(byte[] imageBytes,
String cropType,
String growthStage,
LocalModelResult localResult) {
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
// 构建本地模型的候选结果,作为参考上下文
String candidatesContext = localResult.getTopResults().stream()
.limit(3)
.map(r -> String.format("- %s(%.1f%%)", r.getLabel(), r.getConfidence() * 100))
.collect(Collectors.joining("\n"));
String prompt = String.format("""
请分析这张农作物图像中的病虫害情况。
作物信息:
- 作物类型:%s
- 生育阶段:%s
本地识别模型给出的候选结果(供参考):
%s
请提供:
1. 病虫害名称(中文学名)
2. 识别置信度(0-1)
3. 主要症状描述(从图像观察到的)
4. 发病程度评估(轻度/中度/重度)
5. 可能的误判情况说明(如果有相似病害)
返回JSON格式:
{
"disease_name": "病虫害名称",
"disease_code": "代码,如 rice_planthopper",
"confidence": 0.85,
"symptoms_observed": "症状描述",
"severity": "MILD/MODERATE/SEVERE",
"possible_confusions": ["相似病害1", "相似病害2"],
"additional_notes": "补充说明"
}
""", cropType, growthStage, candidatesContext);
ChatCompletionResponse response = openAIClient.createChatCompletion(
ChatCompletionRequest.builder()
.model("gpt-4o")
.messages(List.of(
ChatMessage.userMessage(
List.of(
ContentPart.text(prompt),
ContentPart.imageBase64("image/jpeg", base64Image)
)
)
))
.responseFormat(ResponseFormat.JSON_OBJECT)
.maxTokens(1000)
.build()
);
String jsonResult = response.getChoices().get(0).getMessage().getContent();
VisionAnalysisResult visionResult = JsonUtils.parseObject(jsonResult, VisionAnalysisResult.class);
return convertToRecognitionResult(visionResult, cropType, growthStage);
}
private DiseaseRecognitionResult buildResult(ClassificationResult topResult,
String cropType,
String growthStage) {
// 从知识库获取病害详细信息
DiseaseKnowledge knowledge = knowledgeRepository.findByCode(topResult.getLabel());
return DiseaseRecognitionResult.builder()
.diseaseName(knowledge != null ? knowledge.getChineseName() : topResult.getLabel())
.diseaseCode(topResult.getLabel())
.confidence(topResult.getConfidence())
.cropType(cropType)
.growthStage(growthStage)
.severity(estimateSeverity(topResult.getConfidence()))
.recognitionTime(LocalDateTime.now())
.build();
}
}农业决策支持引擎
识别出病虫害只是第一步,给出可操作的防治方案才是核心价值:
@Service
public class AgriculturalDecisionEngine {
@Autowired
private OpenAIClient openAIClient;
@Autowired
private WeatherService weatherService;
@Autowired
private SoilDataRepository soilDataRepository;
@Autowired
private PesticideKnowledgeRepository pesticideRepository;
@Autowired
private RegulationRepository regulationRepository;
/**
* 生成综合防治决策方案
*/
public TreatmentDecision generateDecision(DiseaseRecognitionResult recognition,
String fieldId,
String farmerId) {
// 1. 收集多源上下文数据
WeatherForecast weather = weatherService.getForecast(fieldId, 7);
SoilData soil = soilDataRepository.findByFieldId(fieldId);
List<PesticideInfo> applicablePesticides = pesticideRepository.findByDiseaseCode(
recognition.getDiseaseCode()
);
RegulationConstraints regulations = regulationRepository.findByRegion(
getRegionByFieldId(fieldId)
);
// 2. 构建决策上下文
String decisionContext = buildDecisionContext(
recognition, weather, soil, applicablePesticides, regulations
);
// 3. LLM生成决策方案
String prompt = """
你是一位拥有20年经验的农业植保专家,熟悉农作物病虫害防治。
请根据以下情况,给出专业的防治建议:
%s
请提供:
1. 防治紧迫性评估(是否需要立即处理)
2. 推荐防治方案(首选方案+备选方案)
- 化学防治:具体农药名称、用量、施药方式、注意事项
- 物理/生物防治(如适用)
3. 施药时间建议(结合天气预报)
4. 预防措施(避免复发)
5. 预期防治效果和周期
6. 安全注意事项(人员安全/食品安全间隔期)
返回JSON格式:
{
"urgency": "IMMEDIATE/WITHIN_3_DAYS/WITHIN_WEEK/MONITORING",
"urgency_reason": "紧迫性说明",
"primary_treatment": {
"type": "CHEMICAL/BIOLOGICAL/PHYSICAL/INTEGRATED",
"pesticides": [{"name": "农药名", "dosage": "用量", "method": "施药方式"}],
"timing": "建议施药时间",
"precautions": ["注意事项1", "注意事项2"]
},
"alternative_treatment": {...},
"prevention_measures": ["预防措施1", "预防措施2"],
"expected_effect": "预期效果描述",
"safety_interval_days": 天数(上市安全间隔期),
"estimated_cost_per_mu": 每亩估算费用(元)
}
""".formatted(decisionContext);
String jsonResult = callLLM(prompt, "gpt-4o");
DecisionOutput output = JsonUtils.parseObject(jsonResult, DecisionOutput.class);
return TreatmentDecision.builder()
.recognitionResult(recognition)
.fieldId(fieldId)
.farmerId(farmerId)
.decisionOutput(output)
.weatherContext(weather)
.generatedAt(LocalDateTime.now())
.build();
}
private String buildDecisionContext(DiseaseRecognitionResult recognition,
WeatherForecast weather,
SoilData soil,
List<PesticideInfo> pesticides,
RegulationConstraints regulations) {
StringBuilder sb = new StringBuilder();
// 病害信息
sb.append("【病虫害信息】\n");
sb.append(String.format("病害名称:%s(置信度:%.1f%%)\n",
recognition.getDiseaseName(), recognition.getConfidence() * 100));
sb.append(String.format("作物类型:%s,生育阶段:%s\n",
recognition.getCropType(), recognition.getGrowthStage()));
sb.append(String.format("发病程度:%s\n\n", recognition.getSeverity().getDescription()));
// 天气信息
sb.append("【未来7天天气预报】\n");
weather.getDailyForecasts().forEach(day ->
sb.append(String.format("%s:%s,温度%d-%d℃,湿度%d%%,%s\n",
day.getDate(), day.getWeather(),
day.getMinTemp(), day.getMaxTemp(),
day.getHumidity(),
day.getRainfall() > 5 ? "有降雨" : "无降雨"))
);
sb.append("\n");
// 土壤状况
if (soil != null) {
sb.append("【土壤状况】\n");
sb.append(String.format("pH值:%.1f,土壤湿度:%d%%\n\n", soil.getPh(), soil.getMoisture()));
}
// 可用农药(过滤禁用农药)
sb.append("【当前可用农药】\n");
pesticides.stream()
.filter(p -> !regulations.getBannedPesticides().contains(p.getActiveIngredient()))
.forEach(p -> sb.append(String.format("- %s(%s,安全间隔期%d天)\n",
p.getProductName(), p.getActiveIngredient(), p.getSafetyInterval())));
// 法规约束
sb.append("\n【当地监管要求】\n");
sb.append(String.format("农药安全间隔期要求:%d天内不得上市\n",
regulations.getMinSafetyIntervalDays()));
if (!regulations.getBannedPesticides().isEmpty()) {
sb.append("禁用农药:" + String.join("、", regulations.getBannedPesticides()) + "\n");
}
return sb.toString();
}
}区域病害预警系统
单一田块的病害识别,积累足够数据后可以做区域预警:
@Service
public class RegionalDiseaseAlertService {
@Autowired
private DiseaseReportRepository reportRepository;
@Autowired
private WeatherService weatherService;
@Autowired
private OpenAIClient openAIClient;
@Autowired
private AlertNotificationService alertService;
/**
* 区域病害态势分析(每日执行)
*/
@Scheduled(cron = "0 30 6 * * *")
public void regionalSituationAnalysis() {
// 获取所有活跃区域
List<String> regions = regionRepository.findAllActiveRegions();
regions.forEach(this::analyzeRegion);
}
private void analyzeRegion(String regionId) {
// 近7天病害报告统计
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusDays(7);
List<DiseaseReport> reports = reportRepository.findByRegionAndDateRange(
regionId, startDate, endDate
);
if (reports.isEmpty()) return;
// 统计病害分布
Map<String, Long> diseaseCount = reports.stream()
.collect(Collectors.groupingBy(
DiseaseReport::getDiseaseCode,
Collectors.counting()
));
// 检测突增趋势
Map<String, Long> prevWeekCount = reportRepository.findCountByRegionAndDateRange(
regionId, startDate.minusDays(7), startDate
);
// 识别爆发性增长的病害
diseaseCount.forEach((diseaseCode, count) -> {
long prevCount = prevWeekCount.getOrDefault(diseaseCode, 0L);
double growthRate = prevCount > 0 ? (double) (count - prevCount) / prevCount : Double.MAX_VALUE;
if (count >= 10 && growthRate > 1.0) { // 报告数>=10且增速>100%
triggerRegionalAlert(regionId, diseaseCode, count, growthRate);
}
});
}
private void triggerRegionalAlert(String regionId, String diseaseCode,
long reportCount, double growthRate) {
WeatherForecast forecast = weatherService.getForecast(regionId, 14);
DiseaseKnowledge knowledge = knowledgeRepository.findByCode(diseaseCode);
String analysisPrompt = String.format("""
农业病虫害区域爆发分析:
区域:%s
病害:%s
本周报告数:%d件
较上周增长:%.0f%%
未来14天天气:%s
请评估:
1. 爆发风险等级(低/中/高/极高)
2. 可能扩散范围预测
3. 关键防控时间窗口
4. 区域联防联控建议
返回简洁的JSON:
{
"risk_level": "HIGH",
"spread_prediction": "预测扩散情况",
"control_window": "防控时间窗口",
"regional_measures": ["措施1", "措施2"],
"alert_message": "给农技员的告警消息"
}
""",
regionId, knowledge.getChineseName(),
reportCount, growthRate * 100,
summarizeWeather(forecast)
);
String result = callLLM(analysisPrompt, "gpt-4o");
RegionalAlertAnalysis analysis = JsonUtils.parseObject(result, RegionalAlertAnalysis.class);
// 发送区域预警给农技员
alertService.sendToAgriculturalOfficers(
regionId,
RegionalAlert.builder()
.regionId(regionId)
.diseaseCode(diseaseCode)
.riskLevel(analysis.getRiskLevel())
.alertMessage(analysis.getAlertMessage())
.recommendations(analysis.getRegionalMeasures())
.build()
);
}
}工程落地经验
农业AI项目和其他行业有几个显著不同的工程挑战:
1. 样本不平衡问题极严重。常见病害样本很多,偏远地区的罕见病害可能一共只有几十张图。数据增强(旋转、亮度变化、模拟不同光照)和小样本学习技术是必须掌握的。
2. 移动端推理是硬需求。农村网络条件差,系统必须支持离线或弱网使用。把轻量化模型(MobileNet、EfficientNet-Lite)部署到手机端,云端模型作为高精度复核。
3. 决策建议必须有"保守原则"。农药用量建议错了可能造成药害或食品安全问题。LLM的输出必须经过农业知识库约束和专家审核,不能让模型直接输出没有经过验证的建议。
4. 方言和低文化程度用户。很多农民不识字或文化程度不高,系统要支持语音交互,文字输出要简单易懂,最好配合图示。
5. 数据本地化合规。农业数据可能涉及国家粮食安全,要注意数据不能出境,需要私有化部署。
