技术分享

鸿蒙NEXT“应用Skill”到来!让App能力被系统智能体“主动调用”——附3分钟接入实战

重庆华鸿科技 · 鸿蒙实战特训 | 让每个应用都成为系统智能体的“能力外挂”

从“人找App”到“能力找人”

传统的App开发模式,用户与应用的互动路径是这样的:

解锁手机 → 找到图标 → 点击打开 → 在层层菜单中寻找功能 → 完成操作

每一步都是限定的流程,必须一步一步来,走完才能到下一步。

就拿办公场景来说——你想发一封邮件给产品团队,同步下周的评审时间。操作路径是什么?打开邮箱App → 点击写邮件 → 输入收件人 → 输入主题 → 输入正文 → 点击发送。整整六步,一步不能少。

整个过程中,App是被动的。它不会主动响应,不会理解你的意图,只会在被点开后机械地执行指令。

这种模式该翻篇了。

现在你只需要对手机说一句“给产品团队发封邮件,同步下周二的评审时间”,系统智能体直接调起邮箱App的写邮件能力,自动填入收件人、主题和正文,你只需确认发送。

不需要打开App,不需要逐项填写,不需要记住抄送谁。

从“人找功能”到“功能找人”——这是鸿蒙 API Version 26.0.0 引入的 应用Skill 能力带来的转变。它让应用从“被用户操作的工具”,进化为“被系统智能体调用的能力单元”。

一、Skill是什么?能做什么?

Skill 提供一种声明式的能力外化机制。开发者将应用内可被外部调用的业务能力,组织为若干能力单元。每个单元由一份描述文件(声明触发场景、入参约束与返回值契约)和一份 ArkTS 入口脚本(将外部调用桥接到应用内既有业务)共同构成,通过模块配置绑定到指定 Ability。

运行时,系统智能体依据描述文件完成“意图—能力”的语义匹配,并将结果转化为面向用户的自然语言回复。

核心价值:


能力说明意图驱动用户自然语言 → 系统智能体语义理解 → 调用应用能力声明式接入一份SKILL.md描述文件 + 一个ArkTS入口脚本,即可开放能力零业务侵入入口脚本仅做“参数适配”,不改造既有业务代码统一契约系统智能体无需理解各应用内部实现,依赖统一契约完成调度

典型场景:

二、鸿蒙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只是鸿蒙能力树的冰山一角。要真正驾驭鸿蒙应用开发,你需要掌握:

重庆华鸿科技 深耕鸿蒙生态人才培养,推出 《鸿蒙应用开发实战特训营》 ,由华为官方认证讲师授课,手把手带您从零构建商业级鸿蒙应用。

课程亮点:

👉 立即报名,抢占限量试学名额!https://www.huahongkeji.cn/

结语

应用Skill让鸿蒙的智能渗透到每一个应用的能力末梢。当你的应用可以被听懂、被主动调用,用户体验将迎来质的飞跃。

华鸿技术栈 将持续带来鸿蒙一线技术解读,欢迎关注、转发、在看。

*本文技术内容基于 HarmonyOS API Version 26.0.0 官方文档《基于ArkTS脚本的应用Skill开发指导》(2026-06-13)整理。*

重庆华鸿科技 · 鸿蒙培训专家 | 让每个开发者都成为鸿蒙先锋