最近不管是在 Codex、OpenClaw 还是 Claude Code 的讨论区里跟 Skill 相关的问题总是能瞬间热起来。有人问我装了一堆 Skill为什么模型一次都不调用也有人问我自己按教程写了个 Skill运行时模型表现得像个没头苍蝇参数乱传、格式乱出到底哪里出了问题先说结论创建 Skill 这件事难点根本不在写代码而在“理解模型怎么看待你的 Skill”。Skill 本质上是一份给模型看的“操作手册工具包”模型每次都在读这份手册判断要不要用、怎么用。你手册写得不清不楚模型自然就该触发时不触发该干活时瞎发挥。这篇内容我就把自己从零开发、调试、维护多个 Skill 过程中踩过的坑和总结出的门道掰开揉碎讲一遍。不管你是想在 AI 编程工具里沉淀个人工作流还是想把 PCB 设计里的 Allegro 脚本封装成 Skill或者是数学建模竞赛里想用 Skill 提效这篇文章都能帮你少走很多弯路。1. 先搞清楚 Skill 到底是什么再谈怎么创建1.1 Skill 不是脚本是“能力封装”很多人对 Skill 有个误解觉得 Skill 就是一段脚本或者是一堆提示词。其实都不准确。你看现在主流 Agent 工作台里对 Skill 的约定一个 Skill 通常由一个 SKILL.md 主文件带头下面可能挂脚本、模板、参考文档组合成一个完整的目录。模型在任务匹配到 Skill 时会读取这个 SKILL.md然后按里面的指引去调用脚本、读取模板、产出结果。这就有意思了。Skill 和普通脚本最大的区别在于脚本是给“确定的调用方”用的而 Skill 是给“一个会随机应变的模型”用的。你写一个 Python 脚本函数参数定了就是定了调用方不会自己发挥。但 Skill 不一样模型会揣摩你的描述会“猜”你的意图会在参数不全时自作主张补一个值。这就是为什么你写给机器调用的脚本写得好好的但封装成 Skill 后一塌糊涂——因为你面对的调用者从严格的编译器变成了一个会脑补的模型。我自己习惯用一个比喻Skill 就像你招了个实习生你给他写了一份岗位说明书。实习生能力强不强是一回事但你的岗位说明书要是写得模棱两可他要么不知道自己该干什么要么就按自己的想法瞎干。创建 Skill 的过程本质上就是写这份岗位说明书的过程。1.2 Skill、Agent、MCP、插件之间到底是什么关系现在热词里老有人在问“Skill 和 Agent 的区别”“Skill 和 MCP 的区别”我简短说下自己的理解。Agent 是那个做决策、编排流程的主体Skill 是 Agent 可以调用的“技能单元”一个 Agent 身上可以挂很多 Skill。MCPModel Context Protocol则是把外部工具标准化接入进来的协议它解决的是“工具如何被模型调用”的传输问题Skill 解决的是“某个完整任务如何被模型理解和执行”的编排问题。两者可以配合使用不冲突。打个比方Agent 是一个厨师长MCP 是厨房里通水通电的管道接口Skill 则是一道菜的完整菜谱——食材、步骤、火候、摆盘。管道接口让厨师能拿到各种工具但光有工具还不够得有一份菜谱他才知道这道菜具体怎么出。Skill 就是那份菜谱。1.3 创建 Skill 到底在创建什么你去翻 Codex、OpenClaw 的官方文档它们对 Skill 的定义维度还不完全一致但底层思路趋同Skill 是把一个可复用流程“结构化”成模型能自主调用、自主执行、自主交付结果的能力包。所以创建 Skill 这件事不是一个写代码的过程而是一个“决策过程翻译”的过程。你需要把一个过去由人手动执行的工作流拆解成模型能看懂的决策节点什么时候触发、需要哪些输入、按什么顺序执行、每一步用什么工具、输出格式是什么、结果不理想时怎么办。每一步都要翻译成模型的语言。这也是为什么我会反复建议不要一上来就写 SKILL.md先把你要封装的流程自己在脑子里走一遍哪怕先用文字记下来。流程想清楚之前写的 Skill基本都是废的。2. 创建 Skill 的标准结构与核心步骤2.1 一个 Skill 的文件组织长什么样虽然不同平台的 Skill 细节略有差异但目前主流的标准结构大同小异。我拿 Codex 和 OpenClaw 里常用的约定举例一个典型的 Skill 目录是这样的my-skill/ ├── SKILL.md # 模型读取的主文件核心中的核心 ├── scripts/ # 可执行脚本python/shell/js 都行 │ └── run.py ├── templates/ # 输出模板比如代码框架、报告模板 │ └── output_template.md ├── references/ # 参考资料模型执行时可查阅 │ └── checklist.md └── README.md # 给人类看的说明文档SKILL.md 是灵魂。模型每次做任务匹配时主要就是扫各个 Skill 的 SKILL.md 来决策。scripts 和 templates 是血肉负责把模型的决策变成具体产出。references 是弹药给模型在执行中途备查的资料。2.2 SKILL.md 的核心字段与写法结合多个平台的字段约定我建议把 SKILL.md 至少写成下面几个板块nameSkill 的名字要短、要准。别起“reproduce_test_case_new_final_v3”这种名字模型看了也头疼。description最重要的一段。这段话是模型判断“该不该用这个 Skill”的唯一依据。不能含糊得写清楚“当用户想做什么事时使用这个 Skill”还要写明不做哪些事。instructions模型拿到这个 Skill 后的执行步骤。要写清楚“先做什么、再做什么、每一步输出什么”最好是编号列表模型对编号列表的执行遵从度明显高于一大段散文。parameters描述这个 Skill 需要哪些输入尽量用 JSON Schema 定义或者用明确的表格列出每个参数的类型、默认值、取值范围。examples给一个“输入→输出”的实例。模型会模仿示例的格式来输出所以示例长什么样产出的结果基本就长什么样。平台之间字段名可能略有出入但这套信息结构在任何平台都适用。你把这几块写透了不管什么工作台稍作迁移就能用。2.3 从零创建 Skill 的实操流程我每次新建 Skill 时都按下面这套流程来基本不会返工明确任务边界用一句话说清楚“这个 Skill 只负责做什么”。说不清楚说明你对这个 Skill 的理解还没到位。先写 description 草稿以“当用户需要【某个具体场景】时使用此 Skill”为框架把触发场景、输入要求、输出物写清楚。不要先写代码先让模型“知道什么时候该用”。设计参数与输入格式把所有可能要的输入列出来分好类型定好哪些必填、哪些可选。参数名要语义化比如用input_file而不是file1。写 instructions 执行步骤按“第一步做什么、第二步做什么”的方式写拆成小步骤每步尽量只表达一个动作。在需要模型判断的地方主动告诉它“如果遇到什么情况怎么做”减少它的自由发挥空间。挂载脚本/模板并测试写一个最小可用的示例输入跑一遍看输出对不对再逐步加复杂度。补 examples 并迭代 description示例写完后把 description 再读一遍看描述和示例有没有矛盾的地方。实际测试中模型如果频繁不调用或者调用后跑偏多半就是这里需要调整。这套流程看着简单但真正做到第 6 步还会回改第 2 步的人很少。大部分人写完 description 就不再调整了结果 Skill 像个一次性用品换个场景就失灵。3. 创建 Skill 的核心注意事项让模型真正会用的六个铁律3.1 描述决定生死别把 triggers 写成功能清单我在多个平台实测下来一个新 Skill 从“不生效”到“好用”的跃迁八成发生在 description 被重写之后。这是最重要的部分值得反复打磨。很多人写 description 就像在写产品说明书“本 Skill 用于代码审查支持多种语言可以检测安全漏洞、性能问题、代码风格问题……” 字数不少但没有一句是在“告诉模型什么时候用”。模型看完这段话面对一个需要做代码审查的任务可能根本不会触发这个 Skill——因为它的匹配逻辑要求“用户意图”和“描述场景”能对得上。我推荐一种写法框架DESCRIPTION: 当用户要求对一段代码或一组代码进行审查时使用此 Skill。 审查内容包括安全漏洞、性能隐患、代码风格、可维护性。 不适用于代码解释、代码生成、代码重构。这些任务应使用其他工具或直接回答。核心是两点一是“当用户要求什么时”把这个触发场景写得具体最好覆盖用户会用的多种表达方式比如“帮我看看这段代码哪里有问题”“检查一下这个文件的 bug”二是明确“不适用于”什么主动划掉边界模型就不容易跑偏去干别的。3.2 参数设计决定成败给模型留好后路参数设计是最容易被低估的部分。你以为是你在定义参数实际上模型是个“不怎么听话的调用方”你设计得不周全它就会给你传奇怪的数值。几个实操中反复踩到的坑参数名太模糊比如一个参数叫data模型根本不知道你要它传什么数据。改成test_data_file_path模型就知道该给文件路径了。不设默认值模型遇到一个没写过默认值的参数不会“空着不填”而是会自己猜一个。所以所有可选参数都建议给默认值并在描述里写清楚“不填时默认是什么”。缺少边界说明比如一个参数接受 1-10 的等级值你不在描述里写清楚模型可能直接传 99。参数取值范围必须写死。输出格式没定死你要求输出 JSON模型给了你一段 Markdown 无序列表这种事我在初版 Skill 里见得太多了。输出格式不仅要说明最好在 examples 里给一个完整示例。我常用的一段参数设计模板是这样{ skill_input: { code_dir: { type: string, description: 待审查代码所在的目录路径必填, required: true }, focus_level: { type: string, description: 审查深度可选quick / normal / deep, enum: [quick, normal, deep], default: normal }, output_format: { type: string, description: 输出格式可选markdown / json, enum: [markdown, json], default: markdown } } }参数设计的原则就一句话让模型每次做选择时选项都摆在它面前而不是让它自己创造答案。3.3 别把 Skill 做成“万能工具箱”单一职责是命根子新手的通病是喜欢把一堆相关功能塞进一个 Skill。比如说要做代码审查就把安全检查、性能分析、风格检查、依赖审计全放进去还希望模型自动判断该用哪个。实测下来的结果往往是Skill 的 instructions 越长模型的执行质量越差。你让它一次判断太多事它就会在某一个子任务上用力过猛其他部分草草带过。Skill 更合理的粒度是“一个 Skill 只解决一类问题”哪怕那类问题里包含几步操作。比如代码审查你可以拆成三个 Skill一个做安全漏洞审查一个做性能分析一个做风格优化。每个 Skill 的 instructions 都短小精悍模型执行起来反而又快又准。用户侧可能多了一次 Skill 选择的动作但总体验比一个臃肿的万能 Skill 好太多。还有个细节同一个 Skill 的目录里别放一堆互不相关的脚本。如果你发现 scripts 里有三个脚本功能毫无关联说明这个 Skill 拆分得更细才对。3.4 忽略测试等于没做 Skill先建正负样例集很多人的 Skill“开发”完了一次测试都不做就发布。等真正跑起来模型要么不调用要么调用后产出完全不能用。Skill 的测试其实比代码测试还严格因为你测试的对象是“带随机性的模型行为”。我的建议是每个 Skill 在发布前至少要准备三类测试样例正例用户明显需要这个 Skill 的场景测试模型是否主动调用。负例用户的问题和这个 Skill 只有一点儿沾边的场景测试模型是否克制住不乱调用。边界参数比如输入为空、路径不存在、数值超范围测试 Skill 在异常输入下是否还能给出合理反馈。有一个小技巧很好用给 Skill 加一个“自检模式”。在脚本里预留一个参数dry_runtrue这时脚本不实际执行只打印出它接到的所有参数。这样你可以在真实环境里反复测试模型到底有没有正确传参不用一遍遍真的跑完整流程。这个技巧我几乎每个 Skill 里都会留一个开关调试效率提升非常明显。3.5 给模型留“失败预案”别让 Skill 在异常情况里裸奔Skill 运行过程中一定会遇到模型没预料到的情况。文件读不到、依赖没装、输出格式被截断任何一环出问题模型如果没有预案它就会“随机应变”甚至直接报错。因此在 instructions 里务必要写一段“异常处理”指引。比如脚本执行失败时请先检查文件路径是否存在如果依赖缺失请提示用户安装所需依赖并说明安装命令如果输出不规范请按示例模板重新生成。这段听起来很简单但实际效果非常明显。我测试过一个没有异常处理的 Skill遇到路径写错时模型直接输出了一段 Python Traceback然后说“我无法完成该任务”。加上异常处理指引后同一个错误下模型会主动检查路径、给出修正建议体验判若云泥。3.6 版本管理与兼容性你自己也会忘了 Skill 是怎么写的Skill 的迭代速度比传统软件快得多。你今天写的 description两周后可能已经改得面目全非。如果不做版本管理等到某个环节行为异常时你根本不知道是改了 description 导致的还是改了脚本导致的。我用 Git 管理所有 Skill 目录每次修改 description 或者脚本就提交一次。Commit message 里写清楚改了哪部分逻辑。这样做的好处是一旦某个 Skill 在某次更新后“退化”了我可以快速 diff 出变化、定位问题。还有一个规律我实测下来很稳脚本改坏了容易发现description 改坏了一时半会儿发现不了因为它影响的是模型“什么时候调用”和“怎么理解指令”这类问题往往是延迟暴露的。所以每次动 description我都会专门跑一遍正负样例集确认触发行为没有漂移。4. 场景化实操三类典型 Skill 的从0到1全过程4.1 通用向测试用例生成 Skill 实战拆解“测试用例 Skill”这个方向是很多人入门的首选因为它流程清晰、产出可验证。我拿一个实际做过的 Skill 举例讲讲参数和 instructions 是怎么设计的。当时的需求很简单团队的项目里每次新增接口都要人工撰写测试用例费时且格式不统一。这个 Skill 的触发场景当用户要求为某个接口、函数或模块生成测试用例时使用此 Skill。参数方面我设计了三个code_path待测试的源码文件路径必填。test_framework测试框架可选 pytest / jest / go test默认 pytest。case_depth用例覆盖深度可选 basic / normal / full默认 normal。basic 只覆盖主路径full 覆盖边界、异常、性能场景。instructions 里最关键的几步是这样写的读取code_path指向的文件分析其中的函数、类、接口定义。根据case_depth决定覆盖深度。basic 时只覆盖正常主流程normal 时补充边界值full 时再补充异常场景和资源释放场景。按照test_framework对应的语法生成测试代码输出到测试目录下。如果文件无法读取或者源码中没有可测试的公开接口主动向用户说明原因并询问是否调整输入路径。这套设计跑起来后最大的体会是case_depth 这个参数极其关键。一开始我只有 basic 和 full 两档模型经常在 full 档生成一堆过于复杂的测试后来又加了 normal 档模型基本就稳定按档位发挥了。4.2 专业向把 Allegro 脚本封装成可调用的 Skill如果你在硬件领域对 Allegro 肯定不陌生。很多工程师手上积累了大量 Allegro Skill 脚本比如自动跑等长检查、批量设置差分对、快速导出元件清单。但问题在于这些脚本只有你自己会用别人用的时候要么不知道入口要么参数搞错。把它们封装成 Agent 可调的 Skill是特别值得投入的一类实践。这个封装过程跟通用 Skill 的区别主要在参数设计上。Allegro 的 Skill 脚本通常需要 PCB 设计中的物理参数比如网络名、层叠名、间距规则。你把这些参数定义成 JSON Schema 时一定要给枚举值。比如net_type可以设置为clocks、differential_pairs、power几个枚举模型就不会传一个乱写的字符串进来。指令部分需要写清楚“先调用哪个函数、再调用哪个函数”。比如你做了一个自动运行电气规则检查的 Skillinstructions 应该是先通过axlDBFind获取目标网络列表再逐一对每个网络执行间距检查最后把违反规则的 net 汇总成表格。每一步都要写明确不能让模型自己去猜 Allegro Skill 的 API 顺序。这类垂域 Skill 的价值在于你的专业经验通过 Skill 沉淀下来了别人再用的时候不需要知道底层脚本怎么写的、参数怎么传的只需要自然语言说需求就行了。4.3 竞赛向数模国赛背景下团队协作 Skill 怎么设计数学建模竞赛场景下很多人也在尝试把整个参赛流程沉淀成 Skill。看过一些相关讨论这个方向的核心问题不是“怎么写”而是“怎么让多个 Skill 协同配合”。建模竞赛的流程通常是读题拆解、文献检索、模型选择、数据预处理、模型求解、结果分析、论文写作。你不可能用一个 Skill 搞定全部更合理的做法是把每一环节拆成独立 Skill。比如题目解析 Skill负责把赛题拆解成多个可执行的小问题整理出约束条件、目标函数。数据预处理 Skill负责把给定的数据文件清洗成标准化格式输出数据质量报告。模型选择 Skill根据题目特征推荐适合的模型类型并给出选型理由。论文写作 Skill按竞赛论文模板把模型结果整理成规范章节。这里最大的坑是 Skill 之间的“手递手”环节。前一个 Skill 的输出能不能直接成为后一个 Skill 的输入取决于你有没统一好中间格式。我的做法是让“数据预处理 Skill”输出一个标准 JSON 格式的数据摘要然后所有后续 Skill 都从这份 JSON 里取数。中间格式没定义清楚Skill 再多也串不成一条流水线。5. 常见问题快查与长期避坑手册5.1 Skill 不生效、乱调用、参数漂移速查表创建 Skill 过程中遇到问题绝大多数都能归到几个典型症状里。我把经常遇见的几类整理成一张表方便你逐一排查症状表面原因真正的问题解决办法模型完全不调用 Skill描述里没写触发场景description 过于像“功能说明”没有告诉模型何时用用“当用户需要……时”句式重写 description并增加用户常用表达方式模型经常在不需要时调用description 没有划边界没有写“不适用场景”模型误判在 description 中明确增加“不适用于……”的排除清单参数传得离谱参数名太抽象模型无法从参数名推断内容参数名语义化增加枚举值、类型和默认值输出格式混乱没有给出格式实例模型对输出格式理解不到位在 SKILL.md 里增加 examples给一个完整的输入输出示例执行步骤乱序instructions 是散文模型对非结构化指令遵从度低改成编号列表每步只留一个动作减少复合指令路径类参数总出错没有做路径校验模型不知道路径可能不存在、有空格等在 instructions 中加入“先检查路径是否有效”的步骤提供容错逻辑换一个平台就废了用了平台私有能力Skill 与平台绑定过深脚本保持纯命令行接口SKILL.md 只保留通用字段这张表经常回头翻一下。很多问题不是一次性解决就完事的模型版本一变原来稳定的触发行为可能就漂移了需要重新调 description。5.2 Skill 装上太多反而变笨了冲突管理的几个思路热词里一直有人在问“找一个 Skill”但我觉得真正重要的反而是“删 Skill”。装的 Skill 太多模型在匹配时反而容易出现选择困难。任务匹配时对一堆描述相近的 Skill模型很容易混淆。比如你同时装了三四个“代码审查”方向的 Skill描述又互相重叠模型面对一个代码审查任务时可能随机选一个选到哪一个都不一定是最合适的。这就不是 Skill 本身的问题了而是 Skill 库管理的问题。我的做法每个 Skill 的 description 第一句必须是它的细分定位让人一眼就能区分也让模型能从语义上区分。比如一个写成“当用户要求检查代码安全漏洞时”另一个写成“当用户要求优化代码风格时”。定期做一次 Skill 盘点删除超过 3 个月没用过的 Skill。同类 Skill 只保留一个最优版本不要因为“万一有用”就留着。Skill 不是收藏品装一堆吃灰的 Skill不但没有增益反而会稀释掉整个 Agent 的能力。这一点用久了体会特别深系统里活着一个精准的 Skill比躺着一百个描述模糊的 Skill 有用得多。5.3 一个值得长期养成的设计习惯把“不要做什么”写进描述里这大概是我最想分享的一条经验了。大多数人写 description满脑子都是“这个 Skill 应该做什么”但很少去写“这个 Skill 不要做什么”。其实后者的价值往往比前者还大。模型在没有明确边界的时候默认是会“能干就干”的。你做了一个代码审查 Skill如果不写“不适用于代码生成”那用户说“给我写个登录功能的代码”时模型很可能也顺手用这个 Skill 去干了。结果代码写得可能能用但风格和产出逻辑完全不是你想定的那条路线。所以在 description 的末尾固定写上一段不适用于以下场景 - 代码生成、重构、翻译等任务 - 与安全漏洞无关的一般性代码问题 - 用户没有明确要求审查时的主动介入。你写完这段再看模型的调用行为会明显比之前克制得多。给模型立规矩是创建 Skill 最值得花时间的部分之一。最后再说两句我前前后后创建、修改过不少 Skill最大的感受是普通人学 Skill 学的是格式和模板真正拉开差距的是对模型行为的理解。模型是个执行力强但想象力过剩的执行者你得在描述里把边界写清楚在参数里把选项给足在示例里把格式固定住它才能交给你稳定可控的结果。再分享一个小技巧改 description 的时候改完一定要用小样本跑一次看它调不调用、怎么执行。不要在只改了一句话后觉得“应该没问题”就跳过验证。Skill 的开发和传统软件开发最大的不同就是它的运行结果天然带随机性你永远猜不到一次改动会在模型侧引发什么连锁反应。唯一能依靠的就是反复实测用结果说话。希望这篇内容能帮你少踩几个坑。如果你按这套思路去建自己的第一个 Skill大概率你会回来感谢那段“不适用于……”的描述。