首页 / 资讯中心 / 文章详情

Agent Skills实战:用SKILL.md把提示词变成可复用的技能包

Agent Skills实战:用SKILL.md把提示词变成可复用的技能包 ★ FEATURED ARTICLE
1. 从提示词堆砌到按需加载的技能包Skills到底改变了什么1.1 我最初对Skills的误解先说个真实经历。今年早些时候我在做一个自动化内容处理项目需要让AI模型重复完成一系列固定任务抓取网页正文、清洗格式、按模板生成摘要、再转成特定格式输出。最开始我的做法很朴素——把一大段包含所有规则和示例的提示词塞进每次对话里。刚开始效果还行但随着规则增加提示词越来越长最终变成了一个两千多行的怪兽每次调用不仅浪费token而且模型经常顾此失彼处理到后面几条规则时就把前面的要求忘了。我当时就想过一个问题如果能把不同的处理能力拆成独立模块让模型在需要的时候才加载对应的那部分指令是不是就不会互相干扰了后来我接触到Skills这个概念发现它解决的正是这个问题。但说实话我一开始对Skills有误解以为它就是把提示词拆成几个文件放文件夹里。直到自己动手写了一个完整的Skill并在项目中跑通之后我才意识到它背后的设计逻辑远比拆文件要深。1.2 Skills的真实定位程序性知识的文件化Skills也就是Agent Skills本质上是把一类做事的方法——包括操作规程、配套脚本、参考资料——打包成一个独立目录让AI Agent在任务需要时按需读取并执行。这里有个关键词按需。以前我们的做法是有备无患把所有可能的指令全部塞进上下文里让模型自己挑选。这就像你出门前把所有可能用到的工具都背在身上——伞、锤子、扳手、手电筒——结果背包重得走不动路。而Skills的做法是分门别类放在工具箱里模型先看一眼每个箱子上写的标签description需要哪个开哪个。这个设计的核心价值在于上下文窗口是稀缺资源知识加载应该是检索式的而不是全量式的。一次任务里模型可能只需要全部技能中的一两个其余技能完全不必进入上下文。这既降低了token消耗也减少了指令之间的干扰。还有一个容易被忽视的点Skills是文件系统级的。这意味着版本管理、团队共享、权限控制都变得非常自然。一个技能可以像代码一样被review、被迭代、被回滚这比在聊天记录里维护提示词要可靠得多。1.3 与MCP的本质区别很多人刚接触这个概念时会问那Skills和MCPModel Context Protocol有什么区别我刚开始也搞混过后来总结了一个很直观的区分方式MCP是给模型工具模型决定调用哪些工具来完成操作。它强调连接和执行比如读取数据库、调用外部API、操作文件系统。Skills是教模型方法模型读取后知道这件事应该怎么做。它强调知识和流程的传递比如分析日志时应该按什么顺序排查生成周报应该包含哪几个板块。用一句话总结MCP解决的是模型能做什么Skills解决的是模型知道怎么做。实际项目中两者往往配合使用但它们的定位完全不同。2. Skill包拆解一个文件夹就是一个可复用的能力单元2.1 目录结构约定我在实际使用中接触到的Skill目录结构大致是这样的以Anthropic推出的Claude Skills规范为参考my-skill/ ├── SKILL.md # 技能主文件模型最先读取 ├── scripts/ # 配套可执行脚本 ├── references/ # 参考资料按需加载 └── assets/ # 静态资源文件这个结构看起来简单但每个目录的职责边界是有讲究的。SKILL.md是核心。它分为两部分YAML格式的frontmatter元数据和Markdown格式的正文指令主体。frontmatter里的description字段尤其关键它相当于这个技能在模型眼中的名片——模型就是靠它来判断什么时候该调用这个技能。scripts目录放的是可执行的代码文件。Python、JavaScript、Shell脚本都行。这些脚本的特点是它们能做的事情需要外部环境支持而模型本身无法直接完成。比如操作图片、调用命令行工具、解析复杂格式的文件。references目录放参考资料。这些资料不是每次都会被读取只有当SKILL.md正文指示如果需要更详细的信息请参考references/xx.md时模型才会去读取。这种分级加载设计进一步节省了上下文空间。assets目录放静态资源比如模板文件、样本数据、配置文件。我在实际使用中很少用到这个目录但在需要模型生成特定格式文件的场景下很实用。2.2 SKILL.md的frontmatter与正文如何协作frontmatter是YAML格式长这样--- name: image-compress description: 当用户需要批量压缩图片、调整图片尺寸或转换图片格式时使用此技能。支持常见格式JPEG、PNG、WebP的互转。 ---这里最重要的是description的写作质量。我踩过一个大坑第一次写Skills时我把description写得太宽泛——处理图片相关任务。结果模型在用户只是想了解图片格式区别时也触发了这个技能白白浪费了上下文加载。后来我改成了上面那种带具体操作场景的写法触发准确率明显提升。写description有一条经验描述用户会怎么说而不是技能能做什么。也就是说要站在模型接收到用户请求时的视角来写让模型能通过语义匹配判断这个请求和那个技能的描述是否对应。正文部分则是给模型的具体操作指引。这里我吃过不少亏后面第3章会详细展开。简单说正文要写成标准操作程序SOP的形式而不是开放式的建议。2.3 scripts、references、assets的边界职责刚开始写Skills的人容易犯一个错把什么逻辑都往SKILL.md里塞让模型自己看着办。这是不对的。正确的做法是凡是能用代码确定性完成的事情就写成脚本凡是需要模型判断和生成的事情才写在SKILL.md正文里。举个例子。我做图片压缩技能时缩放算法、质量参数这些确定性逻辑全部放在Python脚本里脚本接收输入输出路径返回结果。而SKILL.md正文只负责告诉模型什么时候运行脚本、脚本参数怎么填、脚本输出结果如何呈现给用户。这样分工的理由很简单脚本的结果是确定的、可复现的而模型每一步操作都有概率性。能用代码兜底的不要用模型自由发挥这是Skill设计的第一原则。3. 手写图片压缩Skill从设计到跑通的全过程3.1 为什么选图片压缩作为第一个Skill如果你也想上手写Skill我强烈建议从图片压缩练手。原因有三图片处理逻辑清晰不涉及复杂的状态管理适合用来理解脚本指令的分工模式。模型本身无法直接操作图片文件至少不擅长必须依赖脚本这样能逼着你把模型该干什么、脚本该干什么想清楚。结果可视化压缩前后的文件大小对比一目了然方便验证技能是否真正生效。3.2 完整实现SKILL.md怎么写给模型看先看我的SKILL.md正文核心部分# 图片压缩与格式转换技能 当用户提供图片路径或包含图片的目录路径时按以下步骤操作 1. 确认输入路径是否存在以及图片格式是否受支持JPEG、PNG、WebP。 2. 运行 python3 scripts/compress.py参数如下 - --input输入图片或目录路径必填 - --output输出目录必填 - --qualityJPEG/WebP压缩质量默认85取值范围1-100 - --max-width可选限制图片最大宽度超过则等比缩放 3. 脚本执行完毕后读取脚本输出的JSON结果。 4. 将结果整理成易读的文字反馈给用户说明压缩前后的大小、节省比例、输出位置。注意这里的写法每一步都是明确的指令模型不需要猜测下一步干什么。特别是第4步我明确要求模型读取JSON结构化的输出结果而不是让模型自己看着脚本输出随便发挥。为什么JSON输出这么重要模型读文本的能力虽然强但面对格式混乱的日志输出仍然可能解析错误。而JSON结构清晰、层级固定模型只需要按字段取值出错概率大幅降低。这是一条我在实际开发中总结出来的关键经验——Skill配套脚本的输出应当优先考虑机器可解析性而不是人可读性。3.3 配套脚本结构化输出比能跑更重要脚本我用了Python Pillow库核心逻辑并不复杂但输出格式花了不少心思#!/usr/bin/env python3 批量图片压缩脚本输出JSON结果。 import argparse import json import os import sys from pathlib import Path from PIL import Image def compress_image(input_path: Path, output_path: Path, quality: int, max_width: int 0): 压缩单张图片返回压缩结果信息。 original_size input_path.stat().st_size original_format input_path.suffix.lower() with Image.open(input_path) as img: if max_width and img.width max_width: ratio max_width / img.width new_size (max_width, int(img.height * ratio)) img img.resize(new_size, Image.LANCZOS) output_format JPEG if output_path.suffix.lower() in (.jpg, .jpeg) else ( WEBP if output_path.suffix.lower() .webp else PNG ) if output_format JPEG and img.mode in (RGBA, P, LA): img img.convert(RGB) img.save(output_path, formatoutput_format, qualityquality, optimizeTrue) compressed_size output_path.stat().st_size return { file: input_path.name, original_size_kb: round(original_size / 1024, 2), compressed_size_kb: round(compressed_size / 1024, 2), saved_percent: round((1 - compressed_size / original_size) * 100, 1) if original_size else 0, } def main(): parser argparse.ArgumentParser(description批量图片压缩脚本) parser.add_argument(--input, requiredTrue, help输入图片或目录路径) parser.add_argument(--output, requiredTrue, help输出目录路径) parser.add_argument(--quality, typeint, default85, help压缩质量1-100) parser.add_argument(--max-width, typeint, default0, help最大宽度限制) args parser.parse_args() input_path Path(args.input) output_path Path(args.output) if not input_path.exists(): print(json.dumps({error: f输入路径不存在: {input_path}}, ensure_asciiFalse)) sys.exit(1) output_path.mkdir(parentsTrue, exist_okTrue) if input_path.is_file(): images [input_path] else: images list(input_path.rglob(*.jpg)) list(input_path.rglob(*.jpeg)) \ list(input_path.rglob(*.png)) list(input_path.rglob(*.webp)) if not images: print(json.dumps({error: 未找到受支持的图片文件}, ensure_asciiFalse)) sys.exit(1) results [] for img_path in images: try: out_file output_path / f{img_path.stem}_compressed{img_path.suffix.lower()} result compress_image(img_path, out_file, args.quality, args.max_width) results.append(result) except Exception as exc: results.append({file: img_path.name, error: str(exc)}) summary { total: len(results), success: sum(1 for r in results if error not in r), failed: sum(1 for r in results if error in r), results: results, } print(json.dumps(summary, ensure_asciiFalse, indent2)) if __name__ __main__: main()脚本里有一个我特别想强调的细节对RGBA、P模式的图片在输出JPEG格式时先转成RGB。这是我执行第一次实测时发现的问题——Pillow直接保存RGBA图为JPEG会报错这个错误信息只有脚本运行时才会冒出来。做Skill时脚本的稳健性直接影响模型的执行成功率因为模型遇到脚本报错时虽然可以尝试修复但每次修复都意味着额外的上下文消耗和潜在的思维发散。3.4 实测验证与调试过程把文件按目录结构放好后我在Claude Code里做了一次完整测试。测试场景是把一个包含二十多张PNG截图的目录压缩成WebP格式质量设80最大宽度限制到1280。整个调用过程分三个阶段第一阶段模型读取SKILL.md的frontmatter判断当前用户的请求把图片压一下和这个技能的description匹配于是加载了SKILL.md正文。第二阶段模型根据正文指示构造出运行命令python3 scripts/compress.py --input screenshots/ --output screenshots_webp/ --quality 80 --max-width 1280第三阶段脚本执行完成后输出了一大段JSON模型读取结果把关键数据——压缩前后大小、节省比例、输出目录——整理成用户友好的文字反馈。这次测试中暴露的第一个问题是模型执行前会先检查输入路径是否存在这本身是好事但它花了额外的步骤验证环境。后来我在SKILL.md正文里加了一句除非用户明确要求否则不要在执行前进行额外的路径探查直接运行脚本由脚本自行校验省掉了不少无用操作。第二个问题是输出格式的稳定。在我最早的版本里脚本输出的是纯文本日志结果有一次模型把日志里的中间数据当成了最终结果反馈给用户时数字明显不对。改成JSON输出后这类问题再也没有出现过。4. 真实项目里的效率对比与选型经验4.1 同样任务纯提示词 vs Skill的差别我做了一个对照实验来量化用Skill和用一段长提示词在同样任务上的差异。任务很简单每次对话时用户上传一个日志文件模型需要按固定规则提取关键信息、生成结构化摘要并输出为指定的JSON格式。对照组用的是传统做法——在系统提示词里塞入完整的分析规则、输出模板、字段说明大约五百行。实验组建了一个包含该逻辑的Skill包SKILL.md正文里写处理流程references里放字段说明文档脚本负责解析日志。实测结果非常明显对比维度纯提示词方案Skill方案每轮任务消耗token约4200约1800输出格式稳定性偶尔缺字段稳定规则更新维护成本改动一次全量影响只改对应文件新增任务扩展方式追加到原提示词新建独立Skilltoken消耗差距这么大的原因在于纯提示词方案每轮对话都要把五百行规则全部过一遍而Skill方案只在任务被触发时加载一次流程指引字段说明文档这种细节型知识更是按需读取。实测下来运行效率大概提升了一倍多。4.2 什么时候该用MCP什么时候该用Skill这个选型问题我在多个项目里反复琢磨过目前的判断依据是知识的稳定性和动作的交互性两个维度动作需要实时查询外部状态——比如查询数据库、调用未公开的API、读写远端文件——用MCP。因为这些场景需要真实的网络IO和权限管理Skill脚本虽然也能做到但MCP在连接管理、鉴权、生命周期上更成熟。任务是确定性的内部流程——比如按模板生成报告、对本地文件做批量处理、对文本做标准化清洗——用Skill。因为这些逻辑稳定不变把它沉淀为技能包后成本极低。需要两者结合的场景也存在。比如我的一个数据处理项目里模型先通过MCP读取数据库再加载一个数据清洗Skill来按既定规则清洗然后再通过MCP写回。MCP负责手Skill负责脑。我个人对Skill和MCP的使用原则是能够用本地确定性脚本解决的问题优先用Skill涉及外部系统实时交互的才引入MCP。4.3 实际踩过的坑触发词过宽、上下文浪费、指令冲突踩坑一description写太宽导致误触发。一次我写了一个代码审查Skilldescription写的是用于代码质量检查。结果用户在讨论架构设计时模型也触发了这个技能白白读了一遍SKILL.md。后来我把description改成了当用户要求对已有代码进行审查、找出bug或安全隐患时使用并且加了不要在日常编码讨论中主动使用的排除说明误触发问题基本消失。踩坑二技能内部指令与主指令冲突。项目里有一套全局的代码风格规范但某个Skill内部也写了一套相反的命名规范结果模型执行时犹豫不决导致输出不一致。解决方式是Skill里的SKILL.md开头明确加了一行本技能遵循项目全局指令中的编码规范约定仅对xx流程做补充说明。踩坑三Skill被加载进上下文但它所引用的reference文件路径写错模型读了半天读不出内容最后只能硬着头皮凭经验完成任务。这个教训让我养成了一个习惯Skill上线前必须用包含路径引用操作的完整场景测试一遍。5. 把Skills变成团队资产编排、复用与维护5.1 私有技能库的组织方式Skills实践多了之后我意识到了一个更深的价值它是一个团队级别的知识沉淀单元。以前团队里的经验文档比如售后日志分析SOP周报自动生成规范都存在wiki里人需要主动去查。而Skill包的好处是模型在对应场景出现时会主动加载这个SOP并执行。团队协作时我建议用一个独立的仓库来管理技能包按场景分目录team-skills/ ├── analysis/ │ ├── log-triage/ │ ├── root-cause/ │ └── trend-report/ ├── content/ │ ├── weekly-digest/ │ └── meeting-minutes/ └── images/ └── compress-convert/每个技能一个目录独立版本管理。团队成员提交新技能时走merge request流程至少另一个人review。这种做法把写提示词变成了写代码质量可控性完全不同。5.2 多技能协作的编排思路单个技能解决单点问题但真实项目往往需要多个技能配合。我的经验是不要试图在一个Skill里塞进所有步骤而是拆成多个单一职责的Skill通过SKILL.md里的交叉引用实现编排。举个例子。我的网站更新流程分三个Skill内容清洗Skill、图片压缩Skill、发布检查Skill。当用户说把这篇文章发到网站上模型会依次加载三个Skill每个Skill只负责一个环节环节之间通过脚本文本传递中间产物不需要在上下文里互相直接调用。这样每个Skill可以独立测试、独立改进互不牵连。我在组织脚本时也会特意让脚本之间通过约定好的中间目录传递数据这和微服务架构中通过接口通信的思路是一致的。5.3 维护节奏什么样的Skill值得长期保留最后谈谈维护。我目前的经验是定期review两个指标触发频率如果一个Skill上线两个月都没被触发可能不是用户没用到而是它的description写得不够贴合实际请求方式。这时我会重写description而不是直接删除。如果重写后仍然长期不触发说明这个能力本身就不该独立成一个Skill删除或合并掉。输出稳定性如果一个Skill经常输出不满意的结果优先检查SKILL.md正文是否给了足够明确的步骤而不是急着加脚本。很多时候模型出问题是因为指令太模糊给了它自由发挥的空间。写完这些回过头来看Skills最大的价值不在于省token或者提升准确性这些技术指标而在于它改变了我们组织AI协作的方式——从每一次都要重新交代上下文变成了把方法论固化成可版本管理、可分享、可演化的文件。我个人的建议是如果你已经在用AI模型处理重复性任务第1~2个Skill可以从最常见的日常工作流开始做比如日志分析、报告生成、批量文件处理。做完一个完整的流程再回头看其他任务你会清楚地看到哪些工作应该交给模型判断、哪些应该沉淀为确定性脚本。这比任何教程都更能帮助你真正理解这套机制的用意。
阅读完成 · 觉得有帮助?
咨询建站