鸿蒙操作系统小艺 Skill 开发实战:让应用被 HarmonyOS 7 一句话召唤
·
一、背景说明
HarmonyOS 7 把系统交互从"用户打开 App → 手动操作"推进到"意图即服务":用户只需说出想要的结果,系统级小艺理解意图后自动匹配应用的 Skill 并把服务递上来,全程无跳转。对开发者来说,这意味着应用多了一种被系统直接"召唤"的入口。本文以一个"断食倒计时查询"Skill 为例,完整走通 Skill 的声明、注册、入口脚本与调试全流程,并汇总五个真实联调踩坑点。
二、技术原理
小艺 Skill 的本质是"声明 + 薄封装",不是重写业务逻辑。整体结构只有三样:
- skillProfiles 注册:在
module.json5中声明本应用提供哪些 Skill,包括触发语句(用户可能怎么问)、入口脚本路径与返回方式。小艺基于这些描述做意图匹配。 - SKILL.md 能力描述:用结构化文档向系统描述 Skill 的功能边界、参数与输出格式,小艺的大模型依据它判断"用户这句话归不归你管"。描述要具体,太笼统会匹配不到。
- 入口脚本:Skill 被命中后端侧执行的薄封装层,只做两件事——解析小艺传入的参数、调用应用已有业务层并把结果格式化为自然语言返回。端侧运行,数据不出设备。
调用链路:用户对小艺说话 → 大模型意图匹配(依据 skillProfiles + SKILL.md)→ 端侧执行入口脚本 → 脚本 import 应用业务层取数 → 结果自然语言回传 → 小艺播报。
三、实现步骤
环境要求:DevEco Studio 26.0.0 Release(API 26.0.0),HarmonyOS 7 真机或模拟器。
- 在
module.json5中注册 skillProfiles。注意:skillProfiles放在 module 顶级,不要嵌进extensionAbilities,否则 schema 校验失败:
// entry/src/main/module.json5
{
"module": {
"name": "entry",
"type": "entry",
"ability": [ /* ...原有配置... */ ],
"skillProfiles": [
{
"name": "fasting_timer_query",
"description": "查询用户的断食倒计时:剩余时长、当前所处断食阶段、今日目标完成度",
"entry": "scripts/fasting_query.ets",
"triggerExamples": [
"断食还剩多久",
"我现在断食到哪个阶段了",
"今天的断食目标完成了吗"
]
}
]
}
}
- 编写 SKILL.md 能力描述文件,放在 Skill 目录下,向小艺声明能力边界与 I/O:
# Skill: fasting_timer_query(断食倒计时查询)
## 功能
查询轻食刻应用内的断食计时状态,返回剩余时长与当前阶段。
## 输入参数
- 无必填参数。可选 phaseFilter: string,取值 "all" | "current"。
## 输出格式
自然语言单句,格式:`已断食 X 小时 Y 分钟,距离 16:8 目标还剩 Z 小时 W 分钟。`
## 边界
- 不执行修改操作(开始/结束断食请引导用户打开应用)。
- 数据仅来自本机应用沙箱,无网络请求。
- 实现入口脚本。要点:只做参数解析与结果格式化,直接
import应用已有的服务层,不要在脚本里重写业务逻辑:
// entry/src/main/ets/scripts/fasting_query.ets
import { FastingService } from '../service/FastingService'; // 复用已有业务层
import { hilog } from '@kit.PerformanceAnalysisKit';
const DOMAIN: number = 0x0000;
const TAG: string = 'SkillFastingQuery';
interface SkillResult {
status: string; // "success" | "error"
speechText: string; // 返回给小艺播报的自然语言
}
export async function main(params: Record<string, string>): Promise<SkillResult> {
try {
// 1. 解析参数(本 Skill 无必填参数,容错处理可选过滤项)
const phaseFilter: string = params?.phaseFilter ?? 'all';
// 2. 调用应用已有服务层取数(端侧运行,数据不出设备)
const state = await FastingService.getTimerState();
// 3. 格式化为自然语言返回
const hours: number = Math.floor(state.elapsedMinutes / 60);
const minutes: number = state.elapsedMinutes % 60;
const remainMinutes: number = state.targetMinutes - state.elapsedMinutes;
const speechText = remainMinutes > 0
? `已断食 ${hours} 小时 ${minutes} 分钟,距离 16:8 目标还剩 ` +
`${Math.floor(remainMinutes / 60)} 小时 ${remainMinutes % 60} 分钟。`
: '恭喜,本轮 16:8 断食目标已达成。';
hilog.info(DOMAIN, TAG, 'query ok, filter=%{public}s', phaseFilter);
return { status: 'success', speechText: speechText };
} catch (err) {
hilog.error(DOMAIN, TAG, 'query failed: %{public}s', (err as Error).message);
return { status: 'error', speechText: '断食数据读取失败,请打开轻食刻查看详情。' };
}
}
- 被调用的业务层保持原样(示例):
// entry/src/main/ets/service/FastingService.ets
export class TimerState {
elapsedMinutes: number = 0;
targetMinutes: number = 16 * 60;
}
export class FastingService {
static async getTimerState(): Promise<TimerState> {
// 实际实现:从偏好库读取断食开始时间并计算
// const store = preferences.getPreferencesSync(context, { name: 'fasting' });
// ...
const state = new TimerState();
state.elapsedMinutes = 11 * 60 + 25;
return state;
}
}
四、运行效果说明
真机上长按电源/侧键或对小艺说出触发语句:
- 用户说"断食还剩多久"→ 小艺识别意图并命中
fasting_timer_query; - 端侧执行
fasting_query.ets,返回"已断食 11 小时 25 分钟,距离 16:8 目标还剩 4 小时 35 分钟。"; - 小艺直接播报结果,全程无跳转、无界面拉起;
- 若 Skill 未注册或描述不匹配,小艺会走通用回答,说明配置未生效。
五、技术要点
- skillProfiles 层级:必须放在 module 顶级,嵌进
extensionAbilities会 schema 校验失败,这是最常见的注册报错。 - description 决定命中率:大模型按 description 匹配意图,写"查询断食相关信息"这种笼统描述经常匹配不到;应写成"查询剩余时长、当前阶段、目标完成度"这类动词+宾语明确的句子,并配合
triggerExamples给出真实问法。 - 脚本不写业务逻辑:入口脚本重写业务逻辑会导致双份数据源不一致;正确姿势是 import 已有服务层,脚本只做参数解析和结果格式化。
- 忘记注册 module.json5:只写 SKILL.md 不注册 skillProfiles,小艺完全不认识你的 Skill,调试时先确认注册是否生效。
- SKILL.md 长度限制:超长超限会被驳回,保持"功能/输入/输出/边界"四段式精简描述即可。
六、扩展建议
- 多 Skill 组合:一个应用可声明多个 skillProfiles(查询、开始断食、补记录各一个),每个 Skill 独立入口脚本,共享同一个服务层。
- 参数化触发:在 description 与入口脚本中支持槽位参数(如"断食还剩多久"扩展为"距 18:6 目标还剩多久"),通过 params 传入,提升自然语言覆盖率。
- 与实况窗联动:断食进行中可用 Live View Kit 挂一个计时实况窗(参见笔者上一篇实况窗开发文章),语音查询与卡片展示互补。
结语
本文用约 80 行代码完成了一个小艺 Skill 的完整接入:module.json5 注册、SKILL.md 描述、入口脚本三件套,并汇总了层级、描述、业务复用等五个真实踩坑点。HarmonyOS 7 时代,"被小艺一句话召唤"正在成为应用的第二入口,建议有明确查询/操作型服务的应用尽早接入,抢占意图匹配的心智。
更多推荐
所有评论(0)