agent-skills 实战:为 AI coding agent 构建可复用技能包
1. 从装完就吃灰说起agent-skills 到底解决了什么问题如果你最近半年在折腾 AI coding agents大概率经历过这个循环兴冲冲装好 Claude Code 或者 Cursor跑通第一个 demo觉得这玩意儿真神然后一周之后发现——它还是只会帮你补全几行代码、改改报错真正复杂的活儿一样干不了。问题出在哪不是模型不行是你没给它技能。agent-skills这个项目本质上就是给 AI coding agent 装技能包的一套机制和工具链。你可以把它理解成给一个新员工发《岗位操作手册》模型本身是那个聪明但啥都不懂的新人skills 就是告诉他遇到这类任务按这个流程、用这些工具、注意这些坑的标准化文档。没有 skills你每次都得在对话里从头解释一遍需求背景有了 skillsagent 能自己识别任务类型、加载对应能力、按既定规范执行。我最初接触这个概念是在 Claude Code 的技能体系里后来发现 Cursor、以及一批基于开源模型搭建的 agent 框架都在往这个方向走。核心诉求非常一致把提示词工程沉淀成可复用、可版本管理、可组合的能力单元。这跟当年从写 shell 脚本进化到写 Ansible Playbook 是一个道理——从一次性指令变成声明式的、可维护的能力描述。这篇文章适合三类人看一是刚上手 Claude Code 或 Cursor、还在摸索怎么让它干正经活的新手二是已经在用 agent 但每次都要重复写长提示词、想找更优雅方案的中级用户三是想给自己团队搭一套内部 agent 能力库的工程负责人。我会把 agent-skills 的目录结构、加载机制、编写要点、和 CLI 工具的配合、以及我在实际项目里踩过的坑全部摊开讲清楚。看完你至少能做到给自己常用的三个任务写出可复用的 skill并且知道怎么调试它为什么不生效。2. agent-skills 的整体设计与核心思路拆解2.1 为什么是技能而不是更长的提示词很多人第一反应是我直接把要求写进系统提示词不就行了为什么要搞一套 skills 机制这个问题我认真想过答案在于上下文预算和触发时机。一个 agent 的系统提示词是常驻的每次对话都要消耗 token。如果你把十种任务的操作规范全塞进去光提示词就几千 token还没开始干活呢上下文窗口先被吃掉一大块。而且模型面对一大堆可能用得上的指令时注意力会被稀释真正相关的规则反而容易被忽略——这在长上下文场景下特别明显。skills 的设计思路是按需加载。平时系统提示词里只放一句极简的索引比如你可以使用以下技能代码审查、数据库迁移、API 文档生成……需要时读取对应文件。当 agent 判断当前任务匹配某个技能时才去读取那个技能的完整说明。这就把常驻成本变成了按需成本上下文利用率高了一个量级。提示这个思路和操作系统的虚拟内存很像——不是把所有程序都加载进物理内存而是用到哪页换哪页。理解这一点你就能明白为什么 skills 的描述字段写得准不准直接决定了它会不会被触发。2.2 目录结构与文件组织一个标准的 skill 通常是一个独立目录核心是一个 Markdown 文件一般叫SKILL.md或类似名字里面包含元信息和正文两部分。元信息用 YAML frontmatter 写正文就是给 agent 看的操作说明。典型的目录长这样skills/ code-review/ SKILL.md references/ checklist.md scripts/ run_lint.sh db-migration/ SKILL.md templates/ migration.sql.tplSKILL.md的头部大概是这样--- name: code-review description: 对指定代码文件或目录进行结构化代码审查输出问题清单和修改建议。当用户要求 review 代码、检查代码质量、找 bug 时使用。 --- ## 操作步骤 1. 先用 git diff 确认改动范围 2. 按 references/checklist.md 逐项检查 3. 输出格式文件路径 行号 问题等级 建议 ...这里有个关键点description 字段是给 agent 做匹配用的正文是给 agent 执行用的。很多人写 skill 时把这两者混为一谈description 写得又长又模糊结果 agent 根本不知道该在什么时候加载它。我的经验是 description 要写成什么场景下用我的触发条件而不是我是什么的功能介绍。2.3 加载机制与触发逻辑不同 agent 平台的加载机制略有差异但核心逻辑相通。以 Claude Code 为例它会在启动时扫描 skills 目录把所有 skill 的 name 和 description 读进上下文作为索引。当你的请求进来模型判断需要某个技能就会主动去读取对应的SKILL.md全文然后按里面的步骤执行。Cursor 这边的思路类似但它更偏向通过 rules 文件和自定义命令来实现类似效果。你在.cursor/rules目录下放的规则文件本质上就是一种轻量级的 skill。区别在于 Cursor 的规则触发更多依赖文件匹配比如编辑.py文件时应用这条规则而 Claude Code 的 skills 更依赖语义匹配。理解这个差异很重要因为它决定了你写 skill 时的侧重点语义触发的 skilldescription 要写得像意图识别关键词文件触发的规则要写清楚 glob 匹配模式。搞反了就会出现我明明写了这个技能它死活不用的情况。2.4 组合与复用skills 的复利效应单个 skill 的价值有限真正有意思的是组合。比如你有一个读需求文档的 skill、一个生成接口定义的 skill、一个写单元测试的 skill理论上 agent 可以串起来完成从需求到测试的整条链路。我实测下来组合能否成功取决于两个因素一是每个 skill 的输入输出格式是否明确前一个的输出能不能直接喂给后一个二是 skill 之间有没有职责重叠。如果两个 skill 都声称负责代码质量agent 就会犯迷糊不知道该加载哪个。所以设计 skill 库时边界清晰比功能强大更重要。3. 核心细节解析与实操要点3.1 SKILL.md 的写法把 agent 当成一个聪明但没背景的新人写 skill 正文时最容易犯的错误是写得太抽象。比如你写请仔细检查代码质量这句话对人类程序员等于没说对 agent 更是无效指令。有效的写法是把它拆成可执行的动作检查是否有未处理的异常分支检查是否有硬编码的密钥或路径检查函数是否超过 50 行检查是否有重复代码块每一条都是 agent 能逐项核对的具体标准。我一般会遵循一个原则如果这条规则没法用是/否来回答就说明它还不够具体。另一个要点是给出输出模板。agent 在没有明确格式要求时输出会非常随意有时长篇大论有时又过于简略。在 skill 里直接写死输出格式比如输出格式 ## 问题清单 | 文件 | 行号 | 等级 | 问题 | 建议 | |------|------|------|------|------|这样每次执行结果都稳定可预期方便你后续做自动化处理。3.2 description 字段的触发优化description 是 skill 的广告词它的唯一任务就是让 agent 在对的时候想起你。我总结了几个写法技巧第一包含用户可能说的原话。用户不会说执行代码审查流程他会说帮我看看这段代码有没有问题、review 一下、这段逻辑对不对。把这些口语化表达塞进 description触发率会明显提升。第二明确排除场景。如果有个 skill 只处理 Python就在 description 里写仅用于 Python 项目避免它在 Java 项目里被误触发。第三控制长度。description 太长会占用索引空间一般控制在两三句话内。我见过有人写了 500 字的 description结果索引本身就超预算了得不偿失。3.3 引用文件与脚本的正确姿势skill 目录里可以放辅助文件比如检查清单、代码模板、可执行脚本。这里有个坑agent 不会自动读取这些文件你必须在 SKILL.md 正文里明确指示它去读。比如你放了references/checklist.md就要在正文写第二步读取 references/checklist.md 并逐项核对。否则那个文件就是摆设。脚本的调用也一样要写清楚执行命令和参数。我一般会写成bash scripts/run_lint.sh 目标目录并且说明脚本的输出怎么解读。这样 agent 才知道拿到输出后该干什么。注意脚本路径建议用相对路径并且确保脚本有可执行权限。我踩过一次坑脚本权限不对agent 执行时报 permission denied但它不会主动告诉你而是默默跳过这一步继续往下走最后结果缺了一块你还不知道。3.4 版本管理与团队协作skills 本质上是文本文件天然适合放进 Git 管理。我建议把 skills 目录作为项目仓库的一部分或者单独建一个 skills 仓库用 submodule 引入。这样做的好处是技能可以随项目演进团队成员共享同一套能力新人入职直接拉代码就有全套技能可用。团队协作时要注意命名规范。我见过一个团队里三个人各写了一个代码审查skill名字还不一样agent 加载时随机挑一个行为完全不可预测。统一命名前缀能缓解这个问题比如review-python、review-sql、review-frontend一看就知道边界在哪。4. 实操过程与核心环节实现4.1 环境准备与 skills 目录初始化先说 Claude Code 这边的操作。安装完成后skills 一般放在用户级目录或项目级目录。项目级的优先级更高适合放项目专属技能用户级的放通用技能跨项目复用。初始化步骤大致是# 进入项目根目录 cd your-project # 创建项目级 skills 目录 mkdir -p .claude/skills # 创建第一个 skill mkdir -p .claude/skills/code-review touch .claude/skills/code-review/SKILL.md然后编辑SKILL.md填入 frontmatter 和正文。保存后重启 agent 会话让它重新扫描目录。Cursor 这边对应的是.cursor/rules目录规则文件用.mdc后缀头部也是 frontmatter可以指定globs和alwaysApply等字段。如果你想让某条规则在所有对话里都生效把alwaysApply设为 true如果只想在特定文件类型下生效用 globs 匹配。4.2 写一个能用的代码审查 skill完整示例下面是我实际在用的一个精简版代码审查 skill你可以直接抄去改--- name: code-review description: 对代码进行结构化审查。当用户说review 代码、检查代码质量、找 bug、看看这段逻辑时使用。仅用于已提交或已暂存的改动。 --- ## 执行步骤 1. 运行 git diff HEAD 获取当前改动如果无输出则运行 git diff --staged 2. 对每个改动文件按以下维度检查 - 错误处理是否有未捕获的异常、是否有静默失败 - 边界条件空值、越界、并发场景是否处理 - 安全性是否有硬编码密钥、SQL 拼接、路径穿越风险 - 可读性命名是否清晰、函数是否过长超过 50 行需提示 3. 输出格式 ## 审查结果 | 文件 | 行号 | 等级 | 问题描述 | 修改建议 | |------|------|------|----------|----------| 等级说明P0 必须修复 / P1 建议修复 / P2 可选优化 4. 最后给出总体评价一句话总结改动质量这个 skill 我用了大概两个月触发准确率挺高。关键在于 description 里塞了用户常用的几种说法正文步骤又足够具体agent 执行起来不会跑偏。4.3 参数计算与阈值选择skill 里经常要设一些阈值比如函数超过多少行算长、圈复杂度超过多少要警告。这些数字不是拍脑袋定的我一般参考几个来源一是团队既有规范。如果你们代码规范里写了函数不超过 80 行skill 里就写 80保持一致。二是行业惯例。圈复杂度 10 是个比较通用的警戒线超过 10 的函数测试成本会明显上升。三是实测调整。我一开始把函数长度阈值设成 30 行结果误报太多agent 天天提示这个函数太长反而没人看了。后来调到 50 行信噪比就合理了。提示阈值类参数建议写在 SKILL.md 顶部单独列出来方便调整。别散落在正文各处改起来容易漏。4.4 调试 skill 不生效的问题skill 写完不生效是最让人抓狂的情况。我的排查顺序是这样的第一步确认目录位置对不对。Claude Code 和 Cursor 的 skills 目录路径不一样放错了它根本扫不到。第二步检查 frontmatter 格式。YAML 对缩进极其敏感一个 tab 用错就解析失败。我建议用---包裹字段名和冒号之间不要有空格冒号后面留一个空格。第三步看 description 是否被正确索引。有些平台会打印加载的 skills 列表如果列表里没有你的 skill说明是解析问题如果有但不用说明是触发问题。第四步手动强制触发。在对话里直接说使用 code-review 技能看它能不能加载。能加载说明 skill 本身没问题是自动匹配的锅回去改 description。这套流程走下来九成问题都能定位。5. 常见问题与排查技巧实录5.1 高频问题速查表现象可能原因解决办法skill 完全不触发description 与用户表达不匹配补充口语化触发词触发但执行跑偏正文步骤不够具体拆成可核对的动作项引用文件读不到路径写错或未在正文指示用相对路径并在正文明确要求读取脚本执行失败权限不足或解释器不对chmod x明确写 bash/python多个 skill 冲突职责边界重叠重命名并明确排除场景输出格式不稳定未给输出模板在正文写死输出格式上下文被撑爆skill 正文过长拆分把细节移到引用文件5.2 我踩过的三个真实坑第一个坑是description 写成了功能说明书。我最早写的是本技能用于对代码进行全面的质量审查涵盖安全性、性能、可维护性等多个维度结果 agent 很少主动用它。后来改成当用户说 review、检查代码、找 bug 时使用触发率立刻上来了。教训就是description 是给匹配器看的不是给人看的。第二个坑是skill 之间互相打架。我同时有一个代码审查和一个重构建议的 skill两者都会在用户说看看这段代码时被触发agent 一会儿审查一会儿重构输出很乱。后来我把重构 skill 的 description 改成当用户明确要求重构、优化结构时使用并加了不用于单纯的问题检查冲突就消失了。第三个坑是过度依赖 skill 里的脚本。我写了个 skill 让它调用一个 Python 脚本做静态分析结果换台机器脚本依赖没装agent 执行失败后没有报错而是自己脑补了一份分析结果。这个最危险因为你看不出来它是真跑了还是编的。后来我在 skill 里加了一句如果脚本执行失败必须明确报告失败原因不得自行推断结果才堵住这个漏洞。5.3 让 skill 越用越顺的迭代方法skill 不是写完就完事的它需要迭代。我的做法是每次用完觉得这次输出不太对就顺手改一句 skill 正文。改的时候遵循一个原则把这次的失败案例变成一条明确的规则。比如有一次 agent 审查代码时漏掉了配置文件里的密钥我就在 skill 的检查维度里加了一条检查配置文件.env、config.*中是否有明文密钥。下次它就不会漏了。积累下来一个成熟的 skill 往往迭代过十几版正文里每一条规则背后都是一次真实的翻车。这也是为什么我建议你把 skills 放进 Git——每次修改都有记录能看出它是怎么一步步长起来的。5.4 跨平台迁移的注意事项如果你同时用 Claude Code 和 Cursor想把 skill 复用过去要注意两者的机制差异。Claude Code 的 skill 是语义触发Cursor 的 rule 更偏文件触发。直接复制过去往往效果打折。我的做法是维护一份技能源文档把核心规则写在一个中立的 Markdown 里然后针对不同平台各写一层适配。Claude Code 那边包成 SKILL.mdCursor 那边包成 .mdc 并配好 globs。核心逻辑只维护一份适配层很薄改起来不费劲。另外不同平台对 frontmatter 字段的支持也不一样。Claude Code 认 name 和 descriptionCursor 认 description、globs、alwaysApply。写的时候别把不支持的字段硬塞进去有些平台遇到未知字段会直接报错。6. 把 skills 用出复利一些个人体会我现在的习惯是每当我发现自己在对话里第三次解释同一件事就停下来把它写成一个 skill。这个触发条件很实用因为重复三次说明它是个高频需求值得沉淀。另一个体会是skill 的价值不在于多而在于准。我见过有人一口气写了三十个 skill结果 agent 每次加载索引都要花不少上下文真正用到的没几个。我现在项目里常驻的 skill 不超过八个每个都是反复打磨过的触发准、执行稳。还有一点skill 的正文尽量用短句和列表别写大段散文。agent 读列表的执行准确率明显高于读段落这一点在长 skill 里尤其明显。我甚至会把关键步骤编号因为编号能让 agent 按顺序执行不容易跳步。最后分享一个小技巧给 skill 加一个自检步骤。在正文最后写一句执行完成后确认以上每一步都已执行如有跳过需说明原因。这一句话能显著减少 agent 偷懒跳步的情况实测有效。