HarmonyOS AI 能力接入:端侧识别、端侧推理与意图框架
📱 鸿蒙 HarmonyOS 全栈专栏 · 第 31 篇 / 共 34 篇(第 4 季)
上一篇:第 30 篇 实战项目三 | 下一篇:Native 开发:让 C++ 真正跑进你的 App
目录
这是第 4 季的第一篇,接的是第 30 篇结尾那个投票里的第 4 个方向:AI 能力接入,端侧模型与智能体。
先说一个常见误解:很多人以为「鸿蒙的 AI」就是要自己训模型、自己搞推理框架。实际上华为已经把大量能力封装成了 Kit,文字识别、人脸、条码、语音转文字,几行代码就能用。真正需要自己带模型的场景,比你想象的少得多。
这篇按「四层」往下走:什么时候只用 Kit、什么时候要自己加载模型、以及怎么让系统的意图框架把你的功能推给用户。
📖 本篇导读
全文约 13 分钟。所有 API 以 API 12+ 为基准,具体签名请对照你所用版本的官方文档。
- 端侧 AI 的四层:你实际在写哪一层
- Kit 层:文字识别三行代码跑起来
- 语音与视觉:其他开箱可用的能力
- 端侧推理:把自己的模型放进 App
- 意图框架:不打开 App 也能用你的功能
- 四个现实约束(这段比 API 更重要)
- 选型决策表与六个坑
一、端侧 AI 的四层

图 1:端侧 AI 的四层结构,大多数人只需要用最上面一层
把这张图记住,能省掉很多无用功。判断标准很简单:
| 你的需求 | 用哪层 | 工作量 |
|---|---|---|
| 识别图片里的文字、识别条码、检测人脸 | Kit 层 | 半天 |
| 语音转文字、文本转语音 | Kit 层 | 半天 |
| 图像分割、主体抠图 | Kit 层 | 1 天 |
| 自己训练的分类/检测模型要跑在手机上 | 推理引擎层 | 1-2 周 |
| 要做实时视频处理、算法必须自己写 | 推理引擎 + Native | 1 个月起 |
⚠️ 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」的报错到底在说什么。
如果这篇帮你把豆包用出了点效率,点赞 + 收藏 + 关注 支持一下。
你还有哪个场景没跑通?评论区说清楚你的目标 + 现在怎么问的,我帮你改成能用的提示词。
更多推荐

所有评论(0)