从 App 到 Agent:HarmonyOS 7 应用能力重构实战——以 HMAF 2.0 Skill 化接入为主线
从 App 到 Agent:HarmonyOS 7 应用能力重构实战——以 HMAF 2.0 Skill 化接入为主线
摘要:HarmonyOS 7(API 26)把操作系统的底层逻辑从“App 亲和”推向了“Agent 亲和”。对开发者来说,最直接的变化不是 UI 写法,而是应用能力的组织方式:页面方法需要被拆成可被编排、可被调度的 Skill,业务逻辑需要从“按钮触发”升级为“意图触发”。本文以一个“天气查询”能力为例,完整走一遍从能力拆分、Skill 定义、HMAF 2.0 注册到本地验证的路径,并结合 FAST Kit 给出配套的性能兜底策略。
一、先看清变化:Agent 亲和到底改了哪一层
HarmonyOS 7 的 HMAF 2.0 带来了 90%+ 的复杂任务成功率,开放 20+ AI 能力,首次释放 GUI 操控权限,应用可以 Skill 化,被系统智能体按需调度。系统级智能体小艺不再是被动响应指令的语音助手,而是具备意图理解、服务编排、跨任务流转能力的系统大脑。
但这不意味着每个应用都要“做一个 Agent”。官方给出的建议路径很务实:从意图开始 → 升级为 Skill → 最终构建 Agent,不要一上来就做 Agent。
对大多数应用,第一阶段的目标可以收窄为:把已有的一项核心能力封装成一个可被 HMAF 调度的 Skill。这件事的工程成本可控,收益却直接——应用从“用户必须打开图标才能使用”变成“用户说出需求即可被系统调度”。
这一步的核心难点不在 API 调用,而在能力拆分。页面上一个“查询天气”的按钮背后,通常混着路由跳转、Toast 提示、页面状态读取、网络请求和结果渲染。这种“被按钮调用”的方法,直接注册成 Skill 是无法被编排器稳定调度的。需要先把“业务能力”从“页面行为”中剥出来。
二、能力拆分:把页面方法变成可编排单元
以天气查询为例。原始代码大概率长这样:一个页面方法,读取 @State city,调用网络接口,把结果赋值给 @State weatherText,同时可能顺手弹一个 Toast。这段代码能在按钮点击时正常工作,但一旦被 Skill 调用,就会暴露出三个问题:
- 输入不显式:Skill 框架不知道需要哪些参数、哪些必填;
- 副作用混入:Toast、路由跳转属于页面行为,Skill 执行过程中不应触发 UI 重放;
- 返回非结构化:编排器需要的是可判定的
ok / errorCode,而不是一句拼好的文案。
拆分后的 Skill 执行入口应该只做三件事:接收显式参数、调用业务逻辑、返回结构化结果。页面侧的 Toast、跳转、加载态留在调用方(页面或编排器)处理。下面直接进入 HMAF 2.0 的接入流程。
三、HMAF 2.0 Skill 接入:以“天气查询”为例
3.1 工程基线
HMAF 2.0 要求 Stage 模型,编译 SDK 为 API 23(HarmonyOS 7.0)及以上。在 oh-package.json5 中添加依赖:
"dependencies": {
"@kit.AgentKit": "2.0.0"
}
如果 Skill 只需要在应用内被私有 Agent 调用,不对外暴露给小艺,模式 1 即可满足,不需要在 AGC 或小艺开放平台做额外声明。本文按模式 1 走通最小闭环。
3.2 Skill 的定义方式
HMAF 2.0 提供了两种 Skill 注册方式:本地 Skill 类和动态 SkillSchema。前者适合逻辑稳定、需要复用已有业务代码的能力;后者适合快速试验。天气查询的输入输出明确,适合用 Skill 类来写。
核心是 describe 和 execute 两个契约。describe 告诉 HMAF“这个 Skill 能做什么、需要什么参数”,execute 承载真正的业务逻辑。下面是一个最小可用的示意:
import { Skill, SkillContext, SkillSchema } from '@kit.AgentKit';
export class WeatherQuerySkill extends Skill {
describe(): SkillSchema {
return {
name: 'queryWeather',
description: '根据城市名称查询当前天气',
parameters: [
{
name: 'city',
type: 'string',
description: '城市名称,如“深圳”“北京”',
required: true
}
],
examples: ['深圳天气怎么样', '帮我查一下北京天气']
};
}
async execute(
input: { city: string },
context: SkillContext
): Promise<{ ok: boolean; data?: { city: string; condition: string; temperature: string }; errorCode?: string }> {
if (!input.city) {
return { ok: false, errorCode: 'MISSING_CITY' };
}
// 这里替换为应用已有的天气数据获取逻辑
const weather = await this.weatherRepository.fetchByCity(input.city);
if (!weather) {
return { ok: false, errorCode: 'NO_DATA' };
}
return {
ok: true,
data: {
city: weather.city,
condition: weather.condition,
temperature: weather.temperature
}
};
}
}
这段代码的关键不在语法,而在输入输出都是显式契约。HMAF 2.0 的编排器依赖 describe 中的参数声明来做意图匹配和参数填充,依赖 execute 的 ok / errorCode 来决定重试、阻断还是降级。context 参数可以用于取消检查、幂等键等编排场景,在首版 Skill 中可以先不深度使用,但接口位置需要预留。
3.3 把 Skill 注册到 Agent
Skill 本身不会自动进入 HMAF 的调度视野,需要通过一个 Agent 实例来注册。创建一个轻量的应用内私有 Agent:
import { Agent, AgentConfig } from '@kit.AgentKit';
export class WeatherAgent extends Agent {
onCreate(config: AgentConfig): void {
this.registerSkills([new WeatherQuerySkill()]);
}
onRegister(): void {
console.info('WeatherAgent registered to HMAF');
}
}
如果只需要应用内调用,到这里代码侧的接入已经足够。如果希望该 Agent 能被小艺或其他应用通过 A2A 跨应用调度,还需要在 module.json5 中声明 ohos.hmaf.agent 元数据并配置 agent_config.json,同时在 requestPermissions 中加入 ohos.permission.AGENT_SKILL。首版验证建议先停在模式 1,把 Skill 的输入输出跑通、稳定之后,再打开 A2A 开关。
3.4 本地验证:不要跳过“结构化返回”的检查
Skill 注册成功后,在 DevEco Studio 中可以通过 Agent 调试入口直接传入参数调用 execute。验证的重点不是“结果对不对”,而是返回结构是否始终可判定:缺参数时是否返回明确的 errorCode,网络异常时是否被吞成一句文案,执行过程中是否有意外的 UI 副作用。HMAF 2.0 的高任务成功率建立在 Skill 返回的可判定性之上,一个在成功路径上返回对象、在失败路径上返回 undefined 的 Skill,会让编排器无法做出正确的重试决策。
四、性能兜底:FAST Kit 在 Agent 链路中的位置
Skill 化解决的是“能力能不能被调度”的问题,但被调度之后的执行效率同样影响用户体验。HarmonyOS 7 的 FAST Kit 在这一层提供了系统级的算法加速能力,开发者无需自研底层实现,一步调用即可生效。
对天气查询 Skill 来说,最直接的关联场景是城市列表或历史查询记录的排序。传统字符编码排序在中文城市名场景下并不符合用户直觉,也会成为长列表加载的卡点。FAST Kit 的高效自然语言排序在热点列表场景相比基线三方库性能提升 60%~70%,并且能正确处理数字序列(如 file1, file2, file10 而非 file1, file10, file2)。如果 Skill 内部需要维护一个城市候选列表或缓存索引,这一步替换的收益是立竿见影的。
另一个容易被忽略的点是数据结构。如果 Skill 需要在高频调用中管理会话缓存或城市到天气对象的映射,FAST Kit 的高性能哈希表在单线程场景下对比 std::unordered_map 有 30%~80% 的性能提升;多线程并发场景下,并发哈希表的吞吐量提升约 8~10 倍。这不是要求每个 Skill 都去换数据结构,而是在 Skill 的 execute 被高频调度、且内部存在明显的 key/value 查找热点时,FAST Kit 提供了一个不需要自研底层的加速选项。
五、回到工程:建议的推进顺序
如果正在一个已有应用上尝试 HarmonyOS 7 的 Agent 化改造,比较稳妥的顺序是:
第一步,选一个“输入输出天然清晰”的能力做 Skill。 天气查询、快递追踪、单一维度的状态查询,都比“下单”“编辑内容”这类带有复杂交互和副作用的操作更适合作为第一个 Skill。先跑通 describe → execute → 注册 → 调试 的闭环,比先搭一个空 Agent 更有参考价值。
第二步,把页面副作用清零。 检查 execute 内部是否还有 Toast、路由跳转、@State 写入。这些逻辑应当上移到页面或编排层,Skill 只返回结构化结果。这一步做不干净,后面的 A2A 和跨应用调度都会在重试场景下暴露问题。
第三步,再考虑 A2A 和对外暴露。 模式 1 的应用内私有 Agent 是成本最低的验证形态。确认 Skill 在多次调用、缺参数、网络失败等路径下的返回都稳定之后,再打开 exposeA2A 并处理权限声明。HarmonyOS 7 的 Agent 亲和架构已经为系统级调度提供了原生支持,但对外暴露带来的契约稳定性要求,需要在私有模式下先被验证过。
HarmonyOS 7 的 Agent 化不是一次“重写应用”的运动,而是一次能力表达方式的迁移。把已有业务逻辑中那些输入输出清晰、副作用可控的部分先 Skill 化,让它们进入系统可调度的视野,是当前阶段成本最低、反馈最快的切入点。FAST Kit 则在这个迁移过程中提供了一个不需要改动架构就能拿到的性能底座。两者叠加,构成一条从“被按钮调用”到“被意图调度”的渐进路径。
- 点赞
- 收藏
- 关注作者
评论(0)