返回笔记首页

Agent Skills 完全指南

主题配置

1. Agent Skills 是什么?

核心概念

Agent Skills 是 Anthropic 为 Claude 设计的一种模块化知识和能力扩展机制。它本质上是一个包含特定领域最佳实践、工作流程和工具使用说明的文档系统。

具体形态

一个 Skill 通常是一个包含以下内容的文件夹:

plain
skill-name/
├── SKILL.md          # 主文档,包含触发条件、使用指南
├── examples/         # 示例文件
├── templates/        # 模板文件
└── utils/           # 辅助脚本(可选)

SKILL.md 的典型结构

markdown
# Skill Name

## Description

何时触发这个 skill,它能解决什么问题

## Trigger Conditions

- 用户提到某个关键词
- 用户上传特定类型的文件
- 任务需要特定的输出格式

## Instructions

1. 第一步做什么
2. 如何处理数据
3. 输出格式要求
4. 常见错误和解决方案

## Code Examples

具体的代码示例和最佳实践

## Dependencies

需要的工具、库、API

工作流程

plain
用户请求
    ↓
Claude 分析请求
    ↓
查看 available_skills 列表
    ↓
匹配相关 skill(可能多个)
    ↓
使用 view 工具读取 SKILL.md
    ↓
按照 skill 指引执行任务
    ↓
返回结果

实际执行示例

用户: "帮我创建一个 Word 文档"

python
# Claude 的内部流程
1. 识别关键词 "Word 文档" → 匹配 docx skill
2. view("/mnt/skills/public/docx/SKILL.md")
3. 读取最佳实践:
   - 使用 python-docx 库
   - 注意段落格式
   - 表格创建技巧
   - 图片插入方法
4. 按照 skill 指引生成代码
5. 创建文件并输出

2. Skills vs MCP 的区别

本质差异对比表

维度 Agent Skills MCP (Model Context Protocol)
定位 知识库 + 工作流指南 工具调用协议
内容 文档、最佳实践、模板 可执行的函数/工具
执行方式 Claude 读取后自己写代码 直接调用外部服务
数据来源 静态文档(Markdown) 动态 API/数据库
适用场景 文档生成、格式转换、编码规范 外部系统集成、实时数据查询

具体例子对比

场景: 创建 Excel 报表

使用 Skill
python
# Claude 读取 xlsx skill 后的执行
import openpyxl
from openpyxl.styles import Font, PatternFill

# skill 教 Claude 如何:
wb = openpyxl.Workbook()
ws = wb.active

# 1. 设置标题格式(skill 提供的最佳实践)
header_fill = PatternFill(start_color="4472C4", fill_type="solid")
ws['A1'].fill = header_fill

# 2. 添加数据验证(skill 中的示例)
from openpyxl.worksheet.datavalidation import DataValidation
dv = DataValidation(type="list", formula1='"选项1,选项2"')
ws.add_data_validation(dv)

# Claude 自己写完整代码
wb.save('report.xlsx')
使用 MCP
python
# MCP Server 提供的工具
tools = [
    {
        "name": "create_excel_report",
        "description": "创建 Excel 报表",
        "input_schema": {
            "type": "object",
            "properties": {
                "data": {"type": "array"},
                "template": {"type": "string"}
            }
        }
    }
]

# Claude 直接调用
result = mcp_server.create_excel_report(
    data=sales_data,
    template="monthly_report"
)

MCP 会被淘汰吗?

不会,它们是互补的

  1. Skills 优势场景:
    • 文档格式转换(Word/Excel/PDF)
    • 前端代码生成(React/Vue)
    • 遵循特定编码规范
    • 创意内容生成
  2. MCP 优势场景:
    • 访问实时数据库
    • 调用第三方 API
    • 执行系统级操作
    • 需要认证的服务
  3. 协同工作示例:
plain
用户: "从数据库读取销售数据,生成 PPT 报告"

Claude:
1. 用 MCP 连接数据库获取数据
2. 用 pptx skill 学习如何创建专业 PPT
3. 结合两者生成最终报告

3. 如何使用和创建 Skills

3.1 查找现有 Skills

系统提供的 Skills 位置

bash
/mnt/skills/public/      # Anthropic 官方 skills
/mnt/skills/examples/    # 示例 skills
/mnt/skills/user/        # 用户自定义 skills
查看可用 skills
bash
# 在 Claude 的计算机环境中
ls /mnt/skills/public/
# 输出: docx/ pptx/ xlsx/ pdf/ frontend-design/ ...

3.2 使用 Skill 的标准流程

用户视角

plain
你: "帮我创建一个 Vue3 项目的组件"
Claude: (自动触发相关 skill,你无需手动操作)
开发者视角(如果你想查看 skill 内容)
python
# Claude 内部会执行
view("/mnt/skills/public/frontend-design/SKILL.md")

3.3 创建自定义 Skill - Vue3 项目示例

Step 1: 创建 Skill 文件结构

bash
/mnt/skills/user/vue3-component-builder/
├── SKILL.md
├── templates/
│   ├── component-template.vue
│   ├── composable-template.ts
│   └── store-template.ts
└── examples/
    ├── data-table.vue
    └── form-builder.vue

Step 2: 编写 SKILL.md

markdown
# Vue3 Component Builder Skill

## Description

为 Vue3 + TypeScript + Pinia + Vite 项目生成高质量组件。
遵循 Vue3 Composition API 最佳实践。

## Trigger Conditions

- 用户提到 "Vue3 组件"
- 用户要求创建 .vue 文件
- 用户提到 "Composition API"
- 任务涉及 Pinia store 或 composables

## Core Principles

### 1. 组件结构规范

````vue
<script setup lang="ts">
// 1. 导入顺序
import { ref, computed, onMounted } from 'vue'
import type { ComponentType } from '@/types'

// 2. Props 定义
interface Props {
    modelValue: string
    disabled?: boolean
}
const props = withDefaults(defineProps<Props>(), {
    disabled: false,
})

// 3. Emits 定义
const emit = defineEmits<{
    'update:modelValue': [value: string]
    change: [value: string]
}>()

// 4. 响应式数据
const localValue = ref(props.modelValue)

// 5. Computed
const displayValue = computed(() => localValue.value.toUpperCase())

// 6. Methods
const handleChange = () => {
    emit('update:modelValue', localValue.value)
}

// 7. Lifecycle
onMounted(() => {
    console.log('Component mounted')
})
</script>

<template>
    <div class="component-wrapper">
        <!-- 模板内容 -->
    </div>
</template>

<style scoped>
.component-wrapper {
    /* 样式 */
}
</style>
```text ### 2. Composables 规范 ```typescript // useCounter.ts import { ref,
computed } from 'vue' export function useCounter(initialValue = 0) { const count
= ref(initialValue) const doubled = computed(() => count.value * 2) const
increment = () => count.value++ const decrement = () => count.value-- return {
count, doubled, increment, decrement } } ```text ### 3. Pinia Store 规范
```typescript // stores/user.ts import { defineStore } from 'pinia' import {
ref, computed } from 'vue' export const useUserStore = defineStore('user', () =>
{ // State const user = ref
<User | null></User>
text

#### Step 4: 添加示例

##### examples/data-table.vue

```vue
<script setup lang="ts">
import { ref, computed } from 'vue'

interface Column {
    key: string
    label: string
    sortable?: boolean
}

interface Props {
    columns: Column[]
    data: Record<string, any>[]
}

const props = defineProps<Props>()

const sortKey = ref<string>('')
const sortOrder = ref<'asc' | 'desc'>('asc')

const sortedData = computed(() => {
    if (!sortKey.value) return props.data

    return [...props.data].sort((a, b) => {
        const aVal = a[sortKey.value]
        const bVal = b[sortKey.value]
        const order = sortOrder.value === 'asc' ? 1 : -1
        return aVal > bVal ? order : -order
    })
})

const handleSort = (key: string) => {
    if (sortKey.value === key) {
        sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc'
    } else {
        sortKey.value = key
        sortOrder.value = 'asc'
    }
}
</script>

<template>
    <table class="data-table">
        <thead>
            <tr>
                <th
                    v-for="col in columns"
                    :key="col.key"
                    @click="col.sortable && handleSort(col.key)"
                    :class="{ sortable: col.sortable }"
                >
                    {{ col.label }}
                    <span v-if="sortKey === col.key">
                        {{ sortOrder === 'asc' ? '↑' : '↓' }}
                    </span>
                </th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="(row, index) in sortedData" :key="index">
                <td v-for="col in columns" :key="col.key">
                    {{ row[col.key] }}
                </td>
            </tr>
        </tbody>
    </table>
</template>

<style scoped>
.data-table {
    width: 100%;
    border-collapse: collapse;
}

.data-table th,
.data-table td {
    padding: 12px;
    text-align: left;
    border-bottom: 1px solid #e5e7eb;
}

.data-table th.sortable {
    cursor: pointer;
    user-select: none;
}

.data-table th.sortable:hover {
    background-color: #f3f4f6;
}
</style>
```

### 3.4 使用自定义 Skill

创建好 skill 后,上传到 Claude:

```plain
你: "我上传了一个 Vue3 项目的 skill,帮我创建一个数据表格组件"

Claude:
1. 检测到 vue3-component-builder skill
2. 读取 SKILL.md
3. 参考 examples/data-table.vue
4. 按规范生成组件
```

---

## 4. Skills 实现外部知识检索

### 4.1 传统 RAG vs Skills 对比

#### 传统 RAG 架构

```plain
用户查询
    ↓
向量化查询
    ↓
在向量数据库中检索 (Top-K)
    ↓
拼接检索到的文档片段
    ↓
发送给 LLM
    ↓
LLM 基于片段生成答案
```

##### 问题

- 检索到的片段可能不连贯
- 缺少上下文信息
- 无法执行复杂工作流
- 依赖外部向量数据库

#### Skills 架构

```plain
用户请求
    ↓
匹配相关 skill
    ↓
读取完整 skill 文档
    ↓
Claude 理解完整上下文
    ↓
执行文档中的工作流
    ↓
生成结果
```

##### 优势

- 完整的上下文理解
- 包含可执行的代码示例
- 工作流程清晰
- 无需外部依赖

### 4.2 实际案例: 公司内部知识库

#### 场景设定

某科技公司需要让 Claude 回答关于内部技术栈、编码规范、部署流程的问题。

#### 传统 RAG 实现

##### 步骤 1: 准备向量数据库

```python
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

# 文档分块
docs = [
    "我们使用 Vue3 + Vite...",
    "部署流程: 1. 运行测试 2. 构建...",
    "代码审查规范..."
]

# 向量化
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_texts(docs, embeddings)
```

###### 步骤 2: 查询时检索

```python
query = "如何部署前端项目?"
relevant_docs = vectorstore.similarity_search(query, k=3)

# 拼接上下文
context = "\n".join([doc.page_content for doc in relevant_docs])

# 发送给 Claude
response = claude.complete(
    prompt=f"基于以下文档回答: {context}\n\n问题: {query}"
)
```

###### 问题示例

```plain
检索到的片段:
1. "...运行测试..."
2. "...Vue3 配置..."
3. "...Docker 命令..."

缺少:
- 完整部署流程
- 前置条件
- 错误处理步骤
```

#### Skills 实现

##### 创建 deployment skill

````markdown
# Company Deployment Skill

## Frontend Deployment Workflow

### Prerequisites

- Node.js 18+
- 访问 GitLab CI
- AWS CLI 配置完成

### Step-by-Step Process

#### 1. 本地测试

````bash
npm run test:unit
npm run test:e2e
npm run lint
```text

#### 2. 构建生产版本

```bash
npm run build

## 验证构建产物
ls -la dist/
```text

#### 3. 部署到 Staging

```bash
## 使用公司 CLI 工具
company-cli deploy --env=staging --project=frontend

## 等待健康检查
company-cli health-check --env=staging
```text

#### 4. 运行冒烟测试

```bash
npm run test:smoke -- --env=staging
```text

#### 5. 部署到 Production

```bash
## 需要审批
company-cli deploy --env=production --project=frontend --require-approval

## 监控指标
company-cli monitor --env=production --duration=30m
```text

### Rollback Procedure

如果部署失败:

```bash
company-cli rollback --env=production --to-version=previous
```text

### Common Issues

#### Issue: 构建失败 "Module not found"

Solution:

```bash
rm -rf node_modules package-lock.json
npm install
```text

#### Issue: 健康检查超时

Solution:

1. 检查 AWS 安全组规则
2. 验证环境变量配置
3. 查看 CloudWatch 日志

### Notification Channels

- Slack: #deployments
- PagerDuty: 生产环境问题

### Related Documentation

- [AWS 架构图](https://internal.wiki/aws-arch)
- [CI/CD 配置](https://gitlab.company.com/docs/cicd)

```plain
### 使用示例:
```text

你: "如何部署我们的前端项目到生产环境?"

Claude:

1. 读取 deployment skill
2. 理解完整流程
3. 返回详细步骤

根据公司的部署规范,你需要按以下步骤操作:

[返回完整流程,包含命令、检查点、错误处理]

如果遇到健康检查超时,可以检查 AWS 安全组规则...

```plain
### 4.3 Skills 的优势总结

| 维度 | 传统 RAG | Skills |
|------|----------|--------|
| 上下文完整性 | 片段化 | 完整文档 |
| 代码示例 | 可能被截断 | 完整可执行 |
| 工作流支持 | 难以表达 | 内置支持 |
| 维护成本 | 需要向量数据库 | 纯文件系统 |
| 版本控制 | 困难 | Git 友好 |
| 调试 | 不透明 | 可直接查看 |
| 实时更新 | 需要重新索引 | 直接编辑文件 |

### 4.4 混合方案: Skills + RAG

对于超大规模知识库,可以结合使用:
```text

外层: RAG 检索相关 skill 名称 ↓ 中层: 加载对应的 skill 文档 ↓ 内层: Claude 按 skill 执行

```plain
#### 示例代码:
```python
# 1. 用 RAG 找到相关 skill
query = "前端性能优化"
relevant_skills = vectorstore.search(query)
# 结果: ["frontend-performance", "vue3-optimization"]

# 2. 加载这些 skills
for skill_name in relevant_skills:
    skill_content = read_skill(f"/mnt/skills/user/{skill_name}/SKILL.md")
    # Claude 获得完整的优化指南

# 3. Claude 综合所有 skills 给出答案
text

---

## 5. 实战演示: 完整的 Vue3 组件生成

### 场景

用户需要一个带搜索、排序、分页的数据表格组件。

### 执行流程

#### Step 1: 触发 skill

```plain
用户: "创建一个 Vue3 数据表格组件,要支持搜索、排序和分页"
```

#### Step 2: Claude 读取 skill

```python
view("/mnt/skills/user/vue3-component-builder/SKILL.md")
view("/mnt/skills/user/vue3-component-builder/examples/data-table.vue")
```

#### Step 3: 生成代码

```typescript
// src/components/DataTable.vue
<script setup lang="ts">
import { ref, computed } from 'vue'

interface Column {
  key: string
  label: string
  sortable?: boolean
  width?: string
}

interface Props {
  columns: Column[]
  data: Record<string, any>[]
  pageSize?: number
}

const props = withDefaults(defineProps<Props>(), {
  pageSize: 10
})

// 搜索
const searchQuery = ref('')

const filteredData = computed(() => {
  if (!searchQuery.value) return props.data

  return props.data.filter(row =>
    Object.values(row).some(value =>
      String(value).toLowerCase().includes(searchQuery.value.toLowerCase())
    )
  )
})

// 排序
const sortKey = ref<string>('')
const sortOrder = ref<'asc' | 'desc'>('asc')

const sortedData = computed(() => {
  if (!sortKey.value) return filteredData.value

  return [...filteredData.value].sort((a, b) => {
    const aVal = a[sortKey.value]
    const bVal = b[sortKey.value]
    const order = sortOrder.value === 'asc' ? 1 : -1

    if (typeof aVal === 'number' && typeof bVal === 'number') {
      return (aVal - bVal) * order
    }

    return String(aVal).localeCompare(String(bVal)) * order
  })
})

const handleSort = (key: string) => {
  if (sortKey.value === key) {
    sortOrder.value = sortOrder.value === 'asc' ? 'desc' : 'asc'
  } else {
    sortKey.value = key
    sortOrder.value = 'asc'
  }
}

// 分页
const currentPage = ref(1)

const totalPages = computed(() =>
  Math.ceil(sortedData.value.length / props.pageSize)
)

const paginatedData = computed(() => {
  const start = (currentPage.value - 1) * props.pageSize
  const end = start + props.pageSize
  return sortedData.value.slice(start, end)
})

const goToPage = (page: number) => {
  if (page >= 1 && page <= totalPages.value) {
    currentPage.value = page
  }
}
</script>

<template>
  <div class="data-table-container">
    <!-- 搜索框 -->
    <div class="search-bar">
      <input
        v-model="searchQuery"
        type="text"
        placeholder="搜索..."
        class="search-input"
      />
    </div>

    <!-- 表格 -->
    <table class="data-table">
      <thead>
        <tr>
          <th
            v-for="col in columns"
            :key="col.key"
            :style="{ width: col.width }"
            @click="col.sortable && handleSort(col.key)"
            :class="{ sortable: col.sortable, active: sortKey === col.key }"
          >
            {{ col.label }}
            <span v-if="sortKey === col.key" class="sort-indicator">
              {{ sortOrder === 'asc' ? '↑' : '↓' }}
            </span>
          </th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(row, index) in paginatedData" :key="index">
          <td v-for="col in columns" :key="col.key">
            {{ row[col.key] }}
          </td>
        </tr>
      </tbody>
    </table>

    <!-- 分页 -->
    <div class="pagination">
      <button
        @click="goToPage(currentPage - 1)"
        :disabled="currentPage === 1"
        class="pagination-btn"
      >
        上一页
      </button>

      <span class="page-info">
        第 {{ currentPage }} / {{ totalPages }} 页
        (共 {{ sortedData.length }} 条)
      </span>

      <button
        @click="goToPage(currentPage + 1)"
        :disabled="currentPage === totalPages"
        class="pagination-btn"
      >
        下一页
      </button>
    </div>
  </div>
</template>

<style scoped>
.data-table-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.search-bar {
  display: flex;
  justify-content: flex-end;
}

.search-input {
  padding: 8px 12px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  width: 300px;
  font-size: 14px;
}

.search-input:focus {
  outline: none;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  background: white;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.data-table th,
.data-table td {
  padding: 12px 16px;
  text-align: left;
  border-bottom: 1px solid #e5e7eb;
}

.data-table th {
  background-color: #f9fafb;
  font-weight: 600;
  color: #374151;
}

.data-table th.sortable {
  cursor: pointer;
  user-select: none;
  transition: background-color 0.2s;
}

.data-table th.sortable:hover {
  background-color: #f3f4f6;
}

.data-table th.active {
  background-color: #e5e7eb;
}

.sort-indicator {
  margin-left: 4px;
  color: #3b82f6;
}

.data-table tbody tr:hover {
  background-color: #f9fafb;
}

.pagination {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 16px;
}

.pagination-btn {
  padding: 8px 16px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  background: white;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.2s;
}

.pagination-btn:hover:not(:disabled) {
  background-color: #f3f4f6;
  border-color: #9ca3af;
}

.pagination-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.page-info {
  font-size: 14px;
  color: #6b7280;
}
</style>
```

#### Step 4: 生成使用示例

```vue
<!-- App.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import DataTable from './components/DataTable.vue'

const columns = [
    { key: 'id', label: 'ID', sortable: true, width: '80px' },
    { key: 'name', label: '姓名', sortable: true },
    { key: 'email', label: '邮箱', sortable: true },
    { key: 'role', label: '角色', sortable: true },
    { key: 'createdAt', label: '创建时间', sortable: true },
]

const data = ref([
    {
        id: 1,
        name: '张三',
        email: 'zhang@example.com',
        role: '管理员',
        createdAt: '2024-01-15',
    },
    {
        id: 2,
        name: '李四',
        email: 'li@example.com',
        role: '用户',
        createdAt: '2024-01-16',
    },
    {
        id: 3,
        name: '王五',
        email: 'wang@example.com',
        role: '用户',
        createdAt: '2024-01-17',
    },
    // ... 更多数据
])
</script>

<template>
    <div class="app">
        <h1>用户管理</h1>
        <DataTable :columns="columns" :data="data" :page-size="5" />
    </div>
</template>
```

#### Step 5: 生成类型定义

```typescript
// src/types/table.ts
export interface Column {
    key: string
    label: string
    sortable?: boolean
    width?: string
    formatter?: (value: any) => string
}

export interface TableData {
    [key: string]: any
}

export type SortOrder = 'asc' | 'desc'
```

---

## 6. 总结

### Skills 的核心价值

1. **知识封装**: 将最佳实践、模板、示例打包成可复用模块
2. **上下文完整**: 提供完整的工作流程,而非碎片化信息
3. **即时可用**: 无需外部数据库,纯文件系统即可
4. **易于维护**: 可通过 Git 版本控制,易于协作
5. **灵活组合**: 多个 skills 可协同工作

### 何时使用 Skills vs MCP vs RAG

#### 使用 Skills

- 文档生成(Word/Excel/PPT/PDF)
- 代码生成(遵循特定规范)
- 工作流程执行
- 模板化任务

##### 使用 MCP

- 访问外部系统(数据库/API)
- 需要认证的服务
- 实时数据查询
- 系统集成

###### 使用 RAG

- 海量文档检索
- 语义搜索
- 动态知识库
- 不确定的查询范围

**混合使用:** 大多数复杂应用会结合三者:

```plain
RAG 找到相关领域 → MCP 获取数据 → Skills 指导处理流程
```

### 下一步

1. 查看系统提供的 skills: `view /mnt/skills/public/`
2. 创建你的第一个自定义 skill
3. 在实际项目中测试和迭代
4. 分享给团队使用

记住: Skills 是 Claude 的"技能树",合理构建可以极大提升 AI 助手的专业能力。