最近AI圈子里最热的一个词,不是模型参数量,也不是跑分,而是Skills。我在几个项目里实测了一轮Claude Agent Skills和Codex的Skills机制,说实话,这个功能改变了我对“提示词工程”的理解。以前我们调AI,靠的是把指令写得越来越长、越来越细,现在思路反过来了:把专业能力封装成可复用的模块,让AI在需要的时候自己去取。这篇文章不聊概念,只聊我在这段时间里摸出来的东西:一个Skill到底由什么构成、为什么它能大幅提升Agent的稳定性、从零写一个能用的Skill要注意哪些坑。适合正在用Claude、Codex这类编程Agent,或者做AI工作流自动化的同学参考。
1. 为什么我突然开始研究Agent Skills
1.1 一次偶然的“让AI长出新能力”
事情得从上个月说起。我在做一个小项目,需要让AI按团队规范做前端代码审查。之前的方式是:每次对话我都复制一大段项目规范、组件命名规则、页面结构要求,让AI照着检查。结果不稳定,经常做着做着就漏掉几个点,尤其是对话一长,模型就会“忘掉”前面的约束。后来我试了把规范整理进一个Skill目录,配了一个简洁的SKILL.md,效果完全不一样。只要用户提到“按团队规范审查”,模型会在几秒钟内自动加载技能里的步骤和脚本,输出质量和我手动贴提示词几乎一样,而且每次稳定复现。这次体验让我意识到,Skill解决的不是“让AI听懂一句话”,而是“让AI在合适的时机拿到一套完整的方法论”。
顺着这个思路,我去GitHub翻了一圈开源的skills集合,像superpower skills这类打包好的技能库,里面有很多现成的技能可以下载使用。那些技能五花八门:有的帮助AI做代码重构,有的帮助AI整理会议纪要,还有的专门做文档转换。但它们背后都遵循同一套逻辑:用一个技能目录,把“怎么干这件事”的步骤、工具、参考样例打包在一起,让AI自己决定什么时候取用。这已经不只是提示词技巧了,而是一种让模型能力模块化的设计模式。
1.2 Skills、MCP与提示词的边界在哪里
很多朋友第一次听到Skills,都会问它和普通提示词、插件、MCP到底有什么区别。我一开始也很懵,后来拿实际场景做对照,才慢慢捋清楚。
| 对象 | 本质 | 解决什么问题 | 类比 |
|---|---|---|---|
| 提示词 | 一次性指令 | 让模型完成当次任务 | 临时口头交代 |
| Skill | 可复用的方法包 | 让模型按专业步骤工作 | 岗位说明书+工具箱 |
| MCP | 外部数据与工具通道 | 让模型能读文件、调接口、用外部服务 | 水管和插座 |
| Agent | 任务调度中枢 | 规划、拆解并执行整个流程 | 项目经理 |
Skill和MCP并不冲突,它们解决的是不同层的问题。MCP解决的是“AI有没有手”,而Skill解决的是“AI知不知道怎么用这双手”。比如,通过MCP,AI可以读取本地文件、调用代码分析工具;但“拿到一份前端代码后该按什么顺序检查、检查哪些项、用什么规则判断是否合格”这属于方法论,是Skill要封装的东西。
提示词和Skill的分界就更清楚了。提示词是“对话中写一次,用完就没了”,Skill是“文件里长期沉淀,随时可加载”。我自己的习惯是:一次性、随机性强的任务直接用提示词;反复使用的任务、流程固定且带步骤的任务,值得做成Skill。别把所有东西都塞进Skill,那样维护成本很高。
2. 拆开一个Skill看它的内部构造
2.1 SKILL.md:一切能力的入口
Skill的标准结构其实不复杂。最核心的是一个叫SKILL.md的文件,它放在一个技能目录下面。这个文件相当于技能的门面和操作手册,模型通过它来决定“这个技能要不要用”以及“用了之后要按什么步骤走”。
SKILL.md通常以YAML格式的frontmatter开头,里面至少要写清楚技能的名称和描述信息。举个例子,我做前端审查技能时,开头是这样写的:
--- name: frontend-review description: 按团队前端规范审查代码并给出修改建议,适合在提交PR之前使用。当用户提到“代码审查”“review”“规范检查”时触发。 --- # 前端代码审查 步骤: 1. 先读取 resources/guidelines.md 获取团队规范 2. 遍历需要审查的代码文件 3. 对照规范逐项检查,输出问题列表和修改建议 4. 对每一条问题标注严重等级别看结构简单,这里面的description非常关键。模型不是先打开所有技能,而是先通过描述信息做语义匹配,判断“当前任务和这个技能相关吗”。description写得模糊,模型可能该触发时不触发,不该触发时误触发。我见过不少技能失效的案例,八成都是description没写到位。
2.2 scripts与resources:真正的“手”
SKILL.md只是说明书,真正的执行能力来自技能目录下的其他文件。通用约定中,scripts目录放脚本,resources目录放参考数据,assets目录放模板或静态资源。模型在读取SKILL.md之后,会按照指示去运行脚本、读取资源文件,然后结合结果继续干活。
举个我常用的例子:检查代码文件命名规范时,SKILL.md里让AI运行scripts/check_naming.py,脚本扫描目录里的文件名,输出违规列表,AI再根据这些列表生成修改建议。如果不用脚本,纯靠模型“目测”,文件一多就容易漏。
这里有个重点:Skill里的脚本不是独立于“对话”运行的,它是模型的辅助工具。模型负责理解任务、编排步骤、调用脚本、解释结果。脚本负责做模型做不准的事,比如批量文件操作、正则匹配、数据统计。这种分工让整个技能既灵活又可靠。
我把这层关系比作“总厨师长+后厨团队”。SKILL.md是总厨师长手上的菜谱,scripts是后厨里的锅碗瓢盆,resources是冰箱里的食材。总厨师长负责指挥,后厨负责具体操作,两边配合才能做出一道稳定的菜。
2.3 AI是怎么决定何时调用某个Skill的
这一节是我花了最长时间琢磨的。实际使用中,模型对Skill的调用并不是每次都会完整加载。Claude Agent这类系统会在会话开始时扫描技能目录,形成技能索引,但不会把所有技能内容都灌进上下文。真正的加载发生在任务执行过程中:模型发现当前任务和某个技能的描述匹配,才会去读取那个技能的SKILL.md和必要文件。
所以描述信息不只是一段文字,它实际上承担了两个职责:一是让模型判断“相关性”,二是让模型判断“调用时机”。比如说,我写过一个“分镜脚本生成”的技能,description里特意加了触发条件:“当用户给出故事梗概、小说片段,并希望转化为视频分镜时使用”。后来的测试证明,加了这句话之后,命中率明显提升。模型在用户需求到达时,会快速对照技能描述,一旦匹配,才真正进入技能流程。
这就解释了为什么不同Agent对Skill的支持程度略有差异。有的Agent对描述信息的匹配更激进,有的更保守。激进的好处是调用积极,坏处是乱触发;保守的好处是上下文干净,坏处是技能经常不生效。理解了这一点,写Skill的时候就要有意识地在description里把触发场景写具体,而不是笼统地说“帮助用户处理各种任务”。
3. 从零开发一个自己的Skill
3.1 目录规划与命名规范
从一个最简单的例子说起。假设我要做一个“会议纪要整理”的技能,目录结构可以这样建:
my-skills/ └── meeting-notes/ ├── SKILL.md ├── scripts/ │ └── format_notes.py ├── resources/ │ └── output_template.md └── assets/ └── example_notes.md命名规范上,我踩过几次坑。技能目录名和name字段都要用小写字母和短横线,不要用空格、中文、大小写混拼。原因很简单:Agents扫描目录时对名称的处理规则不同,如果名称里有空格或中文,有些平台能正常识别,有些会报错。稳妥起见,全部用frontend-review、meeting-notes、>--- name: skill-name description: 具体能力概述,必须包含触发场景和功能边界。 --- # 技能名称 ## 适用场景 (写清楚什么情况下用这个技能,什么情况下不该用) ## 执行步骤 1. 第一步做什么 2. 第二步做什么 ## 输入与输出 (说明期望接收什么输入,最终输出什么格式的结果) ## 注意事项 (列出模型执行时容易出错的点,比如不要修改原始文件、不要中断脚本)
关键是把每个步骤写清楚但不啰嗦。描述步骤时不要只讲目的,要讲顺序,因为模型会顺序执行。比如“先读取配置文件,再扫描代码,最后汇总结果”和“扫描代码,读取配置,输出结果”虽然看着都行,但真正执行时,顺序不同会导致结果不同。我在一次测试中发现,如果让AI先扫代码后读规范,它会用“自己理解的规范”去审查,而不是用团队真正的规范,审查结果自然不可靠。
3.3 脚本联动:让AI真的去执行
光有SKILL.md没有脚本,很多技能都会显得“虚”。比如“会议纪要整理”技能,模型本身就能整理文字,但如果输入的是音频转写文本,里面充满了口语词、重复句、碎片信息,纯靠模型整理很容易丢重点。这时候脚本的价值就体现出来了。
我给meeting-notes准备了一个脚本,负责做文本的粗清洗:
import sys import re def clean_transcript(text): lines = text.splitlines() cleaned = [] for line in lines: line = line.strip() if not line: continue if re.search(r'(嗯|啊|那个|然后|就是说)$', line): line = re.sub(r'(嗯|啊|那个|然后|就是说)$', '', line) if line: cleaned.append(line) return '\n'.join(cleaned) if __name__ == '__main__': raw = sys.stdin.read() print(clean_transcript(raw))这个脚本做的事情非常简单:去掉空白行和句尾的口语词。模型拿到清理后的文本再去做结构化摘要,效果明显好很多。这个例子的意义在于:Skill里的脚本不一定要做特别复杂的逻辑,它只需要负责模型“做不准但程序做得好”的部分,剩下的交给模型推理。
脚本怎么和模型交换数据?最稳妥的方式是:脚本从stdin读取输入、向stdout输出结果。不要在脚本里加入需要交互确认的步骤,因为Agent环境下没人会去点确认键,或者模型会卡在一个奇怪的状态。我之前写过一个脚本,运行后弹出了input()等待用户输入,结果整个任务挂起,最后只能强制中断。现在我的原则很明确:脚本必须是批处理式的、无交互的。
3.4 本地验证与多轮调试
Skill不是写完就能用的,至少要经过三轮测试。第一轮,做“触发测试”:把Skill放进Agent的技能目录,重启会话,输入一句明确触发描述的任务,看Agent是否加载这个Skill。如果没加载,第一件事不是改步骤,而是改description,把触发场景描述得更具体。
第二轮,做“边界测试”:故意输入一个看似相关但实际不需要用技能的任务,看模型是否误触发。误触发很烦人,因为它会消耗大量上下文去读取无关文件。我通常会在description里增加“排除条件”来降低误触发率,例如:“当用户只是询问概念而非实际操作时,不要使用本技能”。
第三轮,做“完整链路测试”:用一份真实的、有代表性的输入跑完整流程,重点检查三个点:脚本是否正常执行、执行结果是否被模型正确解读、最终输出是否符合预期。这一轮最容易暴露出SKILL.md里的步骤描述问题,比如“遍历代码文件”这个描述太模糊,模型可能不知道该遍历哪些目录,需要写成“遍历src和tests目录下的.py和.ts文件”。
调技能的过程很像调菜谱配方。每次改动SKILL.md后我都会记录这次改了什么、为什么改、测试结果如何。改动集中在三个变量:description的触发词、步骤顺序、脚本输入输出的约定。只要这三个变量稳定了,技能就基本能用了。
4. 我实测过的几个典型Skill场景
4.1 前端开发:让AI按项目规范出代码
前端开发是Skill应用最成熟的场景之一。原因很简单:前端代码风格差异大,团队规范多,而且规范往往可以被检查脚本自动执行。我封装过一个叫frontend-review的技能,把团队规范、ESLint规则、组件命名习惯全部打包进去。
实际使用中,这条Skill帮了大忙。以前人工审查代码,要逐条对照规范看,特别累且容易漏。现在AI会在审查前先读取resources/guidelines.md,再结合用户提供的代码文件,逐条输出问题清单,标注严重级别和修改建议。最惊喜的是它能识别上下文相关的规范问题,比如某个组件是否应该拆分成子组件、Hook的依赖数组是否完整——这些不是纯规则检查,而是需要结合项目结构的理解,模型在这里做得不错。
我的建议是:前端类Skill不必追求“一次性解决所有问题”,而是把技能拆细。一个技能管代码审查,另一个技能管组件生成,再一个技能管样式统一。每个技能职责单一、触发明确,使用体验远好过一个大而全的技能。
4.2 分镜脚本:把创意转换成可用于生成的画面描写
分镜类Skill是我近期发现的新玩法。它解决的是内容创作中的一个痛点:创作者有了故事想法,但不知道怎么把文字转换成具体的画面语言。分镜技能本质上是一套“转译工具”,它接收一段故事梗概,输出结构化分镜表。
我自己跑通的一条Skill输出格式是这样的:
| 镜头号 | 景别 | 运镜方式 | 画面描写 | 光线与色调 | 备注 |
|---|---|---|---|---|---|
| 01 | 远景 | 缓推 | 雾中的城市天际线,路灯依次亮起 | 冷蓝调,低饱和 | 配合旁白 |
| 02 | 中景 | 平移 | 主角站在落地窗前,手扶玻璃 | 冷暖对比明显 | 情绪转折点 |
| 03 | 特写 | 静帧 | 主角眼睛反光,映出窗外灯光 | 明暗对比增强 | 留白处理 |
这个技能的SKILL.md里写明了每个字段的含义和写作要求,尤其是“画面描写”要具体到视觉元素,不能只说“很好看的画面”。因为这套输出可以直接喂给图像生成工具,所以描写越具体,生成的画面越可控。
这类Skill的价值在于把“感性的创意”和“可执行的视觉语言”无缝连接。以前做视频脚本时,编剧和摄影指导之间经常要反复沟通,现在一份结构化分镜表就能把双方的信息拉齐。我甚至把它用在内部项目的提案上,直接生成分镜表给客户看,效率高了一大截。
4.3 自动挖洞:安全测试中的技能封装
“自动挖洞”这个词在安全圈里指的是一套漏洞发现流程,我把它封装成Skill的过程有些不一样的体会。首先要强调一点:这类技能只应该在获得授权的前提下使用,用于自己的测试环境、靶场或合作关系合规的渗透测试项目。别拿它去碰别人的系统,这是底线。
我做的安全测试辅助Skill,重点不是“自动攻击”,而是“自动整理和规划”。它读入目标信息后,会把常见的测试流程组织成有序步骤:先从信息收集开始,看域名解析、开放端口、指纹识别,再到Web层面的常见风险点排查,最后把发现汇总成结构化的报告。SKILL.md里还特意写了“每个步骤必须说明依据和方法,禁止执行未授权的破坏性操作”,让模型在执行时有清晰约束。
实际测试下来,这个技能最有用的部分是“测试步骤编排”。安全测试过程步骤多且容易漏,AI最大的价值在于不遗漏、不跳步,每次都能按固定顺序把一个站点的基础检查做完,并生成带证据链的检测报告。虽然它不能替代专业漏洞挖掘工具和人工判断,但作为测试辅助,可以把重复劳动的部分自动化掉,让安全人员把时间花在真正需要脑子的地方。
4.4 论文与需求文档:结构化写作技能的模板化
Codex写论文、编写需求文档的场景,在Skills机制下也有很明显的提效。纯用对话让AI写需求文档,问题是模型经常把格式写飞,不同章节详略失衡。我封装了一个名为requirements-writer的Skill,它内置了文档结构模板、章节质量标准,以及每个章节常见的检查项。
SKILL.md里的执行步骤是:先根据用户输入做需求梳理,输出文档大纲,等用户确认后再按大纲逐章扩展;每章之后都要做一次一致性检查,比如“第2章的需求术语是否和第5章一致”“非功能需求是否覆盖性能、安全、兼容性三个维度”。这些检查项如果靠对话里临时叮嘱,AI经常漏,但在Skill里写成固定步骤后,执行率非常高。
写论文同理。学术写作技能最核心的价值是“结构先行”:先定论文主题和论点,再生成提纲,核对逻辑链是否完整,最后才进入正文写作。这种设计避免了一个常见问题——用户直接说“帮我写一篇论文”,AI哗啦写出一大段,看着很多,但结构散乱、论点撑不住。Skill通过强制步骤把“先想清楚再下笔”的信息固定下来,对结果的影响极大。
5. 实测踩坑与排查清单
5.1 描述写不好,Skill就是摆设
最容易踩的坑,就是技能下了一堆,但用的时候没有一个生效。头几次我怀疑是平台问题,后来才发现100%是我自己description写得不行。比如,我曾写过一个技能,description是“帮助用户进行数据处理”,听起来没问题,但实际上太宽泛了。模型面对“把这份CSV的A列按B列分组求和”这样具体的任务时,并不认为它和“数据处理”这个宽泛描述强相关,于是根本没有触发技能。
改进方式是把触发条件直接写进description末尾:“当用户提到分组、聚合、清洗、转换CSV或Excel数据时使用。”加了这句话之后,触发率迅速提升。经验法则:description里至少要有两个部分——能力概述和触发特征,并且触发特征要写得像关键词索引。
5.2 上下文爆炸:日志与中间输出太多
第二个大坑是脚本输出太多。模型的上下文窗口虽然越来越大,但也不是无限量。我最早的版本里,脚本会把整个代码仓库的文件清单全部打印出来,几千个文件名直接灌进上下文,模型很快就被这些噪音淹没,反而忽略了规范文件。
教训是:Skill中的脚本输出要“以摘要为主,以原始数据为辅”。不要让脚本输出所有内容,而是让脚本输出统计信息和异常项列表,原始明细按需再查。比如,代码审查技能里的脚本,现在只输出“检查了哪些目录、发现多少违规、违规集中在哪几个文件”,完整细节写入一个临时文件供后续读取。这样上下文占用少了,模型反而抓得住重点。
还有一点:脚本运行大耗时任务时,要在SKILL.md里注明“如果运行时超过30秒未返回,请检查输入文件是否过大并考虑拆分处理”,避免模型干等或是直接放弃。
5.3 命名空间冲突与加载异常
第三个坑是关于技能加载失败。有次我把技能放到了正确目录,但Agent始终提示找不到。查了半天,发现是某个脚本文件里用了一个相对路径,路径写的是../resources/xxx,但脚本是从技能目录的scripts子目录执行的,实际上应该用../resources/xxx没错。结果问题出在脚本运行时的工作目录不是技能目录,有些Agent会从项目根目录启动脚本,相对路径全变了。
解决方法是:在SKILL.md里明确写明“所有脚本必须基于技能目录解析相对路径,禁止基于工作目录假设路径”;在脚本内部,用os.path.dirname(__file__)这类方式定位脚本所在目录,再向上拼接路径。这是一个非常细节但经常坑到人的点。
另一个更容易忽略的坑:技能目录里不要放置无用的文件。Agent扫描技能目录时,如果发现一个没在SKILL.md里说明用途的文件,可能会尝试读取或整合它,结果引入噪声。目录里的每个文件都应该有存在的理由,并在SKILL.md中说明它的用途。
5.4 一套实用的自检清单
我把自己排查Skill问题时用的清单整理成了表格,每次技能不生效就按这个顺序过一遍:
| 检查项 | 检查方法 | 合格标准 |
|---|---|---|
| name唯一性 | 搜索全部技能目录,确认没有重名 | 无重复 |
| description触发词 | 用触发任务测试是否匹配 | 能正确被加载 |
| 步骤顺序合理 | 人工模拟一次执行,预设输入 | 每步都有明确前置和后置 |
| 脚本可独立运行 | 在命令行手动执行,喂样例输入 | 能正常退出并输出结果 |
| 路径引用可靠 | 从不同工作目录运行测试脚本 | 均能找到资源文件 |
| 输出格式稳定 | 用同一输入反复执行三次 | 结果结构一致 |
| 上下文控制 | 观察脚本输出量 | 每次输出不超过1500字 |
| 边界情况 | 输入空文件、超长文件、特殊字符 | 不崩溃、有明确提示 |
这套清单看起来朴素,但每次解决实际问题都靠它。毕竟Skill的核心属性是“可复用”,一个只跑一次成功的技能不算成功,能在不同环境下稳定复现才算真的可用。
我在实际使用中的体会是:Skills不是一个需要追求“大而全”的功能,更像是给AI写“岗位操作手册”。你用得越频繁、场景越具体,技能创造的价值就越明显。最后分享一个冷技巧——在SKILL.md里加一个“何时不应使用本技能”的小节,写明排除条件。这个技巧极大降低了误触发率,也让真正该触发时模型更果断。你如果正在折腾Claude Agent或者Codex的Skills机制,不妨先把一个反复用的工作流打包成Skill,不用贪多,一个好用就够了。