重庆华鸿科技 · 鸿蒙实战特训 | 让每个应用都成为系统智能体的“能力外挂”
从“人找App”到“能力找人”
传统的App开发模式,用户与应用的互动路径是这样的:
解锁手机 → 找到图标 → 点击打开 → 在层层菜单中寻找功能 → 完成操作
每一步都是限定的流程,必须一步一步来,走完才能到下一步。
就拿办公场景来说——你想发一封邮件给产品团队,同步下周的评审时间。操作路径是什么?打开邮箱App → 点击写邮件 → 输入收件人 → 输入主题 → 输入正文 → 点击发送。整整六步,一步不能少。
整个过程中,App是被动的。它不会主动响应,不会理解你的意图,只会在被点开后机械地执行指令。
这种模式该翻篇了。
现在你只需要对手机说一句“给产品团队发封邮件,同步下周二的评审时间”,系统智能体直接调起邮箱App的写邮件能力,自动填入收件人、主题和正文,你只需确认发送。
不需要打开App,不需要逐项填写,不需要记住抄送谁。
从“人找功能”到“功能找人”——这是鸿蒙 API Version 26.0.0 引入的 应用Skill 能力带来的转变。它让应用从“被用户操作的工具”,进化为“被系统智能体调用的能力单元”。
一、Skill是什么?能做什么?
Skill 提供一种声明式的能力外化机制。开发者将应用内可被外部调用的业务能力,组织为若干能力单元。每个单元由一份描述文件(声明触发场景、入参约束与返回值契约)和一份 ArkTS 入口脚本(将外部调用桥接到应用内既有业务)共同构成,通过模块配置绑定到指定 Ability。
运行时,系统智能体依据描述文件完成“意图—能力”的语义匹配,并将结果转化为面向用户的自然语言回复。
核心价值:
能力说明意图驱动用户自然语言 → 系统智能体语义理解 → 调用应用能力声明式接入一份SKILL.md描述文件 + 一个ArkTS入口脚本,即可开放能力零业务侵入入口脚本仅做“参数适配”,不改造既有业务代码统一契约系统智能体无需理解各应用内部实现,依赖统一契约完成调度
典型场景:
- 邮箱App:“给产品团队发一封下周评审会的通知邮件”
- 日历App:“把周三下午三点的会改到周四上午”
- 会议App:“发起一个和客户的技术方案评审会”
- 审批App:“帮我查一下报销审批到哪一步了”
二、鸿蒙Skill开发要求
要接入应用Skill,工程必须满足以下条件:
项目要求API版本targetAPIVersion ≥ 26.0.0应用模型仅支持Stage模型,FA模型不可用配置文件必须在module.json5中配置skillProfiles
目录结构是固定的。skills/ 是当前模块所有 Skill 的根目录,每个 Skill 以独立子目录组织:
text
skills/{Skill名}/scripts/ ← 入口脚本放这里
skills/{Skill名}/SKILL.md ← 契约描述文件
方法名必须和 SKILL.md 里的 functionName 完全一致。入口脚本的第一个参数固定是 scriptManager.ArkTSScriptInfo。执行结果必须通过 completeArkTSScriptInApp 回传。
三、完整实战:邮件助手Skill
以“发送邮件(sendEmail)”和“查询邮件(queryEmail)”为例。
Step 1:创建目录结构
text
entry/
├── skills/
│ └── email-assistant/
│ ├── scripts/
│ │ └── EmailSkill.ets
│ └── SKILL.md
└── src/main/ets/
├── entryability/
│ └── EntryAbility.ets
└── service/
└── EmailManager.ets
Step 2:配置 module.json5
json
{
"module": {
"skillProfiles": [
{
"name": "email-assistant",
"abilityName": "EntryAbility",
"srcEntries": [
"../../skills/email-assistant/scripts/EmailSkill.ets"
]
}
]
}
}
如果 Skill 需要网络权限(如调用云端邮件服务),在 module.json5 中配置:
json
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" }
]
Step 3:实现入口脚本(EmailSkill.ets)
typescript
import { scriptManager } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { EmailManager } from '../../../src/main/ets/service/EmailManager';
export default class EmailSkill {
// 能力1:发送邮件
public async sendEmail(info: scriptManager.ArkTSScriptInfo, ...argv: string[]): Promise<void> {
const recipient: string = argv.length > 0 ? argv[0].trim() : '';
const subject: string = argv.length > 1 ? argv[1].trim() : '';
const body: string = argv.length > 2 ? argv[2].trim() : '';
if (recipient.length === 0 || subject.length === 0) {
await this.report(info, {
code: -1,
result: {
type: 'result',
status: 'failed',
errCode: 'ERR_INVALID_PARAMS',
errMsg: 'recipient and subject are required',
suggestion: '请指定收件人和邮件主题'
}
});
return;
}
try {
const result = await EmailManager.send({ to: recipient, subject, body });
await this.report(info, {
code: 0,
result: {
type: 'result',
status: 'success',
data: { messageId: result.id, status: 'sent' }
}
});
} catch (error) {
await this.report(info, {
code: -1,
result: {
type: 'result',
status: 'failed',
errCode: 'ERR_INTERNAL',
errMsg: (error as Error).message,
suggestion: '邮件发送失败,请检查网络'
}
});
}
}
// 能力2:查询邮件
public async queryEmail(info: scriptManager.ArkTSScriptInfo, ...argv: string[]): Promise<void> {
const keyword: string = argv.length > 0 ? argv[0].trim() : '';
if (keyword.length === 0) {
await this.report(info, {
code: -1,
result: {
type: 'result',
status: 'failed',
errCode: 'ERR_INVALID_PARAMS',
errMsg: 'keyword is empty',
suggestion: '请输入搜索关键词'
}
});
return;
}
try {
const emails = await EmailManager.search(keyword);
await this.report(info, {
code: 0,
result: {
type: 'result',
status: 'success',
data: {
emails: emails.map(e => ({ from: e.from, subject: e.subject, time: e.time })),
total: emails.length
}
}
});
} catch (error) {
await this.report(info, {
code: -1,
result: {
type: 'result',
status: 'failed',
errCode: 'ERR_INTERNAL',
errMsg: (error as Error).message,
suggestion: '查询失败,请稍后重试'
}
});
}
}
// 统一回包出口
private async report(info: scriptManager.ArkTSScriptInfo, result: scriptManager.ExecuteResult): Promise<void> {
try {
await scriptManager.completeArkTSScriptInApp(info.context, info.requestCode, result);
} catch (e) {
const err = e as BusinessError;
console.error(`completeArkTSScriptInApp failed, code: ${err.code}, message: ${err.message}`);
}
}
}
Step 4:编写 SKILL.md
4.1 元数据(YAML Front Matter)
yaml
--- name: email-assistant description: 提供邮件发送与查询能力,响应"发邮件"、"查邮件"等办公指令 ---
4.2 触发场景
text
## 触发场景 当用户明确表达发送邮件或查询邮件时调用。典型话术: - "给产品团队发一封邮件,同步下周的评审时间" - "给张经理发邮件,附上这份文档" - "查一下上周李总监发的邮件" - "找一下关于预算审批的邮件" 不调用的情况: - 用户说"帮我写一封投诉信"——写作任务,非发送能力 - 用户说"删除收件箱里所有广告邮件"——管理操作,超出能力范围
4.3 执行参数契约
markdown
### 场景1:发送邮件(sendEmail)
**执行参数:**
exec-cli(command: ohos-arkTSScript --skillName 'email-assistant' --scriptPath 'scripts/EmailSkill.ets' --functionName 'sendEmail' --args '{
"arg1": "产品团队",
"arg2": "下周评审会通知",
"arg3": "定在下周二下午三点"
}')
**参数Schema:**
```json
{
"type": "object",
"properties": {
"arg1": { "type": "string", "description": "收件人" },
"arg2": { "type": "string", "description": "邮件主题" },
"arg3": { "type": "string", "description": "邮件正文" }
},
"required": ["arg1", "arg2"]
}
```
4.4 执行返回值契约(完整版)
必须逐一列出所有可能的结果分支:成功 + 各类失败。
text
**执行返回值:**
// 1. 成功
{
"type": "result",
"status": "success",
"data": {
"messageId": "msg_20260618_001",
"status": "sent"
}
}
// 2. 入参非法
{
"type": "result",
"status": "failed",
"errCode": "ERR_INVALID_PARAMS",
"errMsg": "recipient and subject are required",
"suggestion": "请指定收件人和邮件主题"
}
// 3. 内部错误
{
"type": "result",
"status": "failed",
"errCode": "ERR_INTERNAL",
"errMsg": "network timeout",
"suggestion": "邮件发送失败,请检查网络"
}
对应的 JSON Schema:
json
{
"type": "object",
"required": ["type", "status"],
"properties": {
"type": { "type": "string", "const": "result" },
"status": { "type": "string", "enum": ["success", "failed"] },
"data": { "type": "object" },
"errCode": {
"type": "string",
"enum": ["ERR_INVALID_PARAMS", "ERR_INTERNAL"]
},
"errMsg": { "type": "string", "minLength": 1 },
"suggestion": { "type": "string", "minLength": 1 }
},
"oneOf": [
{ "required": ["data"] },
{ "required": ["errCode", "errMsg", "suggestion"] }
]
}
四、关键点总结
关键点说明薄适配层Skill脚本只做参数适配与结果回传,不承载业务逻辑强契约入参、出参必须与SKILL.md的Schema严格一致统一回包必须通过completeArkTSScriptInApp回传结果方法名强一致functionName必须与脚本中的方法名完全相同目录结构固定skills/{Skill名}/scripts/ + SKILL.md
🚀 来重庆华鸿科技,系统掌握鸿蒙开发
应用Skill只是鸿蒙能力树的冰山一角。要真正驾驭鸿蒙应用开发,你需要掌握:
- ArkTS语言与ArkUI声明式UI
- Stage模型与Ability生命周期
- Skill开发、元服务、跨设备协同
- 沉浸光感、空间动效等视觉能力
重庆华鸿科技 深耕鸿蒙生态人才培养,推出 《鸿蒙应用开发实战特训营》 ,由华为官方认证讲师授课,手把手带您从零构建商业级鸿蒙应用。
课程亮点:
- 真实项目驱动:以办公、社交、工具类App为案例,完整实现Skill、元服务等核心特性
- 小班精讲:每位学员获得针对性指导
- 就业直推:合作企业覆盖西南地区鸿蒙生态链,优秀学员直接内推
👉 立即报名,抢占限量试学名额!https://www.huahongkeji.cn/
结语
应用Skill让鸿蒙的智能渗透到每一个应用的能力末梢。当你的应用可以被听懂、被主动调用,用户体验将迎来质的飞跃。
华鸿技术栈 将持续带来鸿蒙一线技术解读,欢迎关注、转发、在看。
*本文技术内容基于 HarmonyOS API Version 26.0.0 官方文档《基于ArkTS脚本的应用Skill开发指导》(2026-06-13)整理。*
重庆华鸿科技 · 鸿蒙培训专家 | 让每个开发者都成为鸿蒙先锋