
“skills”这个词放在2025年的技术语境里已经不太是指简历上的“熟练使用XXXX”了。如果你经常刷AI工具圈、关注Agent类应用大概率会看到越来越多以“skills”命名的文件夹、仓库甚至整个团队都在围绕“给AI加技能”这件事做工程化建设。说得直白一点在模型能力越来越强的背景下真正拉开体验差距的往往是模型外层那一圈“可复用的操作能力”——这就是skills。这篇文章我想好好聊聊我最近大半年在AI Agent项目里折腾skills的心得从“它到底是什么”讲到“怎么自己写一个能用的skill”再到调试、组合、避坑。适合两类人看一类是把Claude、ChatGPT这类模型当生产力工具、想让AI更听话地干活的深度用户另一类是正在做Agent产品、被“提示词越写越长、效果却越来越飘”困扰的开发者。看完之后至少你能知道一个标准的skill该长什么样SKILL.md里的每一段为什么重要以及怎么解决“模型总是想不起来用技能”这个最让人头疼的问题。1. 先弄明白skill到底是个什么东西1.1 一个文件夹就是一个“可调用的技能包”先说我的理解。一个skill本质上不是一个提示词模板也不是一段函数代码而是一个完整的、自包含的文件夹。里面通常有一份说明书SKILL.md以及配套的脚本、参考文档、模板文件、数据文件等。拿我很久以前手工调教Claude的经验对比以前我想让模型按特定格式输出周报做法是把一整段“你是周报助手请按以下格式输出……”塞进System Prompt。问题在于这个Prompt会占用固定上下文窗口不管这个任务用不用得上。而skills不一样它是在“需要的时候才被加载”——模型判断当前任务匹配某个skill时才会把SKILL.md文件内容读进上下文。这个“按需加载”的设计直接改掉了“把所有能力一次性塞进上下文”的笨办法。所以你可以把skills理解成给Agent装上的外挂工具箱。箱子一直放在仓库里不占地方当用户说“我要写单元测试”时Agent才去翻“写测试的箱子”拿出里面的说明和工具来干活。这个逻辑往下延伸好处就很明显了单次请求消耗的token少了模型的注意力更集中在当前任务上输出质量通常也更高。1.2 SKILL.md那份说明书到底写了什么每个skill文件夹的核心是SKILL.md。它用Markdown写成结构大致分成两块。第一块是frontmatter就是文件最顶部用---包起来的元信息里面至少要有name和description两个字段。name好理解就是技能包的名字description才是真正决定“模型会不会用这个技能”的关键——它是一段自然语言描述告诉模型“什么情况下你应该加载本技能”。这部分写得好不好直接决定了整个skills方案的成败。第二块是正文也就是Skill的本体指令。正文可以包含任务描述、执行步骤、约束条件、输出格式、注意事项等。官方推荐一个原则叫渐进式披露意思是SKILL.md正文里只放“当前任务必须知道的核心指令”而更细节的指导内容可以拆分到references目录下的其他文档中等模型真正执行到那一步时再按需读取。我见过不少新手写SKILL.md恨不得把整个领域知识全塞进去结果说明书比操作手册还厚。这样做很蠢——加载进来消耗上下文而且指令太密模型反而抓不住重点。好的SKILL.md读起来应该像一份“作战简报”简洁、可执行、明确边界。1.3 Skills和MCP、Prompt模板到底有什么区别聊skills绕不开MCPModel Context Protocol。很多人会混淆这两者我简单说下我的理解。MCP做的事情是“连接外部工具和数据源”比如让Agent能查数据库、调API、读写文件。MCP更像给AI接了“手”和“眼睛”。Skills做的事情是“提供一套操作某类任务的方法论和指令”。一个skill可以调用MCP暴露的工具也可以直接运行脚本完成操作。Skills更像给AI装了“操作手册”。用生活类比MCP是给厨师准备了全套厨具和食材供应链skills则是给厨师一张“宫保鸡丁标准做法”的配方卡。没有厨具配方卡只能看没有配方卡有厨具也不知道按什么顺序炒。至于它和传统Prompt模板的区别更明显了。Prompt模板是“一次性把话说完”没有状态、没有依赖、没有配套资源而skill是“按需调用且有内部结构”的能力单元。一个项目里放十个skill等于给Agent建立了“遇到XX任务→加载XX文件夹”的自动路由机制。这是规模化的前提。2. 手把手拆解如何从0到1构建一个自己的skill2.1 第一步挑一个“高频、重复、规则明确”的任务不是所有任务都适合做成skill。我踩过的第一个坑就是把一个低频率、弱规则的“头脑风暴辅助”任务硬做成了skill结果模型死活不触发白折腾一下午。什么样的任务适合做成skill以我做过的“代码审查助手”skill为例它满足三个条件触发频率高几乎每天用、规则明确需要检查的点很固定、执行路径相对稳定每次都是拿diff→逐项检查→输出结论。这些特征决定了封装成skill之后收益是可持续的。另一个适合做skill的典型场景是“有配套资源或脚本可复用”。比如我写过一个“生成周报”的skill它的SKILL.md里只写了流程指令但resources目录下放了一个周报模板文件和一个统计git提交记录的小脚本。这样模型被触发后会自动调用脚本拿数据再填入模板。这就是“指令资源工具”的完整闭环。2.2 第二步设计SKILL.md——命名的艺术和描述的科学写SKILL.md时description字段值得花最多时间。模型会不会自动识别并加载这个skill几乎全靠它。我总结了一个写description的心法用“任务类型核心动词边界条件”的句式。不要写“擅长代码相关操作”这种废话而要写“当用户请求审查代码变更、识别潜在bug和安全隐患时使用”。更讲究一点可以在description里加一两个触发场景示例比如“适用于GitHub PR review、本地diff文件分析”。为什么这么写因为模型的加载判断机制是语义匹配它会把用户当前请求和每个skill的description做相似度比对。description写得越具体、越贴近真实用户表达匹配命中率越高。这里有个细节description里可以适当包含同义词和常见变体表达。比如我写“周报生成”skill时description里就同时放了“周报”“weekly report”“本周工作汇总”几个说法实测触发率明显提升。frontmatter之外正文的结构我建议固定成下面这个模式目标 → 输入要求 → 执行步骤 → 输出格式 → 注意事项。这五段不是凑出来的它们分别回答了模型在执行时最关心的五个问题我要干什么我需要什么数据我按什么顺序做结果长什么样我不能碰什么2.3 第三步为skill配上真正能跑的脚本和资源如果说SKILL.md是大脑那scripts和resources就是手脚。一个只靠模型“脑补”的skill能力上限很有限。真正好用的skill通常都会调用一些本地脚本或外部数据文件。拿我做的一个“批量图片压缩”skill为例。SKILL.md里说明流程识别需要压缩的图片→检查是否安装ImageMagick→执行压缩命令→校验输出文件大小。scripts目录下放了一个compress.py脚本处理细节包括目标尺寸、压缩质量、输出目录命名。模型被触发后会读取SKILL.md调用脚本再根据脚本返回结果判断是否完成任务。这里有一个非常需要注意的点skill目录里的脚本路径要按相对路径写。我见过很多人把路径写成绝对路径换一台机器就全部失效。SKILL.md里应该写scripts/compress.py这样的相对路径并明确告诉模型“你的当前工作目录是本skill所在目录”这样整个skill才是可移植的。依赖问题同样容易踩坑。如果脚本依赖第三方库比如pip install requests务必在SKILL.md里写清楚安装命令或者在skill目录里放一个requirements.txt。我自己做的一个经验规则凡是模型执行时可能需要额外安装的东西都要在文档里显式给出安装指令否则运行时报错模型经常会一脸懵然后开始胡编乱造“已成功完成”。2.4 第四步调试和验证——别指望一次就完美写skill这件事最大的错觉就是“写完了就完事了”。实际开发中写一个可用版本的SKILL.md可能只花半小时但调试到“稳定触发、稳定输出”可能要花几天。我习惯的调试流程是这样的先准备一组测试输入至少10条不同说法但表达同一意图的用户请求然后逐一跑一遍看skill触发的命中率。再用另一组“不该触发”的输入测试误触发率——比如我写的“周报生成”skill不应该在用户问“帮我看看这行代码哪里有问题”时加载。双向验证都通过才算基本可用。调试过程中**观察模型的“参考链条”**特别重要。很多Agent类应用会显示“当前使用了哪些skill”如果发现模型该用时没用、不该用时瞎用优先怀疑description写得不到位然后迭代描述文本。这个过程很枯燥但真没什么捷径。3. 实战案例一个“代码审查助手”Skill的完整实现3.1 需求拆解与文件夹规划这块拿我最近在项目里实际用的一个skill举例代码审查助手code-reviewer。这个skill的目标是给定git diff或代码文件自动按照预设规范进行审查输出结构化审查意见。需求拆完之后我给这个skill规划了如下结构code-reviewer/ ├── SKILL.md ├── scripts/ │ └── extract_diff.py ├── references/ │ ├── security_checklist.md │ └── style_guide.md └── assets/ └── review_template.mdSKILL.md负责总控流程extract_diff.py负责从git仓库提取diff数据references下面的checklist文档负责展开细节review_template.md则规定了产出报告的固定格式。这样设计的好处是当模型审查一个具体文件时它只需要加载对应的checklist而不是把所有规则全部读进上下文。3.2 SKILL.md完整示例可直接改着用下面是我精简之后的SKILL.md内容结构可以直接复用--- name: code-reviewer description: - 当用户请求审查代码变更、分析Pull Request、评估代码质量和安全性时使用。 适用于“review my code”、“帮我看看这段代码”、“有没有bug”、“code review”等场景。 --- # 代码审查助手 ## 目标 对用户提供的代码或diff进行专业审查发现潜在bug、安全隐患、性能问题并给出改进建议。 ## 输入 - 用户直接贴入的代码片段 - 用户指定的文件路径 - 通过 scripts/extract_diff.py 从当前git仓库提取的diff使用 --staged 参数可获取暂存区变更 ## 执行步骤 1. 获取待审查代码。如果是git仓库优先调用 python scripts/extract_diff.py 提取变更内容否则直接使用用户提供的代码。 2. 根据变更涉及的文件类型加载 references/ 下对应的检查清单。 3. 逐项检查记录问题。每个问题必须标注严重级别critical/warning/suggestion。 4. 对每个找到的问题给出具体说明、所在位置文件行号和修复建议。 5. 使用 assets/review_template.md 中的格式输出最终审查报告。 ## 输出格式 按 review_template.md 中定义的Markdown表格输出按问题严重级别排序同一级别内按位置顺序排列。 ## 注意 - 只反馈真实存在的问题不要为了凑数量而编造问题。 - 不能确定的问题标为suggestion并说明原因不要用绝对化语言。 - 如果未能成功获取diff或代码立即说明情况不要猜测执行结果。这个SKILL.md的核心思路是“让模型知道每一步该干什么以及该去读哪个文件”。篇幅不长但因为把详细checklist外置了实际能力比很多长篇大论的提示词强得多。3.3 配套脚本与参考文档怎么写extract_diff.py比较直白核心逻辑就是用git diff命令把变更内容导出来#!/usr/bin/env python3 import subprocess import sys def get_diff(stagedFalse): cmd [git, diff] if staged: cmd.append(--staged) result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode ! 0: print(f获取diff失败: {result.stderr}, filesys.stderr) sys.exit(1) print(result.stdout) if __name__ __main__: staged --staged in sys.argv get_diff(staged)写这个脚本没什么玄学但要注意两点一是脚本要能容错git diff执行失败时要有明确报错否则模型会因为拿不到输出而开始瞎编二是输出要格式清晰模型读取stdout后需要快速理解内容所以尽量不要加无意义的日志。references/security_checklist.md则需要写得非常具体比如包含SQL拼接位置是否使用了参数化查询用户输入是否直接拼进了HTML或eval相关函数是否在服务端做了权限校验而不是只依赖前端隐藏按钮敏感信息密码、token是否出现在日志或前端代码中这些检查点写得越细模型的审查结果越有价值。如果只是写“请检查安全性”模型多半只会给你几句正确的废话。3.4 实测效果与调优过程这个skill我用了大概两个月期间迭代了四五次description和checklist。最明显的一次提升是在checklist里加了一个“检查开发调试代码是否残留”的条目之后——从那以后模型开始能主动发现开发时留下的console.log、print调试语句和生产代码混杂的问题。调试过程中最大的坑是模型偶尔会“过度执行”比如用户只贴了一段20行的函数模型却按照diff提取流程去跑git命令结果发现当前目录不是git仓库报错之后开始道歉。最后我在SKILL.md的输入部分加了一句“如果代码已由用户直接提供则优先使用该代码不要执行diff提取脚本”这种情况才基本杜绝。所以说SKILL.md是要在真实使用中不断“驯化”的。别指望第一版就完美把它当做一个持续迭代的活体文档来维护。4. 常见问题与排查技巧实录4.1 问题一模型总是想不起来用skill怎么办这是我被问最多的问题没有之一。排查思路要从三个层面依次看。第一层是不是description写得不够精准。记住模型做的是语义匹配不是关键词精确匹配。如果用户的表达方式口语、英文缩写、技术行话和你description里的措辞距离太远匹配失败很正常。解决办法是看实际触发日志把“模型没加载skill但应该加载”的用户请求都收集起来反向提炼词汇扩充进description。第二层是不是skill文件夹结构不对。不同Agent框架对skill目录的约定不完全一样有的要求放在~/.claude/skills/有的项目里直接放.claude/skills/还有的用skills/顶层目录。层级错了模型根本“看不见”这个skill描述写得再好也没用。先确认你的框架到底从哪里扫描skills。第三层是不是上下文已经太长了。模型中后段的指令相对容易被“淹没”在长上下文里如果你的System Prompt特别长即便skill平时能被扫描到关键时刻也可能被忽略。这种情况可以考虑把不必要的系统指令精简或者把一些低频规则也做成skill让核心上下文保持清爽。4.2 问题二skill加载了但执行到一半“断片”这个问题的典型表现是模型读了SKILL.md也调了脚本但脚本返回结果后它好像忘记了原始任务目标开始答非所问。我遇到过一次是“生成周报”skill在处理一个超大git log时出现的——脚本输出了好几万字的提交记录直接把模型的有效上下文窗口塞爆了。排查方向很明确检查skill执行过程中是否产生了超大中间结果。解决办法是在脚本侧做截断或摘要不要一次性把所有原始数据塞给模型。比如我在生成周报的脚本里加了提交数量限制只取最近50条代码审查的diff脚本也做了行数截断超过指定行数就只保留文件名列表和统计信息。原则是给模型的永远是最适量的信息而不是全部信息。另一种“断片”是因为SKILL.md里出现了矛盾指令。比如前面说“必须输出中文”后面又说“代码注释保留英文”模型会陷入纠结表现就是来回摇摆、输出混乱。写SKILL.md时要注意全局一致性前后要求不要打架。4.3 问题三依赖安装失败或脚本运行报错脚本运行报错是skill“自动化”最脆弱的一环。常见的坑包括Python虚拟环境没激活、ImageMagick没装、Node模块版本不对、系统是Windows而脚本里用了bash命令。我的建议是在SKILL.md里把运行环境要求写在最前面用明确的“前置条件”章节列出所有依赖及其安装命令。同时在脚本里对所有外部依赖做前置检查缺了什么直接打印“缺少依赖XXX请先运行 pip install XXX”别让报错信息变成一行看不懂的Traceback。还有个很多人忽略的细节权限问题。如果你的skill脚本需要写文件或执行某些系统命令在macOS上可能需要额外授予权限在Linux容器里可能要处理文件属主问题。做skill分发的时候最好在README里说明所需权限避免部署到新环境时卡壳。4.4 问题四误触发——不该用的时候偏偏加载了误触发和漏触发是“双胞胎”问题。漏触发是模型该用不用误触发是模型不该用瞎用。比如用户只是随口说了一句“这周数据有点怪啊”周报生成skill就被加载了白白浪费token还有可能让模型进入错误模式。解决误触发核心也在description。写description时除了写“什么情况使用”还要写“什么情况不要使用”。我见过不少写得好的description会在结尾加一句“如果用户只是询问数据问题没有要求生成报告不要使用本skill”。别小看这一句否定式描述实测下来对降低误触发率很有效。另外一个技巧是在SKILL.md正文开头加一段“触发器确认”要求模型在执行前先确认“用户请求确实匹配本skill的目标”如果不匹配说明理由并建议其他方案。这种“二次确认”机制能过滤掉一部分边缘case的错误加载。5. 更进一步的实践心得让skill体系发挥最大价值5.1 把经常重复的“微流程”沉淀成skill很多人对skills的理解停留在“大任务技能包”的层面觉得只有“代码审查”“周报生成”这种完整任务才配做skill。但我实际用下来一些很小的、只有三五步的微流程做成skill后效率提升更明显。举个例子我在项目里有个叫“commit-message”的skill内容特别简单读取git diff的stat信息根据变更类型和规模生成一个符合团队规范type(scope): subject的commit message。它只有短短十几行指令但几乎每天都会触发帮我省下了大量“打字写提交说明”的时间。这类微流程的特点是很明确固定输入、固定规则、固定输出。用skill包装后你就不需要每次重新跟模型解释规则了。很多痛点是重复性的只是你没意识到它们值得被自动化。5.2 Skills之间的组合与依赖当你攒了五六个skill之后会开始遇到“skill之间互相调用”的需求。比如我的“生成周报”skill内部其实需要“提取git提交记录”的能力而后者的逻辑被封装在另一个叫“git-log-analyzer”的skill里。目前不同Agent框架对skill间调用的支持程度不一样。有的框架支持在SKILL.md里通过相对路径引用其他skill中的文件有的则不支持需要在规划阶段就把公共逻辑抽出来让多个skill共用同一份参考文档或脚本。我的建议是尽早识别公共依赖把“操作git”“读取文件片段”“格式化输出”这类基础能力拆成共享模块放到所有skill都能访问到的地方。否则同一个脚本你会复制粘贴三份后面调整逻辑时想死的心都有。5.3 Skill的版本管理与团队协作如果一个项目的skill只有你自己维护版本管理随便怎么玩都行。但一旦进入团队协作skill的版本管理就要认真对待。我的经验是把整个skills目录放进一个独立的git仓库用语义化版本管理。SKILL.md里的大改动比如执行流程变了升minor版本description措辞微调、补充触发词这类小改动升patch版本。每个skill目录下放一个CHANGELOG.md记录每次变更的原因。这样当团队成员反馈“这个skill时好时坏”时你能直接查看最近改动快速定位是不是某次调整引入了问题。另外一个很实操的点skill的代码应该做review。很多人写SKILL.md想怎么写怎么写语法、结构、风格都很随意。但我推荐大家参考传统代码review的流程至少保证SKILL.md有清晰的层级结构、脚本有异常处理、说明文档有更新记录。因为这本质上就是代码只是运行它的“运行时”是语言模型。5.4 关于SKILL.md和description的设计最后几点补充写description这块我再补几个经过验证的技巧放一个“反例”描述在description里写“不要用于……”能帮助模型建立清晰的边界。采用“用户视角”措辞描述时尽量模拟真实用户的表达方式而不是功能视角。比如“用户想快速生成数据分析报告”而不是“本模块用于数据分析报告生成”。前者更容易语义匹配。控制长度description不是写论文两到三句话、百来个字以内最佳。太长了模型在加载判断阶段也会“看不清重点”。至于SKILL.md正文本身的风格我的体会是用“祈使句约束条件”的组合比大段散文式描述更好使。明确告诉模型“先做什么再做什么什么不能做”比“请你像一位资深专家一样细致地……”这类空话有效一百倍。再分享一个从社区里学来的小技巧在SKILL.md开头放一个“快速开始”示例很短的三步让模型先建立对任务路径的整体认知然后再展开详细规则。这有点像是人类读操作手册的习惯——先看“快速上手”再决定要不要深入细节。模型对长文档的理解方式其实很接近人类。5.5 什么时候不建议用skills聊了这么多skills的好处我也想泼点冷水。并不是所有功能都适合做成skill。第一类是本身就极简单的任务。比如“把这段英文翻译成中文”直接在对话里说就行没必要包一层skill。封装会引入额外的触发判断、加载开销得不偿失。第二类是规则高度模糊、主观性强的任务。比如“帮我起个有创意的项目名”这种没有固定流程、没有明确输出标准的任务skill能给的约束很有限效果不一定比直接对话好。第三类是你还没有真正用过三遍以上的任务。一个流程如果你自己都没走顺那大概率也写不出清晰的SKILL.md。与其急着封装不如先手动操作几次梳理出稳定路径之后再动手。我做skills这么久最大的感受是这是一个“越用越值钱”的资产。模型能力本身是“通用引擎”但每个人手里的skills库决定了这台引擎在自己的工作流里到底能跑出多高的效率。它跟快捷键、代码片段、自动化脚本一样是你和AI协作时积累的“私房工具”时间越长复利效应越明显。如果你正准备开始整理自己的第一个skill我的建议很简单从你每周都会重复做三次以上的那个任务入手先写一版粗糙的用起来然后一遍遍改description改步骤加脚本。不要憋大招不要试图一步到位。把skills当成一个活的项目来养它才会真正长成适合你工作方式的样子。