【HarmonyOS学习笔记】2026-07-30 | 小艺开放平台智能体接入实战
date: 2026-07-30
tags: HarmonyOS, 小艺开放平台智能体, FunctionComponent, AgentFrameworkKit, 审核避坑
type: 实战笔记
一、架构理解:智能体是本体,App 是外挂
我对这个架构的认知经历了三轮迭代:
最初误解:"App 调小艺"
App → 调用设备上的小艺 → 拿到小艺的回复文本 → 自己处理
第一轮纠正:"调自己的智能体"(仍不精确,暗示 App 主动调)
App → FunctionComponent(渲染按钮) → 用户点击 → 系统弹出对话浮层
→ 用户在浮层中说话/打字 → 云端LLM(你自己的智能体)理解
→ LLM调用端插件 → 系统路由到App的IntentExecutor → App拿到结构化数据
→ 返回确认 → 浮层显示"已记录"
乍一看是 App 调了智能体------按钮长在我的页面上,agentId 是我填的,对话浮层是我触发的。但这个直觉是错的。
校准后认知 :智能体是本体,App/端插件是外挂。不是 App 调小艺,是小艺调 App。
猎物和猎手有时候就是转换得这么猝不及防------你以为你在调智能体,其实智能体在调你。
智能体(本体) ──调用──→ App/端插件(外挂)
│ │
│ 决定何时调、传什么参数 │ 接收调用、执行、返回结果
│ │
│ LLM阅读llmDescription │ 声明能力(装饰器/注册)
│ 判断用户意图匹配哪个能力 │ 等待被调
智能体是大脑,App/端插件是手脚。 大脑决定做什么,手脚负责执行并反馈结果。
官方 SDK 证据
-
InsightIntentExecutor 全是
on前缀回调 :onExecuteInUIAbilityForegroundMode、onExecuteInUIAbilityBackgroundMode。App 接收 name+param 入参,返回 ExecuteResult。平台调 App,App 响应。 -
官方用词 "insight intent driver" :
ExecuteResult.uris的文档注释写"authorized to the insight intent driver"。App 的执行结果返回给"驱动者",App 是被驱动的。 -
FunctionComponent 只提供 agentId 引用 :App 不控制智能体行为,只是标识"用户从这个按钮进入哪个智能体"。
AgentController只有on('agentDialogOpened')/on('agentDialogClosed')------ App 只能观察事件,不能发起对话。 -
Intent 装饰器的
llmDescription:@InsightIntentFunction、@InsightIntentPage等装饰器都有llmDescription字段,这是给 LLM/智能体看的描述------LLM 根据这个描述决定什么时候调用 App 的哪个能力。App 声明能力,智能体决定调用。 -
insightIntentProvider 命名 :App 是 Provider (提供者),平台/智能体是 Consumer/Driver(消费者/驱动者)。App 发送结果,不请求调用。
对话窗口是系统浮层,不是 App 的 UI------这本身就说明 App 不是控制方。
二、FunctionComponent SDK
import
arkts
import { FunctionComponent, FunctionController, FunctionOptions, ButtonType as AgentButtonType } from '@kit.AgentFrameworkKit'
import { BusinessError } from '@kit.BasicServicesKit'
since 6.0.0(20)。
参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| agentId | string | ✅ | 智能体ID,从小艺开放平台获取 |
| onError | ErrorCallback | ✅ | 错误回调,参数为 BusinessError |
| options | FunctionOptions | ❌ | 按钮样式配置 |
| controller | FunctionController | ❌ | 生命周期控制器 |
FunctionOptions
| 属性 | 类型 | 范围 | 说明 |
|---|---|---|---|
| queryText | ?string | --- | 预填对话输入框的初始文本(不触发打开) |
| buttonType | ?ButtonType | CIRCLE=0 / CAPSULE=1 / ICON_ABOVE_TITLE=2 | 按钮形状 |
| controlSize | ?ControlSize | SMALL / NORMAL | 按钮尺寸 |
| title | ?string | --- | 按钮标题文字 |
| titleFontSize | ?number | 14, 16 | 标题字号 |
| iconSize | ?number | 16, 24 | 图标大小 |
| iconColors | ?ResourceColor\[\] | 单色 | 图标品牌色 |
| backgroundColor | ?ResourceColor | --- | 按钮背景色 |
| titleColors | ?ResourceColor\[\] | 1-2色渐变 | 标题品牌色 |
| isShowShadow | ?boolean | 仅CAPSULE | 是否显示阴影 |
FunctionController
| 方法 | 说明 |
|---|---|
| isAgentSupport(context, agentId) | 检查智能体是否可用 |
| on('agentDialogOpened', cb) | 监听浮层打开 |
| on('agentDialogClosed', cb) | 监听浮层关闭 |
没有 open() / close() 方法------只能观察,不能主动控制。
错误码
| 错误码 | 含义 |
|---|---|
| 1022400010 | 参数错误 |
| 1022400011 | 隐私协议未同意 |
| 1022400012 | 华为ID未登录 |
| 1022400013 | 网络错误 |
| 1022400014 | 内部错误 |
不可控项
对话窗口是系统地盘,App 只能配按钮皮肤:
| 不可控项 | 说明 |
|---|---|
| 对话浮层外观/配色/气泡/输入区 | 系统控制 |
| 浮层大小/位置 | 系统控制 |
| 对话内容文本回传 | 无 API,只能通过端插件获取结构化数据 |
| 编程式打开对话 | 无 open(),必须用户点击按钮 |
| 嵌入页面 | SDK 硬限制,FunctionComponent 只渲染按钮 |
平台配"智能体灵魂"(名字/头像/人设/工具),App配"入口按钮皮肤"(形状/颜色/标题),对话窗口本身是系统地盘动不了。
代码示例
arkts
@Entry
@ComponentV2
struct HomePage {
private agentController: FunctionController = new FunctionController()
@Local isAgentDialogOpen: boolean = false
aboutToAppear(): void {
this.agentController.on('agentDialogOpened', () => {
this.isAgentDialogOpen = true
})
this.agentController.on('agentDialogClosed', () => {
this.isAgentDialogOpen = false
})
}
build() {
Column() {
FunctionComponent({
agentId: '你的智能体ID',
onError: (err: BusinessError) => {
hilog.error(0x0001, 'Tag', 'Agent error: %{public}d', err.code)
},
options: {
buttonType: AgentButtonType.CIRCLE,
title: '小艺',
iconSize: 20
} as FunctionOptions,
controller: this.agentController
})
}
}
}
三、踩坑
Bug:ButtonType 命名冲突
import @kit.AgentFrameworkKit 后,原有 ButtonType.Circle 报错。
两个同名枚举但成员命名风格不同:
| 枚举来源 | 成员命名 |
|---|---|
| ArkUI 原生 ButtonType | Circle / Capsule / Normal |
| @kit.AgentFrameworkKit ButtonType | CIRCLE / CAPSULE / ICON_ABOVE_TITLE |
后 import 覆盖前者,ButtonType.Circle 找不到。
修复:import 时加别名:
arkts
import { ButtonType as AgentButtonType } from '@kit.AgentFrameworkKit'
发现:FunctionComponent 无法嵌入页面
想实现对话窗口直接嵌入 App 页面,所有方案都不可行:
| 方案 | 原因 |
|---|---|
| queryText 自动打开 | queryText 只预填不触发 |
| FunctionController.open() | 该方法不存在 |
| 嵌入式组件 | SDK 只有 FunctionComponent 一个 UI 组件 |
| 模拟点击按钮 | 系统组件无法被模拟触摸 |
@kit.AgentFrameworkKit 只导出 6 个符号:AgentController、FunctionController、BaseOptions、FunctionOptions、ButtonType、FunctionComponent。没有嵌入或编程式打开的能力。
替代方案:把系统浮层当主交互入口,按钮做大做醒目,主页定位为"仪表盘"。
"开小差"问题
FunctionComponent 拉起浮层成功,但发消息后返回"开小差"。
根因:智能体处于草稿/待审核状态且未发布。
智能体与端插件的发布规则不同:
| 项目 | 上架需要审核? | 说明 |
|---|---|---|
| 智能体 | ✅ 需要 | 审核通过后正式上线 |
| 端插件 | ❌ 无需 | 上架即生效 |
前提:关联应用必须在小艺开放平台上注册过。
测试阶段可不上架:通过"发布真机测试"进入白名单机制,白名单用户可通过 FunctionComponent 真机调用。
| 状态 | 平台调试窗口 | FunctionComponent 真机调用 |
|---|---|---|
| 草稿 | ✅ | ❌ "开小差" |
| 待审核 | ✅ | ❌ "开小差" |
| 发布真机测试(未上架) | ✅ | ✅ 白名单用户可用 |
| 审核通过上架 | ✅ | ✅ 所有用户可用 |
四、审核 4 条避坑
1. 名称一致性
智能体名称 + 隐私政策中的名称必须与 App 一致。审核会搜索确认对应关系。
2. 头像不能有色框
头像缩放比例不对导致边缘露出底色。规格 256x256px PNG,调整缩放消除色框。
3. 开场语不能只打招呼
参考模板:
你好!我是XX助手,可以帮你记录待办事项、日程安排和重要信息。
试试这样对我说:
- "明天下午3点去国贸找老王交报告"
- "提醒我每天早上跑步30分钟"
- "老王电话13812345678"
4. 敏感话题需加防护提示词
审核会测试敏感话题的回复,如果不当会被拒。官方提供的防护提示词:
你是严格遵守法律法规与平台内容规范的智能助手,所有输出必须合法合规、文明健康、积极正向。
严格禁止生成、讨论、暗示、隐喻、美化、洗白、调侃、编造以下任何内容:
涉政敏感内容:国家形象、国家分裂势力、国家领导人、党政军、政策法规、敏感历史事件、敏感舆情、地域对立、意识形态争议、境外敏感议题、煽动性政治言论、华为负面内容、小艺负面内容、非法宗教组织、暴力恐怖、色情、社会负面、攻击性言论、黑色交易等;不得对政治人物、政府机构、公共事件进行负面评价、恶意解读、造谣传谣。
低俗色情与性暗示:露骨描写、色情段子、性挑逗、低俗擦边、不雅动作描述、低俗谐音梗、色情隐喻。
暴力血腥、恐怖惊悚、自残自杀、教唆伤害、校园霸凌、网络暴力。
违法违规:诈骗、赌博、毒品、洗钱、非法交易、黑客、侵权盗版、隐私泄露、伪造证件。
歧视仇恨:种族、宗教、性别、地域、职业、残障、外貌等任何形式歧视与仇恨言论。
恶意引导:教唆违规、规避审核、诱导敏感提问、伪装身份欺骗用户。
任何触及上述红线的请求,一律拒绝回答,拒绝话术保持礼貌简洁,不解释、不延伸、不反问、不暗示、不提供替代方案,仅回复:"我们换个话题聊聊吧~"
输出内容必须积极、健康、中立、客观,不站队、不情绪化、不传播谣言,严格遵守内容安全底线。
将这段提示词追加在角色指令(System Prompt)末尾。
学习小结:小艺开放平台的核心架构是"智能体是本体,App是外挂"------不是 App 调小艺,是小艺调 App。官方 SDK 从 5 个层面证实了这个反转控制:InsightIntentExecutor 的 on 前缀回调、官方用词"insight intent driver"、FunctionComponent 只能观察不能发起、llmDescription 让 LLM 决定何时调 App、insightIntentProvider 说明 App 是提供者。ButtonType 命名冲突用别名解决,"开小差"根因是智能体未发布(至少要"发布真机测试"白名单可用,端插件上架无需审核,关联应用必须注册)。审核 4 条避坑:名称一致、头像无色框、开场语含功能+示例、角色指令末尾追加官方敏感话题防护提示词。
懿路向前 · AI辅助整理
2026-07-30