
最近折腾Agent技能包skills的人越来越多了无论是Claude生态还是Codex生态你都会发现同一个趋势——大模型本身的“聪明程度”已经不是瓶颈怎么让它稳定地执行一套标准流程、调用正确的工具、输出符合预期的结果才是真正拉开体验差距的地方。Skills就是用来解决这个问题的把一段可复用的能力打包成标准化的技能文件让Agent在需要的时候自动加载、按步骤执行。这篇文章我打算从第一性原理出发把skills的底层逻辑、开发方法、安装生态和实战经验一次讲透给正在研究Agent开发、想让自己的AI工作流更稳定的朋友一份可以直接落地的参考。1. 先说清楚skills到底是什么1.1 你其实每天都在用“伪skills”很多人在接触skills之前其实已经在用类似的思路了——比如在系统提示词里塞一大段“你是一个擅长XXX的助手”或者在每个任务开始时把一段长长的背景说明粘贴给模型。这些都是“伪skills”它们看起来能让模型表现得专业一点但本质上只是临时性的指令注入没有办法被复用、不能被检索、也不会被模型主动“意识到自己需要调用”。真正的Agent skills是一套结构化的、可持久化的能力封装。它的核心不是“告诉模型怎么做”而是“给模型一套可以按需调用的标准化操作手册”。模型在拿到任务时会先理解任务内容然后从自己的技能库里判断这个任务是否匹配某个技能匹配的话就加载这个技能对应的说明文件和脚本按照里面的步骤去执行。我用一个生活化的类比来解释把模型想象成一个新入职的工程师他脑子很聪明、学习能力很强但他不知道你们公司的代码规范、不知道部署流程、不知道线上出现问题该找谁。Skills就是把“新人入职手册”写成标准文档放到他桌上他遇到对应场景时会自己去翻手册而不是每天都靠你口头嘱咐一遍。这里的关键差异在于“主动检索”和“被动等待”。伪skills是模型被动接收的上下文skills是模型主动调用的工具集。这个差异在实际体验中非常明显伪skills在对话长度增加后会被逐渐遗忘skills则不会因为模型每次执行前都会重新读取技能文件。1.2 一个skill组件的真实构成从实现层面看一个标准的Agent skill由三大部分组成描述文件通常是SKILL.md、可执行脚本Python/Shell/JavaScript等、以及辅助资源模板、配置文件、数据文件等。描述文件是整个技能的“门面”它决定了模型什么时候会调用这个技能。我见过太多人写不好这个文件导致技能明明写得很完善Agent却从来不触发。描述文件里最重要的是frontmatter区的name和description字段description尤其关键它需要精准描述“这个技能在什么场景下使用”而不是简单写一句“用于处理图片”这种模糊描述。我在实战中发现description的措辞会直接影响触发率写得越具体、越带场景化触发越稳定。脚本部分则是技能的执行体。模型读取描述文件后会按照里面的指引生成调用脚本的命令然后通过Agent的沙箱环境执行脚本把结果反馈给它。这个过程对模型的推理能力要求并不高真正考验的是脚本本身的健壮性——脚本需要处理好参数校验、异常捕获、输出格式统一这些基础问题否则Agent再聪明也会被不靠谱的脚本拖垮。辅助资源往往是被忽视的一环。一个写好的技能最好能把模板文件、参考样例、依赖清单都放到技能目录下让模型在需要时可以自行查看。这样一来技能就从一个“会执行动作的工具”升级成了“自带知识库的完整工作流”在复杂任务中的表现会好非常多。2. 动手开发一个自己的skill2.1 目录结构与SKILL.md的标准写法先给大家一个最基础、最标准的目录结构我建议所有技能都从这个骨架开始my-skill/ ├── SKILL.md ├── scripts/ │ ├── compress.py │ └── requirements.txt └── assets/ └── template.mdSKILL.md是模型的入口文件它的frontmatter格式在不同平台上略有区别但基本都遵循YAML规范。以我目前用的方案为例下面是SKILL.md的完整示例--- name: image-compress description: 批量压缩指定目录下的图片适用于需要优化网页资源体积、减小图片大小、提升加载速度的场景。不建议用于需要保留100%无损质量的图片处理场景。 --- # 图片批量压缩 ## 何时使用 当用户提供图片目录路径并表达压缩、优化、减小体积等意图时使用。 ## 执行步骤 1. 确认目录存在且包含支持的图片格式jpg/jpeg/png/webp 2. 检查scripts目录下脚本的运行环境必要时先安装依赖pip install -r requirements.txt 3. 执行命令python scripts/compress.py --input-dir [目录路径] --quality 80 4. 将压缩前后的文件大小对比反馈给用户 ## 注意事项 - 压缩png时建议保留原图备份 - 输出格式统一使用表格不要用markdown外的其他格式这里有几个写作要点非常关键。description不能使用否定式描述空泛带过要给出正向触发条件和反向不适用场景帮助模型快速判断。正文部分的结构要清晰让模型看到“何时使用”四个字就能建立条件反射式的触发逻辑。执行步骤要写成“直接可执行的指令”而不是“应该做什么”的意图描述不要出现“分析一下”这种模糊动词。我实际写了几十个skill之后发现SKILL.md的篇幅也需要控制。太短会让模型缺少上下文太长则会消耗大量token、影响模型对关键信息的提取。根据我自己的体感大部分成功的SKILL.md在500到1000字之间核心指令尽早在前面出现细节尽量放后面。2.2 推理与执行的分离原则这是skill开发里最重要、也最反直觉的一条原则描述文件管推理脚本管执行两者不要混在一起。很多新手写skill时喜欢把所有逻辑都塞进SKILL.md让模型“根据规则自己想怎么做”这其实走回了伪skills的老路。Skills设计的本意是人类把确定性逻辑写进脚本模型只负责判断“要不要用”和“怎么调”。这么做有非常实际的好处。第一确定性逻辑交给脚本后执行效率高、错误率低不会因为模型幻觉导致步骤错乱。第二脚本可以用Python的完整生态处理文件、调用API、解析数据这些能力模型在沙箱里很难稳定复现。第三调试方便——脚本出问题可以直接跑脚本看报错不用再审一遍对话记录。我开发时遵循一个简单法则凡是能用代码实现的内容绝不让模型“思考”完成。比如“批量压缩图片”这件事模型不需要知道Pillow库内部怎么处理像素它只需要知道运行哪个脚本、传什么参数、输出什么格式。脚本代码是确定性的模型只要按说明调用结果就可预期。有一点需要提醒脚本参数的设计要尽量简单直观不要设计太多难以理解的flag。模型生成的命令不一定完全按你预期来参数越少越不容易出错。我在设计脚本时一般只保留两到三个必要参数全用--param value格式并在SKILL.md里给一两个默认值示例模型照抄就能跑通。2.3 写一个可用的命令行脚本上面示例里的compress.py我贴一个具体可跑的实现#!/usr/bin/env python3 批量压缩图片脚本支持jpg/png/webp格式。 import argparse import os from pathlib import Path from PIL import Image SUPPORTED_FORMATS {.jpg, .jpeg, .png, .webp} def compress_image(input_path: Path, output_dir: Path, quality: int) - str: 压缩单张图片返回压缩后文件大小。 try: img Image.open(input_path) output_path output_dir / input_path.name if input_path.suffix.lower() in {.jpg, .jpeg}: img.save(output_path, qualityquality, optimizeTrue) elif input_path.suffix.lower() .png: img.save(output_path, optimizeTrue) else: img.save(output_path, qualityquality) original_size input_path.stat().st_size compressed_size output_path.stat().st_size return f{input_path.name}: {original_size} - {compressed_size} bytes except Exception as e: return f{input_path.name}: ERROR {e} def main(): parser argparse.ArgumentParser(description批量压缩图片) parser.add_argument(--input-dir, requiredTrue, help图片目录路径) parser.add_argument(--output-dir, defaultcompressed, help输出目录默认compressed) parser.add_argument(--quality, typeint, default80, help压缩质量默认80) args parser.parse_args() input_dir Path(args.input_dir) if not input_dir.is_dir(): print(f目录不存在: {input_dir}) return output_dir Path(args.output_dir) output_dir.mkdir(parentsTrue, exist_okTrue) results [] for file_path in sorted(input_dir.iterdir()): if file_path.suffix.lower() in SUPPORTED_FORMATS: results.append(compress_image(file_path, output_dir, args.quality)) for result in results: print(result) print(f处理完成共{len(results)}张图片) if __name__ __main__: main()这个脚本代码本身很简单强调几个容易被忽略的细节。第一输出信息一定要结构化、包含文件名和前后大小对比模型需要这些信息给用户做反馈。第二异常不能静默吞掉要用ERROR标记这样模型读取输出时能识别哪张图片出了问题。第三输出目录要自动创建减少模型额外操作的步骤。脚本写完后我会先直接在终端跑一遍确认输入输出都符合预期再放入skill目录。这一步非常必要——如果你自己手动调用都报错模型调用时只会更乱。3. 安装、分发与生态盘点3.1 官方市场与社区平台去哪儿找现阶段skills的安装方式主要有三大类手动复制目录、通过市场/平台安装、从代码仓库克隆。手动复制是最原始也最通用的方式适用于所有支持skills的Agent。以Claude生态为例个人级技能放在用户目录下的.claude/skills/项目级技能放在工程目录下的.claude/skills/。Codex CLI则对应.codex/skills/。直接把技能文件夹放进去重新启动会话就能生效。这种方式对单机用户很友好但没法解决多设备同步和版本管理的问题。市场与平台是更系统的分发方式。目前社区里已经出现了不少收集和分发skills的平台形式类似npm或者Hugging Face的模型库用户可以浏览、搜索、一键安装。我个人的经验是选平台时重点看三个指标更新频率、审核机制、评论质量。更新频率决定技能会不会跟着模型能力演进及时优化审核机制决定技能质量的下限评论质量则能帮你避开明显有坑的技能。代码仓库尤其是GitHub依然是最硬核的获取渠道。很多开发者会把自己的skills仓库开源仓库里包含多个技能目录、使用说明和版本历史。这种方式的好处是可以直接git clone下来还能通过PR跟踪别人的改进对想深入研究的开发者特别友好。3.2 Claude与Codex的差异点市面上主流的Agent对skills的支持并不完全一样我目前深度使用过的两个代表是Claude系和Codex。描述格式上总体一致都是SKILL.md加脚本的结构但细节有差异。Claude的skills更强调对长文档的处理SKILL.md里允许写较多的上下文和规范Codex的skills相对更轻量description往往起到决定性作用正文太多反而容易被忽略。触发机制也有区别。Claude Agent在执行任务时会把技能库中的description都读一遍做一个匹配判断之后再选择加载哪些技能文件。Codex CLI则采用更轻量的模式依赖模型在操作过程中的自主判断。这个差异导致了调参思路的不同在Claude生态里description像“目录索引”要让匹配算法容易命中在Codex生态里description像“广告文案”要让模型在开放式推理中更容易联想到。沙箱环境方面Claude提供了更完整的沙箱隔离机制脚本执行的资源控制较严格Codex则更像本地执行与系统环境的交互更直接写文件、跑命令都更自由。这带来一个实用建议涉及大量文件操作、需要调用系统本地方令的技能在Codex环境里更容易开发需要与外部API稳健交互的技能Claude的沙箱隔离能提供额外的安全层。对普通用户来说不用纠结选哪个生态建议以你日常使用的Agent为准技能结构两边共用只需调整描述文件和安装目录的细节就行。3.3 测试skill的完整流程测试一个skill我按照从浅到深的顺序走四个阶段能避免后期反复返工。第一步是静态检查。检查SKILL.md的frontmatter格式是否合法路径是否与脚本实际位置一致脚本依赖是否声明。这一步可以自动化我习惯写一个小脚本扫描目录看每个技能的frontmatter是否完整。第二步是单次调用测试。直接给Agent一个明确指令看它是否能触发技能、输出的中间信息是否正确、最终结果是否符合预期。注意观察Agent的“思考过程”——如果它没有读取SKILL.md而是用自己的理解乱操作那问题多半出在description需要重写。第三步是边界测试。把输入条件改到极致比如空目录、超大文件、损坏图片看脚本会不会崩、Agent会不会被误导。这一步非常考验脚本的健壮性我发现很多技能在正常路径下表现完美一到边界情况就原形毕露。第四步是回归测试。连续跑多个任务确认技能不会因为上下文积累而“忘了自己”也不会与另一个技能的功能重叠产生混乱。理论上每次Agent都需要重新读取技能文件状态是独立的但实际中我遇到过触发优先级冲突的情况——两个技能都对同一个任务“感兴趣”这时候就需要调整其中一个技能的description明确“不适用于”的场景。4. 实战中踩过的坑与避坑技巧4.1 触发不稳定的根源在描述文件如果你发现技能写好了、安装对了但模型就是不用它十有八九问题出在description上。我拆解过大量这种案例归纳出三个高频根源。第一个是description写得太抽象。光说“处理图片”四个字模型无法判断什么任务算“需要处理图片”它可能就默默忽略了你。正确写法是带上具体场景词比如“当用户要求压缩图片尺寸、优化页面加载速度、减小图片文件体积时使用”。第二个是description缺少反向条件。只告诉模型什么时候用不告诉它什么时候不用会导致过度触发。比如一个“图片压缩”技能用户只是想让图片变滤镜效果模型也可能误触发。在description里加一句“不要用于添加滤镜、修改颜色、裁剪等非压缩操作”触发准确率立刻提升。第三个是正文结构混乱。模型读取SKILL.md后需要在几秒内快速建立行动方案。如果正文一堆大段论述、步骤藏在一大段话里模型的提取效率会大幅下降。把正文改成“何时使用-执行步骤-注意事项”三段式是最稳妥的写法。我还发现一个细节部分Agent对SKILL.md的换行和缩进非常敏感。YAML里如果缩进不一致、列表符号混用解析时会静默失败。写完后把文件丢到一个YAML校验器里过一遍能节约很多排查时间。4.2 环境依赖和路径陷阱脚本运行时依赖和路径这两个问题出现的频率最高。依赖问题主要是“脚本里import的库在Agent沙箱里没装”。我就遇到过技能在本地跑得很顺、放进Agent环境后疯狂报ModuleNotFoundError。解决方案有两个一是SKILL.md里明确写清楚需要先执行pip install -r requirements.txt二是尽量只用标准库解决或者把依赖声明成必须的可选项。我目前更倾向标准库优先——Pillow虽然好用但原生标准库做不了图片处理那就把依赖声明写清楚让模型先装再跑。路径问题则更隐蔽。Agent沙箱的工作目录往往和你的本地目录不同如果你的脚本用相对路径可能在用户机器上就是另一套目录结构。最佳实践是所有路径相关参数必须通过命令行参数传入脚本内部一律用绝对路径形式处理SKILL.md里的示例命令也要写明“用用户提供的实际路径替换示例路径”避免模型死板照抄导致路径错误。另一个我经常踩的坑是权限问题。脚本写文件时如果Agent沙箱对某些目录只读就会出PermissionError。解决方法是输出目录统一放在用户指定的可写目录或者默认放/tmp之类Agent明确可写的位置并且脚本要提前mkdir并带上exist_okTrue避免目录冲突。4.3 什么时候不该用skill说了这么多最后聊聊skills的边界。并不是所有能力都适合封装成skill强行封装反而增加维护成本。低价值、一次性任务不值得。如果一个操作你三个月才做一次、每次场景变化都很大写成技能后的维护成本比临时提示词高得多。技能的真正价值来自“高频、稳定、可复用”的三重属性缺一都不划算。高度依赖实时判断的任务要慎重。比如客服对话、心理咨询这类需要深度理解语境的任务硬编码成固定步骤会显得僵硬反而拉低输出质量。模型的临场发挥能力应该在推理阶段体现而不是被脚本五花大绑。需要外部密钥或私有账号的能力要额外小心。技能脚本如果涉及API调用我不建议把密钥直接写在脚本里至少要用环境变量注入避免技能分发后密钥泄露。最后还有个体验层面的坑技能加载过多反而拖慢速度。每次任务开始时Agent都要过一遍技能描述来做匹配如果你的技能库里有几十个描述文件匹配判断的消耗会明显影响响应速度。定期清理不再使用的技能保持技能库精简长期看很有必要。我在日常使用中逐渐形成的习惯是技能库永远控制在10个以内每个都保持单一职责宁可多装一个轻量技能也不做一个臃肿的全能技能。这个原则帮我在Agent的响应速度和任务准确率之间找到了很好的平衡点也推荐你尝试。