从打字员到超级助手
之前我们学会了用Claude Code做项目,你可能已经体验到了AI编程的强大。但你有没有发现一个问题:
每次做类似的事情,都要重新描述一遍需求。
比如你想让AI帮你:
- 写Git提交信息
- 审查代码
- 生成项目文档
- 同步文件
这些任务你可能每天都要做好几次,但每次都要打一长段话告诉AI该怎么做,太累了!
这就像你每次点外卖,都要跟店家说:
“我要一份红烧牛肉面,不要香菜,多加辣椒,面要硬一点,汤要少一点……”
有没有办法把这些常用操作变成一键调用?
有的,这就是今天要讲的Skill。
什么是Skill?
一句话解释
Skill = AI的快捷指令
就像你手机上的快捷指令App,Skill把复杂的操作封装成一个简单的命令。
官方定义
Skill指的是可复用的"能力模块",把工具/API/脚本与提示封装成标准接口,让AI按需调用完成特定任务。
它强调:
- 清晰的输入输出
- 依赖与版本管理
- 可测试、可更新
- 把通用AI变成面向业务的专业助手
通俗理解
没有Skill的时候:
你:请帮我审查这段代码,检查以下几点:
1. 是否有性能问题
2. 是否有安全漏洞
3. 代码风格是否符合规范
4. 是否有重复代码
5. 变量命名是否清晰
6. 注释是否完整
……(还要继续描述10行)
有了Skill之后:
你:/review
AI自动按照预设的标准审查代码,并给出详细报告。
差别看出来了吗? 从几百字变成一个命令,这就是Skill的威力。
Skill、提示词、MCP的区别
很多人会问:Skill、提示词(Prompt)、MCP这三个概念有什么区别?
概念对比
| 对比项 | 提示词(Prompt) | Skill | MCP |
|---|---|---|---|
| 本质 | 文本指令 | 封装好的能力模块 | 连接外部工具的协议 |
| 复用性 | 低,每次要重新输入 | 高,定义一次重复使用 | 高,一次配置持续使用 |
| 复杂度 | 简单 | 中等 | 复杂 |
| 能力范围 | 仅文本处理 | 文本 + 简单脚本 | 文本 + 外部系统交互 |
| 学习门槛 | 最低 | 中等 | 较高 |
用比喻说明
提示词 = 口头指令
- 你每次都要口头告诉AI做什么
- 适合一次性、临时的任务
- 例如:“帮我翻译这段话”
Skill = 工作流程
- 把常用的指令固化成标准流程
- 适合重复性、标准化的任务
- 例如:"/commit"自动生成Git提交信息
MCP = 外部系统
- 让AI连接到外部工具和数据源
- 适合需要访问外部系统的任务
- 例如:连接Obsidian读写笔记、连接数据库查询数据
三者的关系
提示词 → 最基础的交互方式
↓
Skill → 封装了提示词 + 简单逻辑
↓
MCP → Skill + 外部系统的能力
形象地说:
- 提示词 = 你自己做饭
- Skill = 用微波炉加热速食
- MCP = 连接外卖平台点餐
什么时候用哪个?
用提示词,如果:
- 任务简单、一次性
- 需求灵活多变
- 不需要复用
用Skill,如果:
- 任务重复性高
- 有标准化流程
- 想提高效率
用MCP,如果:
- 需要访问外部数据(数据库、API、文件系统等)
- 需要和其他软件交互(Obsidian、浏览器等)
- 需要实时获取信息
实际案例对比:
场景一:翻译一段话
- 用提示词:“请翻译这段话”(最简单)
场景二:每天翻译很多文档
- 用Skill:"/translate"(标准化翻译流程)
场景三:自动翻译Obsidian笔记并保存
- 用MCP:连接Obsidian,自动读取、翻译、保存(最强大)
Skill的基本使用
怎么查看已有的Skill?
在Claude Code或Codex中,输入:
/skill
会列出所有可用的Skill。

怎么使用Skill?
方法一:直接执行
输入 /skill,然后用Tab键选中想用的Skill,按回车执行。

方法二:带参数执行
选中Skill后,继续输入你的具体需求:
/translate 把这段代码的注释翻译成英文
常用的内置Skill
大部分AI编程工具都自带一些常用Skill:
| Skill | 作用 | 示例 |
|---|---|---|
/commit |
自动生成Git提交信息 | /commit |
/review |
审查代码质量 | /review |
/fix |
修复代码错误 | /fix |
/test |
生成测试用例 | /test |
/doc |
生成文档 | /doc |
/refactor |
重构代码 | /refactor |
这些内置Skill已经能解决80%的日常需求。
创建自己的Skill
如果内置Skill不够用,你可以创建自己的Skill。
两种创建方法
方法一:让AI帮你创建(推荐)
在Codex中自带了一个创建Skill的Skill(很绕,但很强大)。
操作步骤:
- 输入
/skill - 找到"Create Skill"相关的选项
- 选中后,告诉AI你想要什么Skill
示例:
/create-skill
我想要一个翻译Skill,功能是:
1. 自动检测代码中的中文注释
2. 翻译成英文
3. 保持代码格式不变

AI会自动帮你创建Skill文件,并放到正确的位置。
方法二:手动创建
如果你想更深入了解Skill的结构,可以手动创建。
Skill的文件结构:
每个Skill是一个文件夹,里面必须包含 SKILL.md 文件:
my-skill/
├── SKILL.md # Skill的说明和配置
└── scripts/ # 可选:辅助脚本
└── helper.py
SKILL.md的基本格式:
---
name: 技能名称
description: 技能描述
---
# 详细说明
这里写详细的使用说明和实现逻辑。
## 参数
- `--param1`: 参数1说明
- `--param2`: 参数2说明
## 示例
使用示例代码
后面我们会详细介绍如何创建一个完整的Skill。
安装别人的Skill
GitHub上有很多现成的Skill,你可以直接下载使用。
找到Skill文件夹
Codex的Skill位置:
- Mac/Linux:
~/.codex/skills/ - Windows:
%USERPROFILE%\.codex\skills\
Claude Code的Skill位置:
- Mac/Linux:
~/.claude/skills/ - Windows:
%USERPROFILE%\.claude\skills\
安装步骤
- 打开Skill文件夹
如果文件夹不存在,可以手动创建:
# Mac/Linux
mkdir -p ~/.codex/skills
# Windows (PowerShell)
New-Item -Path "$env:USERPROFILE\.codex\skills" -ItemType Directory -Force

- 下载Skill文件
从GitHub或其他来源下载Skill文件夹。
- 复制到Skill目录
把整个Skill文件夹复制到对应的skills目录。

- 重启工具
注意: Codex目前不支持热更新,需要退出重启才能看到新Skill。Claude Code通常可以自动识别。
验证安装
重启后,输入 /skill 查看列表,确认新Skill已经出现。
实战案例——创建一个同步Skill
问题场景
如果你同时使用Codex和Claude Code(很多人都这样),会遇到一个麻烦:
两个工具的Skill要分别管理,非常不方便。
- Codex的Skill在
~/.codex/skills/ - Claude Code的Skill在
~/.claude/skills/
每次你在Codex创建了一个好用的Skill,还要手动复制到Claude的文件夹,太繁琐了!
这时候我们就可以创建一个Skill,自动同步两个文件夹的内容,用skill来管理skill
这个Skill会:
- 检查两边的Skill差异
- 报告哪些Skill需要同步
- 经过你确认后,自动同步
我们只需要把需求告诉AI即可

下面是AI帮你做的事情,请注意,这些步骤都是它自动的,不用你任何操作! 放在这里只是演示
第一步:创建Skill文件夹
在Codex或Claude Code的skills目录下,创建一个新文件夹:
mkdir ~/.codex/skills/codex-claude-skill-sync
第二步:创建SKILL.md
在文件夹中创建 SKILL.md 文件:
name: codex-claude-skill-sync
description: 同步Codex与Claude技能
---
# Codex/Claude Skill Sync
## 概述
用于检查并同步 Codex 与 Claude 的技能目录,保持两边一致。默认只报告差异,获得用户确认后再执行同步。
## 工作流
1. 运行差异报告(不修改):
`python3 scripts/sync_skills.py`
2. 用中文向用户汇报差异并等待明确同意后再执行。
3. 同意后执行同步:
`python3 scripts/sync_skills.py --apply`
4. 遇到冲突(同一修改时间但内容不同)时暂停,询问用户选择保留哪一侧。
## 规则
- 默认目录:
- Codex: `/Users/你的用户名/.codex/skills`
- Claude: `/Users/你的用户名/.claude/skills`
- 仅处理顶层且包含 `SKILL.md` 的目录,跳过隐藏目录与 `.system`
- 以目录内最新修改时间判断哪一侧更新
- 同步时删除目标技能目录后再整体拷贝来源目录
## 参数
- `--apply` 执行同步(默认只报告)
- `--codex <path>` 覆盖 Codex 目录
- `--claude <path>` 覆盖 Claude 目录
- `--prefer codex|claude` 当修改时间相同但内容不同,用指定一侧覆盖(需用户明确授权)
重要: 把上面的路径改成你自己的实际路径!
第三步:创建脚本文件
在Skill文件夹下创建 scripts 目录,然后创建 sync_skills.py:
mkdir ~/.codex/skills/codex-claude-skill-sync/scripts

sync_skills.py 的完整代码:
#!/usr/bin/env python3
"""
Compare and sync skill folders between Codex and Claude.
Default behavior is report-only. Use --apply to perform sync.
"""
from __future__ import annotations
import argparse
import hashlib
import os
from datetime import datetime
from pathlib import Path
import shutil
import sys
DEFAULT_CODEX = Path("/Users/你的用户名/.codex/skills")
DEFAULT_CLAUDE = Path("/Users/你的用户名/.claude/skills")
IGNORE_DIR_NAMES = {".git", ".idea", ".vscode", "__pycache__", ".pytest_cache", ".mypy_cache"}
IGNORE_FILE_NAMES = {".DS_Store"}
TIME_EPSILON = 1.0
def format_time(timestamp: float) -> str:
return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")
def list_skill_dirs(root: Path) -> tuple[dict[str, Path], list[str]]:
if not root.exists():
raise FileNotFoundError(f"Root path does not exist: {root}")
if not root.is_dir():
raise NotADirectoryError(f"Root path is not a directory: {root}")
skills: dict[str, Path] = {}
ignored: list[str] = []
for entry in sorted(root.iterdir(), key=lambda p: p.name):
if not entry.is_dir():
continue
if entry.name.startswith("."):
ignored.append(entry.name)
continue
if not (entry / "SKILL.md").is_file():
continue
skills[entry.name] = entry
return skills, ignored
def dir_state(path: Path) -> tuple[str, float, int]:
hasher = hashlib.sha256()
latest_mtime = path.stat().st_mtime
file_count = 0
for root, dirs, files in os.walk(path):
dirs[:] = [d for d in dirs if d not in IGNORE_DIR_NAMES]
dirs.sort()
files = sorted(f for f in files if f not in IGNORE_FILE_NAMES)
rel_dir = os.path.relpath(root, path)
if rel_dir == ".":
rel_dir = ""
hasher.update(f"D|{rel_dir}\n".encode())
try:
latest_mtime = max(latest_mtime, os.stat(root).st_mtime)
except FileNotFoundError:
continue
for name in files:
file_path = Path(root) / name
rel_path = os.path.relpath(file_path, path)
if file_path.is_symlink():
try:
target = os.readlink(file_path)
except OSError:
target = ""
hasher.update(f"L|{rel_path}\n{target}\n".encode())
try:
latest_mtime = max(latest_mtime, file_path.lstat().st_mtime)
except FileNotFoundError:
pass
continue
if not file_path.is_file():
continue
stat = file_path.stat()
latest_mtime = max(latest_mtime, stat.st_mtime)
file_count += 1
hasher.update(f"F|{rel_path}\n{stat.st_size}\n".encode())
with open(file_path, "rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
hasher.update(chunk)
return hasher.hexdigest(), latest_mtime, file_count
def build_plan(
codex_skills: dict[str, Path],
claude_skills: dict[str, Path],
codex_root: Path,
claude_root: Path,
prefer: str | None,
) -> tuple[list[dict], list[str], list[dict]]:
actions: list[dict] = []
identical: list[str] = []
conflicts: list[dict] = []
all_names = sorted(set(codex_skills) | set(claude_skills))
for name in all_names:
codex_path = codex_skills.get(name)
claude_path = claude_skills.get(name)
if codex_path and not claude_path:
actions.append(
{
"name": name,
"src": codex_path,
"dst": claude_root / name,
"reason": "only in codex",
"direction": "codex -> claude",
}
)
continue
if claude_path and not codex_path:
actions.append(
{
"name": name,
"src": claude_path,
"dst": codex_root / name,
"reason": "only in claude",
"direction": "claude -> codex",
}
)
continue
if not codex_path or not claude_path:
continue
codex_hash, codex_mtime, _ = dir_state(codex_path)
claude_hash, claude_mtime, _ = dir_state(claude_path)
if codex_hash == claude_hash:
identical.append(name)
continue
time_delta = codex_mtime - claude_mtime
if abs(time_delta) <= TIME_EPSILON:
if prefer == "codex":
actions.append(
{
"name": name,
"src": codex_path,
"dst": claude_path,
"reason": "same mtime, prefer codex",
"direction": "codex -> claude",
"codex_mtime": codex_mtime,
"claude_mtime": claude_mtime,
}
)
elif prefer == "claude":
actions.append(
{
"name": name,
"src": claude_path,
"dst": codex_path,
"reason": "same mtime, prefer claude",
"direction": "claude -> codex",
"codex_mtime": codex_mtime,
"claude_mtime": claude_mtime,
}
)
else:
conflicts.append(
{
"name": name,
"codex_mtime": codex_mtime,
"claude_mtime": claude_mtime,
}
)
continue
if time_delta > 0:
actions.append(
{
"name": name,
"src": codex_path,
"dst": claude_path,
"reason": "codex newer",
"direction": "codex -> claude",
"codex_mtime": codex_mtime,
"claude_mtime": claude_mtime,
}
)
else:
actions.append(
{
"name": name,
"src": claude_path,
"dst": codex_path,
"reason": "claude newer",
"direction": "claude -> codex",
"codex_mtime": codex_mtime,
"claude_mtime": claude_mtime,
}
)
return actions, identical, conflicts
def print_report(
actions: list[dict],
identical: list[str],
conflicts: list[dict],
codex_root: Path,
claude_root: Path,
apply: bool,
ignored_codex: list[str],
ignored_claude: list[str],
) -> None:
print("Skill sync report")
print(f"Codex: {codex_root}")
print(f"Claude: {claude_root}")
if ignored_codex:
print(f"Ignored in Codex: {', '.join(sorted(ignored_codex))}")
if ignored_claude:
print(f"Ignored in Claude: {', '.join(sorted(ignored_claude))}")
print("\nPlanned sync actions:")
if not actions:
print("- none")
else:
for item in actions:
codex_mtime = item.get("codex_mtime")
claude_mtime = item.get("claude_mtime")
details = []
if codex_mtime is not None:
details.append(f"codex mtime: {format_time(codex_mtime)}")
if claude_mtime is not None:
details.append(f"claude mtime: {format_time(claude_mtime)}")
detail_text = f" ({', '.join(details)})" if details else ""
print(f"- {item['name']}: {item['direction']} [{item['reason']}]" + detail_text)
print("\nConflicts:")
if not conflicts:
print("- none")
else:
for item in conflicts:
print(
f"- {item['name']}: same mtime but different content "
f"(codex {format_time(item['codex_mtime'])}, claude {format_time(item['claude_mtime'])})"
)
print(f"\nUp-to-date skills: {len(identical)}")
if not apply:
print("\nDry run only. Re-run with --apply to sync.")
def apply_actions(actions: list[dict]) -> None:
for item in actions:
src = Path(item["src"])
dst = Path(item["dst"])
if dst.exists():
if dst.is_dir():
shutil.rmtree(dst)
else:
dst.unlink()
shutil.copytree(src, dst, symlinks=True)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Sync Codex and Claude skill folders")
parser.add_argument("--codex", type=Path, default=DEFAULT_CODEX, help="Codex skill root")
parser.add_argument("--claude", type=Path, default=DEFAULT_CLAUDE, help="Claude skill root")
parser.add_argument("--apply", action="store_true", help="Apply sync actions")
parser.add_argument(
"--prefer",
choices=["codex", "claude"],
help="Break ties when mtimes are equal",
)
return parser.parse_args()
def main() -> int:
args = parse_args()
try:
codex_skills, ignored_codex = list_skill_dirs(args.codex)
claude_skills, ignored_claude = list_skill_dirs(args.claude)
except (FileNotFoundError, NotADirectoryError) as exc:
print(str(exc), file=sys.stderr)
return 2
actions, identical, conflicts = build_plan(
codex_skills,
claude_skills,
args.codex,
args.claude,
args.prefer,
)
print_report(
actions,
identical,
conflicts,
args.codex,
args.claude,
args.apply,
ignored_codex,
ignored_claude,
)
if args.apply and actions:
apply_actions(actions)
print("\nSync complete.")
elif args.apply and not actions:
print("\nNo changes to apply.")
if conflicts and not args.prefer:
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
重要: 记得修改开头的路径:
DEFAULT_CODEX = Path("/Users/你的用户名/.codex/skills")
DEFAULT_CLAUDE = Path("/Users/你的用户名/.claude/skills")
改成你实际的路径。
使用同步Skill
第一步:查看差异
在Claude Code或Codex中输入:
/codex-claude-skill-sync
AI会自动运行脚本,报告两边的Skill差异。
第二步:确认同步
如果你同意同步,告诉AI:
同意,请执行同步
AI会运行 python3 scripts/sync_skills.py --apply 完成同步。
搞定! 以后你在任意一边创建或修改Skill,只需要运行一次这个同步Skill,两边就会保持一致。
Skill进阶技巧
技巧一:组合使用Skill
多个Skill可以串联使用:
/review 然后 /fix 修复发现的问题
AI会先审查代码,然后根据审查结果自动修复。
技巧二:自定义Skill参数
很多Skill支持参数:
/commit --type feat --scope api
会生成符合特定格式的提交信息。
技巧三:Skill模板
你可以创建Skill模板,快速生成新Skill:
- 复制一个现有Skill文件夹
- 修改SKILL.md
- 保存即可
技巧四:团队共享Skill
把Skill文件夹放到Git仓库,团队成员可以共享:
git clone https://github.com/your-team/skills.git ~/.codex/skills/team-skills
总结
今天学到了什么:
- Skill是什么:可复用的能力模块,把复杂操作变成简单命令
- Skill vs 提示词 vs MCP:三者的区别和适用场景
- 如何使用Skill:
/skill查看和调用 - 如何创建Skill:让AI帮忙或手动创建
- 如何安装Skill:复制到对应文件夹
- 实战案例:创建同步Skill,解决多工具管理问题
核心要点:
- Skill让AI从"打字员"升级为"专业助手"
- 常用操作应该封装成Skill
- 好的Skill可以节省90%的时间
下期预告
下一篇我们会介绍MCP:
MCP深度解析——让AI连接整个世界
MCP(Model Context Protocol)是AI工具的"插件系统",可以让Claude Code或Codex:
- 连接Obsidian,自动整理笔记
- 连接浏览器,自动操作网页
- 连接数据库,智能查询数据
- 连接任何你想连接的工具
这才是AI编程的最终形态!
敬请期待!
如果觉得有帮助,记得关注这个系列!