最近我把散落在各个提示词文件里的“套路”抽出来,单独整理成了一个项目,名字就叫skills。简单说,这就是一组给 AI 代理用的可复用能力包:每个能力一个目录,目录里有说明文件、脚本、示例,代理在运行时会根据用户需求自动加载对应技能。
做这件事的起因很朴素:我发现自己写的系统提示词越来越长,什么都往里塞,最后模型反而不知道优先执行哪条规则。而把能力拆成skills之后,每个技能独立维护、独立测试、按需触发,代理的“专业度”一下子清晰了很多。如果你也在折腾智能体、自动化脚本、或者想让自己反复调用的 AI 工作流变得更规范,这篇文章应该能帮上忙。我会把这个项目的设计思路、目录结构、技能文件怎么写、路由匹配怎么调,以及我实际踩过的坑都摊开讲一遍。
为什么叫skills:这个项目到底解决什么问题
很多人第一反应是:skills不就是提示词吗?把提示词写长一点、写详细一点不就有了?确实,早期我也是这么干的。但当你需要让代理处理十几种不同任务时,问题马上就来了。
系统提示词的长度有限制,就算没有硬性限制,模型对超长上下文的注意力也会被稀释。你把“计算文件里有多少行”这种指令跟在“按周报格式输出”后面,模型在处理周报时大概率会忽略掉前者。更麻烦的是,改一处逻辑就要重新生成整个提示词,版本管理完全失效。skills的思路是把一个完整能力封装成独立文件夹,比如:
skills/ bash-exec/ SKILL.md web-search/ SKILL.md json-transform/ SKILL.md每个技能内部自带“什么时候用、怎么用、有哪些注意事项”,代理在任务开始时先去技能库里检索一遍,命中哪个技能就加载哪个技能的内容。这相当于把大而全的“人格设定”改成了小而精的“工具手册”,每次只把当前任务真正需要的手册塞进上下文,信息密度和准确率反而都上来了。
从信息加载效率上讲,这也更贴合大模型的工作方式。代理好比一个厨师,系统提示词是你贴在厨房墙上的总规则,skills则是你放在手边的独立菜谱。做菜的时候只看当前这道菜的菜谱,显然比翻完一整本菜谱再动手更不容易出错。
所以skills项目的核心目标就三个:能力可复用、上下文可裁剪、版本可追溯。这三个点相互影响,也让这个项目对使用场景非常聚焦——它不是通用的提示词集合,而是专门服务于需要“按需加载能力”的代理场景。
目录结构与设计思路:先搭好骨架再填内容
初始目录怎么规划
我不会一上来就建二十个技能目录,那样根本维护不过来。比较实际的做法是从 3 到 5 个你每天都在用的动作开始,比如执行代码、搜索网页、解析 JSON、读取文件。骨架搭起来之后,后续加技能就是往skills/下面再丢一个文件夹的事情。
一个比较稳的初始结构长这样:
skills/ _shared/ common_utils.py bash-exec/ SKILL.md scripts/ safe_exec.py examples/ count_lines.md web-search/ SKILL.md json-transform/ SKILL.md templates/ output_schema.json_shared目录放多个技能共用的代码片段,避免每个技能都复制一份逻辑。bash-exec和json-transform是两种典型技能:前者偏执行类,核心是安全边界;后者偏处理类,核心是输入输出结构。examples目录也很关键,我后面会讲到它为什么能直接提升模型命中率。
为什么用 SKILL.md 而不是 prompt.txt
如果你只是临时用一下,叫prompt.txt没问题。但一旦进入项目化管理,SKILL.md这种结构化的命名能带来两个实际好处:一是文件头可以写 YAML 元信息,二是整个技能库能被工具自动索引。
一个标准SKILL.md的头部长这样:
--- name: json_transform description: 将任意 JSON 数据转换成指定结构。当用户要求“改字段名”“重新组织 JSON”“按模板输出数据”时使用。 version: 1.2.0 allowed_tools: [python3] ---这些字段不是摆设。name是技能的唯一标识,description是路由匹配的核心依据,version用来追踪更新,allowed_tools声明技能运行时允许调用的外部工具。模型在挑选技能时,实际看到的主要就是这段description和后续的正文字。也就是说,SKILL.md本质上是一份“带结构化索引的操作手册”,模型能快速识别该不该用、怎么用,这比一段光秃秃的提示词可靠得多。
命名规范和依赖隔离
命名是我比较坚持的一点:技能目录统一用小写字母加连字符,比如bash-exec而不是BashExec。原因不是美观,而是路径匹配和检索的时候,小写连字符风格更不容易出现歧义。另外,每个技能目录内部的资源路径,建议用相对路径写死在技能里。如果你在某一段指令里写“读取 /home/user/ 下的数据”,换台机器就废了。
依赖隔离同样重要。我一开始做过一个含金融计算和文本摘要的“全能”技能,后来发现每次加载它,模型都倾向于把任务往金融方向靠。一个技能只做一件事,这句话听着简单,执行的时候最难。如果你真的需要组合能力,正确做法是在代理的编排层去调用两个不同技能,而不是把两个技能揉成一个。
核心实操:编写一个可复用的技能文件
什么样的能力才值得沉淀成技能
不是所有事情都值得建一个技能。判断标准我总结成三条:频率够不够高、逻辑够不够稳、边界够不够清。
频率很好理解,你三天两头让代理做的事,值得固化下来。逻辑够稳的意思是这事的结果有明确判定标准,比如“统计日志里的错误数量”就很稳,“帮我想想这个方案好不好”就不适合做成技能。边界清晰则意味着输入输出能说清楚,它接收什么、返回什么、在什么条件下中止,如果在写技能时需要大量“如果用户那样说就怎么处理”这种分支,说明这个能力的边界还没收敛明白。
一个可以直接抄的 SKILL.md 模板
拿我项目里最常用的bash-exec做例子,它的SKILL.md核心部分是这样写的:
--- name: bash_exec description: 在受控环境中执行 Bash 命令,适用于文件统计、文本替换、批量重命名、日志筛选等操作。当用户要求“跑一下命令”“统计文件”“替换文本”“查看目录结构”时使用。 version: 1.3.0 allowed_tools: [bash, python3] --- # 执行 Bash 命令 ## 适用场景 - 用户需要查看文件、统计行数、批量操作文件 - 用户的脚本逻辑简单,不需要完整开发环境 ## 执行规则 1. 先检查命令是否在 allowed_tools 列表中,不在则拒绝执行。 2. 执行前用 `pwd` 确认当前工作目录,防止路径错误。 3. 任何写操作(删除、覆盖、重命名)必须先输出将要执行命令的内容,让用户确认。 4. 命令输出超过 200 行时,只返回前 100 行和最后 20 行,并提示用户“结果过长,已截断”。 ## 安全边界 - 禁止执行 `rm -rf`、`mkfs` 等高风险命令。 - 禁止使用 `sudo` 提权。 - 如果当前用户权限不足,直接报错并说明,不尝试绕过。 ## 示例 用户问题:“帮我统计当前目录下所有 .log 文件的行数” 代理执行: 1. 运行 `wc -l *.log` 2. 按文件名排序后返回统计列表 3. 若某文件行数异常,主动提示用户检查你可能会注意到,这份文档里大量使用“必须”“禁止”“如果则”这种条件句。这正是为了让模型照着做不会出现二义性。写自然人看的说明可以模糊,写模型执行的指令一定要精确——把动作拆到位,把边界划清楚。
为什么 examples 目录能显著提升命中率
我发现只写规则还不够,模型对抽象规则的遵循能力有限,但它对“模仿示例”的泛化能力很强。所以在examples/目录里放几组“问题 → 执行过程 → 最终结果”的案例,效果立竿见影。举个例子,我在json-transform技能里放了一个“把嵌套对象拍平”的案例,之后模型遇到类似需求时,几乎不需要额外引导就会自动调用这个技能。
写示例时有个技巧:不要只放“标准答案”,还要放一两组“边界案例”,比如字段缺失时怎么处理、空数组怎么处理。模型从这些边界案例里学会的容错策略,比你在正文里写十句“注意空值”更有效。
路由匹配与加载机制:技能不是越多越好
description 怎么写才容易被命中
技能选不选得对,一半看调用框架的检索能力,另一半看你的description写得好不好。我第一次写的描述是“用于执行 Bash 命令”,结果碰到“帮我看看这个目录里面有什么”这种问法,技能根本不会被触发。后来改成“执行命令、查看文件、统计信息、批量处理”加一句“当用户提到文件、目录、命令行时使用”,命中率立刻就上去了。
这里有个基本规律:描述词要覆盖用户可能的自然表达,而不是覆盖技能内部的实现逻辑。用户在意的不是“你用 Python 还是 Bash”,而是“你能不能帮我数一下文件”。所以在description里多放用户常用动词和名词,少放技术内部细节。你甚至可以把自己过去一周和代理的真实对话翻出来,把出现频率高的句式做成描述词,这比拍脑袋写有效得多。
上下文裁剪与加载粒度
技能文件不是越长越好。SKILL.md加上示例和脚本说明,我一般控制在 400 到 600 行以内。如果超过这个量,先问自己一个问题:到底是要一个技能,还是要拆成两个?比如“网页搜索”和“网页内容解析”,看着像一回事,实际使用场景差别很大,拆开之后加载负担小,描述也更精准。
加载粒度上我推荐“懒加载”:只有在任务匹配到技能描述时才把整个技能内容写入上下文,不匹配就完全不载入。这套逻辑在任何支持工具调用的代理框架里都能实现。代价是每次任务前需要先做一轮技能检索,多一次小请求;收益是主任务的上下文空间被大幅释放出来。实测下来对于长文本处理类任务,这个交换很划算。
多技能冲突时的优先级
当用户的问题同时命中两个技能描述,框架通常会把两个技能都交给模型,让模型自行选择或者组合。这时候技能描述的“排他性”就很重要了。我不会写“可以读取文件”,因为几乎所有技能都涉及读文件;而是写“专门处理文件内容解析”。用“专门”“主要用于”“优先处理”这类词做限定,能减少同时命中的概率。如果你发现两个技能频繁被同时触发,多半是它们的职责边界真的重合了,这时候应该回去改技能,而不是改描述。
参数、安全与调试:我踩过的几个深坑
参数写死,技能换台机器就废
这个问题我在多个项目里遇到。最开始的bash-exec技能里直接写了cd /Users/me/work,结果换到另一台电脑执行,路径不存在,所有命令直接失败。后来我把所有环境相关变量提出来,统一放在技能顶部的parameters段,并标注“运行前由用户或配置环境补充”。这样做的好处是技能文件本身保持通用,换环境只需要改配置,不需要改逻辑。
给出命令选择权而不是直接执行
代理在执行系统命令时一旦出错,轻则文件被误删,重则弄乱环境。我的做法是:默认所有写操作都要先输出“将要执行的内容”并要求确认。这个策略一开始很多人觉得麻烦,但实际跑起来后发现影响并不大,因为大量代理任务其实是读操作,只有少数写操作需要多一步确认。真正救了命的场景是,代理有一次生成了一个rm -rf build/的命令,因为路径拼接错误,差点把src/目录也匹配进去。如果没有确认步骤,那次就真凉了。
调试技能时最需要看的东西
技能不生效时,很多人的第一反应是“再改一改提示词”,但我建议先打开调用日志,重点看两个地方:一是这次任务到底加载了哪个技能,二是没有加载任何技能时模型怎么回答的。只要确认了“该技能没被命中”,问题基本就能锁定在description和路由匹配上;如果技能已经被加载但输出还是不对,那要改的是正文规则。这两类问题的解决路径完全不同,用日志定位能省下大量试错时间。
防止上下文被无关输出撑爆
代理执行技能时,会把过程中的所有输出都带回家。你明明只想要一个统计结果,它却把整个文件夹列表返回了,白白占了几千 token。我在技能里加了一条明确规则:输出必须精简,只返回结论和必要的数据摘要。此外给命令输出长度加硬性上限,超过部分自动截断。这一段听着琐碎,但对上下文窗口的管理其实是成本最直接的优化。
常见问题排查:一张表解决大半烦恼
我把实践中反复遇到的问题整理成了一个速查表,遇到异常时可以照着查一遍:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 技能完全没有触发 | description里的关键词和用户表述不匹配 | 收集真实提问,重写description,扩充同义词 |
| 技能被触发但执行结果错误 | 技能正文缺少明确步骤 | 把执行流程改成编号步骤,并加入边界示例 |
| 同一个问题同时命中多个技能 | 技能职责边界重合 | 合并技能,或在描述中增加排除性限定词 |
| 在 A 机器正常,在 B 机器报错 | 路径、环境变量写死 | 环境相关参数全部参数化,运行前动态补充 |
| 模型频繁返回不相关内容 | 技能加载过多撑爆上下文 | 减少同时加载技能数量,修正路由逻辑 |
| 命令执行权限错误 | 技能声明的allowed_tools与实际不符 | 检查当前环境,调整工具声明或运行权限 |
| 输出结果被截断仍不完整 | 技能没限制单次输出长度 | 在技能里加输出长度上限和摘要策略 |
这里想特别提一下“技能被触发但执行结果错误”这类情况。绝大多数模型失误并不是它不理解任务,而是你给的流程不够“机械”。你在技能里写“分析数据并总结”,模型就可能真的只给一段总结;但你写“先查看数据前 5 行 → 判断类型 → 计算关键指标 → 输出为 Markdown 表格”,模型大概率就能按步骤走完。对模型来说,步骤越具体,自由度越低,出错率也越低。
沿着这个项目继续往下走
skills项目做到现在,我觉得它已经不仅仅是“一堆提示词”了,更像是一个不断迭代的个人能力库。每当代理在某类任务上表现不稳定,我就回去看对应技能的SKILL.md,要么是边界没写清楚,要么是缺了合适的示例。技能多了之后,我还会定期做一次“技能体检”,把三个月没被触发过的技能翻出来,看是合并、删除,还是重写描述词。
另外我逐渐加了一些辅助脚本:一个用于在启动代理时自动扫描skills目录、生成技能索引;一个用于对每个技能做基础校验,比如检查name字段和目录名是否一致、description是否为空、是否有重复技能名。这些自动化工具虽然简单,却让整个仓库从“手工作坊”变成了“半自动生产线”。如果你也在维护自己的技能库,建议你也尽早把校验类脚本加上,越早积累越省心。
最后再分享一个小体会:技能库的质量比数量重要得多。五个精雕细琢的技能,产生的工作流效果往往好过五十个写两句话就丢进去的半成品。别急着追求覆盖所有场景,把一个高频技能打磨到“加载后不用再补提示词”的程度,你就已经跑赢大多数人了。