鸿蒙智能体开发实战:25.自定义 Skill 开发入门
前言
在前面的文章中,我们深入了解了智能体的编排方式、插件开发、工作流和消息卡片等核心概念。本文将带你进入智能体开发的另一个重要领域——自定义 Skill(技能)开发。
Skill 是智能体能力的"技能单元",它封装了特定的业务能力和交互逻辑。与插件(Plugin)提供工具调用能力不同,Skill 更侧重于完整的交互体验和任务执行流程。
本文将详细介绍 Skill 的概念、与 Workflow/Plugin 的区别与联系,以及如何从零创建一个自定义 Skill。
一、Skill 概述
1.1 什么是 Skill
Skill(技能)是鸿蒙智能体平台中一种高级能力封装单元。一个 Skill 代表智能体可以执行的一项完整技能,它通常包含:
- 触发条件:什么情况下激活该 Skill
- 交互流程:与用户的多轮对话逻辑
- 执行逻辑:具体的业务处理步骤
- 输出格式:返回给用户的结果展示方式
通俗理解:如果说 Plugin 是智能体的"工具",Workflow 是"流程编排",那么 Skill 就是智能体的"专业技能"——它定义了一个完整的、可独立运行的能力模块。
1.2 Skill 的核心价值
| 特性 | 说明 | 受益场景 |
|---|---|---|
| 封装性 | 将完整的业务逻辑封装为独立单元 | 团队协作开发、模块复用 |
| 可复用 | 一个 Skill 可在多个智能体中使用 | 跨项目共享能力 |
| 可组合 | 多个 Skill 可组合成更复杂的能力 | 复杂业务场景 |
| 可测试 | 每个 Skill 可独立测试和调试 | 提升开发效率 |
| 版本管理 | Skill 支持版本迭代和灰度发布 | 平滑升级、A/B 测试 |
1.3 Skill vs Plugin vs Workflow
在鸿蒙智能体平台中,Skill、Plugin(插件)和 Workflow(工作流)是三种不同的能力扩展方式,它们各有侧重:
| 维度 | Skill(技能) | Plugin(插件) | Workflow(工作流) |
|---|---|---|---|
| 定位 | 完整的能力模块 | 工具/API 封装 | 任务流程编排 |
| 交互方式 | 多轮对话交互 | 单次 API 调用 | 节点化流程执行 |
| 状态管理 | 内置状态管理 | 无状态 | 节点间数据传递 |
| 复用范围 | 跨智能体复用 | 跨智能体复用 | 跨智能体复用 |
| 开发复杂度 | 高 | 中 | 中 |
| 用户感知 | 用户感知为完整技能 | 用户感知为工具 | 用户无感知 |
| 典型场景 | 壁纸生成、旅行规划 | 天气查询、订单查询 | 数据清洗、文档处理 |
选择建议:
- 如果只是调用外部 API,使用 Plugin
- 如果需要编排多步骤任务,使用 Workflow
- 如果需要完整的、有状态的对话交互体验,使用 Skill

上图展示了 Skill 作为核心交互单元,通过 Plugin 获取工具能力,通过 Workflow 编排多步骤流程的协作关系
二、Skill 的架构与组成
2.1 Skill 的整体架构
一个完整的 Skill 通常包含以下组成部分:
Skill (技能)
├── 触发条件 (Trigger)
│ ├── 关键词触发:当用户提到相关关键词时激活
│ ├── 意图触发:当 LLM 识别到相关意图时激活
│ └── 事件触发:当收到外部事件时激活
├── 交互配置 (Interaction)
│ ├── 开场白:Skill 激活时的首轮对话
│ ├── 引导语:引导用户提供所需信息
│ └── 确认语:确认用户意图的对话
├── 执行逻辑 (Execution)
│ ├── 参数提取:从对话中提取所需参数
│ ├── 业务处理:调用 Plugin/API 处理业务
│ └── 结果组装:组装返回结果
└── 输出展示 (Output)
├── 文本回复:自然语言回复
├── 消息卡片:结构化数据展示
└── 后续引导:引导下一步操作
2.2 Skill 的生命周期
# Skill 生命周期状态流转
class SkillLifecycle:
"""
Skill 的完整生命周期状态
状态流转:
IDLE -> ACTIVATED -> COLLECTING -> EXECUTING -> COMPLETED
|
v
FAILED
"""
IDLE = "idle" # 空闲状态,等待触发
ACTIVATED = "activated" # 已激活,开始交互
COLLECTING = "collecting" # 参数收集中
EXECUTING = "executing" # 执行中
COMPLETED = "completed" # 执行完成
FAILED = "failed" # 执行失败
@staticmethod
def get_state_description(state: str) -> str:
"""获取状态描述"""
descriptions = {
"idle": "Skill 处于待命状态,等待用户触发",
"activated": "Skill 已激活,正在与用户交互",
"collecting": "正在收集执行所需的参数信息",
"executing": "正在执行业务逻辑",
"completed": "Skill 执行完成,已返回结果",
"failed": "Skill 执行过程中出现错误",
}
return descriptions.get(state, "未知状态")
2.3 Skill 的配置结构
一个 Skill 的配置通常采用 JSON 格式定义:
{
"skillName": "wallpaper_generator",
"displayName": "壁纸生成技能",
"description": "根据用户描述自动生成精美壁纸",
"version": "1.0.0",
"trigger": {
"type": "intent",
"keywords": ["壁纸", "生成壁纸", "制作壁纸", "桌面背景"],
"confidence": 0.7
},
"interaction": {
"opening": "你好!我是你的壁纸创作助手,请描述你想要的壁纸风格和主题。",
"greeting": "想生成什么风格的壁纸呢?",
"parameters": [
{
"name": "style",
"type": "string",
"description": "壁纸风格",
"required": true,
"enum": ["极简主义", "水墨国风", "梦幻星空", "自然森系"]
},
{
"name": "theme",
"type": "string",
"description": "壁纸主题",
"required": false,
"examples": ["远山", "星空", "花朵"]
}
]
},
"execution": {
"type": "plugin",
"pluginId": "plugin_image_generation",
"timeout": 60000,
"retry": 3
},
"output": {
"format": "card",
"cardType": "DisplayFaCard",
"followUp": "还可以继续生成其他壁纸哦,告诉我你的想法吧!"
}
}
三、创建自定义 Skill
3.1 在平台上创建 Skill
在小艺开放平台上创建自定义 Skill 的步骤如下:
# 创建 Skill 的整体步骤
1. 登录小艺开放平台 → 技能管理
2. 点击"新建技能" → 选择"自定义技能"
3. 填写基本信息(名称、描述、版本)
4. 配置触发条件(关键词/意图/事件)
5. 设计交互流程(对话模板、参数提取)
6. 配置执行逻辑(调用插件或 API)
7. 配置输出展示(文本/卡片)
8. 发布测试版本进行验证

上图展示了小艺开放平台中 MCP 插件的创建入口和基础配置界面,开发者可以在此定义插件的名称、描述和工具能力

上图展示了云插件的创建界面,支持通过标准注册和外部平台导入两种方式创建插件
提示:在创建 Skill 之前,建议先在「意图框架 & MCP → 插件」页面中创建好所需的插件工具,Skill 可以直接引用已创建的插件来扩展执行能力。
3.2 Skill 的触发条件配置
Skill 的触发条件是决定何时激活 Skill 的关键配置:
| 触发类型 | 配置方式 | 适用场景 | 示例 |
|---|---|---|---|
| 关键词触发 | 定义关键词列表 | 明确需求 | “帮我生成壁纸” |
| LLM 意图触发 | 描述意图场景 | 模糊需求 | “想让手机更好看” |
| 正则匹配 | 定义正则表达式 | 格式化输入 | “生成[风格]壁纸” |
| 事件触发 | 外部事件驱动 | 自动化场景 | 每日推送 |
| 复合触发 | 多种条件组合 | 复杂场景 | 关键词+上下文 |
关键词触发配置示例:
{
"trigger": {
"type": "keyword",
"keywords": [
"生成壁纸",
"制作背景",
"换个壁纸",
"设计桌面"
],
"matchMode": "contains", // 包含匹配
"minMatchCount": 1 // 最少匹配数量
}
}
LLM 意图触发配置示例:
{
"trigger": {
"type": "llm_intent",
"description": "用户想要生成、更换或设计手机壁纸/桌面背景",
"examples": [
"帮我做个好看的手机壁纸",
"想要一张星空背景",
"给我设计桌面图片"
],
"confidence": 0.6
}
}
3.3 交互流程设计
交互流程是 Skill 的核心,它决定了智能体如何与用户进行多轮对话来收集执行所需信息:
# 交互流程状态机设计示例
class SkillConversationFlow:
"""
Skill 交互流程状态机
以壁纸生成为例,多轮交互流程如下:
步骤1: 问候 → 询问风格偏好
步骤2: 用户选择风格 → 询问主题
步骤3: 用户选择主题 → 询问尺寸/场景
步骤4: 用户确认 → 执行生成
"""
def __init__(self):
self.state = "initial"
self.collected_params = {}
def process_user_input(self, user_text: str) -> dict:
"""处理用户输入,推进流程"""
if self.state == "initial":
# 第一步:问候,询问风格
self.state = "asking_style"
return {
"reply": "你好!想要什么风格的壁纸呢?",
"options": [
"极简主义", "水墨国风",
"梦幻星空", "自然森系"
],
"need_input": True
}
elif self.state == "asking_style":
# 第二步:用户选择了风格,询问主题
self.collected_params["style"] = user_text
self.state = "asking_theme"
return {
"reply": f"好的,{user_text}风格!想要什么主题的画面呢?",
"options": ["山川", "花鸟", "抽象", "星辰"],
"need_input": True
}
elif self.state == "asking_theme":
# 第三步:用户选择了主题,询问尺寸
self.collected_params["theme"] = user_text
self.state = "confirming"
return {
"reply": "最后,请选择壁纸的使用场景:",
"options": [
"竖屏 · 锁屏",
"竖屏 · 主屏",
"横屏 · 锁屏",
"横屏 · 主屏"
],
"need_input": True
}
elif self.state == "confirming":
# 第四步:确认所有参数,开始执行
self.collected_params["scene"] = user_text
self.state = "completed"
return {
"reply": "好的,马上为你生成壁纸!",
"params": self.collected_params,
"execute": True
}
return {"reply": "请告诉我你的需求"}
3.4 参数提取策略
在多轮对话中,如何准确提取用户提供的参数是 Skill 开发的关键:
import re
from typing import Optional, Dict, Any
class ParameterExtractor:
"""
参数提取器
从自然语言对话中提取结构化参数
"""
def __init__(self):
# 定义参数提取规则
self.extractors = {
"style": [
(r"(极简|简约|简单)", "极简主义"),
(r"(水墨|国风|中国风)", "水墨国风"),
(r"(星空|银河|宇宙)", "梦幻星空"),
(r"(自然|森林|森系|绿色)", "自然森系"),
],
"color": [
(r"(蓝色|蓝)", "蓝色系"),
(r"(粉色|粉|樱花)", "粉色系"),
(r"(黑白|灰色|灰)", "黑白灰"),
(r"(暖色|暖色调)", "暖色系"),
],
"size": [
(r"(竖屏|手机|9:16)", "竖屏"),
(r"(横屏|平板|电脑|16:9)", "横屏"),
]
}
def extract(self, user_text: str) -> Dict[str, Any]:
"""
从用户输入中提取参数
Args:
user_text: 用户输入的文本
Returns:
提取的参数键值对
"""
extracted = {}
for param_name, patterns in self.extractors.items():
for pattern, value in patterns:
if re.search(pattern, user_text):
extracted[param_name] = value
break
return extracted
def extract_with_llm(
self,
user_text: str,
api_key: str
) -> Dict[str, Any]:
"""
使用 LLM 从用户输入中提取参数
Args:
user_text: 用户输入
api_key: API Key
Returns:
提取的结构化参数
"""
import httpx
import json
prompt = f"""请从用户输入中提取壁纸相关的参数,返回 JSON 格式。
用户输入:{user_text}
可提取的参数:
- style: 风格(如极简主义、水墨国风等)
- theme: 主题(如山川、花鸟等)
- color: 色调偏好
- scene: 使用场景(锁屏/主屏)
返回格式示例:
{{"style": "极简主义", "theme": "远山"}}"""
# 调用 LLM 提取
# 实际代码中会调用火山引擎等 API
response = httpx.post(
"https://api.example.com/chat/completions",
headers={"Authorization": f"Bearer {api_key}"},
json={
"model": "doubao-lite-4k",
"messages": [
{"role": "system", "content": prompt},
{"role": "user", "content": user_text}
],
"temperature": 0.1
}
)
if response.status_code == 200:
result = response.json()
content = result["choices"][0]["message"]["content"]
try:
return json.loads(content)
except:
return {}
return {}
3.5 Skill 的执行逻辑配置
Skill 的执行逻辑可以调用内部能力或外部 API:
# Skill 执行器示例
class SkillExecutor:
"""
Skill 执行器
负责执行 Skill 的业务逻辑
"""
async def execute(
self,
skill_config: Dict[str, Any],
params: Dict[str, Any]
) -> Dict[str, Any]:
"""
执行 Skill 逻辑
Args:
skill_config: Skill 配置
params: 执行参数
Returns:
执行结果
"""
execution_type = skill_config.get("execution", {}).get("type")
if execution_type == "plugin":
# 通过插件执行
return await self._execute_via_plugin(
skill_config["execution"]["pluginId"],
params
)
elif execution_type == "api":
# 直接调用外部 API
return await self._execute_via_api(
skill_config["execution"]["apiUrl"],
params
)
elif execution_type == "workflow":
# 调用工作流
return await self._execute_via_workflow(
skill_config["execution"]["workflowId"],
params
)
else:
return {"error": f"Unknown execution type: {execution_type}"}
async def _execute_via_plugin(
self,
plugin_id: str,
params: Dict[str, Any]
) -> Dict[str, Any]:
"""通过插件执行"""
# 实际代码中会调用插件服务
return {"status": "executing", "plugin_id": plugin_id, "params": params}
async def _execute_via_api(
self,
api_url: str,
params: Dict[str, Any]
) -> Dict[str, Any]:
"""通过外部 API 执行"""
import httpx
async with httpx.AsyncClient() as client:
response = await client.post(api_url, json=params)
return response.json()
async def _execute_via_workflow(
self,
workflow_id: str,
params: Dict[str, Any]
) -> Dict[str, Any]:
"""通过工作流执行"""
return {"status": "executing", "workflow_id": workflow_id, "params": params}
四、Skill 的最佳实践
4.1 设计原则
在设计自定义 Skill 时,应遵循以下原则:
| 原则 | 说明 | 实践建议 |
|---|---|---|
| 单一职责 | 一个 Skill 只做一件事 | 壁纸生成 Skill 不混入天气查询功能 |
| 高内聚 | 相关功能组织在一起 | 参数提取、业务处理、结果展示在同一 Skill |
| 低耦合 | 减少对其他能力的依赖 | Skill 应可独立运行和测试 |
| 容错性 | 处理各种异常情况 | 参数缺失时引导用户补充 |
| 可测试 | 支持隔离测试 | 提供模拟数据和测试接口 |
4.2 交互设计最佳实践
# Skill 交互设计最佳实践示例
class SkillInteractionGuide:
"""
Skill 交互设计指南
"""
@staticmethod
def get_best_practices() -> list:
"""获取交互设计最佳实践列表"""
return [
{
"practice": "开场明确能力边界",
"good": "你好!我是壁纸助手,可以帮你生成各种风格的手机壁纸。",
"bad": "你好!有什么可以帮你的?",
"reason": "用户第一时间了解能做什么",
},
{
"practice": "引导式提问",
"good": "你想要什么风格的壁纸呢?如:极简主义、水墨国风、梦幻星空...",
"bad": "请选择风格。",
"reason": "提供具体选项降低用户认知负担",
},
{
"practice": "确认式回复",
"good": "好的,极简主义风格!想要什么主题的画面呢?",
"bad": "已记录。",
"reason": "让用户感知到交互反馈",
},
{
"practice": "灵活输入兼容",
"good": "支持选择预设选项或自由描述",
"bad": "只能从预设中选择",
"reason": "满足不同用户的输入习惯",
},
{
"practice": "错误引导",
"good": "抱歉没理解,请重新描述或选择以下选项:...",
"bad": "输入错误。",
"reason": "友好引导用户回到正轨",
},
]
4.3 日志与监控
# Skill 通用日志记录示例
import logging
import uuid
from datetime import datetime
class SkillLogger:
"""Skill 日志记录器"""
def __init__(self, skill_name: str):
self.skill_name = skill_name
self.logger = logging.getLogger(f"skill.{skill_name}")
def log_activation(self, trigger_type: str, trigger_value: str):
"""记录 Skill 被激活"""
self.logger.info(
f"Skill[{self.skill_name}] 被激活, "
f"触发类型={trigger_type}, 触发值={trigger_value}"
)
def log_parameter_collected(self, param_name: str, param_value: str):
"""记录参数收集"""
self.logger.info(
f"Skill[{self.skill_name}] 收集参数, "
f"{param_name}={param_value}"
)
def log_execution_start(self, params: dict):
"""记录执行开始"""
execution_id = uuid.uuid4().hex[:8]
self.logger.info(
f"Skill[{self.skill_name}] 开始执行, "
f"execution_id={execution_id}, params={params}"
)
return execution_id
def log_execution_end(self, execution_id: str, success: bool, duration: float):
"""记录执行结束"""
self.logger.info(
f"Skill[{self.skill_name}] 执行结束, "
f"execution_id={execution_id}, "
f"success={success}, duration={duration:.3f}s"
)
4.4 权限与安全
# Skill 权限控制示例
class SkillPermissionManager:
"""Skill 权限管理器"""
def __init__(self):
self.required_permissions = {
"wallpaper_generator": [
"image_generation",
"file_storage",
"device_info"
],
"weather_query": [
"location",
"network"
],
"order_manager": [
"user_info",
"payment"
]
}
def check_permissions(
self,
skill_name: str,
granted_permissions: list
) -> dict:
"""
检查 Skill 所需的权限是否已授予
Args:
skill_name: Skill 名称
granted_permissions: 已授予的权限列表
Returns:
检查结果
"""
required = self.required_permissions.get(skill_name, [])
missing = [p for p in required if p not in granted_permissions]
return {
"has_all_permissions": len(missing) == 0,
"missing_permissions": missing,
"required_permissions": required,
"granted_permissions": granted_permissions
}
六、Skill 与插件的协作模式
6.1 Skill 调用 Plugin 的方式
Skill 可以通过以下方式调用已创建的插件工具:
# Skill 中调用 Plugin 的示例
class SkillPluginInvocation:
"""Skill 调用 Plugin 的封装"""
async def invoke_plugin(self, plugin_name: str, tool_name: str, params: dict):
"""
调用指定插件的工具
Args:
plugin_name: 插件名称
tool_name: 工具名称
params: 调用参数
"""
# 构建调用请求
request = {
"plugin": plugin_name,
"tool": tool_name,
"parameters": params
}
# 执行调用并返回结果
result = await self.executor.execute(request)
return result
6.2 Skill 与 Plugin 的协作流程
| 协作模式 | 说明 | 适用场景 |
|---|---|---|
| 单插件调用 | Skill 直接调用一个 Plugin 工具 | 简单功能实现 |
| 多插件编排 | Skill 按顺序调用多个 Plugin | 复杂业务流程 |
| 条件分支调用 | 根据参数选择不同 Plugin | 多场景适配 |
| 并行调用 | 同时调用多个 Plugin 并汇总 | 数据聚合场景 |
最佳实践:Skill 负责交互流程编排,Plugin 负责具体能力执行,两者各司其职,保持解耦。
七、Skill 开发工具与调试
7.1 调试与预览
在小艺开放平台的调试界面中,开发者可以实时预览 Skill 的交互效果:
# 调试 Skill 的步骤
1. 进入技能管理 → 选择目标 Skill
2. 点击"调试"进入调试界面
3. 在对话框中输入测试语句
4. 观察 Skill 的触发、参数提取和执行结果
5. 检查 Plugin 调用日志和响应数据
6. 根据调试结果优化触发条件和交互流程
7.2 版本管理
Skill 支持版本管理,开发者可以管理不同版本的发布状态:
| 版本状态 | 说明 | 操作 |
|---|---|---|
| 草稿 | 未发布的编辑版本 | 可编辑、可调试 |
| 测试版 | 发布供测试使用的版本 | 可调试、可回退 |
| 正式版 | 通过审核的正式版本 | 不可编辑 |
| 下架版 | 已下线的版本 | 可查看历史数据 |
五、Skill 开发常见问题
5.1 触发不准确
问题:Skill 在不应该触发时被触发了,或者应该触发时没触发。
解决方案:
# 触发条件优化建议
def optimize_trigger_conditions():
"""
Skill 触发条件优化指南
"""
suggestions = [
"1. 关键词触发:使用精确匹配而非包含匹配",
"2. 意图触发:提供更多正向和负向示例",
"3. 置信度阈值:调整合适的置信度阈值(0.6-0.8)",
"4. 上下文判断:结合对话历史避免误触发",
"5. 否定检测:检测用户是否想取消操作"
]
return "\n".join(suggestions)
5.2 参数提取失败
问题:用户表达含糊,无法提取必要参数。
解决方案:
# 参数提取失败处理
def handle_missing_parameters(missing_params: list) -> str:
"""
处理参数缺失情况,引导用户提供
Args:
missing_params: 缺失的参数列表
Returns:
引导提示语
"""
guides = {
"style": "你想要什么风格的壁纸呢?比如极简主义、水墨国风等。",
"theme": "想要什么主题的画面呢?山川、花鸟、星空都可以哦。",
"scene": "壁纸是用在锁屏还是主屏呢?竖屏还是横屏?",
}
if not missing_params:
return "好的,马上为你生成!"
guide = "请告诉我以下信息:\n"
for param in missing_params:
if param in guides:
guide += f"- {guides[param]}\n"
return guide
总结
本文详细介绍了鸿蒙智能体平台中自定义 Skill 开发的基础知识:
- Skill 概述:Skill 的概念、核心价值和与 Plugin/Workflow 的对比
- 架构组成:Skill 的触发、交互、执行、输出四层架构
- 生命周期:Skill 从空闲到完成的六种状态流转
- 配置结构:Skill 的 JSON 配置规范和各字段说明
- 触发条件:关键词触发、LLM 意图触发等多种方式
- 交互流程:多轮对话状态机设计方法
- 参数提取:基于规则和 LLM 的参数提取策略
- 执行逻辑:通过 Plugin/API/Workflow 三种执行方式
- 最佳实践:设计原则、交互设计、日志监控、权限安全
Skill 是构建高质量智能体的重要能力单元。合理设计和使用 Skill,可以让智能体的能力更加模块化、可复用、易于维护。下一篇文章将介绍 Skill 与插件的协同开发,深入探讨如何在 Skill 中调用和组织多个插件实现复杂功能。
如果这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐ 和关注 🎯!你的支持是我持续创作的动力!
相关资源
更多推荐




所有评论(0)