“agent-skills”这个词最近频繁出现在我的信息流里,一开始我以为又是某个新的 Agent 框架套壳,结果扒了一圈发现,它并不是某个具体仓库的名字,而更像是一整类项目和讨论的集合:把“技能”做成标准化的、可复用的、能跨平台安装的资源包,然后让 Claude Code、Codex、opencode、pi agent 这些不同的执行壳(harness)直接调用。我自己前后折腾了一个多月的 skills,从照着别人仓库抄结构,到自己写、给团队用、再跑评测,最大的感触是:skill 不是把提示词换个后缀,它解决的是 agent 工程里“能力复用”和“行为稳定”这两个老大难问题。
这篇文章不打算给你罗列“十大推荐 skill”,而是把 agent-skills 这类项目的里子拆开:一个 skill 包到底长什么样、放在哪里才会被 agent 发现、写之前要想清楚什么、以及我在实际使用中最容易翻车的地方。读完你至少能把一套能用的 skill 跑起来,还会踩得比别人少一点。适合刚开始玩 agent 开发、或者正给团队做内部 agent 统一规范的人看。
1. 先把概念捋清楚:Skill 到底是给谁用的
1.1 Skill、Prompt、Tool、Agent 各管哪一段
我先说一个特别常见的混淆:Skill 是不是就是“优化过的提示词”?不完全是,但它和提示词绑定得非常紧密。你可以把 Prompt 理解成一张“临时任务说明”,它跟着对话走,说没就没了;而 Skill 是一份“有目录、有前置技能说明、有可执行脚本”的完整能力包,它可以被 agent 在对话中途主动“发现”并加载。
我习惯用一个生活化的类比:Prompt 是老板当场交代你怎么做,Tool 是给你一把电钻,而 Skill 是“一份工作手册+配套工具+操作禁忌”,甚至还包括了完工验收标准。Agent 拿到任务后会先看手册,再决定是否调用电钻,做完还要按验收标准自查一遍。所以 Skill 不是替 agent 思考,而是把某类任务的做法固化下来,让 agent 不用每次从零发挥。
再反过来说 Tool。现在大家熟悉的是 MCP 或 Function Calling 里的外部工具,他们解决的是“agent 能调用什么”,偏向动作本身,但 tool 本身不会告诉你什么时候该用、用完怎么检查。Skill 在结构上比 tool 更靠上,它是“会判断要不要用 tool 的一层”。所以如果你在项目里只做了一堆函数让 agent 调,那还只是 tool 集合,谈不上 skills 体系。
Agent 这个词就更大了。它是整个执行流程的编排者,负责理解任务、规划步骤、调用资源、交付结果。Skill 是 agent 的“内功模块”,Agent 框架则是“运功的经脉”。我一直觉得,让 Agent 直接吞一篇长文档当提示词,是最容易失控的玩法;把它拆成若干个 Skill,让 agent 在需要的时候才读对应的那部分,既不占上下文,行为也可控——这才是 skill 机制设计的核心动机。
1.2 Harness 负责执行,Skill 负责规范
“harness 和 agent 区别”这个问题我见过不下十次。Harness 是装 agent 的那个壳,负责读配置、管理上下文窗口、跟模型 API 通信、把模型输出转成可执行动作,比如 Claude Code、Codex CLI、opencode 都属于 harness。Agent 是大脑,harness 是身体和感官。一个 Skill 会被放进 harness 能找到的目录里,harness 在合适的时机把它作为资料、动作规范或脚本注入给当前 agent。
同一个 Skill,只要格式兼容,就能在不同 harness 间迁移。比如我在 Claude Code 里调试好的一个“输出项目结构图”的 skill,放到 Codex 的 skills 目录下也能被识别,只是加载方式和触发语法略有差异。所以这些热词里反复出现的“skill 和 agent 的区别”,本质是:Skill 是被复用的知识/动作单元,Agent 是组织这些单元完成目标的执行者。前者的质量决定 agent 的下限,后者的框架决定上限。
Skill 格式目前没到 “USB-C 统一”的程度。Anthropic 带火了 Claude Skill 的 SKILL.md 目录风格后,很多工具开始兼容类似结构,但命名、目录位置、触发方式仍有差异。这是我建议你动手前先锚定一个主要 harness 的原因,不要一开始就想着全平台通吃,否则光是适配就够你烦的。
2. 核心细节拆解:一个 Skill 包的三层结构
2.1 最小可用包:SKILL.md 才是灵魂
先看我在内部项目里使用的一个最小 Skill 结构:
my-skill/ ├── SKILL.md ├── scripts/ │ └── generate_structure.py ├── references/ │ └── naming_convention.md └── assets/ └── templates/如果时间特别紧,你甚至可以只保留一个 SKILL.md。它是 agent 能否正确使用这个技能的关键。SKILL.md 通常分成两个区块:meta 信息区域和正文指导区域。我这里不贴某一个平台的官方模板,而是给一个你手动改也能通过的通用骨架:
--- name: generate-project-structure description: 输出指定目录的树状结构图。当用户想了解项目文件布局、或需要给新成员展示目录概览时使用。 allowed-tools: - bash - glob --- # 项目结构图生成技能 ## 适用场景 - 用户询问“这个项目怎么组织的” - 需要在文档中插入项目结构图 ## 操作步骤 1. 使用 glob 或 bash 列出目标目录下的文件与文件夹。 2. 忽略 node_modules、.git、dist、build 等生成目录。 3. 输出 markdown 格式的树状图。 ## 验收标准 - 结构图包含主要目录与顶层文件 - 忽略规则生效description 一定要写清楚“什么时候用”,因为 harness 通常是靠 description 做意图匹配的。你写“生成结构图”这种过于简单的描述,agent 很可能没意识到这个技能也能用于“介绍项目框架”这类任务。description 就是技能的检索入口,写得好不好直接决定被调用的频率。
正文部分不要写一堆模型的“角色扮演”,而是写“怎么做”与“边界”,尤其是规则和禁区,比如哪些目录不要管、哪些文件必须展示、输出格式长什么样。Agent 在触发技能后,会把整个 SKILL.md 注入上下文,你说得越具体,它的动作越稳定。
2.2 示例脚本:让 Skill 真正跑起来
只有一个文档的技能只能约束行为,跑不了活;真正提升效率的是配套脚本。拿上面这个结构图技能来说,我会放一个 Python 脚本,这样 agent 不用自己临时写代码,直接调用脚本即可。
#!/usr/bin/env python3 # scripts/generate_structure.py import os import sys from pathlib import Path IGNORED_DIRS = {".git", "node_modules", "dist", "build", "__pycache__"} IGNORED_FILES = {".DS_Store", ".env.local", "*.pyc"} def render_tree(root: Path, prefix: str = "", is_last: bool = True) -> list[str]: lines = [] entry = root.name if root.name else str(root) arrow = "└── " if is_last else "├── " lines.append(prefix + arrow + entry) if not root.is_dir(): return lines children = [p for p in sorted(root.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower())) if should_ignore(p) is False] next_prefix = prefix + (" " if is_last else "│ ") for i, child in enumerate(children): lines.extend(render_tree(child, next_prefix, i == len(children) - 1)) return lines def should_ignore(path: Path) -> bool: if path.name in IGNORED_DIRS or path.name in IGNORED_FILES: return True return any(pattern.endswith("*") and path.name.endswith(pattern[:-1]) for pattern in IGNORED_FILES if "*" in pattern) if __name__ == "__main__": target = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else Path.cwd() print("\n".join(render_tree(target)))这个脚本只做一件事:打印 ASCII 结构树,默认忽略一堆噪音目录。你在 SKILL.md 的“操作步骤”里明确要求 agent 优先执行python scripts/generate_structure.py <path>,而不是现场现写一段遍历代码,能避免好几个小时的路径问题和大小写问题。Script 不是炫技,是为了卡住 agent 的“自由发挥”,让结果可复现。
2.3 设计技术要点:为什么 SKILL.md 的“边界”是核心
我见过新手写技能,特别喜欢在 SKILL.md 里塞大段“你是专家,你很厉害,请用严谨的态度分析”。坦白讲,这些语义放在模型权重里可能有点用,但放在 Skill 里纯粹浪费 tokens。Harness 注入技能后,这些口号并不会提高输出质量,反而稀释了真正有用的指令。
真正该写的是边界:什么时候不用这个技能?遇到权限不足怎么办?输出超长时如何截断?数据敏感时是否只输出统计信息?我在实际项目里写了一个“数据库 schema 分析”技能,核心内容不是“怎么执行 SQL”,而是“哪些库不能碰、哪些表脱敏、查询超时要主动降级”。这几个限制比三页专业术语都管用。
所以在设计一个技能时,把 60% 的时间花在定义边界上,30% 写步骤,10% 写验收标准。步骤写得再好,边界没定,agent 容易跑飞;边界清晰了,哪怕是第一次写,也能把事办得八九不离十。
3. 实操过程与核心实现:从零写一个可复用的文档解析 Skill
3.1 明确目标和输入输出
为了让整个过程不悬空,我拿一个我做“数学建模求职辅助”的 skill 举例。这个技能的目标是:给 agent 一份多文件 Markdown 报告,让它提炼出关键结论、假设、局限和下一步建议。
为什么选这个任务?因为数学建模场景里面的报告通常又臭又长,模型初次阅读后经常抓不住重点。Skill 的目标是强制输出固定结构,避免 agent 自由发挥成一篇散文。
输入:若干 Markdown/PDF 文件链接或内容,附带用户指定要关注的维度(比如“只看总结和参数敏感性”)。输出:一份固定格式的九宫格摘要,通常是“问题定义 / 假设 / 方法 / 关键结论 / 局限 / 下一步”。
3.2 编写 SKILL.md 与辅助文件
项目结构长这样:
math-model-report-reader/ ├── SKILL.md ├── references/ │ ├── report_focus.md │ └── output_template.md └── scripts/ └── extract_headers.pySKILL.md 里我重点写了“触发条件”:当用户提供多页报告并要求归纳时可用;也明确了“不要做什么”:不逐段翻译,不重新建模,不脑补数据。references 里放的是输出模板,凡是 agent 要返回固定结构的场景,我都推荐把模板拆到单独文件,保证 SKILL.md 的主干仍然简洁。
extract_headers.py 这个脚本的作用是把 Markdown 文档里的所有标题按层级抽出来,形成一张目录索引。Agent 拿到目录索引后,不再需要通读全文才能决定从哪读起,这会让长文档分析快很多,也减少 token 浪费。
#!/usr/bin/env python3 # scripts/extract_headers.py import re import sys from pathlib import Path def extract(md_text: str): lines = md_text.splitlines() result = [] for line in lines: m = re.match(r"^(#{1,6})\s+(.*)", line) if m: level = len(m.group(1)) title = m.group(2).strip() result.append(f"{' ' * (level - 1)}- [{title}]") return result if __name__ == "__main__": for p in sys.argv[1:]: text = Path(p).read_text(encoding="utf-8") print(f"## {p}") print("\n".join(extract(text)))3.3 安装到 Claude Code 与 Codex
这个技能我在 Claude Code 里是这样安装的:
mkdir -p ~/.claude/skills cp -r math-model-report-reader ~/.claude/skills/如果只想当前项目生效,就放进项目根目录的.claude/skills下。Claude Code 会同时扫描用户级和项目级目录。个人使用放用户级,团队项目建议放项目级并提交到代码仓库,这样大家拿到的版本一致。
Codex 的 skills 安装逻辑类似,但对目录命名比较敏感,我一般把技能包直接放进~/.codex/skills或者项目的codex/skills下。opencode 最近也开始支持 skills 目录,大致可以给它设置opencode skills add ./my-skill这类命令。harness 之间没有完全统一,装之前先看一眼官方文档,别用同一个路径去猜所有工具。
3.4 流程演示:让 Agent 调用新 Skill
装好后,我测试时会直接输入:
请分析 docs/report01.md 和 docs/report02.md,输出建模要点摘要。如果 agent 判断这个问题匹配了 description,就会把 SKILL.md 注入上下文,然后调用 extract_headers 脚本先拿目录,再定向读取关键段落。最终输出一份按 output_template.md 组织的内容。第一次跑就完美命中不太现实,我通常会在测试后调整 description 的措辞,让匹配更准确。这个调参过程,其实和 SEO 的标题优化很像:你想让某个搜索意图命中你的内容,就得反复试。
3.5 安装第三方技能库:superpower skills 与 awesome-claude-skills
如果是小白上手,不想自己写,可以直接装现成技能仓。最常用的是 superpower skills 这类集合,里面有一堆针对 Claude Code 或 Codex 的预置技能,覆盖代码 review、SQL 分析、文档生成等场景。安装方式一般就是 clone 到本地,再把对应目录软链到 skills 目录。
git clone https://github.com/xxx/superpower-skills.git ln -s "$(pwd)/superpower-skills/frontend-skill" ~/.claude/skills/frontend-skill但我不建议全量塞进去,skill 太多会加重 agent 的检索负担。装五六个真正高频用到的就够。可以先把仓库 clone 下来,手动挑选需要的子目录软链进去。在“agent-skills”这个生态里,数量从来不是优势,精准才是。
4. 常见问题与排查技巧实录
4.1 技能不触发:八成是 Description 的问题
这个问题我遇到得太多了。明明 Skill 已经放进目录,但 agent 就是不用。你问它“能不能分析这个项目”,它只会跟你说“可以,我来看看”,完全不读 SKILL.md。
排查第一步:查 Description。Description 里的触发条件写得越像用户可能使用的表达,命中率越高。比如“前端开发 skills”如果描述成“提供前端开发最佳实践”,那用户问“帮我优化这个页面加载速度”时,模型可能不会联想到这个描述。改成“用于帮助优化前端页面性能、分析打包体积、诊断加载瓶颈”,命中明显改善。
第二步:查目录是否正确。Claude Code 只认特定目录,你放错一层它连扫描都不会扫。Codex 则对文件命名有要求,有的版本要求 SKILL.md 必须放在 skill 根目录下,不能嵌套太深。
第三步:看上下文中的说明。有些 harness 要求用户显式 @ 技能名或输入 /skill 命令,否则只是待命状态。Claude Code 里你可以直接输入/skill 技能名把它拉进上下文。
4.2 Agent execution terminated due to error:切分脚本要最小化
这个报错我看到过无数次。你把一个技能写得特别大,脚本里又依赖了一堆第三方库,结果 agent 执行时刚好缺库、缺环境变量、路径不对,整个管道直接终止。这类错误其实不是模型的问题,是 skill 实现得太脆弱。
我的经验是:技能里的脚本必须保持最小依赖,最好只用 Python 标准库,或者提前写死可 pip 安装的依赖清单,并在 SKILL.md 里写明安装命令。此外,给脚本加上清晰的参数校验和错误提示,agent 看到报错后能自己根据提示修正,而不是卡死。
一个重要心得:不要把一个需要交互式确认的操作写进 skill。Agent 无法像人一样在终端里输入 y/n,它只能通过内部工具与 shell 交互。遇到需要确认的步骤,要么改成非交互,要么提前用环境变量指定默认值。
4.3 Skill 与 Tool 的命名冲突
当你的 agent 环境中同时存在同名函数、同名 MCP 工具、同名 skill 时,执行顺序和优先级经常很谜。我发现最稳妥的策略是:给 skill 名称加上业务前缀,如frontend-audit、>