1. 为什么这个系列到第16篇,必须开始聊AI了
“高高种地”这个系列做到现在,前面的15篇一直没有碰AI。不是不想碰,而是AI这件事在前面碰是空的。
前15篇我们把智慧农业管理应用的骨架搭完了:环境传感器数据采集、土壤墒情监测、灌溉设备远程控制、告警推送、数据可视化大屏,再到多设备间的数据同步和元服务卡片展示。走到这一步,应用已经具备了“感知”和“执行”的能力——它能告诉你温度高了、土壤干了、设备开了,但它不能告诉你叶片上这个黑斑到底是炭疽病还是褐斑病,也不能在你拍了一袋复合肥的标签后自动告诉你这个肥料的氮磷钾配比适不适合当前作物,更不能把你说的一堆方言农事语音整理成一条规范的生产记录。
这就是AI要补上的那一块:从“数据能看”到“数据能懂”,从“远程控制”到“辅助决策”。
第16篇作为AI篇章的起点,我做两件事:先把HarmonyOS生态里到底有哪些可用的AI能力梳理清楚,再从中挑出几个能立刻集成进农业管理场景的,把端侧推理和系统级AI服务的接入链路说透。这篇读完之后,你不需要成为一个算法工程师,也不用自己训练模型,就能让应用具备图像识别、文本识别、语音转写和本地离线判断的能力。
适用对象很明确:已经跟着这个系列做到数据采集和可视化阶段、想给应用加智能化功能的开发者,以及想要评估“端侧AI到底能跑在什么水平”的架构选型人员。这一篇不会泛泛讲人工智能概念,全部以智慧农业中的真实功能点为载体展开。
2. 智慧农业里“值得做”的AI任务,先盘一个清单再动手
2.1 前15篇攒下的功能,AI到底往哪里接
先说实话:很多开发者做AI集成失败,不是模型不行,而是没想清楚AI在原有应用里到底扮演什么角色。AI不是独立功能,它是插在原有流程中间的一个“理解层”。
拿我们这个农业管理应用举例。原有流程是这样的:
- 采集层:传感器上报温度、湿度、光照、土壤EC值
- 控制层:远程开关水泵、电磁阀、补光灯
- 展示层:数据大屏展示历史曲线和设备状态
- 告警层:温度越限、湿度异常时推送给用户
AI接入之后,应用的主流程会变成“感知、理解、建议、执行”。传感器负责感知,AI负责理解,控制层负责执行,而“建议”是新增的一环。具体放在哪个环节,决定了AI任务的形态:
- 摄像头拍照后识别作物状态,属于“图像理解”,插在采集层和展示层之间
- 用户语音输入农事操作记录,属于“语音语意理解”,插在告警层和记录层之间
- 根据历史数据和外部气象信息预测灌溉量,属于“数值预测”,插在展示层和控制层之间
所以第一步不是急着去调API,而是把你应用已有的页面、服务、数据流图画出来,然后问自己:哪个环节最消耗人的注意力?哪个环节的判断最依赖经验?那个环节就是AI最先落地的位置。
2.2 农业场景下高频且可落地的AI任务清单
我在这个项目里整理过一张任务优先级表,按“落地价值”和“实现成本”两个维度筛过一遍。这里直接把结果放出来,你可以对照自己的业务做裁剪。
| AI任务 | 典型场景 | 实现方式 | 落地价值 | 起步成本 |
|---|---|---|---|---|
| 作物叶片病害识别 | 拍照判断叶片异常类型 | 端侧轻量模型推理 | 高,农民最痛的点 | 中,需要数据集和模型 |
| 果实成熟度判断 | 判断番茄/柑橘是否可采摘 | 端侧图像分类或检测 | 中高,采摘排期用 | 中,需要分阶段标注数据 |
| 农资标签OCR识别 | 拍肥料袋/农药瓶,提取名称、成分、配比 | 系统OCR服务 | 高,农资管理刚需 | 低,几乎零成本 |
| 农事语音记录转写 | 把口述农事操作转为结构化文本 | 系统语音服务+文本处理 | 中高,替代手工记录 | 低 |
| 农业资料翻译 | 查阅外文种植手册 | 系统翻译能力 | 中,低频但好用 | 低 |
| 灌溉/施肥量预测 | 结合土壤数据和天气做建议 | 云端接口或自建模型 | 高,需要长期数据积累 | 高,依赖数据质量 |
这张表看完你会发现一个规律:排在前面的落地项,几乎都集中在“让设备能看懂现场、听懂人话”这两类任务上。这也正是HarmonyOS AI能力集成最划算的两个切入点——系统级AI服务负责听懂和看懂不依赖特定领域的数据,端侧推理引擎负责跑你自己训练的领域模型。
2.3 HarmonyOS生态里的AI能力,实际上分三路
集成之前必须建立这个认知:HarmonyOS的AI能力不是一个统一的“人工智能大礼包”,而是分层的三种路径。我在初学阶段就吃过亏,总想用一个SDK解决所有问题,后来发现每种能力有它自己的定位和约束。
第一路是系统级AI服务。语音识别、文本转写、OCR、翻译这类能力被系统封装成服务接口,应用不需要训练模型,也不需要关系模型文件,直接调用即可。它的优点是接进来快、识别质量经过系统调优,缺点是不可定制——你没法让系统OCR只识别化肥成分而不识别其他文字。
第二路是端侧推理引擎。HarmonyOS生态里提供了一套轻量化的端侧推理组件,支持把训练好的主流模型格式转换成端侧可加载的模型文件,然后在应用进程内执行推理。它的优点是不依赖网络、延迟低、数据不出设备,缺点是性能受设备算力限制,不适合跑大参数模型。
第三路是云端服务接口。通过系统云侧能力或第三方服务,把数据送到云端执行重计算,再把结果返回。它的优点是模型可以更大、效果更强,缺点是必须有网络连接,而且数据出设备要过隐私合规这一关。
智慧农业场景的特殊性在于,田间网络不可靠,所以我在实际架构里把顺序定成:能端侧绝对不云侧,系统服务优先于自建模型。后面第4节和第5节的内容,就是按这个顺序来组织的。
3. 集成前先把三件事定下来:算力、网络和模型形态
3.1 设备算力评估:你手头的设备到底能跑多大模型
端侧AI第一个被低估的问题是设备差异。HarmonyOS应用可能跑在用户的中端手机上,也可能跑在某个大棚里的旧平板上,还可能在带有屏幕的开发板上演示。同一个模型在不同设备上的推理耗时可能差出3倍。
我用一个非常简单的评估方法:在目标设备上跑一次标准推理测试,模型选一个图像分类网络,输入224×224分辨率,单张推理。中端设备如果耗时在100毫秒以内,就说明这个量级的模型在端侧完全可以流畅跑;如果耗时超过300毫秒,就要考虑是否需要对模型做量化压缩或者换更轻的网络结构。
以叶片病害分类为例,这个任务用的是轻量分类网络,参数量级别在数百万级,量化之后的模型文件大小一般能控制在10MB以内。在中等定位的设备上,单张图片推理耗时大概在30到80毫秒之间;在入门级设备上可能到150毫秒。这个水平对拍照识别场景来说完全可用,用户感知不到延迟。
如果打算跑更重的检测模型,比如同时识别叶片上多个病斑的边界框,模型会大不少,文件可能到30MB以上,推理耗时也可能上涨。农业场景里我建议优先用分类模型起步,把“这张叶片有没有病、是什么病”先做对,再考虑病斑定位这类精细任务。
3.2 网络条件决定端云分工,而农业场景网络是最不确定的
智慧农业和办公室应用最大的区别,是网络条件非常不友好。蔬菜大棚里有Wi-Fi覆盖还算好,露天大田、山地果园经常是信号一格或者完全离线。
我建议在做AI能力集成之前,先定义三种网络状态,然后给每种AI任务打一个标签:“在线任务”“离线任务”“自适应任务”。
- 大棚内、有Wi-Fi:可以使用云端服务接口,把复杂计算交给云侧
- 田地里、移动信号弱:端侧推理为主,系统OCR等本地服务仍然可用
- 完全离线:只有端侧模型和本地缓存能力可用,所有云侧调用必须降级
打完标签之后你会发现,真正必须依赖云端能力的任务其实不多。叶片病害识别、农资标签OCR、语音转写这些高频场景,全部可以端侧化。唯一需要云端的可能是大模型辅助决策,比如“根据当前土壤数据生成一份施肥建议”这类语言生成任务,但这类功能作为辅助选项存在,不应该阻塞主流程。
3.3 模型形态与转换链路:从训练产物到应用资源文件
很多没接触过端侧推理的开发者,第一次卡住的地方是模型文件格式。训练框架产出的模型和端侧推理引擎需要的格式不一样,必须经过转换。完整链路是这样的:
- 在训练环境里完成模型训练,导出通用格式的模型文件
- 使用模型转换工具,指定输入张量的形状、数据类型、量化方式
- 转换完成后得到端侧推理引擎可加载的格式,放入应用工程的原始资源目录
- 在应用启动时加载模型,而不是每次识别都重新加载
这个过程中最需要注意的是输入张量的形状和归一化参数。转换工具里填的shape必须和训练时保持一致,否则推理结果全错。我见过有人把输入填成224×224但模型训练时用的是299×299,结果模型加载不报错,推理出来的概率分布完全乱套。
量化方式也需要结合农业场景来选。如果目标设备基础配置较低,建议开启8位整数量化,模型体积能缩小到四分之一左右,推理速度也更快,代价是精度有小幅下降。叶片病害分类这种类别差异明显的任务,精度下降通常可以接受。
关于模型文件放哪里,我放在工程的resources/rawfile/ai_models/目录下。这样模型会随应用安装到设备上,读取时用资源接口按文件名加载,不需要处理复杂的文件路径权限问题。
4. 端侧推理完整链路实录:作物叶片病害分类
4.1 先跑通最小闭环,再谈优化
这一节是整篇的重头戏。我会用一个“叶片拍照—病害分类—结果输出”的最小闭环,把端侧推理的链路完整过一遍。项目代号叫“叶诊”,模拟场景是种植户在田里发现作物叶片异常,拍照后应用判断可能是哪种常见病害并给出初步提示。
模型层面的准备我不展开训练细节,因为不是本篇重点。用到的模型是一个轻量分类网络,训练数据来自通用的植物病害公开数据集,取了苹果黑星病、葡萄黑腐病、番茄叶霉病、健康叶片等8个类别。模型导出后完成转换,最终模型文件体积不到10MB。
4.2 ArkTS侧的初始化与模型加载
初始化放在应用进入识别页面的时机,不要放在应用全局启动阶段。原因很直接:模型加载消耗时间和内存,如果用户从没打开过识别页面,提前加载就是白耗资源。代码如下:
import { AIKit } from '@ohos.ai.kit'; // 模型加载成功后返回推理会话实例 const MODEL_FILE = 'rawfile/ai_models/leaf_disease.lite'; async function initLeafDiseaseModel(): Promise<AIKit.Session> { // 1. 创建推理配置 const config = new AIKit.Config(); config.modelUri = MODEL_FILE; config.deviceType = AIKit.DeviceType.CPU; config.powerMode = AIKit.PowerMode.BALANCED; // 2. 加载模型,返回会话 const session = await AIKit.createSession(config); console.info('叶诊模型加载成功'); return session; }这里有几个必须注意的要点。模型路径前缀要核对清楚,写在“rawfile”还是不写“rawfile”在不同版本API里行为有差异,以当前SDK版本的文档为准,但统一写法能避免低级问题。设备类型优先选CPU,虽然部分设备支持NPU加速,但CPU兼容性最好,不会因为设备差异导致运行时报错。功率模式选平衡模式,识别场景对功耗不敏感,但长时间挂机会导致设备发热。
4.3 拍照后的图像预处理流程
模型加载完成只是万里长征第一步,真正容易出错的环节是图像送入模型之前的那几步预处理。逻辑上顺序固定:解码、缩放、通道转换、归一化。
用系统相机接口拿到的是原始图像帧,可能是4800万像素的大图,直接送进模型绝对不行,推理时间会爆炸。我先把图像缩放到模型要求的224×224尺寸,然后做通道顺序调整和归一化。
function preprocessImage(pixelMap: image.PixelMap): Float32Array { // 1. 将图像缩放至模型输入尺寸 const targetSize = 224; const resized = pixelMap.scale(targetSize, targetSize); // 2. 读取像素数据,注意通道顺序通常为BGRA const buffer = new ArrayBuffer(targetSize * targetSize * 4); resized.readPixelsToBuffer(buffer); // 3. 转为浮点数组并做归一化 const input = new Float32Array(1 * 3 * targetSize * targetSize); const uint8 = new Uint8Array(buffer); const mean = [0.485, 0.456, 0.406]; const std = [0.229, 0.224, 0.225]; for (let h = 0; h < targetSize; h++) { for (let w = 0; w < targetSize; w++) { const idx = (h * targetSize + w) * 4; const b = uint8[idx] / 255.0; const g = uint8[idx + 1] / 255.0; const r = uint8[idx + 2] / 255.0; const a = uint8[idx + 3] / 255.0; // 按RGB顺序填入CHW布局 input[0 * targetSize * targetSize + h * targetSize + w] = (r - mean[0]) / std[0]; input[1 * targetSize * targetSize + h * targetSize + w] = (g - mean[1]) / std[1]; input[2 * targetSize * targetSize + h * targetSize + w] = (b - mean[2]) / std[2]; } } return input; }这段代码里最阴间的坑就是通道顺序。相机输出的像素数据通常是BGRA顺序,而训练时模型看到的是RGB顺序。不转换就直接送进去的结果是:模型准确率立即掉到随机水平,而且你不容易察觉,因为程序不报错。这个问题我在新手期折腾了一个晚上,最后用一张特征颜色明显的图片做单张推理对比才定位到。
4.4 执行推理与结果置信度过滤
图像处理成张量之后,推理本身反而很简单。把输入张量传给会话,执行同步推理,获得输出张量。输出张量是一组8个类别的概率值,取最大值对应的类别索引就是识别结果。
async function predict(session: AIKit.Session, input: Float32Array): Promise<PredictResult> { const output = await session.predict(input); // 解析输出概率 const scores = Array.from(output.data); let maxIdx = 0; let maxScore = scores[0]; for (let i = 1; i < scores.length; i++) { if (scores[i] > maxScore) { maxIdx = i; maxScore = scores[i]; } } return { categoryId: maxIdx, confidence: maxScore, }; }拿到类别和置信度之后,一定不要直接把这堆数值怼到UI上。用户在田间地头看的是“这是什么病、怎么办”,不是“类别3,置信度0.87”。我在应用里做了两层包装:置信度高于0.75时给出病害名称和农事建议;低于0.5时明确提示“识别不确定,建议咨询当地农技人员”,中间区间提示“可能是XX,请观察叶片正反面再拍一次”。
置信度阈值不是拍脑袋定的。我拿验证集的数据实测过一轮,0.75这个阈值能让准确率保持在可接受范围,同时召回率不会过低。如果你换数据集,一定要重新标定,不要沿用别人的经验值。
5. 系统级AI服务接入:OCR、语音转写与翻译的“零成本”实现
5.1 农资标签OCR:拍一下肥料袋,自动提取成分信息
端侧模型解决的是领域定制问题,但有些通用能力完全没必要自己做模型。农资标签文字识别就是典型案例。化肥袋、农药瓶上的文字内容包括产品名、氮磷钾含量、登记证号、使用方法,这些信息拍下来转成文本就够用了,轮不到自训模型。
系统OCR能力的接入方式比端侧推理简单得多,不需要模型文件,也不需要预处理管道,直接调用服务接口,传入图片或PixelMap,拿到文本结果。我封装了一个工具方法:
import { textRecognition } from '@ohos.ai.ocr'; async function recognizeLabel(pixelMap: image.PixelMap): Promise<string> { const options = { languages: ['zh'], detectOrientation: true, }; const result = await textRecognition.recognize(pixelMap, options); return result.text; }OCR结果拿到后不要直接显示,农业场景里更需要的是结构化提取。我用一个简单的规则引擎处理文本内容:“含氮量”“N-P-K”“总养分”这类关键词出现时,把后面的数值和单位切出来。这样识别结果可以直接进入农资台账,和施药记录关联起来。
5.2 农事语音记录:方言识别要管理好预期
语音转写我在应用里用作文事记录输入,核心场景是让农户干活时不用停手打字,直接说“上午八点给三号棚番茄打了百菌清,兑水三十斤”,系统自动生成结构化记录。
接入链路是:调用录音能力获取音频,将音频送入语音识别服务获得文本,再用关键词解析把时间、作物、农事类型、用量提取出来。文本解析我用了最朴素的关键词映射表,维护一个“标识动作词表”,百菌清、嘧菌酯这类农药名预先录入。
这里必须说实话:方言识别效果和普通话不在一个水平,尤其老农户口音重时,转写错误率会明显上升。我的处理策略是:应用不做自动静默处理,识别结果先展示给用户确认,确认后再落到生产台账。宁可让用户多点一次确认,也不能把错误记录写进数据库。这条产品原则各位做农业场景时建议直接抄走。
5.3 翻译能力用于农业资料查阅
这个功能加进来其实是顺手的事,但很多开发者不知道。系统级翻译能力可以直接复用,不用申请额外的云服务配额。我在应用里放了一个“外文资料”入口,用户遇到外文种植手册、进口农资说明书时,拍照后先走OCR提取文字,再把文本丢给翻译服务。
效果上,短句和专业术语翻译可用性尚可,长段落会存在语序机械的问题。作为辅助查阅工具够用,但不能依赖它做精确的法律性或者用药剂量判断。这个边界要在产品说明里写清楚。
6. 田间网络不稳:AI调用链路的降级与缓存策略
6.1 用“端侧优先、云侧兜底”的分层调用解决网络抖动
智慧农业应用最尴尬的场景是:用户站在田里,刚拍完一张病害叶片,应用弹出“网络连接失败,请稍后重试”。本来AI是帮用户省事的,结果因为依赖云端,反而变得不可用。所以我给应用定了一条铁律:核心AI能力必须端侧可用,云侧只是增强选项。
MACD分段策略在代码里的实现也不复杂,核心是一个路由函数:
function decideRoute(taskType: TaskType): RouteType { const networkStatus = getCurrentNetworkStatus(); if (networkStatus === NetworkStatus.OFFLINE) { // 离线:只能走端侧模型,云侧任务直接降级 return RouteType.LOCAL_ONLY; } if (networkStatus === NetworkStatus.WEAK) { // 弱网:优先端侧,云侧任务需要检测请求超时 return RouteType.LOCAL_FIRST; } return RouteType.CLOUD_FIRST; }语音转写这类系统服务虽然看似本地能力,但部分语言包和高质量模型需要联网加载,弱网时也会失败。所以我对于这类服务同样封装了路由逻辑:尝试本地识别,失败降级到“请在有信号的环境下重试”,而不是堆一个转圈圈动画让用户傻等。
6.2 结果缓存:重复识别不能每次白跑
智慧农业识别还有一个被忽略的问题:同一块田、同一批叶片,用户今天拍明天拍,特征其实差不多。每次都跑一遍模型属于纯浪费。我在应用里加了一层结果缓存,以图片的感知哈希作为key,把识别结果和置信度存起来,三天内重复出现相似图片时直接返回缓存结果。
缓存实现用的是应用沙箱内的轻量数据库,不依赖网络。为了不让缓存变成脏数据,我在识别结果页展示时会标注“该结果来自历史记录”,并且缓存命中时强制降低置信度等级,引导用户对关键判断重新拍摄验证。
这个细节说起来小,但实际使用中很能提升体验。农户往往会对同一片病叶反复确认,缓存命中能避免每次等同样的推理耗时。
6.3 降级的用户提示要可执行,不要纯报错
技术上的降级做完了,产品上的降级也要跟上。很多应用的降级提示就是一句话“当前网络不可用”,这对用户没有任何帮助。我在应用里定了三种降级提示模板:
- 网络不可用时:“当前处于离线状态,病害识别仍可用,农事建议生成已停用”
- 云侧接口超时时:“识别结果来自本地模型,建议在信号良好环境重新上传获取更全面的分析”
- 系统OCR失败时:“识别失败,请调整光线角度重新拍摄,避免标签反光”
原则是告诉用户当前功能边界和下一步动作,而不是让他面对一个冰冷的错误码。
7. 实测记录:推理耗时、内存峰值和踩过的坑
7.1 三台不同档位设备上的实测表现
写这篇的时候我把叶诊模型跑到了三台定位差异明显的设备上进行了一次基准测试,数据记录如下。测试条件统一为:模型文件9.6MB,224×224输入单张推理,连续执行10次取平均值。
| 设备定位 | 单次推理耗时 | 加载耗时 | 峰值内存增长 | 连续10次温升 |
|---|---|---|---|---|
| 中端机型 | 约45ms | 约300ms | 约180MB | 不明显 |
| 入门机型 | 约120ms | 约520ms | 约220MB | 温热 |
| 折叠屏大屏机型 | 约35ms | 约280ms | 约200MB | 不明显 |
从数据能得出几个结论。模型加载耗时会明显感知,所以必须放后台加载,不能让用户在页面傻等;推理过程中的内存增长幅度大,要关注进程被系统回收的问题;入门机型上连续识别会发热,量产时要考虑限制单次批量识别数量或降低推理频率。
7.2 踩坑记录一:模型文件加载路径与大小写问题
我在这项目里遇到的最莫名其妙的问题,是模型文件在部分设备上加载失败,但在另一台设备上又完全正常。排查了很久发现是文件路径大小写问题。资源目录在一种设备上区分大小写,模型文件名我写的是“LeafDisease.lite”,实际文件在工程里却是“leaf_disease.lite”,编译打包时没做归一化,部分设备按原始文件名找资源就找不到。
这类问题调试时不会报错信息,只会返回一个“模型加载失败”的笼统错误。解决方案是把模型文件的命名规则统一全部小写下划线,并在代码里用常量维护路径,禁止手打文件名。
7.3 踩坑记录二:输入张量内存复用与释放
第二个坑和内存相关。我第一次跑通推理后,每识别一次就新建一个输入Float32Array,结果连续识别十几张后应用内存明显上涨。原因是系统底层可能持有输入张量引用的时间比预期更长,频繁创建大数组导致内存碎片化和抖动。
优化方式是复用输入输出缓冲区:初始化时创建最大尺寸的数组,每次推理前填充数据,推理完成后不释放,等下次推理复用。实测这样调整后,内存增长曲线平坦了很多,频繁识别场景也不再触发内存告警。
7.4 踩坑记录三:系统OCR在高反光农资标签上的失败率
系统OCR在识别化肥袋标签时有一个产品层面的问题:塑料编织袋上的标签经常反光,反光区域文字识别成功率骤降。我一开始怀疑是OCR能力的问题,后来用同样的图片测试发现,问题出在拍摄成像质量。
解决办法在拍摄环节做文章:应用内引导用户调整拍摄角度,提供“是否反光”的自动检测,检测到高光区域面积过大时提示用户变换角度重拍。这比在识别端做任何图像增强都有效。识别前的直方图均衡化、灰度化这种传统图像处理手段我也试过,没那么可靠,反而增加预处理耗时。
8. AI能力之后再往前走:从“识别出病害”到“给出决策”
8.1 智能判断的下一步是设备联动
叶片识别结果目前停留在“告诉用户这是什么病”。但应用既然有设备控制能力,就不应该止步于此。我规划里下一步是建立识别结果与控制指令的联动规则:识别到真菌性病害,应用给出喷药建议,用户确认后一键触发对应棚区的施药设备。这个闭环把AI从“信息提供者”变成了“行动发起者”,价值完全不一样。
技术上要做的是把识别类别映射到控制指令模板,同时增加人工二次确认环节。农业控制这件事出不起错,任何自动化指令都必须保留用户在环审核。
8.2 端侧识别结果回传,形成本地农事知识库
识别结果不应该只停留在本地。在网络允许时,我把每一次端侧识别的图片缩略图、类别、置信度、地理位置、时间戳回传到服务端,经过一段时间的积累,就能形成区域性的病害分布热力图。这个数据反过来可以用于模型迭代和农事建议的本地化调优,形成真正有用的数据闭环。
这里提醒一句,图片上传涉及用户隐私,必须先做匿名化脱敏,并且明确告知用户数据用途,提供关闭开关。
8.3 从第16篇往后,AI集成会越来越占篇幅
第16篇做的其实是“地基工程”:梳理能力边界、跑通端侧推理、接入系统AI服务、建立降级策略。后面的篇章我会按这个顺序继续展开:先做农资识别的结构化台账,再做语音农事记录的完整链路,然后是基于识别结果的设备联动,最后才是需要数据积累的预测类功能。如果你想提前动手,优先把这一篇的端侧推理链路和OCR接入练熟,这两个点覆盖了智慧农业应用里八成以上的AI需求。
最后分享一个体会:HarmonyOS的AI能力集成,真正的门槛从来不在API调用本身,而在场景的理解。农业场景网络不稳、用户操作水平参差、数据敏感度高,这些约束条件决定了很多在互联网应用里顺理成章的做法在这里需要彻底重构。把“端侧优先、降级可用、结果可解释”这三条原则当底线,AI功能才能从技术演示变成真正能在地里用起来的工具。