📱 鸿蒙 HarmonyOS 全栈专栏 · 第 31 篇 / 共 34 篇(第 4 季)
上一篇:第 30 篇 实战项目三 | 下一篇:Native 开发:让 C++ 真正跑进你的 App

目录

一、端侧 AI 的四层

二、Kit 层:文字识别三行代码跑起来

三、语音与视觉:其他开箱可用的能力

四、端侧推理:把自己的模型放进 App

第一步:模型转换

第二步:在 App 里加载并推理

第三步:性能调优

五、意图框架:不打开 App 也能用你的功能

接入分三步

三个必须提前想清楚的问题

六、四个现实约束

七、选型决策表与六个坑

六个坑

这一篇你该记住什么


 

这是第 4 季的第一篇,接的是第 30 篇结尾那个投票里的第 4 个方向:AI 能力接入,端侧模型与智能体。

先说一个常见误解:很多人以为「鸿蒙的 AI」就是要自己训模型、自己搞推理框架。实际上华为已经把大量能力封装成了 Kit,文字识别、人脸、条码、语音转文字,几行代码就能用。真正需要自己带模型的场景,比你想象的少得多。

这篇按「四层」往下走:什么时候只用 Kit、什么时候要自己加载模型、以及怎么让系统的意图框架把你的功能推给用户。

📖 本篇导读

全文约 13 分钟。所有 API 以 API 12+ 为基准,具体签名请对照你所用版本的官方文档。

  1. 端侧 AI 的四层:你实际在写哪一层
  2. Kit 层:文字识别三行代码跑起来
  3. 语音与视觉:其他开箱可用的能力
  4. 端侧推理:把自己的模型放进 App
  5. 意图框架:不打开 App 也能用你的功能
  6. 四个现实约束(这段比 API 更重要)
  7. 选型决策表与六个坑

一、端侧 AI 的四层

图 1:端侧 AI 的四层结构,大多数人只需要用最上面一层

把这张图记住,能省掉很多无用功。判断标准很简单:

你的需求用哪层工作量
识别图片里的文字、识别条码、检测人脸Kit 层半天
语音转文字、文本转语音Kit 层半天
图像分割、主体抠图Kit 层1 天
自己训练的分类/检测模型要跑在手机上推理引擎层1-2 周
要做实时视频处理、算法必须自己写推理引擎 + Native1 个月起
⚠️ Kit 层的 API 有个共同特点: 它们依赖设备能力,不是所有设备都支持。必须先做能力检查,做不了就降级,否则在你手上能跑、在用户的老设备上直接崩。

二、Kit 层:文字识别三行代码跑起来

以最常用的文字识别(OCR)为例。它属于 Core Vision Kit,不需要任何模型文件。

entry/src/main/ets/utils/ocr.ets

import { textRecognition } from '@kit.CoreVisionKit';
import { image } from '@kit.ImageKit';
import { BusinessError } from '@kit.BasicServicesKit';

async function recognize(pixelMap: image.PixelMap): Promise<string> {
  // 1. 检查设备是否支持(必做)
  const supported = await textRecognition.isSupported();
  if (!supported) {
    return '当前设备不支持文字识别';
  }

  // 2. 组装入参
  const info: textRecognition.VisionInfo = {
    pixelMap: pixelMap,
  };

  // 3. 识别
  try {
    const result = await textRecognition.recognizeText(info, {});
    // result.value 是整段文本;result.blocks 里有每块的坐标
    return result.value ?? '';
  } catch (e) {
    const err = e as BusinessError;
    console.error(`OCR failed: ${err.code} ${err.message}`);
    return '';
  }
}

拿到 pixelMap 的方式取决于图片来自哪:相册选图用 photoAccessHelper,相机拍照用 cameraKit 的预览帧,截图用 snapshot。这部分属于常规媒体能力,第 24 篇音视频里讲过类似流程。

识别结果里除了整段文本,通常还有分块信息(每块文本 + 位置坐标)。很多人只用 value,其实块坐标更有用——比如做「拍照翻译」时要按位置排版,做「名片识别」时要靠位置判断哪行是姓名。

💡 OCR 的实际精度高度依赖图片质量。 上线前一定要用真实用户拍的照片测:倾斜、反光、暗光、手写体,这四种情况和你自己截的图完全是两回事。

三、语音与视觉:其他开箱可用的能力

能力所属 Kit典型用途要注意
文字识别Core Vision Kit拍照取字、票据录入、证件识别对倾斜和低光敏感
人脸检测Core Vision Kit活体辅助、贴纸、人像裁剪只给关键点,不做身份识别
条码/二维码Core Vision Kit扫码登录、商品查询要处理模糊和反光
图像分割Core Vision Kit抠图、背景替换边缘处理一般,复杂背景较差
语音识别(ASR)Core Speech Kit语音输入、会议记录长语音要分段,注意静音检测
语音合成(TTS)Core Speech Kit朗读、无障碍情感和停顿不如云端自然
分词 / 实体识别Natural Language Kit关键词提取、地址解析专业领域词容易漏

这张表的用法是:先查表,表里有就别自己造。自己训一个 OCR 模型的成本和效果,几乎不可能打赢系统内置的。

语音识别的一个实际写法要点:它不是「录完再识别」,而是边录边出结果,所以要维护一个「已确认文本 + 临时结果」的状态,否则界面会不停闪回。

语音识别的状态处理

// 伪代码,示意状态管理方式(具体 API 名以官方文档为准)
let confirmed = '';        // 已确认的文本
let partial = '';          // 当前这句的临时结果

onResult((text: string, isLast: boolean) => {
  if (isLast) {
    confirmed += text;
    partial = '';
  } else {
    partial = text;        // 只更新临时区,不动 confirmed
  }
  this.display = confirmed + partial;   // 界面上拼起来显示
});

四、端侧推理:把自己的模型放进 App

当 Kit 里的能力不够用(比如你有自己训练的缺陷检测模型),才需要走到这一层。鸿蒙的端侧推理框架是 MindSpore Lite,支持加载 .ms 模型。

第一步:模型转换

PyTorch / ONNX 的模型不能直接跑,要先转成 .ms。这一步在 PC 上做,不在手机上做:

模型转换

# 大致流程(具体工具链以官方文档为准)
# 1. PyTorch → ONNX
torch.onnx.export(model, dummy_input, "model.onnx", opset_version=12)

# 2. ONNX → MindSpore Lite (.ms)
# 用官方提供的转换工具,注意指定输入 shape 和量化方式
# 量化(int8)能把模型压到 1/4,但精度会掉,要重新测

第二步:在 App 里加载并推理

推理封装

import { mindSporeLite } from '@kit.MindSporeLiteKit';

let model: mindSporeLite.Model | null = null;

async function loadModel(context: common.UIAbilityContext) {
  // 模型放在 resources/rawfile 下,运行时拷到沙箱或用 rawfile 直接读
  const modelBuffer = await context.resourceManager.getRawFileContent('model.ms');
  model = await mindSporeLite.loadModelFromBuffer(modelBuffer.buffer);
}

async function infer(input: Float32Array): Promise<Float32Array> {
  if (!model) throw new Error('model not loaded');

  const inputs = model.getInputs();
  inputs[0].setData(input.buffer as ArrayBuffer);

  const outputs = await model.predict(inputs);
  return new Float32Array(outputs[0].getData());
}

推理代码本身只有二十行,难的是前后处理。图片要先 resize、归一化、转成 NCHW 排布;输出要解码(比如 YOLO 的框要 NMS)。这两段代码往往比推理本身长十倍,而且写错了不会报错,只会「结果不对」。

💡 先用 PC 上同一份前后处理代码跑一遍,把结果存成基准;再在手机上跑,对比数值差异。差得远就是前后处理写错了,而不是模型有问题。这个对比能省掉你两天瞎猜。

第三步:性能调优

手段效果代价
用 NPU 后端常见模型快 3-10 倍算子支持不全,不支持的会回落到 CPU
int8 量化体积降到 1/4,速度提升明显精度下降,要重新评估
减小输入尺寸线性提速小目标检测精度下降
复用 Model 实例省掉加载时间(几百毫秒)要注意并发时的线程安全
⚠️ 不要把模型加载放在页面 aboutToAppear 里同步做。一个大模型加载要几百毫秒到几秒,会直接卡住首屏。 放到 Worker 或异步加载 + 骨架屏。

五、意图框架:不打开 App 也能用你的功能

图 2:意图框架的分发流程——从「用户找你」变成「系统推你」

这是鸿蒙比较独特的一块。简单说:你把「我能做什么」注册给系统,用户在任意界面说一句话,系统识别出意图后直接拉起你的代码执行,用户根本不用打开你的 App。

对用户是少操作几步,对你是多一个免费入口——这是鸿蒙和小艺打通带来的位置。

接入分三步

① 定义意图:在配置文件里声明「我支持创建日程这个意图」,包括参数结构。② 实现执行器:写一个继承 InsightIntentExecutor 的类,实现 onExecute。③ 返回结果:把执行结果组装成卡片返回,让系统直接展示。

意图执行器

// 示意结构(类名和配置字段以官方文档为准)
import { insightIntent } from '@kit.IntentsKit';

export default class CreateNoteExecutor extends insightIntent.InsightIntentExecutor {
  async onExecuteInPage(
    intentName: string,
    param: Record<string, Object>,
    pageLoader: insightIntent.PageLoader,
  ): Promise<insightIntent.ExecuteResult> {
    const title = param['title'] as string;

    // 真实业务:写数据库
    await noteRepo.create({ title, createdAt: Date.now() });

    return {
      code: 0,
      result: { speakText: `已帮你记下:${title}` },
    };
  }
}

三个必须提前想清楚的问题

问题想错的后果
意图边界划多宽太宽会被滥用(什么话都触发你),太窄永远命中不了。要贴着你的核心场景定义
能不能无界面完成如果要求用户再点开 App 确认,那这个入口就废了。设计时必须假设「用户看不到界面」
结果怎么说清返回「详见 App」等于没做。卡片本身要能独立表达结果
⚠️ 意图注册不是想注册什么就注册什么, 要符合平台规范的意图清单,并且审核比普通功能严。开工前先确认你的场景在支持范围内,别做完才发现不能上。

六、四个现实约束

这一段是我认为比 API 更值得看的部分。端侧 AI 的坑,基本都在这里:

约束具体表现应对
设备能力差异大老设备没有 NPU、Kit 不支持、内存不足所有能力都要先 isSupported(),准备降级路径
模型体积一个 50MB 的模型会让安装包翻倍,影响下载转化量化、裁剪、或改成首次使用时下载
耗电与发热连续推理五分钟,手机就烫了,系统会降频控制帧率、避免常驻推理、及时释放
精度不如云端同一个小模型,端侧和云端的差距是肉眼可见的关键场景用云端,端侧做「快速初筛 + 离线兜底」

最后一条尤其要说:端侧 AI 的正确定位不是「替代云端」,而是「在没网、要快、要隐私的场景兜底」。指望它在精度上打赢云端大模型,是不现实的。

七、选型决策表与六个坑

你的情况建议理由
只要识别文字/条码/人脸Core Vision Kit零成本,效果比自己训的好
要语音输入或朗读Core Speech Kit延迟低,离线可用
有自己训的小模型(分类、检测)MindSpore Lite + int8 量化体积可控,端侧可跑
要复杂生成、多轮对话云端 API,端侧只做缓存端侧算力和内存都撑不住
想被系统主动调用意图框架多一个入口,但要审核

六个坑

坑表现怎么破
没做能力检查开发机正常,用户机崩溃所有 Kit 调用前先查支持性
模型放 rawfile 直接读读取慢、内存翻倍首次启动拷到沙箱,之后读文件
主线程推理界面卡住 2 秒放 Worker 或异步,配骨架屏
前后处理与训练不一致结果全错但不报错PC 端先跑基准,数值对齐
忘记释放模型内存持续上涨页面销毁时 model.destroy()
图标/权限没配相机、相册打不开module.json5 里补权限,运行时再申请

这一篇你该记住什么

① 先查 Kit 表,再考虑自己训模型。九成需求在 Kit 层就解决了,成本差一个数量级。

② 端侧 AI 的定位是兜底,不是替代。快、离线、隐私是它的价值,精度不是。

③ 意图框架是鸿蒙少有的「结构性红利」——它能把你的功能送到用户还没打开 App 的那一刻。值得为它单独设计一个场景,而不是把现有功能硬套上去。

下一篇是这个系列里最硬的一篇:Native 开发。讲怎么让 C++ 代码(包括 ffmpeg 这种大型库)真正跑进你的鸿蒙 App,以及那条「找不到 so」的报错到底在说什么。


如果这篇帮你把豆包用出了点效率,点赞 + 收藏 + 关注 支持一下。
你还有哪个场景没跑通?评论区说清楚你的目标 + 现在怎么问的,我帮你改成能用的提示词。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐