HarmonyOS7 的 Agent 到底怎么跑?HMAF 架构一次讲明白
文章目录
前言
上篇我们把项目的模块架构搭好了,这篇来啃一个硬骨头——HMAF。
说实话,我第一次看 HMAF 的官方文档时有点懵。概念多,层次深,跟以前写 UIAbility 的思路完全不一样。花了几天时间把 Demo 跑通之后才算真正理解。今天试着把这些概念掰开了讲清楚。
HMAF 是什么
HMAF 全称 HarmonyOS Multi-Agent Framework,翻译过来就是鸿蒙多智能体框架。
一句话概括:它让你可以在鸿蒙应用里创建和管理多个 Agent(智能体),每个 Agent 有自己的 Skill(技能),Agent 之间还能通过 A2A 协议互相通信。
你可以把它想象成一个"智能体管理平台"。传统 App 是用户点按钮触发逻辑,而基于 HMAF 的 App 可以主动感知用户意图,调度合适的 Agent 去执行任务。
核心概念:Agent 和 Skill
HMAF 里最核心的两个概念就是 Agent 和 Skill,搞清楚它俩的关系,后面的东西就好理解了。
Agent(智能体) 是一个能自主决策的实体。它接收请求,判断该用哪个 Skill 处理,然后执行并返回结果。Agent 不一定要有界面,它可以纯后台运行。
Skill(技能) 是 Agent 的能力单元。一个 Agent 可以有多个 Skill,每个 Skill 负责一件具体的事。
打个比方:Agent 是你雇的一个助理,Skill 是这个助理会的具体技能——订机票、查天气、安排日程。你跟助理说"帮我看看明天北京的天气",助理匹配到"天气查询"这个 Skill,执行完把结果告诉你。
一个 Agent 和多个 Skill 的关系就像这样:
SmartLifeAgent(生活助手智能体)
├── WeatherSkill(天气查询)
├── CalendarSkill(日程管理)
├── DeviceControlSkill(设备控制)
└── NewsSkill(资讯播报)
Agent 的生命周期
Agent 从生到死经历四个阶段,每个阶段都有对应的回调方法:
创建 (onCreate) → 注册 (onRegister) → 运行 (onInvoke) → 销毁 (onDestroy)
创建阶段,Agent 实例被创建出来。这时候做一些初始化工作,比如加载配置、注册 Skill 列表。但 Agent 还不能接收外部请求。
注册阶段,Agent 向 HMAF 框架注册自己。注册成功后,系统就知道有这个 Agent 了,可以把对应的请求路由过来。
运行阶段,Agent 开始接收请求。每次请求进来都会触发 onInvoke 回调,Agent 在里面做 Skill 匹配和执行。
销毁阶段,Agent 被回收。释放资源,注销回调,清理干净。
用代码来看更直观:
import { Agent, AgentConfig, SkillContext, AgentRequest, AgentResponse } from '@kit.AgentKit'
export class SmartLifeAgent extends Agent {
// 创建阶段:初始化
onCreate(config: AgentConfig): void {
console.info('SmartLifeAgent 正在创建...')
this.registerSkills([
new WeatherSkill(),
new CalendarSkill()
])
}
// 注册阶段:向系统报到
onRegister(): void {
console.info('SmartLifeAgent 注册成功,等待调用')
}
// 运行阶段:核心处理逻辑
async onInvoke(request: AgentRequest): Promise<AgentResponse> {
console.info(`收到请求: ${request.intent}`)
// 根据意图匹配合适的 Skill
const skill = this.matchSkill(request.intent)
if (!skill) {
return AgentResponse.error('抱歉,我不太理解你的意思')
}
// 执行 Skill 并返回结果
const context: SkillContext = {
agentId: this.getId(),
requestId: request.id,
params: request.params
}
const result = await skill.execute(context)
return AgentResponse.success(result)
}
// 销毁阶段:清理
onDestroy(): void {
console.info('SmartLifeAgent 已销毁')
this.unregisterAllSkills()
}
}
跟 UIAbility 有什么不同
很多人会问:Agent 跟 UIAbility 到底啥区别?我用 UIAbility 不也能后台处理任务吗?
这个问题我当初也纠结过,后来发现两者的定位完全不同:
| 维度 | UIAbility | Agent (HMAF) |
|---|---|---|
| 核心定位 | 管理 UI 界面 | 管理智能体能力 |
| 生命周期 | onCreate → onStart → onForeground → onBackground → onDestroy | onCreate → onRegister → onInvoke → onDestroy |
| 触发方式 | 用户操作触发(点击、跳转) | 系统/其他 Agent 调用触发 |
| 界面 | 必须有 WindowStage | 不需要界面 |
| 运行环境 | 前台为主 | 后台为主 |
| 通信方式 | Want 跳转 | A2A 协议 |
| 多实例管理 | 系统按需创建 | Agent 池统一管理 |
一个关键区别:UIAbility 是被动的,用户点了才有反应。Agent 可以是被动的也可以是主动的,它可以被系统调度,也可以被其他 Agent 通过 A2A 协议唤醒。
比如用户对着手机说"明天天气怎么样然后帮我加个日程",系统可以把这个请求拆成两部分:天气 Agent 处理天气查询,然后把结果传给日程 Agent 让它创建日程。两个 Agent 通过 A2A 协作完成,全程不需要打开任何界面。
在 module.json5 里声明 Agent
Agent 的配置跟 UIAbility 的 abilities 是平级的,都写在 module.json5 里:
// agent/src/main/module.json5
{
"module": {
"name": "agent",
"type": "har",
"agents": [
{
"name": "SmartLifeAgent",
"srcEntry": "./ets/SmartLifeAgent.ets",
"description": "$string:agent_desc",
"skills": [
{
"name": "weather_query",
"description": "查询指定城市的天气信息",
"parameters": {
"location": {
"type": "string",
"description": "城市名称",
"required": true
},
"date": {
"type": "string",
"description": "日期,默认今天",
"required": false
}
}
},
{
"name": "calendar_manage",
"description": "创建或查询日程",
"parameters": {
"action": {
"type": "string",
"description": "操作类型:create 或 query",
"required": true
},
"title": {
"type": "string",
"description": "日程标题",
"required": false
}
}
}
],
"systemEntry": {
"voiceCommands": [
"查天气",
"今天天气怎么样",
"帮我安排日程"
],
"textPatterns": [
".*天气.*",
".*日程.*"
]
}
}
]
}
}
几个关键字段说一下:
srcEntry指向 Agent 的入口文件skills数组定义了这个 Agent 拥有的所有 SkillsystemEntry告诉系统什么时候该路由到这个 Agent,包括语音命令和文本匹配模式
A2A 协议:Agent 之间的通信
HMAF 不光管单个 Agent,还管 Agent 之间的协作。A2A(Agent-to-Agent)协议就是干这个的。
假设我们的天气 Agent 查完天气后,想自动通知日程 Agent “明天有雨,建议把户外活动改到室内”,可以这样写:
import { A2AClient, AgentMessage } from '@kit.AgentKit'
// 在 WeatherSkill 执行完之后
async function notifyCalendarAgent(weatherResult: WeatherResult): Promise<void> {
const a2aClient = new A2AClient()
const message: AgentMessage = {
fromAgentId: 'smart_life_agent',
toAgentId: 'calendar_agent',
action: 'suggest_reschedule',
payload: {
reason: `明天${weatherResult.condition}`,
suggestion: weatherResult.condition.includes('雨')
? '建议将户外活动改为室内'
: '天气不错,可以安排户外活动',
date: weatherResult.date
}
}
await a2aClient.send(message)
}
A2A 的通信是异步的,发送方不等接收方处理完就继续执行。这跟传统的函数调用不一样,更像是发消息。
写在后面
HMAF 的门槛确实比 UIAbility 高一些。概念多了,Agent、Skill、A2A 这些东西要一起理解才行。
我自己的经验是:不要一上来就在代码层面理解,先在脑子里建一个"助理 + 技能"的模型。Agent 就是你的助理,Skill 就是助理会的本事,A2A 就是助理之间传话。这个模型建立起来之后,再看代码就容易多了。
另外有个建议:不是所有功能都得做成 Agent。纯 UI 交互的东西,老老实实用 UIAbility 就好。Agent 更适合那些"需要理解意图、做决策、可以后台执行"的场景。别为了用新特性而用新特性,把事情搞复杂了反而不美。
下一篇我们动手写一个完整的天气查询 Agent,从 Skill 定义到系统级调用,把整个链路跑通。
更多推荐


所有评论(0)