BACK_TO_BLOG
TECH_LOG :: 2026.01.29

Claude_Code_Skills 更新后指南

Avatar
By Gankudadiz 7 min read

太累了,真的,这更新频率太高了,前段时间还是用json和md形势的skill,现在马上变成YAML了

本文将详细介绍如何通过 Skills 扩展 Claude Code 的能力,包括创建、配置、管理和共享技能的全流程。

一、前置知识

在阅读本文之前,你需要具备以下基础:

  • 熟悉 Claude Code 的基本使用方法
  • 了解 YAML 语法和 Markdown 写作基础
  • 具备基本的命令行操作能力

二、核心概念:什么是 Skills

2.1 Skills 的本质

Claude Code Skills 是一种扩展 Claude 能力的标准化方式。通过创建一个包含说明的 SKILL.md 文件,Claude 会将其添加到工具包中,在相关场景下自动调用或通过 /skill-name 手动触发。

Skills 遵循 Agent Skills 开放标准,Claude Code 在此基础上扩展了调用控制、子代理执行和动态上下文注入等功能。

2.2 Skills 的存储位置

技能的存储位置决定了其作用域:

位置 路径 适用范围
企业级 托管设置中配置 组织内所有用户
个人级 ~/.claude/skills/<skill-name>/SKILL.md 用户的全部项目
项目级 .claude/skills/<skill-name>/SKILL.md 仅当前项目
插件级 <plugin>/skills/<skill-name>/SKILL.md 启用插件的位置

优先级规则:项目技能 > 个人技能 > 企业技能

2.3 技能目录结构

graph TD
    A[技能目录] --> B[SKILL.md 必需]
    A --> C[template.md 可选]
    A --> D[examples/ 可选]
    A --> E[scripts/ 可选]

    B --> F[前置元数据 YAML]
    B --> G[Markdown 说明内容]

    D --> H[sample.md 示例输出]
    E --> I[validate.sh 验证脚本]

三、快速入门:创建你的第一个技能

3.1 创建步骤详解

假设我们需要创建一个用于解释代码的技能,包含视觉图表和类比:

步骤 1:创建技能目录

# 在个人技能目录下创建目录
mkdir -p ~/.claude/skills/explain-code

步骤 2:编写 SKILL.md 文件

---
name: explain-code
description: 使用视觉图表和类比解释代码。当解释代码工作原理、教学代码库或用户询问"这是如何工作的"时使用。
---

# 代码解释技能使用指南

在解释代码时,始终遵循以下结构:

## 1. 类比开场
将代码概念与日常生活中的事物进行类比,降低理解门槛

## 2. 可视化图表
使用 ASCII art 展示代码流程、数据结构或关系

## 3. 逐步解读
按执行顺序逐步说明代码逻辑

## 4. 常见误区
指出开发者容易犯的错误或误解

保持解释的对话感,对于复杂概念使用多种类比进行阐述。

3.3 测试技能

技能创建后,可以通过两种方式测试:

方式一:让 Claude 自动触发

用户:这段代码是如何工作的?

方式二:手动调用技能

/explain-code src/auth/login.ts

四、SKILL.md 深入解析

4.1 前置元数据配置

SKILL.md 文件由两部分组成:YAML 前置元数据和 Markdown 说明内容。

---
name: deploy                    # 技能名称(小写字母、数字、连字符)
description: 将应用部署到生产环境  # 技能描述(Claude 自动加载的依据)
disable-model-invocation: true  # 禁止 Claude 自动调用
user-invocable: true            # 是否可在 / 菜单中显示
allowed-tools: Read, Grep       # 允许使用的工具列表
context: fork                   # 运行上下文(fork 为子代理模式)
agent: Explore                  # 子代理类型
hooks:                          # 生命周期钩子
  post-tool: scripts/hook.sh
---

技能说明内容...

4.2 前置元数据字段详解

字段 必需 描述
name 技能显示名称,省略则使用目录名
description 推荐 技能作用描述,决定何时自动加载
argument-hint 参数提示,如 [issue-number]
disable-model-invocation 设为 true 仅允许用户手动调用
user-invocable 设为 false 从 / 菜单隐藏
allowed-tools 技能激活时允许使用的工具
model 指定使用的模型
context fork 表示在子代理中运行
agent 子代理类型
hooks 技能生命周期钩子

4.3 字符串替换变量

技能支持动态值注入:

---
name: session-logger
description: 记录当前会话活动
---

# 会话日志

日志将保存到 logs/${CLAUDE_SESSION_ID}.log

调用参数:$ARGUMENTS
变量 描述
$ARGUMENTS 传递的所有参数
${CLAUDE_SESSION_ID} 当前会话 ID

五、调用控制策略

5.1 三种调用模式

graph LR
    A[用户调用] --> B[Claude 调用]

    subgraph 默认模式
        C1[描述在上下文]
        C2[完整内容调用时加载]
    end

    subgraph 手动模式
        D1[添加 disable-model-invocation: true]
        D2[仅用户可调用]
        D3[内容不在上下文中]
    end

    subgraph 背景模式
        E1[添加 user-invocable: false]
        E2[仅 Claude 可调用]
        E3[描述常驻上下文]
    end

5.2 调用控制示例

仅允许用户手动调用的部署技能

---
name: deploy
description: 将应用部署到生产环境
disable-model-invocation: true
---

部署步骤:

1. 运行测试套件
2. 构建应用
3. 推送到部署目标
4. 验证部署成功

仅允许 Claude 调用的背景知识技能

---
name: legacy-system-context
description: 遗留系统的技术背景知识
user-invocable: false
---

# 遗留系统上下文

本系统是一个2015年构建的单体架构,主要技术栈:
- 后端:Java 7 + Spring 4
- 数据库:Oracle 11g
- 部署:WebLogic 12c

注意:数据库连接池配置复杂,不要轻易调整参数。

5.3 调用权限矩阵

前置元数据 用户可调用 Claude 可调用 何时加载到上下文
(默认) 描述始终在,调用时加载完整内容
disable-model-invocation: true 仅调用时加载完整内容
user-invocable: false 描述始终在,调用时加载完整内容

六、工具访问控制

6.1 限制技能可用工具

使用 allowed-tools 字段创建只读模式技能:

---
name: safe-reader
description: 以只读方式浏览文件,不进行修改
allowed-tools: Read, Grep, Glob
---

# 安全阅读模式

你可以浏览代码库但不能修改任何文件。

使用 Read 工具阅读文件内容
使用 Grep 工具搜索特定模式
使用 Glob 工具查找文件

6.2 工具限制语法

# 精确工具列表
allowed-tools: Read, Write, Edit

# 使用通配符
allowed-tools: Bash(gh:*)

# 组合使用
allowed-tools: Read, Grep, Bash(git:*), Bash(gh:*)

七、高级模式

7.1 动态上下文注入

使用反引号命令语法在技能执行前注入动态数据:

---
name: pr-summary
description: 总结 Pull Request 的变更内容
context: fork
agent: Explore
allowed-tools: Bash(gh:*)
---

## Pull Request 上下文

- 变更差异:`!gh pr diff`
- PR 评论:`!gh pr view --comments`
- 变更文件列表:`!gh pr diff --name-only`

## 任务

请总结这个 Pull Request 的主要变更,包括:
1. 新增功能
2. 修改内容
3. 可能的潜在问题

执行流程

sequenceDiagram
    participant 用户
    participant Claude
    participant Shell

    用户->>Claude: /pr-summary 123
    Claude->>Shell: 执行 gh pr diff
    Shell-->>Claude: 返回 PR diff 内容
    Claude->>Shell: 执行 gh pr view --comments
    Shell-->>Claude: 返回评论内容
    Claude->>Shell: 执行 gh pr diff --name-only
    Shell-->>Claude: 返回文件列表
    Claude->>Claude: 替换占位符,生成完整提示
    Claude->>Claude: 返回总结结果

7.2 在子代理中运行技能

使用 context: fork 在隔离环境中运行技能:

---
name: deep-research
description: 深入研究某个主题
context: fork
agent: Explore
---

研究目标:$ARGUMENTS

研究步骤:

1. 使用 Glob 和 Grep 定位相关文件
2. 阅读并分析代码实现
3. 总结发现,附上具体文件引用

子代理类型选项

代理类型 用途
Explore 代码库探索,只读工具
Plan 制定实施计划
general-purpose 通用任务(默认)
自定义 .claude/agents/ 中定义的代理

7.3 技能与子代理的协同

graph TB
    subgraph 技能驱动子代理
        A1[SKILL.md] -->|context: fork| B1[子代理]
        B1 --> C1[执行任务]
    end

    subgraph 子代理预加载技能
        A2[子代理定义] -->|skills 字段| B2[预加载技能]
        B2 --> C2[作为参考材料]
    end

八、支持文件管理

8.1 分离详细文档

保持 SKILL.md 简洁,将详细文档分离到单独文件:

my-skill/
├── SKILL.md              # 必需 - 概述和导航
├── reference.md          # 详细 API 文档(按需加载)
├── examples.md           # 使用示例(按需加载)
└── scripts/
    └── helper.py         # 工具脚本(执行,不加载)

SKILL.md 中引用支持文件

# 我的技能

这是技能的简要概述。

## 详细信息

- 完整 API 说明:查看 [reference.md](reference.md)
- 使用示例:查看 [examples.md)

## 警告

<Tip>保持 SKILL.md 在 500 行以下,将详细材料移到单独文件。</Tip>

九、实战场景

9.1 场景一:代码库可视化技能

创建交互式代码库结构可视化工具:

创建技能目录结构

mkdir -p ~/.claude/skills/codebase-visualizer/scripts

创建 SKILL.md

---
name: codebase-visualizer
description: 生成代码库的交互式树状可视化。用于探索新仓库、理解项目结构或识别大文件。
allowed-tools: Bash(python:*)
---

# 代码库可视化技能

生成一个交互式 HTML 树视图,展示项目文件结构,支持目录展开折叠。

## 使用方法

从项目根目录运行:

```bash
python ~/.claude/skills/codebase-visualizer/scripts/visualize.py .

这将在当前目录生成 codebase-map.html 并在浏览器中打开。

可视化特性

  • 可折叠目录:点击文件夹展开或折叠
  • 文件大小:每个文件旁边显示
  • 颜色编码:不同文件类型使用不同颜色
  • 目录汇总:显示每个文件夹的总大小

**创建可视化脚本(Python)**

```python
#!/usr/bin/env python3
"""生成代码库的交互式树状可视化"""

import json
import sys
import webbrowser
from pathlib import Path
from collections import Counter

# 忽略的目录
IGNORE = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', 'dist', 'build'}

def scan(path: Path, stats: dict) -> dict:
    """扫描目录树,收集文件和目录信息"""
    result = {"name": path.name, "children": [], "size": 0}
    try:
        for item in sorted(path.iterdir()):
            # 跳过忽略的目录
            if item.name in IGNORE or item.name.startswith('.'):
                continue
            if item.is_file():
                # 处理文件
                size = item.stat().st_size
                ext = item.suffix.lower() or '(no ext)'
                result["children"].append({"name": item.name, "size": size, "ext": ext})
                result["size"] += size
                stats["files"] += 1
                stats["extensions"][ext] += 1
                stats["ext_sizes"][ext] += size
            elif item.is_dir():
                # 处理目录
                stats["dirs"] += 1
                child = scan(item, stats)
                if child["children"]:
                    result["children"].append(child)
                    result["size"] += child["size"]
    except PermissionError:
        pass
    return result

def generate_html(data: dict, stats: dict, output: Path) -> None:
    """生成 HTML 可视化文件"""
    # 统计扩展名占比
    ext_sizes = stats["ext_sizes"]
    total_size = sum(ext_sizes.values()) or 1
    sorted_exts = sorted(ext_sizes.items(), key=lambda x: -x[1])[:8]

    # 文件类型颜色映射
    colors = {
        '.js': '#f7df1e', '.ts': '#3178c6', '.py': '#3776ab',
        '.go': '#00add8', '.rs': '#dea584', '.rb': '#cc342d',
        '.css': '#264de4', '.html': '#e34c26', '.json': '#6b7280',
        '.md': '#083fa1', '.yaml': '#cb171e', '.yml': '#cb171e',
    }

    # 生成语言占比条形图
    lang_bars = "".join(
        f'<div class="bar-row"><span class="bar-label">{ext}</span>'
        f'<div class="bar" style="width:{(size/total_size)*100}%;'
        f'background:{colors.get(ext,"#6b7280")}"></div>'
        f'<span class="bar-pct">{(size/total_size)*100:.1f}%</span></div>'
        for ext, size in sorted_exts
    )

    # 格式化文件大小
    def fmt(b):
        if b < 1024: return f"{b} B"
        if b < 1048576: return f"{b/1024:.1f} KB"
        return f"{b/1048576:.1f} MB"

    # 生成 HTML 内容
    html = f'''<!DOCTYPE html>
<html><head>
  <meta charset="utf-8"><title>Codebase Explorer</title>
  <style>
    body {{ font: 14px/1.5 system-ui, sans-serif; margin: 0; background: #1a1a2e; color: #eee; }}
    .container {{ display: flex; height: 100vh; }}
    .sidebar {{ width: 280px; background: #252542; padding: 20px; border-right: 1px solid #3d3d5c; overflow-y: auto; flex-shrink: 0; }}
    .main {{ flex: 1; padding: 20px; overflow-y: auto; }}
    /* 其他样式... */
  </style>
</head><body>
  <div class="container">
    <div class="sidebar">
      <h1>📊 Summary</h1>
      <div class="stat"><span>Files</span><span class="stat-value">{stats["files"]:,}</span></div>
      <div class="stat"><span>Directories</span><span class="stat-value">{stats["dirs"]:,}</span></div>
      <div class="stat"><span>Total size</span><span class="stat-value">{fmt(data["size"])}</span></div>
      <div class="stat"><span>File types</span><span class="stat-value">{len(stats["extensions"])}</span></div>
      <h2>By file type</h2>
      {lang_bars}
    </div>
    <div class="main">
      <h1>📁 {data["name"]}</h1>
      <ul class="tree" id="root"></ul>
    </div>
  </div>
  <script>
    const data = {json.dumps(data)};
    const colors = {json.dumps(colors)};
    function fmt(b) {{ /* 大小格式化 */ }}
    function render(node, parent) {{ /* 渲染逻辑 */ }}
    data.children.forEach(c => render(c, document.getElementById('root')));
  </script>
</body></html>'''
    output.write_text(html)

if __name__ == '__main__':
    # 解析命令行参数
    target = Path(sys.argv[1] if len(sys.argv) > 1 else '.').resolve()
    stats = {"files": 0, "dirs": 0, "extensions": Counter(), "ext_sizes": Counter()}
    data = scan(target, stats)
    out = Path('codebase-map.html')
    generate_html(data, stats, out)
    print(f'Generated {out.absolute()}')
    webbrowser.open(f'file://{out.absolute()}')

9.2 场景二:GitHub Issue 自动修复技能

---
name: fix-issue
description: 自动修复 GitHub Issue
disable-model-invocation: true
---

# 自动修复 Issue

修复编号:$ARGUMENTS

## 步骤

1. 读取 Issue 描述,理解需求
2. 分析相关代码文件
3. 实现修复方案
4. 编写测试用例
5. 创建提交

## 编码规范

- 遵循项目现有的代码风格
- 函数需要有完整的类型注解
- 提交信息格式:[fix] #Issue号 简述

9.3 场景三:API 设计规范技能

---
name: api-conventions
description: 当前项目的 API 设计规范
---

# API 设计规范

## 命名约定

- 使用 RESTful 命名规范
- 资源名称使用复数形式
- 使用连字符分隔多词路由

## 请求格式

- GET: 获取资源列表
- POST: 创建新资源
- PUT: 全量更新资源
- PATCH: 部分更新资源
- DELETE: 删除资源

## 响应格式

```json
{
  "data": {},
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 100
  }
}

错误响应

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "邮箱格式不正确",
    "details": []
  }
}

十、共享与分发

10.1 共享方式

方式 适用场景
项目技能 .claude/skills/ 提交到版本控制
插件 在插件中创建 skills/ 目录
托管 通过托管设置部署组织范围技能

10.2 从嵌套目录自动发现

Claude Code 支持从嵌套的 .claude/skills/ 目录自动发现技能:

packages/
├── frontend/
│   └── .claude/skills/frontend-conventions/
└── backend/
    └── .claude/skills/backend-conventions/

当你在 packages/frontend/ 中编辑文件时,Claude 会自动加载该目录下的技能。

十一、故障排除

11.1 技能未触发

如果 Claude 在预期时不使用技能:

  1. 检查描述是否包含用户会自然说的关键词
  2. 验证技能是否出现在"有哪些技能可用?"中
  3. 尝试重新表述请求以更接近描述
  4. 使用 /skill-name 直接调用

11.2 技能触发过于频繁

如果 Claude 在不想要的时候使用技能:

  1. 使描述更加具体
  2. 添加 disable-model-invocation: true 限制为手动调用

11.3 Claude 看不到所有技能

技能描述加载到上下文中有字符限制(默认 15000 字符):

# 增加字符预算
export SLUFFIX_COMMAND_TOOL_CHAR_BUDGET=30000

十二、总结要点

  1. Skills 本质:通过 SKILL.md 文件扩展 Claude 能力的标准化方式

  2. 存储位置:企业级 > 项目级 > 个人级 > 插件级

  3. 核心配置:YAML 前置元数据 + Markdown 说明内容

  4. 调用控制

    • disable-model-invocation: true - 仅用户可调用
    • user-invocable: false - 仅 Claude 可调用
  5. 高级特性

    • 动态上下文注入(`!command`
    • 子代理执行(context: fork
    • 支持文件管理
  6. 最佳实践

    • SKILL.md 保持在 500 行以下
    • 详细文档分离到独立文件
    • 使用描述性强的技能名称

COMMENTS (0)

No comments yet. Be the first to share your thoughts.

LEAVE A COMMENT