从Prompt到Skill:构建可复用的AI技能包实战指南 1. 为什么“skills”突然成了技术圈的热词这几年做 AI 应用的人应该都有同感真正难的从来不是把模型跑起来而是让模型稳定地产出符合预期的东西。早期大家靠的是堆提示词一个复杂的任务恨不得写两千字的 prompt里面全是角色设定、输出格式、思考步骤、禁忌事项。用过几次之后就会发现这套方案维护成本极高——提示词稍微改一个词可能输出风格就全变了换个模型迭代版本原来的写法可能直接失效。我前段时间在一家公司做技术顾问团队把一堆精心调教过的 prompt 存成文档每次换人接手都要从头看一遍上下文才能理解当初为什么要那么写。更麻烦的是这些提示词和业务逻辑绑得太紧换个场景完全没法复用。当时我就意识到prompt 这种表达形态迟早要升级而最近 GitHub 上出现的一个叫 “skills” 的概念恰好就是这个升级方向里很有代表性的一种实践。简单说skills 的核心思路是把“能力”从“对话”里抽出来做成一个独立的、可复用的、结构化的模块。它不再是一段写在聊天框里的提示词而是一个有明确目录结构、有元信息、有可执行逻辑的技能包。你可以把它理解成给 AI 助手装上一个“插件”需要什么能力就把对应的 skill 加载进来用完也可以随时卸载。这个思路最早出现在一些开源的个人 AI 助手项目里后来随着 agent 类应用的流行越来越多人开始用 skill 的方式来组织模型的能力边界。这篇文章不会去讲某一家平台的具体操作手册因为我更想分享的是这套“技能化开发”的通用方法论一个 skill 应该长什么样、怎么设计它的目录和文件、写核心描述文件时有哪些坑、以及怎么测试和调试一个技能包。我自己在几个真实项目里折腾过完整的流程踩过不少坑下面把这些经验原原本本写出来。不管你是做个人 AI 助手、给团队搭知识库机器人还是做面向特定行业的 agent 应用这套思路应该都能直接用上。文章后面涉及代码的地方我用的是比较通用的目录和配置风格注释里会按需说明。个别字段名在不同项目里叫法不一样但核心逻辑是相通的你按自己实际使用的框架对照着看就行。2. 拆解一个 skill它的设计思路和结构逻辑2.1 从 prompt 到 skill到底解决了什么问题我们先回到最初的问题为什么 prompt 不够用了把一段 2000 字的提示词丢给模型它会忠实地按你的要求输出。但问题是这段提示词本身没有结构模型只能靠“理解”来执行而理解的稳定性是有限的。同一段话这个模型可能严格遵守那个模型可能选择性忽略某些部分。更麻烦的是当你有十个不同领域的任务时就得维护十份互相独立又可能互相干扰的提示词。skill 的思路是把传统 prompt 里的内容拆成两类一类是“描述能力”另一类是“执行逻辑”。描述能力部分告诉系统这个模块是干什么的、什么时候该用执行逻辑部分则是具体的工作流程、输出规范和知识参考。这两部分被装进一个固定的目录结构里每个 skill 可以有自己专属的资源文件、参考文档、脚本模板。这样一来模型不再需要从一大段混杂的文字里提取意图而是直接读取一个结构化的技能包按里面定义的流程去执行。我拿个生活化的例子解释prompt 就像你口头交代别人“帮我把这堆文件整理好先分类再编号还要做个目录”对方能不能做好全看听没听懂你的话skill 则像你递过去一本操作手册里面写了分类规则、编号格式、目录模板甚至附带了参考样例。后者显然要可靠得多。2.2 skill 的标准目录结构一切从 SKILL.md 开始我见过很多种不同的 skill 组织方式也见过一些项目试图发明自己的私有格式但到头来大家都收敛到了差不多的结构上。下面这套是当前开源社区里比较主流、也最容易理解的写法我建议新手直接按这个来my-skill/ ├── SKILL.md # 技能的核心描述文件相当于技能的名片和说明书 ├── scripts/ # 可执行脚本目录按需 │ └── run.py ├── references/ # 参考文档目录按需 │ ├── guide.md │ └── examples.md ├── assets/ # 静态资源目录按需图片、模板等 └── requirements.txt # 依赖清单按需先说最重要的SKILL.md。我见过一些项目里把它叫SKILL.md也有叫SKILLS.md或者skill.md的命名大小写不统一其实问题不大但如果你用的框架是识别固定文件名的那就必须按框架的要求来。这个文件是整个技能包的心脏它至少承担三件事一是声明这个技能是什么、什么时候该用二是说明什么时候不该用三是给出执行这个技能的具体步骤。一个典型的内容结构长这样--- name: write-blog-post description: 将零散的项目记录整理为结构化中文博客文章适合技术经验分享场景。 when_to_use: 对话中用户提供项目标题、零散笔记或关键词期望生成一篇完整博文时。 when_not_to_use: 用户提供的材料与博客写作无关或仅需要翻译而不需要结构化改写时。 version: 1.0.0 license: MIT --- # 技能概述 本技能定义了一套从零散项目资料到完整博文的转换流程包含信息拆解、章节组织、经验注入三个阶段。 ## 执行步骤 1. 读取用户提供的原材料识别核心主题和关键信息。 2. 按“理解-架构-创作-打磨”四个阶段构建文章骨架。 3. 每个章节需补充原理讲解、实操注释与避坑经验。 4. 输出最终 Markdown 格式正文不需要额外说明。 ## 注意事项 - 严禁在开头出现“根据您的要求”等模板化表述。 - 标题层级必须编号不能跳级。 - 每段正文不少于 150 字。你注意看SKILL.md里的内容其实比传统 prompt 更“结构化”。传统 prompt 是一大段叙事文字而这里用 YAML 格式的元信息 分级标题 列表把指令拆成了机器可读的字段。这就是 skill 的第一个核心价值让模型按字段去解析而不是靠语义去猜。2.3 为什么要有references和scripts知识库与执行力的边界很多人第一次接触 skill 的时候会问我把知识直接写在SKILL.md里不就完了吗为什么还要单独建一个references目录我的答案是SKILL.md适合放“逻辑”references适适合放“知识”。举个例子如果你做一个法律咨询的 skillSKILL.md里应该写的是“如何分析一个法律问题”、“回答时应该包含哪些要素”、“不得作出确定性承诺”这样的流程性指令而具体的法条内容、典型案例、司法解释应该放在references目录下的文档里。为什么因为SKILL.md会被模型当作核心指令来处理它的优先级很高如果塞的东西太多模型容易把知识性内容和指令性内容混在一起导致该遵守的没遵守、该引用的没引用。分开之后模型可以按需去检索 reference 文件——需要引用法条的时候再去读而不是把几千个法条全部塞进上下文里。至于scripts目录它是更进一步的能力延伸。有些 skill 不只是让模型“写东西”还需要模型“做事情”比如查数据库、跑数据分析脚本、生成一个文件。模型本身不会执行代码但 skill 可以声明“这个技能依赖某个脚本”agent 框架在加载 skill 时会把这个脚本的调用方式暴露给模型。这样模型在那个技能场景下不只是输出文本而是能驱动真实工具完成任务能力边界一下子宽了很多。不过这里要提醒一句引入脚本不等于 skill 就变成了万能插件。我见过有人把特别复杂的业务逻辑塞进 scripts然后用自然语言让模型去调用结果模型根本不知道在什么条件下应该调用哪个脚本。skill 里的脚本要尽量简单、单一、指令清晰脚本和模型的分工是模型负责任务拆解和判断脚本负责具体动作的执行。2.4 name 和 description 的命名技巧决定技能能不能被正确触发现在如果你要开始写自己的第一个 skill我建议先别急着写SKILL.md的正文先从name和description这两个字段开始。它们看起来短实际上决定了这个技能能不能在正确的时候被调用。大多数 agent 框架是这么工作的用户发来一个请求框架先扫描所有已安装技能的description用相似度匹配的方式判断该激活哪个。如果你的 description 写得含糊模型可能该用的时候不用、不该用的时候乱用。命名和描述我总结了三个要点名称用动词短语直接表达动作意图。比如write-blog-post、review-code、analyze-data比blog-helper这种名词结构好得多因为机器理解动词短语更精准。description 里写清楚“何时该用”和“何时不用”。这是同类技能做区分的关键。两个技能都叫>my-skills/ └── note2blog/ ├── SKILL.md ├── references/ │ ├── structure-guide.md │ ├── style-rules.md │ └── examples.md └── assets/ └── skeleton-template.md你如果之前没接触过技能包的安装逻辑这里顺便解释下大多数框架会把my-skills这个目录作为技能根目录扫描里边的每一个子目录识别到包含SKILL.md的文件夹就把它当做一个可用的技能。所以你的技能根目录下可能有十几个子文件夹每个文件夹都是一个独立的技能包。3.2 编写 SKILL.md让模型能从文件里读出“操作手册”接下来写SKILL.md的核心内容。我把它拆成几个区块每个区块解决一个特定问题。第一个区块是 YAML 格式的元信息给系统做技能识别和触发用--- name: polish-notes-to-blog description: 将用户提供的零散笔记、项目标题、碎片关键词整合为结构清晰的中文技术博客文章适用于技术经验分享、项目复盘和知识沉淀场景。 when_to_use: 用户提供了项目标题或零散资料期望获得一篇完整、可直接发布的文章且内容与个人项目、技术实践相关。 when_not_to_use: 用户只是需要润色翻译已有完整文章或需要生成营销带货类文案时不应使用本技能。 version: 1.0.0 ---第二个区块是正文的“执行流程”这是模型真正会照着做的东西。写作风格的细节我放在 references 里这样SKILL.md本身保持简洁# 技能说明 本技能用于把零散、不完整的项目资料整理为结构完整的 Markdown 技术文章整体流程分三个阶段 ## 阶段一信息提取 - 从用户输入中识别核心主题、场景描述、关键词、目标读者。 - 如材料中缺乏细节结合相关领域的通用知识进行合理补全但必须保持主题不偏离。 ## 阶段二结构组织 - 按标准文章骨架排布章节开头引入、主体拆解、实操细节、经验总结。 - 相关章节需包含二级标题和三级标题层级编号必须连续。 - 开头不少于 200 字主体不少于 5000 字各段落不少于 150 字。 ## 阶段三输出与打磨 - 使用从业者口吻避免教科书式表达和归纳总结式套话。 - 在关键环节补充“为什么这样做”的原理分析与实操注意事项。 - 文章在核心主题内容处自然结束如确需收尾只用个人经验体会作结。 # 硬性约束 - 禁止在文章开头出现“根据您的要求”类表述。 - 禁止出现任何实际存在的公司、机构、人名或地名。 - 如涉及记叙实际经历一律使用虚构代称。你仔细看这段内容和传统 prompt 的区别。传统 prompt 写“你是一名资深博主”而这里没有这个角色设定。原因很微妙传统 prompt 靠角色来约束输出风格比如“资深博主”这个词在不同模型心里有不同的解释结果非常不稳定。skill 的做法是弱化角色的作用强化流程的作用——不告诉模型“你是谁”而是告诉模型“按什么步骤、什么规则做”。你的风格约束被拆成了硬性规则比如每段不少于 150 字、禁止出现真实机构名这些可比一个模糊的角色可靠得多。3.3 编写 references把知识性内容从指令里抽出来光有SKILL.md还不够你的模型可能知道怎么组织结构但不知道“一篇好的技术博文具体应该长什么样”。我把这些判断标准写进references/structure-guide.md# 技术博文结构参考 ## 推荐的章节组织逻辑 一个高质量的技术分享文章通常包含以下几个功能块 1. 引入段交代背景说明做的内容是什么、解决什么问题并点明读者对象。 2. 核心拆解把项目拆成若干设计决策说明每个决策的取舍理由。 3. 实操实现按步骤描述关键操作包含工具、参数、原因。 4. 问题与排查列出真实遇到的故障、解决路径整理成参考表格或清单。 ## 段内表达规则 - 每个段落至少包含一个“怎么做”和一个“为什么这么做”。 - 避免空泛的概括性表述如“这个功能很好很重要”之类没有信息量的话。 - 用生活化类比说明复杂概念比如把 skill 的加载比喻成安装浏览器插件。references/examples.md则是放一个完整的开头范例和一个小节范例让模型有一个具体的风格锚点。有人会觉得这类内容可以直接靠模型自己“脑补”但实测下来给一个具体范例比连续写十条规则都管用尤其对于控制表达风格这件事。模型可以从范例里学会什么叫“从业者口吻”、什么叫“AI 味”而不是被一些抽象的形容词搞得云里雾里。3.4 在 agent 配置中引入 skill加载与启用的完整链路目录和文件都准备齐了接下来要让这个技能真正被 AI 助手用起来。以某开源个人 AI 助手的配置为例它的配置文件里支持声明技能加载路径agent: name: my-writer skills: - path: ./my-skills/note2blog enabled: true启用的瞬间框架会把SKILL.md的内容注入到系统提示词的一部分同时把references目录下的文件注册为“可按需读取”。也就是说框架不会一次性把所有 reference 文档都塞进上下文而是给模型一个“文件列表”和“读取工具”让模型在执行任务的过程中自行决定什么时候去读哪个文件。这算是 skill 机制相对聪明的一点有效控制了上下文长度又保证了知识能按需加载。整个链路大致可以画成三步配置声明告诉框架“有这个技能存在”启动时框架读取SKILL.md注入模型执行中模型按需调用references和scripts。理解这条链路之后你就会明白skill 并不是一种全新的模型能力它只是改变了上下文组织的方式让模型在正确的时间看到正确的内容。4. 测试与调试技能开发里最容易被忽视的环节4.1 单技能测试最小可行验证写完一个技能不代表能跑我见过太多人直接在正式对话里测试新技能结果出了问题还不知道是自己写的指令有问题还是模型自身波动根本无从排查。正确做法是先做单技能回归测试而且要用固定输入测固定输出。我自己常用的测试方式是准备三个标准输入覆盖典型场景、边界场景和负面场景。典型场景是这个技能最应该处理的输入边界场景是勉强够得着的输入负面场景是“明确不该用这个技能但容易误触发”的输入。然后把三个输入分别跑一遍看结果是否符合预期。比如对polish-notes-to-blog这个技能我准备的测试输入是典型一段比较完整的项目记录包含标题、问题描述和部分代码预期输出是一篇结构化博文。边界只有三个关键词如“skills、标题、热词”预期输出依然是一篇结构完整但内容更依赖合理延展的博文。负面用户给出一篇已经写好的完整文章要求“帮我润色一下”预期输出是拒绝使用本技能。第一次跑的时候边界场景就出了问题模型收到“skills、标题、热词”这类输入之后居然挑了一个跟写作完全无关的方向去扩写输出了关于关键词热度分析的文案。查下来发现是SKILL.md里缺少对“输入类型不完整时如何补全”的说明。我在阶段一里补了一句“如果用户输入只有少量关键词优先从相关领域常识进行结构化补全而不是发散到其他话题”问题立刻解决。4.2 技能间干扰排查description 是罪魁祸首当你的技能数量多起来之后会遇到一个新的坑不同技能互相干扰。常见原因是两个技能的 description 语义太接近导致模型在触发时二选一甚至错误叠加。我搭的一个助手环境里同时存在polish-notes-to-blog和translate-article两个技能前者负责把笔记整理成博客后者负责中英互译。有一次我给了一个中文笔记让它整理成中文博文结果它居然先做了一遍中译英再按英文习惯组织内容输出的东西简直没法看。排查之后发现两个技能的description都提到了“处理文章内容”这个短语模型在触发阶段拿不准该选哪个就干脆两个都激活了。解决方式很简单让两个技能的 description 在“适用面”上做出明确区分。一个写明“输入是未经整理的笔记输出是中文博文”另一个写明“输入是成文内容输出是另一种语言的版本”。改完之后误触发的情况基本消失。4.3 实测技能输出的评估怎么判断一个技能“成功”了最后聊一个特别主观但特别重要的问题怎么评价技能输出的好坏我的标准是看“是否偏离核心主题”、“是否忠实执行硬性规则”、“是否有真正的干货信息”三个维度。偏离不偏离核心主题看输出内容是否围绕用户输入展开硬性规则看段落字数、标题编号、禁用词等干货信息看有没有实际的参数说明、操作流程、踩坑经验。我习惯给每次测试输出打一个简单评分表比如评估维度检查点通过标准主题相关性输出是否围绕输入的核心话题展开全文未跑题结构合规标题编号是否连续、层级是否不跳级标题层级完整无跳级内容深度是否有原理、实操、经验等干货至少包含 3 处实操细节测试跑一轮之后把所有不通过的项目整理出来回头去改SKILL.md或者 references然后重新跑。小步快跑比憋一个大版本要稳步得多。5. 多技能协同的成熟实践5.1 工作流模式一个技能搞定一个环节的问题当技能数量越来越多你会发现有些任务是串行关系先做 A 技能的输出再把结果交给 B 技能处理。这种模式我用得比较多尤其在内容生产流水线里。举个我实际搭过的例子我按“拆解需求与资料收集”和“资料整理与成文”两段式配置了两个技能。第一个技能extract-info把零散对话里的关键信息结构化提取出来存成字段清晰的 JSON第二个技能polish-notes-to-blog读取 JSON再按写作框架生成博文。这样有两个好处一是每个技能的指令都更简洁模型不需要在一个技能里同时胜任两种能力二是中间产物是结构化数据方便人检查哪里出了问题。串行模式也有一个要注意的地方中间产物的格式必须稳定。前一个技能输出的 JSON 结构一旦随意变动后一个技能就会不知所措。所以我在extract-info的SKILL.md里做了强约束输出 JSON 必须包含title、keywords、raw_material、missing_info四个字段写入“输出格式”时还附带了一个具体的 JSON 示例。这样后一个技能拿到数据时路径是确定的。5.2 条件路由模式让系统自己决定用哪个技能比串行模式复杂一点的是条件路由。系统根据用户请求的类型自动决定调用哪个技能来处理。这种结构特别适合做平台型的助手——用户可能来查资料、要写文章、要做翻译、要做数据分析你不可能把所有能力塞进一个技能里而应该让路由层去分发。路由的前提是每个技能的 description 写得足够清晰。框架把用户的请求向量化和所有技能的 description 做相似度匹配选出最合适的那个。所以我特别强调 description 里“when_not_to_use”的重要性——它不仅是一个负面约束更是一个排除项能显著提高匹配准确度。具体操作上你可以在 description 里把话说得再细一点“当用户提供的是已经成文的中文内容并要求转发为英文时应使用 translate-article当用户提供的是零散笔记且输出预期为结构化中文文章时应使用 polish-notes-to-blog。”这样模型在做路由决策时靠的是明确的规则所指而不是模糊的含义联想判断的可靠性高非常多。5.3 技能版本管理不只是改名那么简单技能包本质上是文件集合所以完全可以纳入版本管理。不过我在实践中发现很多人只把技能当代码来管却忘了管理“技能之间的依赖关系”。比如polish-notes-to-blog里的 references 文件被另一个技能共用那更新引用文件时要评估对另一个技能的影响。我用的方案是在每个技能的SKILL.md元信息里加一个dependencies字段列出这个技能依赖哪些共享资源然后在更新共享资源时先跑一遍全量测试。虽然多花一点时间但比线上突然生效一个破坏性更新要好得多。另外技能的版本号也有讲究。我建议按语义化版本来主版本变化说明技能的行为模式变了次版本变化说明增强了某些环节补丁版本说明修复了小问题。这样你在升级技能时可以通过版本号快速判断它跟别的技能的兼容性。6. 常见问题与避坑记录真实项目中的排查速查表6.1 技能没有被触发最常见的原因不是“你没写好”每次有人来找我吐槽“技能没有被触发”我第一反应就是让他贴出description的内容。很多人容易忽略description的重要性把它当成一句可有可无的介绍结果模型在整个技能库里根本找不到匹配。我整理过一份排查表基本覆盖了我会遇到的情况症状常见原因解决方案技能完全不触发description 表述模糊或与其他技能相似度过高重写 description增加“何时不适用”的负向描述触发了但输出不符合预期SKILL.md 执行步骤不够具体模型自由发挥空间过大把执行步骤拆细每一步加上明确的输出约束输出风格不稳定只靠抽象形容词约束风格没有提供具体范例在 references 里加 example 文件提供全文范例引用了不存在的知识references 路径写错或文件没有注册到框架检查路径和框架的加载配置确认文件可读技能依赖的脚本没执行脚本路径配置错误或模型不知道何时该调用脚本在 SKILL.md 中明确写出脚本的触发条件和调用方式6.2 写 SKILL.md 时的四个避坑点第一不要写“你是一个”系列。类似“你是一个资深博主”、“你是一个数据分析专家”这类角色设定看起来合理但实际效果不稳定。直接用“按以下步骤执行”来替代角色设定输出稳定性会好很多。第二不要给模型留“可选的”指令。如果SKILL.md里出现“可以补充一些背景信息”这种表述模型就会陷入选择困难输出质量会明显波动。改成“必须在第二段补充背景信息不少于 150 字”结果就可靠多了。第三不要忘了负面清单。明确写出“不要做”和“只做”比“尽量”和“避免”要有力得多。比如“不要使用任何真实存在的公司名称”比“尽量使用匿名信息”可靠得多。第四不要过度堆满SKILL.md。如果某个知识点在 references 里有正文里就不需要重复。因为重复过多会增加模型混淆指令和知识边界的概率还可能白白消耗上下文窗口。6.3 关于加载机制的一个容易被忽略的细节不同框架对SKILL.md的加载策略不一样有的会在每次对话开始时整个加载有的会在触发时加载还有支持按需读取 references 文件。这决定了一个问题——如果你的技能包体积非常大reference 文件特别多那么模型实际读到的可能不是全部内容而只是它“认为需要”的那一部分。此时你可能要在SKILL.md里明确指定某个 reference 文件是“启动时必须先读”的确保模型在正确的时间看到正确的内容。我实际碰到过一种情况references里的风格规范文档写得很完整但模型在生成时根本没有去读而是凭记忆写了一篇显得很“AI 腔”的文章。后来我在SKILL.md的阶段三里加了一行“开始输出之前必须先读取 references/style-rules.md 中的格式要求”这个问题就消失了。你得主动声明依赖关系而不是指望模型自己会去查文件。7. 额外说两个我常用的调试技巧最后补两个小工具都是在实战里反复验证过好用的。第一个是“最小复现法”。遇到输出异常时把输入材料删减到只剩一个关键句反复用同一个句子测试同一个技能观察输出变化。这可以帮你排除材料本身对模型决策的干扰快速定位到底是不是技能指令的问题。我在调试polish-notes-to-blog时就是靠这个办法发现了输入类型缺失时模型会发散的老大难问题。第二个是“语料对照法”。先把一段你期望的理想输出手写出来存成references/example-output.md然后让模型在输出前先阅读这个文件再模仿它的风格去写。这比写十条风格规则都管用。你现在在看的这篇文章其实用的就是这类方法先把范文结构拆好放在 references 里再让模型照着结构来写出来的东西质量会稳很多。我个人的体会是技能开发这件事关键不在于把文件写得多花哨而在于能不能把“什么时候该做什么、不该做什么”说清楚。模型像一个极其聪明但缺少常识的执行者你给它的不是一堆角色人设而是一份边界清晰、步骤明确、有参照样例的工作手册。当你把这一套玩顺手之后你会发现你积累的不再是一堆一个模型一个用法的提示词而是真正可以跨场景、跨项目、跨模型迁移的能力模块。这算是目前阶段最值得投入的方向之一。