前言

在前面的文章中,我们深入了解了智能体的编排方式插件开发工作流消息卡片等核心概念。本文将带你进入智能体开发的另一个重要领域——自定义 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 作为核心交互单元,通过 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 插件创建界面

上图展示了小艺开放平台中 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 开发的基础知识:

  1. Skill 概述:Skill 的概念、核心价值和与 Plugin/Workflow 的对比
  2. 架构组成:Skill 的触发、交互、执行、输出四层架构
  3. 生命周期:Skill 从空闲到完成的六种状态流转
  4. 配置结构:Skill 的 JSON 配置规范和各字段说明
  5. 触发条件:关键词触发、LLM 意图触发等多种方式
  6. 交互流程:多轮对话状态机设计方法
  7. 参数提取:基于规则和 LLM 的参数提取策略
  8. 执行逻辑:通过 Plugin/API/Workflow 三种执行方式
  9. 最佳实践:设计原则、交互设计、日志监控、权限安全

Skill 是构建高质量智能体的重要能力单元。合理设计和使用 Skill,可以让智能体的能力更加模块化、可复用、易于维护。下一篇文章将介绍 Skill 与插件的协同开发,深入探讨如何在 Skill 中调用和组织多个插件实现复杂功能。


如果这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐ 和关注 🎯!你的支持是我持续创作的动力!

相关资源

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐