【HarmonyOS学习笔记】2026-08-04 | 端插件新装饰器与CreateRecord全链路验证

【HarmonyOS学习笔记】2026-08-04 | 端插件新装饰器与CreateRecord全链路验证


date: 2026-08-04

tags: HarmonyOS, 端插件, InsightIntentEntry, 小艺开放平台, CreateRecord, LLM, 参数链路
type: 实战笔记

一、@InsightIntentEntry 新装饰器 vs legacy

端插件有两种实现方式,我一开始用的是 legacy 方式,踩坑后查到了新 API。

对比

特性 legacy InsightIntentExecutor @InsightIntentEntry (since API 20)
装饰器 @InsightIntentEntry
意图分发 单个Executor按intentName switch分发 每个意图独立文件+类
参数注入 手动从param取值 框架自动注入同名public属性
注册方式 insightIntents数组 + srcEntry指向Executor insightIntentsSrcEntry数组 + srcEntry指向各意图文件
metadata ohos.insight_intent ohos.insight_intent

新版代码示例

arkts 复制代码
@InsightIntentEntry({
  intentName: 'CreateRecord',
  domain: 'com.example.myapp',
  intentVersion: 1,
  displayName: '创建记录',
  llmDescription: '创建一条记录,关联到所属父级',
  keywords: ['记录', '新增', '创建'],
  abilityName: 'EntryAbility',
  executeMode: insightIntent.ExecuteMode.UI_ABILITY_BACKGROUND,
  parameters: {
    title: { type: 'string' },
    parentId: { type: 'string' },
    scheduledDate: { type: 'string' }
  }
})
export class CreateRecordImpl extends InsightIntentEntryExecutor<CreateRecordResult> {
  public title: string = ''
  public parentId: string = ''
  public scheduledDate: string = ''

  async onExecute(): Promise<insightIntent.IntentResult<CreateRecordResult>> {
    // title/parentId/scheduledDate 已由框架自动注入
  }
}

insight_intent.json 两种格式

legacy格式(insightIntents数组,所有意图指向同一个Executor):

json 复制代码
{
  "insightIntents": [
    {
      "intentName": "UpdateRecord",
      "domain": "com.example.myapp",
      "intentVersion": 1,
      "srcEntry": "./ets/entryability/IntentExecutor.ets",
      "uiAbility": { "ability": "EntryAbility", "executeMode": "background" }
    }
  ]
}

新格式(insightIntentsSrcEntry数组,每个意图指向独立文件):

json 复制代码
{
  "insightIntentsSrcEntry": [
    { "srcEntry": "./ets/insightintents/CreateRecordImpl.ets" }
  ]
}

新装饰器的3种UI能力

装饰器 功能 适用场景
InsightIntentPage 端插件触发时打开App指定页面 深度链接跳转
InsightIntentLink 端插件触发时打开深度链接 页面导航
InsightIntentForm 端插件绑定到桌面卡片(Widget) 桌面卡片展示

踩坑注意点

新API比legacy更简洁:自动注入参数、独立文件避免switch分发。 但要注意:

  1. 属性名必须与parameters的key一致,否则框架无法注入
  2. llmDescription影响LLM何时调用这个意图,要认真写
  3. keywords帮助LLM匹配用户意图,要覆盖常见同义词

二、端插件三种执行模式

模式对比

模式 能渲染UI? 说明
后台模式(background) 纯数据处理,不显示任何界面
前台模式(foreground) 收到WindowStage,可加载全屏自定义页面
UI扩展模式(UIExtension) 收到UIExtensionContentSession,可渲染自定义UI内容

踩坑:页面操控选错导致报错

现象:后台存储类端插件在平台上选择"涉及端侧app页面操控=是"后,小艺调用时报错:"应用未安装或未升级到最新版本"。

根因:"页面操控=是"意味着端插件执行时需要以前台模式拉起App的UI页面。但后台存储操作不需要UI,选择"是"后系统尝试前台拉起App,可能因签名、权限等原因拉不起来,就报"未安装"。

教训端插件工具的"页面操控"选项必须按实际需求选择。 后台存储类工具选"否",只有真正需要展示UI的工具才选"是"。


三、CreateRecord 三轮验证

第一轮:参数全空

复制代码
onExecute START: title=, parentId=, scheduledDate=
create: record rec_5 created

LLM知道要调CreateRecord工具,但不填任何参数。

根因:平台上参数的description=""、required=false。LLM不知道填什么,也不觉得必须填。

修复:补上清晰的description,title和parentId设为required。

第二轮:title有值,parentId和scheduledDate空

复制代码
onExecute START: title=去XX地点做XX事, parentId=, scheduledDate=

用户说了时间信息,但LLM没有单独提取到scheduledDate。

根因:scheduledDate的description太弱("计划日期,如明天"),对optional参数,LLM倾向跳过或把时间信息融进title而不是单独提取。

修复:加强description为"时间,如明天,2026-08-04,如果没有默认当前日期"。

第三轮:三个参数都有值

复制代码
onExecute START: title=明天要做XX事, parentId=XX父级, scheduledDate=明天
create: record rec_11 created ✅

onExecute START: title=明天要做YY事, parentId=YY父级, scheduledDate=明天
create: record rec_12 created ✅

✅ 全链路跑通:LLM调工具→系统路由→端侧执行→存储→返回code:0

遗留问题

问题 说明 修复方向
parentId填的是描述而非ID LLM把"XX父级"填到parentId,而非"parent_1"这样的ID parentId描述改为"父级ID,由SetParent工具返回的parentId值";或改为parentTitle让LLM填描述,端侧自己查ID
LLM假装调工具 小艺回复"创建成功"但端侧没执行记录,LLM用文字模拟了工具调用 端插件返回值包含明确的执行标记(_source+操作结果),提示词约束"必须基于工具返回值回复,不得编造结果"

三轮测试的教训

踩坑 根因 教训
参数全空 description="" + required=false description像给新人写文档一样写清楚,required严格按业务设置
optional参数被跳过 description太弱,LLM倾向跳过或合并到其他字段 optional参数的description要更强,特别是时间/日期等容易融进title的信息
parentId填描述 description写"属于哪个父级",LLM理解为描述文字 参数名和description要匹配LLM的理解方式,"parentId"要说明"由XX工具返回的ID值"
页面操控选错 后台工具选"是"导致前台拉起失败 后台存储类选"否",真正需要UI才选"是"

四、参数定义链路:三处一致性

开发过程中我一直困惑"参数到底在哪边定义",直到三轮测试后才理清。

完整链路

复制代码
平台侧参数配置                端侧代码
──────────────                ──────
description + required         @InsightIntentEntry的parameters
  → LLM看这个                   → 框架看这个
  → 决定提取什么参数             → 声明参数Schema
  → 决定填不填                   → 必须与平台同名一致

                                执行器类public属性
                                → 框架自动注入同名参数值
                                → 属性名须与parameters key一致

平台参数定义=LLM的说明书,端侧属性=框架的接收器,两者必须同名一致。

三处参数定义对比

位置 作用 谁看 示例
平台工具配置的参数 告诉LLM"你可以填这些参数" LLM title: String, required, "记录描述"
@InsightIntentEntry的parameters 声明参数Schema给框架 系统/框架 {"title": {"type": "string"}}
执行器类的public属性 接收注入的参数值 框架注入 public title: string

三处必须同名且类型一致。平台说有3个参数,端侧就要有3个同名属性。

踩坑:修改平台参数后必须重新发布

现象:修改平台参数description后直接测试,LLM行为没有变化。

根因:平台上的工具参数配置属于插件元数据,修改后需要重新发布才能生效。LLM读取的是已发布版本的元数据,不是草稿。

教训修改平台工具参数后必须重新发布插件,否则LLM看到的还是旧配置。 这个生效周期可能包含审核时间,修改前要确认好再提交。

我补充的经验:云上更改≠实机生效

调试中我进一步发现,小艺开放平台会因为缓存或网络等不确定因素 ,导致云上更改和实机测试实际版本不一致

这不是简单的"改完要重新发布"这么明确------即使重新发布了,也可能因为缓存/网络延迟,实机拿到的还是旧版本。

处理方式:等待、刷新、或者重新发布。改完平台配置后,要留出传播时间,必要时强制刷新或重新发布,确认实机版本与云上一致后再测试。否则会出现"明明改了,LLM行为却不变"的假象,容易误判为代码问题。


五、LLM行为踩坑

5.1 LLM有时"假装"调工具

现象:小艺回复"已为你创建了一个明天去XX的记录",但端侧没有任何onExecute日志。看起来像调了端插件,实际没调。

根因:LLM有时会选择不调用工具,而是用文字描述"已经做了"来回复用户。这在以下场景更容易发生:

  • 插件刚重新发布,LLM的缓存还没更新
  • LLM对工具调用的信心不足(参数不确定等)
  • LLM觉得文字回复就够了

验证方法

方法 真实调用 LLM假装
查端侧日志 onExecute START 没有
查返回值 _source_timestamp 无返回值
查小艺回复 "工具返回结果:..." "已为你创建..."

5.2 parentId填了描述而非ID

现象:parentId有值了,但填的是父级描述而非父级ID。

根因:parentId的description是"属于哪个父级",LLM理解为"父级的描述文字"。因为只测试了单个工具,没有SetParent先创建父级,LLM不知道parentId应该是什么格式的ID。

修复方向

  1. 改description为"父级ID,由SetParent工具返回的parentId值",让LLM知道这是ID
  2. 或者改字段名为parentTitle,让LLM填描述,端侧自己根据描述查找或创建父级
  3. 多个工具配合使用时,先有父级才有父级ID

教训参数名和description要匹配LLM的理解方式。 "parentId"对LLM来说可能理解为"父级的描述"而非"父级的ID",除非description明确说明格式和来源。

5.3 返回值可观测标记

端插件返回结果包含两个调试字段:

arkts 复制代码
result: {
  actionId: actionId,
  _source: 'MyEndPlugin',
  _timestamp: Date.now()
}

用途:

  • _source:确认数据来自端插件真实执行,而非LLM模拟
  • _timestamp:端侧处理时间戳,可对比调用时序

5.4 我补充的经验:幻觉问题的双方案

大模型幻觉问题会导致一个很坑的现象:明明没有调用端插件,返回的答案却说调过了端插件。小艺回复"已创建成功",但端侧根本没有执行记录------这是LLM在"编"结果,不是真实执行。

针对这个问题,我有两个方案:

方案①:在端插件侧加入详细日志

端插件每次执行都记录关键日志(onExecute进入、参数值、执行结果、返回值),作为"是否真的执行过"的铁证。出现疑似幻觉时,直接查端侧日志就能判定------有日志就是真调了,没日志就是LLM编的。

方案②:在云端大模型侧加上经过验证的明确且稳定的可观测标记

在端插件的返回值(会回到云端LLM上下文里)中加入稳定、明确的可观测标记,例如 _source(数据来源)+ _timestamp(执行时间)。这个标记经过验证、不会丢失、格式稳定,LLM的回复必须能对上这些标记,才能证明端插件真的执行过。

两个方案配合使用:端侧日志是"是否执行"的物理证据,云端可观测标记是"LLM是否基于真实返回作答"的逻辑证据。光有日志,LLM照样能编;光有标记,查不到端侧明细。两个一起上,才能确认更改实际准确性。

5.5 平台参数配置的三类陷阱

陷阱类型 表现 防御方法
参数description空 LLM不知道填什么,参数全空 description像给新人写文档一样写清楚
required设置错误 LLM跳过必填参数或强填可选参数 严格按业务需求设置required
页面操控选错 后台工具选"是"导致报错 后台存储类选"否",真正需要UI才选"是"

5.6 端插件调试的三类陷阱

陷阱类型 表现 防御方法
LLM假装调工具 小艺说成功但端侧没执行 端插件返回_source+操作结果,提示词约束"必须基于工具返回值回复,不得编造结果"
改参数没发布 修改后LLM行为不变 修改后必须重新发布插件;且注意缓存/网络导致云上更改与实机版本不一致,需等待/刷新/重新发布
参数两端不一致 框架注入不到属性 平台参数名、@InsightIntentEntry的parameters key、执行器public属性三处同名

六、经验法则汇总

  1. 遇到端插件参数为空 --- 先查平台description是否为空、required是否正确
  2. 遇到小艺说成功但端侧没执行 --- LLM可能在假装,查端侧日志或返回值可观测标记
  3. 修改平台参数后 --- 必须重新发布插件,否则LLM看到的还是旧配置
  4. 参数三处定义 --- 平台参数名、@InsightIntentEntry的parameters key、执行器public属性必须同名一致
  5. optional参数的description要更强 --- 特别是时间/日期等容易融进title的信息,description要明确说明"从用户话中提取单独填入"
  6. 后台存储类工具选"页面操控=否" --- 选"是"会导致系统尝试前台拉起App,增加约束和失败风险
  7. 端插件返回值加可观测标记 --- _source标识来源、_timestamp标识时序,防止LLM编造结果
  8. 云上更改≠实机生效 --- 小艺开放平台会因缓存或网络导致云上配置和实机版本不一致,需要等待、刷新或重新发布后再测试
  9. 幻觉问题双方案 --- 端插件侧加详细日志(物理证据)+ 云端大模型侧加经过验证的明确稳定的可观测标记(逻辑证据),两者配合确认更改实际准确性
  10. 新API(@InsightIntentEntry)比legacy更优 --- 自动注入参数、独立文件避免switch分发
  11. 提示词中递归逻辑必须显式约束 --- 明确写出"缺口→递归→直到明天可行",否则LLM倾向跳步

先画参数链路图再写代码,先查SDK .d.ts再写import,能省很多调试时间。


学习小结:端插件开发的核心是理解"三处一致"------平台参数配置(LLM的说明书)、@InsightIntentEntry的parameters(框架的Schema)、执行器public属性(注入的接收器)必须同名一致。CreateRecord三轮验证揭示了LLM行为规律:description决定LLM填什么,required决定LLM填不填,optional参数必须强化description否则被跳过。两个最深的坑:一是平台更改与实机生效之间存在缓存/网络导致的不一致,要等待/刷新/重新发布;二是LLM幻觉会"假装"调工具,需要端侧详细日志+云端经过验证的稳定可观测标记双方案配合,才能确认更改实际准确性。

懿路向前 · AI辅助整理

2026-08-04

相关推荐
j7~1 小时前
【Linux】二十八.线程篇五《Linux多线程编程:线程同步之条件变量》---详解
linux·运维·c++·学习·条件变量·线程同步
min(a,b)2 小时前
学习第10天:日志、测试、配置与容器化部署
学习
xqqxqxxq2 小时前
AI Agent学习:用户记忆系统(李博杰《深入理解 AI Agent》3.1观后总结)
人工智能·学习
wangyue_msn_862 小时前
Agent知识学习笔记——01 Prompt/Function call/记忆/上下文
笔记·学习·prompt
呱呱巨基2 小时前
CMake基础
linux·c++·笔记·学习
min(a,b)2 小时前
AI 每日学习 — RAG 效果评估体系设计与实现
学习
云端漫步19872 小时前
HarmonyOS NEXT AI 智能生活助手:AI 翻译助手
人工智能·华为·生活·harmonyos
智闲电子设计3 小时前
STM32 定时器 PWM 实战:从呼吸灯到舵机控制
c语言·stm32·单片机·嵌入式硬件·学习
ZZHow10243 小时前
PyTorch深度学习入门笔记(小土堆)P1-6
人工智能·pytorch·笔记·python·深度学习