前言
当智能体执行耗时较长的任务时(如AI绘图、视频生成、批量数据处理),用户可能暂时离开智能体。当任务执行成功后,如何及时通知用户?消息推送功能正是为解决这一场景而设计的。
鸿蒙智能体平台提供了Webhook消息推送机制,允许智能体在后台任务完成后,通过推送通知的方式告知用户。本文将详细介绍消息推送的配置方法和API规范。
消息推送是提升用户体验的关键功能——不需要用户一直等待,任务完成后自动通知,实现"即走即用"的流畅体验。
一、消息推送概述
1.1 什么是消息推送
消息推送是指智能体在后台任务执行完成后,主动向用户发送通知消息的机制。这与即时通信中的消息推送类似,但更加智能化。
推送场景示例:
- AI绘图:用户请求生成一张图片,智能体处理完成后推送结果
- 视频生成:长视频渲染完成后通知用户查看
- 数据分析:大量数据处理完成后推送分析报告
- 定时任务:定时执行的批量任务完成后通知
1.2 推送类型
鸿蒙消息推送支持两种类型的通知消息:
| 推送类型 | 说明 | 效果 |
|---|---|---|
| text | 纯文本通知 | 点击后进入智能体,展示文本内容 |
| data | 结构化数据通知 | 点击后触发触发器的任务执行,展示执行结果 |
注意:如果同时发送 text 和 data 类型消息,只有 text 消息生效。
1.3 推送流程
完整的消息推送流程如下:
步骤1: 用户发起耗时任务(如"帮我画一幅山水画") 步骤2: 智能体开始处理,用户可离开 步骤3: 任务完成后,智能体服务器调用Webhook API 步骤4: 华为推送服务将通知发送到用户设备 步骤5: 用户收到推送通知 步骤6: 用户点击通知,进入智能体查看结果二、配置推送功能
2.1 添加推送变量
首先需要在智能体的变量配置中添加push_id变量:
- 进入智能体编排页面
- 找到「变量」配置区域
- 添加系统变量
push_id - 保存配置
push_id变量说明:
| 属性 | 说明 |
|---|---|
| 变量名 | push_id |
| 类型 | 系统变量(只读) |
| 用途 | 代表通过Webhook推送通知时使用的唯一ID |
| 获取方式 | 请求中的系统变量,自动生成 |
2.2 Webhook凭证配置
消息推送使用Webhook事件的凭证进行鉴权:
- 进入小艺开放平台 → 「工作空间」→「凭证」
- 点击「新建凭证」
- 设置Key名称并保存
- 保存生成的Key(Access Key)和安全密钥(Security Key)
注意:安全密钥只在创建成功时可复制,关闭窗口前请务必妥善保管。该凭证通用,可供该账号下所有智能体的Webhook使用。
三、Webhook推送API详解
3.1 API端点
POST https://hag.cloud.huawei.com/open-ability-agent/v1/agent-webhook3.2 请求头格式
Content-Type: application/json Accept: application/json x-hag-trace-id: {{请求标识,使用随机数生成,用于问题定位}} X-Access-Key: {{从小艺开放平台获取的Access Key}} X-Sign: {{HMAC-SHA256签名}} X-Ts: {{时间戳毫秒数}}请求头字段说明:
| 字段 | 类型 | 说明 | 是否必填 |
|---|---|---|---|
x-hag-trace-id | string | 随机生成的请求标识,用于问题定位 | 是 |
X-Access-Key | string | 凭证的Access Key | 是 |
X-Sign | string | HMAC-SHA256签名 | 是 |
X-Ts | string | 当前时间戳(毫秒) | 是 |
3.3 签名计算
签名算法使用HMAC-SHA256,具体实现如下:
importhashlibimporthmacimportbase64importtimedefgenerate_sign(secret_key:str,timestamp:str=None)->str:"""生成X-Sign签名 Args: secret_key: 从小艺开放平台获取的安全密钥 timestamp: 时间戳(毫秒),为空则自动生成 Returns: base64编码的签名结果 """iftimestampisNone:timestamp=str(int(time.time()*1000))# 使用HMAC-SHA256算法message=timestamp.encode('utf-8')secret=secret_key.encode('utf-8')sign=hmac.new(secret,message,hashlib.sha256).digest()# Base64编码returnbase64.b64encode(sign).decode('utf-8')defverify_sign(secret_key:str,timestamp:str,sign:str,timeout:int=900)->bool:"""验证签名 Args: secret_key: 安全密钥 timestamp: 请求中的时间戳 sign: 请求中的签名 timeout: 签名超时时间(秒),默认15分钟 Returns: 签名是否有效 """# 验证时间戳是否在有效期内(防重放攻击)now=int(time.time()*1000)ifabs(now-int(timestamp))>timeout*1000:returnFalse# 重新计算签名并比对expected_sign=generate_sign(secret_key,timestamp)returnsign==expected_signJava示例:
importjavax.crypto.Mac;importjavax.crypto.spec.SecretKeySpec;importjava.nio.charset.StandardCharsets;importjava.util.Base64;publicclassSignUtil{publicstaticStringgenerateSign(Stringsecret,Stringts)throwsException{Macmac=Mac.getInstance("HmacSHA256");SecretKeySpeckeySpec=newSecretKeySpec(secret.getBytes(StandardCharsets.UTF_8),"HmacSHA256");mac.init(keySpec);byte[]byteHMAC=mac.doFinal(ts.getBytes(StandardCharsets.UTF_8));returnBase64.getEncoder().encodeToString(byteHMAC);}}签名验证示例:
# 验证参数secret="2e3b71f5def64d95a727314f028bf5aa"ts="1547630863716"# 计算签名sign=generate_sign(secret,ts)print(f"签名结果:{sign}")# 预期输出: 6lFqepUu79KSxVCsrXyB/aLVFIdutsTLLx1cZjxDE4I=提示:服务端应校验ts与当前时间差值的绝对值不超过15分钟,用于防重放攻击。
3.4 请求体格式
{"jsonrpc":"2.0","id":"{{全局唯一消息序列号}}","result":{"id":"{{使用请求中的该字段返回}}","apiId":"{{API ID}}","pushId":"{{系统变量push_id的值}}","agentLoginSessionId":"{{用户授权身份ID}}","pushText":"{{通知展示内容}}","kind":"task","artifacts":[{"artifactId":"{{Artifact唯一ID}}","parts":[{"kind":"text","text":"{{响应文本内容}}"},{"kind":"data","data":"{{结构化数据}}"}]}],"status":{"state":"{{任务状态:completed/canceled/failed}}"}},"error":{"code":0,"message":"success"}}3.5 请求体字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 全局唯一消息序列号 |
result.id | string | 任务ID,与发起请求时一致 |
result.apiId | string | 创建API时生成的API ID |
result.pushId | string | push_id系统变量的值 |
result.pushText | string | 通知展示内容,会显示在推送通知中 |
result.artifacts[].parts[].kind | string | 内容类型:text/data |
3.6 完整请求示例
curl'https://hag.cloud.huawei.com/open-ability-agent/v1/agent-webhook'\-H'Content-Type: application/json'\-H'Accept: application/json'\-H'x-hag-trace-id: a1b2c3d4-e5f6-7890-abcd-ef1234567890'\-H'X-Access-Key: your-access-key'\-H'X-Sign: generated-base64-signature'\-H'X-Ts: 1712345678000'\-d'{ "jsonrpc": "2.0", "id": "a3f9b2c1-d9e4-4b8f-9a7c-2e1d5f3b8c0a", "result": { "id": "7c1d3e5f-9a2b-4c8d-6e3f-1a9b4c2d8e6f", "apiId": "webhook794ed095874f4c68888", "pushId": "d2e4f1c8-9b3a-4d7e-8f2c-6a1b5e9f3d4c", "agentLoginSessionId": "MDEr1a7L0wxJpyjiaur43RicGHm9FVbJSB", "pushText": "您的照片已完成,请查看", "kind": "task", "artifacts": [ { "artifactId": "b5c8d1a3-f9e2-4b7c-8d6a-1f9e3b5c7d8a", "parts": [ { "kind": "data", "data": { "prompt": "生成一只可爱小猫", "imageUrl": "https://example.com/cat.png" } } ] } ], "status": { "state": "completed" } }, "error": { "code": 0, "message": "success" } }'3.7 响应格式
{"id":"43667960-d455-4453-b0cf-1bae4955270d","resultId":"c295ea44-7543-4f78-b524-7a38915ad6e4","result":{"code":0,"message":"success"}}四、推送效果展示
4.1 小艺在后台时的推送
当小艺APP处于后台时,用户会收到系统推送通知:
通知效果说明:
- 通知栏显示推送标题和内容(即
pushText) - 点击通知进入智能体,展示任务结果
- 支持多条推送的堆叠展示
4.2 小艺在前台时的推送
当小艺APP处于前台时,推送消息显示在消息列表中:
前台展示说明:
- 消息列表中显示推送通知
- 点击后进入对应的智能体对话
- 展示完整的任务执行结果
五、 Data数据类型推送
5.1 触发插件任务
使用data类型推送可以触发智能体执行插件任务:
{"kind":"data","data":{"cityName":"南京"}}触发后,插件使用data中的参数执行任务。
5.2 触发工作流任务
data类型推送也可以触发工作流执行:
{"kind":"data","data":{"cityName":"南京"}}触发后,参数作为EVENT_INPUT.payload传递给工作流:
{"payload":{"cityName":"南京"},"header":{"name":"CloudEvent","namespace":"Common"}}5.3 A2A模式下的推送
在A2A模式下,推送的data参数通过data.events发送给Agent Server:
[{"header":{"name":"Trigger","namespace":"Common"},"payload":{"dataMap":{"cityName":"南京"},"dialogueHistorySwitch":false,"eventDescription":"{{apiID}}","eventName":"{{apiID}}","eventType":"Webhook","triggerName":"{{触发器名称}}","triggerType":"event"}}]六、最佳实践
6.1 推送策略建议
- 合理设置pushText:简明扼要说明任务结果,如"图片已生成完成!"
- 避免频繁推送:短时间内多次推送可能被系统聚合
- 区分重要级别:重要任务推送,次要任务在下次打开时展示
- 附带上文信息:让用户看到通知就知道是哪个任务的结果
6.2 错误处理
# 推送错误处理和重试逻辑importtimeimportrequestsdefsend_push_notification(push_data:dict,max_retries:int=3):"""发送推送通知,支持重试"""url="https://hag.cloud.huawei.com/open-ability-agent/v1/agent-webhook"headers={"Content-Type":"application/json","x-hag-trace-id":generate_trace_id(),"X-Access-Key":ACCESS_KEY,"X-Sign":generate_sign(SECRET_KEY),"X-Ts":str(int(time.time()*1000))}forattemptinrange(max_retries):try:response=requests.post(url,json=push_data,headers=headers,timeout=10)ifresponse.status_code==200:returnresponse.json()elifresponse.status_code==429:# 限流,等待后重试time.sleep(2**attempt)continueelse:# 其他错误,记录日志log_error(f"Push failed:{response.status_code}-{response.text}")returnNoneexceptrequests.RequestExceptionase:log_error(f"Push request error:{e}")time.sleep(2**attempt)returnNone6.3 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 推送未收到 | push_id未配置 | 检查变量中是否添加了push_id |
| 签名验证失败 | secret_key错误 | 检查凭证配置是否正确 |
| 推送内容为空 | pushText为null | 确保设置了pushText字段 |
| 接口超时 | 网络问题 | 检查网络连接,增加超时时间 |
| HTTP 401 | 鉴权失败 | 检查Access Key是否正确 |
| HTTP 429 | 请求过于频繁 | 增加重试间隔 |
总结
本文详细介绍了鸿蒙智能体消息推送功能的开发和配置:
- 推送概述:推送的场景、类型和完整流程
- 配置准备:push_id变量配置和Webhook凭证创建
- API详解:推送接口的请求格式、签名算法和响应处理
- 效果展示:前后台不同状态下的推送效果
- Data推送:插件/工作流/A2A模式的data类型推送
- 最佳实践:推送策略、错误处理和常见问题排查
消息推送是提升智能体用户体验的重要功能,合理使用可以让用户获得"即走即用"的流畅体验。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- PUSH通知 - 华为开发者联盟
- Webhook事件 - 华为开发者联盟
- 鸿蒙Agent通信协议 - 华为开发者联盟
- HMAC-SHA256算法说明
- Python hashlib文档
- 小艺开放平台 - 凭证管理
- 华为Push Kit文档
title: 鸿蒙智能体开发实战:13.消息推送
date: 2026-04-13 08:00:00
tags: [鸿蒙智能体开发实战, 消息推送, AI]
背景
当智能体运行较长时间的任务时,用户可能短暂离开智能体,当任务执行成功后,可以通过消息推送的方式,告知用户任务执行成功。
配置
首先我们需要在智能体编排中的变量中,添加 push_id
请求格式说明:
curl'https://hag.cloud.huawei.com/open-ability-agent/v1/agent-webhook'\-H'Content Type: application/json'\-H'Accept: application/json'\-H'x-hag-trace-id: {{客户端使用随机数生成。}}'\-H'X-Access-Key: {{从小艺开放平台获取的触发器事件WebHook分配的appKey}}'\-H'X-Sign: {{从小艺开放平台获取的触发器事件WebHook分配的secretKey生成的签名,参数签名=Base64(HMAC-SHA256(secretKey, ts))。 其中secretKey 为开发者在小艺开放平台上配置的接入密钥(secretKey)}}'\-H'X-Ts: {{时间戳,用于加密和缓存穿透。 格式为:当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。 例如:2018/1/1 08:00:00.000 的时间戳为"1514764800000"}}'\-d '{"jsonrpc":"2.0","id":"{{与agent-server通信的全局唯一消息序列号,给agent-server答复请求结果时需取出返回}}","result":{"id":"{{使用请求中的该字段返回,一次流式交互中(从发起本次请求到本次请求完成处理之间)保持不变}}","apiId":"{{创建api时生成的API ID,CP请求时带上}}","pushId":"{{请求时使用平台系统变量push_id,代表通过webhook推送通知时使用的唯一ID。}}","agentLoginSessionId":"{{账号授权时三方智能体服务器提供的用户授权身份ID。}}","pushText":"{{Push通知的展示内容,按Push服务规格提供}}","kind":"{{事件类型,值为task}}","artifacts":[{"artifactId":"{{本条Artifact的唯一ID,用于CP请求消息的去重}}","parts":[{"kind":"text","text":"{{agent-server处理的响应,如果是markdown流式输出也在此处存放}}"},{"kind":"data","data":"{{结构化数据,以JSONObject形式存放,承载用户结果过程数据及A2A的扩展字段}}"}]}],"status":{"state":"{{任务状态,取值为[completed|canceled|failed]其中之一}}"}},"error":{"code":"{{JSONRPCError错误码,整形类型}}","message":"{{JSONRPCError错误描述}}"}}'请求示例:
curl'https://hag.cloud.huawei.com/open-ability-agent/v1/agent-webhook'\-H'Content Type: application/json'\-H'Accept: application/json'\-H'x-hag-trace-id: {{请求标识,使用随机数生成,用于问题定位。}}'\-H'X-Access-Key: {{从小艺开放平台获取的触发器事件WebHook分配的Access Key。}}'\-H'X-Sign: {{从小艺开放平台获取的触发器事件WebHook分配的Security Key生成的签名,参数签名=Base64(HMAC-SHA256(secretKey, ts)), 其中secretKey 为开发者在小艺开放平台上配置的接入密钥(Security Key)。}}'\-H'X-Ts: {{时间戳,用于加密和缓存穿透。 格式为:当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。 例如:2018/1/1 08:00:00.000 的时间戳为"1514764800000"}}’\ -d '{"jsonrpc":"2.0","id":"a3f9b2c1-d9e4-4b8f-9a7c-2e1d5f3b8c0a","result":{"id":"7c1d3e5f-9a2b-4c8d-6e3f-1a9b4c2d8e6f","apiId":"webhook794ed095874f4c68888","pushId":"d2e4f1c8-9b3a-4d7e-8f2c-6a1b5e9f3d4c","agentLoginSessionId":"MDEr1a7L0wxJpyjiaur43RicGHm9FVbJSB","pushText":"您的照片已完成,请查看","kind":"task","artifacts":[{"artifactId":"b5c8d1a3-f9e2-4b7c-8d6a-1f9e3b5c7d8a","parts":[{"kind":"data","data":{"prompt":"生成一只可爱小猫"}}]}]}}'效果
当小艺至于后台时,会收到推送消息,如下图:
当小艺处于前台时,会显示在消息列表中,如下图:
参考资料
- PUSH通知
- Webhook事件