“skills”这个概念,最近在我关注的 AI 工程化圈子里越来越热。说白了,它就是把过去散落在提示词里、文档里、甚至老师傅脑子里的经验,整理成一套结构化的、能让大模型直接照着执行的方法论资产。我前阵子花了两个周末,把自己手头几个重复度高的任务,比如代码审查、周报生成、SQL 写数,分别封装成了独立的 skill,跑通之后有个很明显的感受:过去是每次跟模型对话都要重新调教一遍,现在是把经验沉淀下来,一次封装,到处复用,输出质量还稳得一批。
这篇文章就把我这段时间折腾“skills”的完整心得写出来,包括它到底解决了什么问题、一个高质量的 skill 该怎么设计、完整实操案例,以及我踩过的一堆坑。适合正在做 AI 应用开发、提示词工程,或者想把自己的工作流标准化的朋友参考,不管你是用 Claude、Cursor 这类现成工具,还是自己在封装 Agent,这套思路都通用。
1. 先搞明白“skills”到底解决了什么问题
1.1 模型什么都知道,但就是不按你的规矩干活
我一开始跟大模型协作,最大的痛点就是“飘”。你问它“什么是代码审查”,它给你列得头头是道,什么可读性、性能、安全,八股文一套一套的。但当你让它真正去审查你团队的一段代码时,问题就出来了:它总是凭“常识”在审,而不是按你们团队的规范在审。比如你们团队明确要求所有错误处理必须用自定义异常,禁止裸抛 Exception,模型偏偏每次都能给你挑出几个别的毛病,但对这种硬性规范视而不见。
这就是一个很核心的矛盾:大模型的知识是通用的,而你要它干的活是高度个性化的。通用知识它管够,但“你们这里该怎么做事”这种隐性知识,它没有。过去我们怎么解决?靠提示词,把规范写进去。但提示词的毛病也很明显:写短了不够用,写长了每次对话都要占用大量上下文,而且改一版规范就要改所有相关提示词,维护成本极高。
Skills 这套机制,本质上是把“该怎么做”这件事,从对话上下文里抽离出来,变成一个独立的能力单元。模型在执行任务时,会根据任务描述,动态加载匹配的 skill,然后把技能里的流程、规则、示例当作执行依据。这就好比,你请了一个知识渊博的顾问,但你不会每次都把公司规章制度从头到尾背给他听,而是直接甩给他一本《员工手册》,告诉他:按这个来。Skills 就是那本《员工手册》。
1.2 Prompt、RAG、Fine-tuning、Skill,到底该怎么选
很多朋友一听这个,第一个反应是:这跟 RAG 有什么区别?跟 Fine-tuning 又是什么关系?这里我直接给一张对比表,是我自己整理用的,看完基本就清楚了。
| 技术方案 | 实现成本 | 维护成本 | 解决的核心问题 | 适用场景 |
|---|---|---|---|---|
| Prompt 模板 | 低 | 高 | 临时的指令约束 | 一次性或低频任务,简单对话 |
| RAG | 中 | 中 | 让模型“知道”外部知识 | 知识问答、文档摘要、信息检索 |
| Fine-tuning | 极高 | 极高 | 改变模型的“能力”和“行为习惯” | 特定风格生成、专业领域深度定制 |
| Skills | 中低 | 低 | 让模型“会按流程做事” | 高频复用的工作流、标准化操作、专家经验固化 |
我个人理解是,RAG 解决的是“知识”问题,它回答的是“是什么”;Skills 解决的是“方法”问题,它回答的是“怎么做”。Fine-tuning 太重了,改一次业务规则就要重新训练一次,对绝大多数团队来说完全没必要。而 Skills 恰好站在一个中间位置:比 Prompt 更结构化,比 RAG 更偏执行流程,比 Fine-tuning 轻量得多,而且改起来极快,改完立即生效。
1.3 Skills 的本质不是堆规则,而是把专家经验结构化
这是我最想强调的一点。很多人以为写 Skill 就是写一堆“你必须怎样怎样”的规则清单,大错特错。一个真正好用的 Skill,它的核心是“决策逻辑”,而不是“命令列表”。
举个例子,写代码审查的 Skill,不是简单地写“遇到命名不规范要指出”,而是要让模型理解:什么情况下命名不规范是必须指出的(比如对外 API 的命名)、什么情况下只是建议(比如内部临时变量的命名)、什么情况下可以不提(比如第三方库兼容代码)。这种带条件的、分优先级的判断逻辑,才是专家经验。否则写出来的 Skill 就是一本死板的说明书,模型照着执行,反而会把代码吹毛求疵地审一遍,产出全是噪音。
所以,构建 Skill 的过程,本质上就是把你脑子里的“隐性经验”外化成“显性逻辑”的过程。你被迫去思考:我处理这个任务时,第一步看什么?什么情况必须拦下来?什么情况可以放行?什么情况下我自己的判断也会出错?把这些想清楚,写出来的 Skill 才真正有用。
2. 拆解一个高质量 Skill:核心要素与结构设计
2.1 先定目录结构,别一个 Markdown 文件打天下
我见过很多朋友写 skill,就写一个巨大的 SKILL.md,里面什么都有,结果模型加载起来上下文爆掉,输出质量反而下降。我自己通常采用这样的目录组织方式:
skills/ code-review/ # 技能名,全小写加连字符 SKILL.md # 主文件,模型优先加载 examples/ # 示例目录,按需引用 bad-sample.py # 反例:有明显问题 good-sample.py # 正例:合规写法 review-report.md # 输出格式示例 references/ # 参考资料目录 team-style-guide.md # 团队规范原文 checklist.md # 快速检查清单这么设计的考虑有三点。
第一,SKILL.md 保持精简,只放执行流程、判断标准、边界条件,控制在 200 行以内。大模型对上下文的注意力是有限的,你塞了太多噪音,它就会忽略真正的重点。
第二,把大段参考资料放进 references 目录,让模型按需加载。现在不少 Agent 框架支持 skill 内部的文件引用,模型觉得需要查具体规范时,会自己去 references 里找。这就避免了每次执行都把一大堆文档塞进上下文。
第三,examples 目录单独放,是为了让模型在不确定的时候有个对照模板。示例的作用不是给模型“背诵”,而是给它一个“参照物”,帮助它理解抽象规则的具体表现。
2.2 SKILL.md 里最重要的不是正文,是 Frontmatter
一个合格的 SKILL.md,开头应该有 YAML 格式的元信息(Frontmatter),这部分是给模型看的,不是给人看的。它决定了模型在什么场景下会调用这个技能。
--- name: code-review description: 用于 Python 代码审查。当需要检查代码质量、发现潜在 Bug、评估代码是否符合团队规范时使用。不适用于架构设计评审、性能压测分析。 when_to_use: 用户提交代码变更、Pull Request、或要求“帮我看看这段代码”的场景。 version: 1.2.0 tags: [python, code-quality, review, backend] ---这里有个血泪教训:description千万别写得太大而全。我最初写的是“用于代码质量分析和审查”,结果模型动不动就调用它,连用户问“这段代码的时间复杂度是多少”都去加载这个技能,反而把简单问题复杂化了。正确做法是:既要说清楚“什么时候用”,也要明确“什么时候不用”(比如不适用于架构评审),这样模型才能精准匹配。
这几个字段的真实作用是“技能路由”。大模型看到用户请求后,会先根据所有可用技能的 description,选一个最匹配的来执行。如果你 description 写得不清楚,要么模型不该用的乱用,要么该用的不调用,所以这块值得仔细打磨。
2.3 正文结构:目标、步骤、标准、边界、示例,一个都不能少
我推荐的 SKILL.md 正文结构是五段式,清晰地告诉模型“为什么要做、怎么做、做到什么程度、别做什么、做成什么样”。
第一段是“技能目标”,用两三句话说清楚这个技能服务的最终业务目标。代码审查的目标不只是“找 Bug”,而是“在不阻塞业务迭代的前提下,守住代码质量底线”,这个认知会影响模型后续的所有判断。你写目标时想清楚,模型执行时才不会跑偏。
第二段是“执行步骤”,分步骤描述处理任务的标准流程。代码审查我会拆成四步:先看整体结构和变更范围,再查核心逻辑正确性,然后对照团队风格规范,最后输出结构化结论。每步都要写清楚“做什么、关注什么”。
第三段是“判断标准与优先级”,这是最核心的部分。必须明确哪些问题必须改、哪些建议改、哪些只是可选优化。我习惯用三级标签:[BLOCKER](必须修改)、[MAJOR](强烈建议)、[MINOR](可选)。没有优先级体系的 skill,模型就会把所有发现的问题一视同仁地抛出,产出价值就很低。
第四段是“边界与禁忌”,写得越清楚,模型越不会越界。比如明确说:本技能只审查代码实现层面,不讨论产品需求合理性;不重写代码,只提供修改建议;不审查第三方库内部实现。边界的意义是限制模型“自由发挥”的空间。
第五段是“输出格式”,明确告诉模型最终产出的报告长什么样。输出格式不稳定是 AI 应用里最烦人的问题之一,解决办法就是给出模板,并要求严格套用。
2.4 写示例的核心心法:成对出现,并说清楚“为什么”
不管什么类型的 skill,示例都极其重要。但我发现一个通病:大家给的示例只有正例,没有反例。这是不够的。
正例告诉模型“对的什么样”,但模型可能不知道怎么从错的状态迁移到对的状态。反例的价值在于,让模型知道“识别出问题”是什么样的。我把示例成对放,每个反例旁边都标注清楚问题,再把对应的正例和修改说明放一起,模型的模仿效果会好很多。
另外,示例最好用真实场景中的代码或文本片段,不要用虚构的、刻意构造的例子。因为虚构例子往往过于典型、过于简单,模型学了反而会变得教条。用真实世界里那些“模棱两可”的案例,模型才能学到那种微妙的判断力。
3. 从 0 到 1 实操:构建一个“代码审查”Skill 全流程
3.1 第一步:需求梳理与目标定义
我拿自己团队的真实需求来做示范。我们团队后端以 Python 为主,日常有大量 Pull Request 需要人工审查,代码风格不统一、基础错误反复出现,审查效率低。我想做一个 Skill,让模型先做第一轮自动化审查,把低级问题全部过滤掉,人工只关注模型筛出来的重点。
动手前,我先回答了三个问题。
一是“业务目标”:减少人工审查负担,把重复性、机械性问题自动化。这决定了技能的设计导向——宁可漏报,也尽量不要误报,因为误报会让人不再相信这个系统。二是“处理对象”:Python 后端的业务代码,不包含架构评审。三是“成功标准”:模型能找出 80% 以上的基础问题(比如未处理的异常、明显的命名不规范、明显的逻辑错误),且误报率控制在 20% 以下。
这个前置思考非常重要。很多 skill 做出来不好用,就是因为目标定义模糊,连设计者自己都不清楚要达到什么效果。你先想清楚“做成什么样算成功”,后面所有编写工作才有参照。
3.2 第二步:编写完整 SKILL.md
直接看我最终版本的 SKILL.md 主体内容,你可以照着他改自己的。
--- name: python-code-review description: 审查 Python 后端代码质量。当用户提交代码片段、Pull Request 或要求进行代码走查时使用。重点关注异常处理、数据校验、日志规范、性能隐患。不适用于架构设计评审。 when_to_use: 用户要求“帮我 review 代码”“看看这段有什么问题”“这个 PR 能合吗” version: 1.3.0 tags: [python, code-review, backend] --- # 角色 你是一位有 10 年经验的 Python 后端代码审查专家。你的任务是帮助团队在代码合入前发现潜在问题。 # 审查流程 严格按照以下步骤进行审查: 1. **先看整体**:阅读全部代码,理解核心逻辑,确认代码的职责边界。 2. **找致命问题**(优先级最高): - 是否有未捕获的异常可能导致程序崩溃? - 是否有明显的逻辑错误,导致功能不符合预期? - 是否有严重的安全隐患(SQL 注入、命令注入等)? 3. **查规范问题**: - 命名是否符合 PEP8 及团队规范(蛇形命名法)? - 是否有未使用的导入、明显的冗余代码? - 错误处理是否使用了自定义异常体系? 4. **给出改进建议**: - 对于非阻塞问题,给出具体的优化方向。 # 问题分级 所有发现的问题必须分级: - `[BLOCKER]`:必须修复才能合入。如:致命逻辑错误、安全隐患。 - `[MAJOR]`:强烈建议修复。如:异常处理缺失、资源未释放、明显性能问题。 - `[MINOR]`:可选优化。如:命名建议、代码简化。 # 边界与禁忌 - 不要重写代码,只提供修改建议。 - 不讨论产品需求是否合理。 - 不审查第三方库内部实现。 - 不确定的问题标注“需人工确认”,不要强行下结论。 # 输出要求 使用以下 Markdown 格式输出: ## 审查结论 通过 / 需修改 ## 问题列表 - `[级别] 文件/位置:问题描述` - 修改建议:具体方案 ## 改进建议 (可选,补充非阻塞性的优化建议)你注意一下,这个文件里我没有放具体代码示例,只放了流程和标准。示例放在 examples 目录里,等模型看完主文件后,如果对某些抽象描述不确认,再去翻具体例子。这样设计,主文件加载起来轻量,执行效率更高。
3.3 第三步:构造反例与正例,并用真实历史代码验证
写完 SKILL.md,还不能直接用。我花了大半天时间构造示例集。先说反例,我特意从历史代码里找那些被 review 出来过问题的真实代码,而不是自己编。比如下面这个典型的坏味道:
# bad-sample.py import os from datetime import datetime def save_user(user_data): data = get_db() user_id = user_data["id"] user_name = user_data["name"] if os.path.exists(f"/tmp/{user_id}"): return user_data["create_time"] = datetime.now() data.insert(user_data, "users") return user_data这段代码的问题非常典型:存在路径拼接安全隐患(user_id未经过校验直接拼进文件系统)、裸抛Exception风险(get_db()和data.insert()都没有异常处理)、变量命名没有体现业务含义、没有日志记录。关键是,它不是一眼就烂得离谱的代码,而是那种“看起来能跑,但问题一抓一大把”的代码,这才贴近真实工作。模型通过一个这样的完整反例,比我写一百条“要处理异常”的规则都管用。
正例则是在此基础上一一修复后的版本,每个修改点都对应反例里的一个问题。构造这种“同场景正反对”的示例,能让模型建立清晰的映射:什么样的坏味对应什么样的好改法。
然后我用团队过去两个月的 10 个真实 Pull Request 做了测试。第一版跑完,发现问题集中在两点:一是对业务逻辑里的“空值保护”判断过严,很多本来可以靠上一层逻辑保证的地方,模型也报成[MAJOR],形成了噪音;二是对团队自定义异常体系不敏感,总是建议用内置Exception,反而违反了团队规范。我针对这两个问题调整了边界描述和参考文档,第二版明显好很多。
这种基于真实反馈的迭代过程,是打磨 skill 质量的必经之路。一次写到位的 skill 是不存在的。
3.4 第四步:持续用失败案例“喂”给技能
Skill 上线之后不是一劳永逸。我会把日常人工审查中发现的问题分为两类:一类是模型能稳定发现的,不用管;另一类是模型连续漏掉的,我会把漏掉的典型代码片段加入 references/checklist.md,并在 SKILL.md 中补充对应的判断逻辑。
比如有段时间,模型总是漏掉“数据库查询结果未判空直接取下标”的情况。我就在 checklist 里加了一条,并在主文件的第 2 步强调“访问列表或字典前,是否确认存在对应索引或 Key”,同时提供了一个小示例。下次模型执行时就会覆盖到这一点。
这个迭代节奏,让 Skill 像滚雪球一样越来越懂你们团队的代码风格。你用一次,它强一次,三个月之后,它基本就变成了你们的“团队专属审查官”。
4. 常见问题与排查思路:技能封装避坑指南
4.1 模型就是不调用我的 Skill,问题多半出在描述上
这是新手最高频的困惑。我排查过的案例里,90% 是description写得不到位。模型在做技能匹配时,是拿用户请求和每个技能的description做相似度匹配,如果你描述得太笼统,比如“用于代码质量分析”,模型就很难把它和“帮我看看这段代码”关联起来。
解决办法是:在 description 里明确写出触发场景和典型用户提问方式。比如写成“当用户提交代码片段、Pull Request,或要求‘review 一下代码’‘帮我看看这段有什么问题’时使用”。把触发词直接写进去,命中率会大幅提高。
另一个排查点是技能目录的加载位置。有的工具框架要求必须把 skill 放在指定目录,路径不对的话,你的技能根本不会进入候选列表。仔细对照你所用框架的文档,确认目录命名和放置位置是否正确。
4.2 Skill 内容太长,Token 成本高,加载慢
一开始我图省事,把团队规范、检查清单、示例代码全塞进 SKILL.md,结果一次执行消耗巨量上下文,响应也变慢。后来我调整了策略:主文件只保留核心流程和高频规则;低频参考内容全部放进 references 目录,由模型按需加载;示例文件每个控制在 50 行以内,只放典型场景。
这里有个经验数据供参考:一个 skill 的主文件,我建议控制在 150 到 250 行之间。超过这个量,模型对后面内容的注意力会明显下降,你后面写的规则基本属于白写。如果必须有很多内容,那就拆分成多个小 skill,而不是一个巨型技能。
4.3 输出格式总是变来变去,模型有自己的想法
模型不按格式输出,这是 Agent 应用里的经典难题。我的排查顺序是:先看 SKILL.md 里的输出模板是否足够具体,是否给了完整的 Markdown 示例;再看问题分级标签是否明确,模型不确定怎么分级时,它就会自由发挥;最后看示例里是否有输出报告的例子,给模型一个“填空”的参照物。
我的经验是,输出模板这一段,既要给结构又要给示例。光给结构(比如“## 审查结论”),模型不知道结论该写多详细;光给示例不给结构,模型又可能模仿示例的措辞导致生硬。两个都给了,稳定性会大幅提升。
有些框架还支持在 SKILL.md 里指定输出风格,比如“始终以 Markdown 表格输出”“必须列出前三项最重要问题”,这类强化约束也值得用上,相当于给技能装了一个“输出侧护栏”。
4.4 多个技能之间互相冲突,模型不知道选哪个
当你的技能库越来越大,这个问题就必然出现。我一开始有code-review和python-review两个技能,描述高度重叠,模型经常随机加载一个,导致输出风格不统一。
解决办法有三招:第一,技能命名时避免泛化,比如统一用python-code-review、javascript-code-review,按语言拆开;第二,在 description 中明确写出“本技能用于 XX,不用于 YY”,强化边界;第三,如果两个技能边界确实重合严重,就合并成一个,内部按条件分支处理。
我在技能库里设立了一条铁律:同一个领域只保留一个主动技能,其他全部归入参考资料。宁可让一个技能处理多类任务(通过分支逻辑),也不要让多个技能看起来都能处理同一类任务,这能从根上避免调用混乱。
5. 从 Skills 到个人与团队的能力沉淀
5.1 Skills 是一份“可执行的团队文化手册”
我在把几个核心工作流都封装成 skill 之后,发现了一个很有价值的副产品:它把团队里很多“口口相传”的做法变成了“可执行、可追溯”的规范。新同学入职,不用再追着老同事问“代码规范都在哪看”“周报怎么汇报项目进度”“线上告警处理流程是什么”,直接把这些技能装进工具里,照着执行就行。
相较于传统文档,skill 的核心优势是它不只是给人看的,更是给 AI 执行的。传统文档写“提交 PR 前要自查”,人看到了不知道具体查什么;但 skill 会把自查拆成步骤、标准和示例,AI 能直接帮人把自查做一遍。团队规范从此不再是一纸空文,而是嵌入了日常工作流。
5.2 技能库的长期维护:像维护代码库一样维护技能
我建议每个团队和个人都像维护代码仓库一样维护自己的技能库。用 Git 管理版本,每个 skill 独立目录,遵循统一命名规范,提交信息写清楚“为什么改”。我自己还会维护一个CHANGELOG.md,记录每个版本的变更原因,这样三个月后回看还能想起来当初为什么加了这条规则。
目录结构我推荐这样组织:
skills/ README.md # 技能库总览与索引 python-code-review/ weekly-report/ sql-query-optimization/ >