概念
Skills 本质上就是“示例(Examples)”与“能力描述(Capability)”的组合。它的核心作用是告诉 AI:
- 这个技能叫什么、能做什么
- 遇到什么场景时应该调用
- 调用的具体方式是什么(脚本、工具)

参考文档:Claude Skills 官方说明
实战
只要支持 Skills 的 IDE 都可以,比如:Claude Code、Cursor、Trae、CodeBuddy 等,我这里以 CodeBuddy 为例。
1. Skills 基础安装使用
因为腾讯自建了 SkillHub,所以 CodeBuddy 内置了技能市场,Skills 安装和使用非常丝滑。
- 下载登录好 CodeBuddy 之后,来到技能市场,搜索对应技能,点击添加,即可安装该 Skills。

PS:当然除了在插件市场直接安装,CodeBuddy 还提供了导入功能,我们可以通过上传文件夹安装自己的 skill。

- 使用 skills:比如我安装了
csv to excel 这个 skill,那么我直接给 AI 一个 csv,并让它帮我转换为 excel,它就会自动识别可以使用的 Skills,并调用。


📢 注意:如果 AI 识别不准,我们也可以指定 AI 使用哪个 Skills。


- 最终效果:成功转换并可正常打开文件。


2. 从 0 到 1 开发上线并使用自己的 skill
2.1 通用 Skill 源码拆解
首先我们可以观察一下,标准 Skill 的构成是什么,看看需要哪些文件夹和目录结构。
# 可以直接在家目录的 .codebuddy 下找到自己安装的 skills
# cd /Users/ziyi/.codebuddy/skills/csvtoexcel
cd ~/.codebuddy/skills/

SKILL.md 文件:介绍
该文件主要规定了 skill 的名称和描述,可以用来说明做什么,以及给一个案例告诉模型怎么使用。

scripts 文件夹:具体实现逻辑
该文件夹下提供了对应脚本,是 Skills 的核心实现。比如我需要将 csv 转换为 excel,该脚本就通过 Python 的方式读取 csv 文件并调用对应 API 将其转换为 excel。


主要定义了 skill 的所属者、版本号、发布时间等。该文件是安装/发布时由 SkillHub 平台自动生成,本地开发时无需创建。
{
"ownerId": "kn7795tvpv9b8mq9wvh01g2e3n8167q2",
"slug": "csvtoexcel",
"version": "1.0.0",
"publishedAt": 1771151066098
}

主要定义了 skill 从哪个市场安装、安装时间等。该文件由 SkillHub 平台自动生成,本地开发时无需创建。
{
"slug": "csvtoexcel",
"name": "csv to excel",
"version": "1.0.0",
"installedAt": 1776138450722,
"source": "skillhub"
}

2.2 Skill 开发
我们日常生活中经常遇到有些平台需要上传图片,但对图片大小有要求。那么现在就可以做一个 skill,用于减少或者增加 jpg 图片大小。比如命名为 jpg-resizer,最终目录结构如下:

jpg-resizer/
├── SKILL.md ✅ 必须手动创建
├── scripts/ ⚙️ 可选
│ └── resize_jpg.py
├── _meta.json 🤖 SkillHub平台自动生成(无需手动创建)
├── _skillhub_meta.json 🤖 SkillHub平台自动生成(无需手动创建)
└── assets/ 📦 可选
scripts:核心脚本/能力开发
作用:本地通过代码实现核心逻辑,比如 Python、JS、Bash 等都可以。
是否必须:非必须。
场景:需要通过代码实现某个能力时,会用到该文件夹。
在本地新建 jpg-resizer/scripts 文件夹,然后实现核心代码逻辑 resize_jpg.py:
#!/usr/bin/env python3
"""
JPG Image Resizer - 调整JPG图片大小,支持压缩或放大到目标尺寸范围
"""
import os
import sys
import argparse
from pathlib import Path
from PIL import Image
import math
def get_file_size_kb(path):
"""获取文件大小(KB)"""
return os.path.getsize(path) / 1024
def resize_image(input_path, output_path, target_size_kb=None, quality=85,
max_dimension=None, scale_factor=None, preserve_aspect=True):
"""
调整图片大小
参数:
input_path: 输入文件路径
output_path: 输出文件路径
target_size_kb: 目标文件大小(KB),None表示不限制
quality: JPEG质量 (1-100)
max_dimension: 最大边像素值
scale_factor: 缩放因子 (如 2.0 表示放大2倍)
preserve_aspect: 是否保持宽高比
"""
img = Image.open(input_path)
# 转换为RGB(处理PNG透明通道等)
if img.mode in ('RGBA', 'P', 'LA'):
background = Image.new('RGB', img.size, (255, 255, 255))
if img.mode == 'P':
img = img.convert('RGBA')
background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
img = background
elif img.mode != 'RGB':
img = img.convert('RGB')
original_size = img.size
# 计算缩放
if max_dimension:
# 根据最大边缩放
width, height = img.size
max_side = max(width, height)
if max_side > max_dimension:
ratio = max_dimension / max_side
new_width = int(width * ratio)
new_height = int(height * ratio)
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
elif scale_factor:
# 按比例缩放
new_width = int(img.width * scale_factor)
new_height = int(img.height * scale_factor)
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
# 迭代调整质量以达到目标大小
current_quality = quality
min_quality = 10
max_quality = 100
tolerance = target_size_kb * 0.1 if target_size_kb else float('inf') # 10%容差
if target_size_kb:
for iteration in range(20): # 最多迭代20次
img.save(output_path, 'JPEG', quality=current_quality, optimize=True)
current_size = get_file_size_kb(output_path)
diff = current_size - target_size_kb
if abs(diff) <= tolerance:
break
# 根据差异调整质量
if diff > 0:
# 文件太大,降低质量
max_quality = current_quality
current_quality = (min_quality + current_quality) // 2
else:
# 文件太小,增加质量
min_quality = current_quality
current_quality = (current_quality + max_quality) // 2
if current_quality == min_quality or current_quality == max_quality:
break
else:
# 不需要目标大小,直接保存
img.save(output_path, 'JPEG', quality=current_quality, optimize=True)
final_size = get_file_size_kb(output_path)
return {
'original_size': original_size,
'new_size': img.size,
'file_size_kb': final_size,
'quality': current_quality
}
def process_single(input_file, output_file=None, target_size_kb=None, quality=85,
max_dimension=None, scale_factor=None, preserve_aspect=True):
"""处理单个文件"""
if not os.path.exists(input_file):
print(f"错误: 文件不存在 - {input_file}")
return None
if output_file is None:
path = Path(input_file)
output_file = path.stem + '_resized.jpg'
print(f"\n处理文件: {input_file}")
print(f"原始大小: {get_file_size_kb(input_file):.2f} KB")
if target_size_kb:
print(f"目标大小: {target_size_kb} KB")
if max_dimension:
print(f"最大边: {max_dimension}px")
if scale_factor:
print(f"缩放比例: {scale_factor}x")
print(f"质量: {quality}")
result = resize_image(
input_file, output_file,
target_size_kb=target_size_kb,
quality=quality,
max_dimension=max_dimension,
scale_factor=scale_factor,
preserve_aspect=preserve_aspect
)
print(f"新尺寸: {result['new_size'][0]}x{result['new_size'][1]}")
print(f"最终质量: {result['quality']}")
print(f"输出文件: {output_file}")
print(f"文件大小: {result['file_size_kb']:.2f} KB")
return result
def process_directory(input_dir, output_dir=None, target_size_kb=None, quality=85,
max_dimension=None, scale_factor=None, recursive=False, preserve_aspect=True):
"""批量处理目录"""
input_path = Path(input_dir)
if output_dir:
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
else:
output_path = input_path
# 查找JPG文件
patterns = ['*.jpg', '*.jpeg', '*.JPG', '*.JPEG']
files = []
for pattern in patterns:
if recursive:
files.extend(input_path.rglob(pattern))
else:
files.extend(input_path.glob(pattern))
if not files:
print(f"在 {input_dir} 中未找到JPG文件")
return
print(f"找到 {len(files)} 个JPG文件")
results = []
for i, file in enumerate(files, 1):
print(f"\n[{i}/{len(files)}] 处理中...")
if output_dir:
relative = file.relative_to(input_path)
output_file = output_path / relative.with_suffix('.jpg')
output_file.parent.mkdir(parents=True, exist_ok=True)
else:
output_file = file.parent / (file.stem + '_resized.jpg')
try:
result = resize_image(
str(file), str(output_file),
target_size_kb=target_size_kb,
quality=quality,
max_dimension=max_dimension,
scale_factor=scale_factor,
preserve_aspect=preserve_aspect
)
results.append((str(file), str(output_file), result))
print(f"✓ 完成: {result['file_size_kb']:.2f} KB")
except Exception as e:
print(f"✗ 失败: {file} - {e}")
# 汇总统计
if results:
total_original = sum(get_file_size_kb(r[0]) for r in results)
total_new = sum(r[2]['file_size_kb'] for r in results)
print(f"\n========== 批量处理完成 ==========")
print(f"处理文件数: {len(results)}")
print(f"原始总大小: {total_original:.2f} KB")
print(f"新总大小: {total_new:.2f} KB")
print(f"变化: {(total_new - total_original) / total_original * 100:+.1f}%")
def main():
parser = argparse.ArgumentParser(
description='JPG图片大小调整工具 - 支持压缩和放大到目标尺寸',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
示例:
# 压缩图片到100KB
resize_jpg.py photo.jpg --target-size 100
# 放大图片2倍
resize_jpg.py photo.jpg --scale 2
# 设置最大边为1000px
resize_jpg.py photo.jpg --max-dimension 1000
# 批量处理目录
resize_jpg.py ./photos --output-dir ./output --target-size 200
'''
)
parser.add_argument('input', help='输入文件或目录')
parser.add_argument('output', nargs='?', help='输出文件(单文件模式)或目录(批量模式)')
# 大小控制组(互斥)
size_group = parser.add_mutually_exclusive_group()
size_group.add_argument('--target-size', type=int, help='目标文件大小(KB)')
size_group.add_argument('--max-dimension', type=int, help='最大边像素值')
size_group.add_argument('--scale', type=float, help='缩放倍数 (如 2.0)')
# 质量设置
parser.add_argument('--quality', type=int, default=85, help='JPEG质量 1-100 (默认: 85)')
parser.add_argument('--no-preserve-aspect', action='store_true', help='不保持宽高比')
# 批量处理选项
parser.add_argument('--output-dir', help='输出目录(批量模式)')
parser.add_argument('--recursive', '-r', action='store_true', help='递归处理子目录')
args = parser.parse_args()
# 参数验证
if args.quality < 1 or args.quality > 100:
print("错误: 质量必须在 1-100 之间")
sys.exit(1)
if os.path.isdir(args.input):
process_directory(
args.input,
output_dir=args.output_dir or args.output,
target_size_kb=args.target_size,
quality=args.quality,
max_dimension=args.max_dimension,
scale_factor=args.scale,
recursive=args.recursive,
preserve_aspect=not args.no_preserve_aspect
)
else:
process_single(
args.input,
output_file=args.output,
target_size_kb=args.target_size,
quality=args.quality,
max_dimension=args.max_dimension,
scale_factor=args.scale,
preserve_aspect=not args.no_preserve_aspect
)
if __name__ == '__main__':
main()
SKILL.md:Skill 描述文档完善
作用:描述 Skill 的基本信息,如名称、描述、用法等。
是否必须:必须。
在本地 jpg-resizer 文件夹下,新建 SKILL.md 文件:
---
name: jpg-resizer
description: |
JPG图片大小调整工具,支持压缩减少体积或放大增加体积到用户指定的目标大小范围。
This skill should be used when users want to: resize JPG images to a specific file size range,
compress images to reduce file size, enlarge images to increase file size,
batch process images to uniform file sizes,
or adjust image dimensions while maintaining quality.
触发场景包括:调整图片大小、压缩图片、放大图片、指定目标文件大小等。
---
# JPG Image Resizer
JPG图片大小调整工具,支持压缩或放大到用户指定的目标尺寸范围。
## 核心功能
1. **目标大小模式** - 用户指定KB值,自动调整质量和/或尺寸达到目标
2. **压缩模式** - 减少图片体积,可通过降低质量或尺寸实现
3. **放大模式** - 增加图片体积,通过放大尺寸实现
4. **尺寸控制** - 支持最大边限制或缩放倍数控制
## 使用方式
### 单文件处理
```bash
resize_jpg.py <input_file> [output_file] [options]
...后续省略,大家感兴趣的可参考 SkillHub 上源码...
##### 其他文件
除了 `scripts` 文件夹、`SKILL.md` 文件,有些可能还有 `assets` 文件夹,用来存储示例等。总之 Skill 目录结构并非是固定的,只要能给模型描述好这个技能怎么使用即可。
#### 2.3 Skill 上线使用
最终我们在本地开发好的 Skill 如下图所示:

1. 将开发好的 Skill 上传到 SkillHub(如果没注册需要先注册,然后完成实名认证即可)。
> SkillHub 官方网址:https://skillhub.cn/dashboard
2. 点击发布 Skill,将本地 `jpg-resizer` 文件夹拖动到该位置,并按要求填写其他字段,最后点击发布即可。

3. 等待审核完成后,就可以在 SkillHub 官方平台搜到自己的 skill 了。

4. 接下来就可以直接在 CodeBuddy 技能模块搜索安装。

5. 安装完成之后,我们可以来简单使用一下。

6. 我们本地找个 jpg 文件,让 AI 帮我们压缩或者增加体积。


7. 执行效果:

> PS:当然除了上传到 SkillHub 市场安装,如果只是个人使用的话,完全可以本地安装(导入我们开发的 Skill 文件夹即可)。
