# Skill 技能模組

## 什麼是 Skill？

Skill（技能）是 MaiAgent 平台中用於封裝 AI 助理專業能力的模組化機制。與 Function Calling 讓 LLM 能呼叫單一工具不同，Skill 將一組**指令（Instructions）**、\*\*工具（Tools）**與**資源檔案（Resources）\*\*封裝為一個可重複使用的能力單元，使 AI 助理能夠在對話過程中動態展開完整的任務執行流程。

簡而言之：

* **Function Calling / 工具**：LLM 呼叫單一 API 或函式
* **Skill**：LLM 展開一整套 SOP 指令，並在流程中按需調用多個工具

<figure><img src="https://527168072-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F38pkhhqHl1oA6yyE9R2n%2Fuploads%2Fgit-blob-d8cf8aa85fc73203db4a2e33e8b6a38fa0d69035%2Fskill-composition.png?alt=media" alt=""><figcaption><p>技能（Skill）= 指令（Instructions）+ 工具（Tools）+ 資源（Resources）</p></figcaption></figure>

***

## Skill 的運作原理

### 運作流程

```
使用者提問
    │
    ▼
AI 助理接收訊息
    │
    ▼
LLM 分析意圖，比對已綁定技能的描述
    │
    ├─ 匹配到技能 → 呼叫 SkillExpandTool
    │                    │
    │                    ▼
    │              展開技能的完整指令內容
    │              + 列出可用的附加工具
    │                    │
    │                    ▼
    │              LLM 依指令逐步執行
    │              按需呼叫 LoadSkillTool 載入工具
    │                    │
    │                    ▼
    │              工具執行結果回傳 LLM
    │                    │
    │                    ▼
    │              LLM 依指令格式生成回覆
    │
    └─ 未匹配 → 一般對話回覆
```

### 1. 技能展開（Skill Expansion）

當 AI 助理判斷使用者的問題應由某個技能處理時，系統會呼叫 `SkillExpandTool`：

* **輸入**：技能名稱（`skill_name`）
* **處理**：根據名稱查詢技能，取得完整指令內容與附加工具列表
* **輸出**：Markdown 格式的指令內容 + 可用工具清單

```json
{
  "name": "expand_skill",
  "arguments": {
    "skill_name": "休假天數計算"
  }
}
```

### 2. 工具動態載入（Tool Loading）

技能展開後，LLM 在執行指令過程中若需要調用工具，會透過 `LoadSkillTool` 動態載入：

* **輸入**：工具名稱（`tool_name`）
* **處理**：查詢工具（支援 MCP 工具與 API 工具，名稱不區分大小寫）
* **輸出**：工具的 ID、名稱、描述與可用狀態

這種動態載入機制讓技能的工具不需要預先全部載入對話上下文，降低 Token 消耗。

***

## SKILL.md 規格

Skill 的核心定義檔案為 `SKILL.md`，使用 YAML Frontmatter + Markdown 內容格式：

```markdown
---
name: 技能名稱
description: 技能描述（決定 AI 何時觸發此技能）
---

# 技能標題

## 觸發條件
使用者詢問 XXX 相關問題時觸發。

## 執行步驟

### Step 1：確認資訊
引導使用者提供必要資訊...

### Step 2：查詢資料
使用 retrieve_text_nodes 搜尋知識庫...

### Step 3：產出回覆
依照以下格式回覆：
- ① 適用法規
- ② 計算結果
- ③ 參考範例
```

### Frontmatter 欄位

| 欄位            | 必填 | 說明                   |
| ------------- | -- | -------------------- |
| `name`        | 是  | 技能名稱，組織內不可重複         |
| `description` | 是  | 技能描述，LLM 用於判斷是否觸發此技能 |

### 指令內容撰寫建議

1. **觸發條件明確**：在描述和指令中清楚定義「何時觸發」與「何時不觸發」
2. **步驟結構化**：使用編號步驟（Step 1, Step 2...）讓 LLM 能循序執行
3. **工具呼叫指引**：在步驟中明確指出應使用哪個工具與查詢策略
4. **回覆格式定義**：用模板或表格定義最終回覆的格式，確保輸出一致性
5. **防錯清單**：在指令末尾加入檢查清單，讓 LLM 自我驗證結果

***

## 技能包（Skill Package）

### 檔案結構

上傳的 `.skill` 或 `.zip` 檔案應包含以下結構：

```
my-skill.skill (ZIP 格式)
├── SKILL.md          # 必要：技能定義檔
├── reference.pdf     # 選填：參考資料
├── template.xlsx     # 選填：模板檔案
└── examples/         # 選填：範例資料
    └── case1.json
```

### 安全性驗證

系統在解析技能包時會進行以下安全檢查：

* **壓縮比檢查**：最大 100:1，防止 ZIP 炸彈攻擊
* **路徑遍歷防護**：阻擋 `../` 等路徑注入
* **檔案大小限制**：依組織設定的上傳限制（預設 100 MB）
* **SKILL.md 驗證**：必須存在且包含有效的 `name` 和 `description`

***

## API 端點

### Skill CRUD

| 方法       | 端點                     | 說明                 |
| -------- | ---------------------- | ------------------ |
| `GET`    | `/api/v1/skills/`      | 列出組織內所有技能（支援分頁、搜尋） |
| `POST`   | `/api/v1/skills/`      | 手動建立技能             |
| `GET`    | `/api/v1/skills/{id}/` | 取得技能詳情             |
| `PATCH`  | `/api/v1/skills/{id}/` | 更新技能               |
| `DELETE` | `/api/v1/skills/{id}/` | 刪除技能（含 S3 清理）      |

### 技能包操作

| 方法     | 端點                                       | 說明                        |
| ------ | ---------------------------------------- | ------------------------- |
| `POST` | `/api/v1/skills/upload/`                 | 上傳 `.skill` / `.zip` 建立技能 |
| `POST` | `/api/v1/skills/{id}/reupload/`          | 重新上傳替換技能包                 |
| `GET`  | `/api/v1/skills/{id}/export/`            | 匯出技能為 `.skill` 檔案         |
| `GET`  | `/api/v1/skills/{id}/package-structure/` | 查看技能包檔案結構                 |

### 資源管理（巢狀路由）

| 方法       | 端點                                              | 說明             |
| -------- | ----------------------------------------------- | -------------- |
| `GET`    | `/api/v1/skills/{id}/resources/`                | 列出技能資源檔案       |
| `POST`   | `/api/v1/skills/{id}/resources/`                | 上傳資源（僅手動建立的技能） |
| `DELETE` | `/api/v1/skills/{id}/resources/{rid}/`          | 刪除資源（僅手動建立的技能） |
| `GET`    | `/api/v1/skills/{id}/resources/{rid}/download/` | 下載資源檔案         |

### 建立技能範例

**手動建立：**

```json
POST /api/v1/skills/
{
  "name": "退貨處理流程",
  "description": "當客戶要求退貨、換貨時觸發。查詢訂單、確認退貨資格、建立退貨單。",
  "instructions": "# 退貨處理\n\n## Step 1：查詢訂單\n...",
  "attached_tool_ids": [
    "uuid-of-order-query-tool",
    "uuid-of-return-api-tool"
  ]
}
```

**上傳技能包：**

```bash
curl -X POST /api/v1/skills/upload/ \
  -F "file=@my-skill.skill" \
  -F "attached_tool_ids=[\"uuid-1\",\"uuid-2\"]"
```

***

## 技能與 AI 助理的綁定

技能透過 `ChatbotSkill` 中介模型與 AI 助理建立多對多關聯：

* 一個 AI 助理可綁定多個技能
* 一個技能可被多個 AI 助理使用
* 綁定/解綁操作會記錄在 `ChatbotSkillEvent` 歷史追蹤表中

```
AI 助理 A ──┬── 技能：退貨處理
            ├── 技能：產品諮詢
            └── 技能：郵件發送

AI 助理 B ──┬── 技能：產品諮詢  ← 共用
            └── 技能：會議查詢
```

***

## MaiAgent Skill 的獨特優勢

### 1. 指令與工具解耦

技能的指令內容和附加工具是獨立管理的，可以隨時調整指令邏輯而不影響工具設定，反之亦然。這使得技能的維護和迭代更加靈活。

### 2. 動態展開機制

技能指令不會預先載入對話上下文，而是在 LLM 判斷需要時才動態展開。這大幅減少每次對話的 Token 消耗，尤其適用於綁定大量技能的 AI 助理。

### 3. 技能包生態

透過 `.skill` 檔案格式，技能可以在不同組織間分享與匯入。企業可以建立內部技能庫，或將最佳實踐封裝為技能包分發給合作夥伴。

### 4. 完整的版本控管

上傳方式建立的技能支援重新上傳（Reupload），可在不刪除原有技能的情況下更新技能包內容。系統會完整替換技能包與資源檔案，確保版本一致性。

### 5. 權限控管

技能的存取受 `chatbot_skill_access` 權限控制，組織管理員可透過角色權限系統精細管理誰能建立、編輯和刪除技能。
