Agent Skills实战:从零构建AI编程助手的技能包
1. 从“skills”这个标题说起它到底指什么“skills”这个词单独拎出来看信息量其实很低。但把它放进当前的技术语境里尤其是和 Claude Code、Codex、agents、plugin 这些词放在一起的时候它指向的东西就非常明确了——Agent Skills也就是给 AI 编程助手加装的“技能包”。你可以把它理解成给一个刚入职的实习生配的一套标准化操作手册。这个实习生脑子很聪明但对你项目里的构建流程、代码规范、部署方式一无所知。你当然可以每次口头交代一遍但更高效的做法是写一份 SOP 放在他桌上他遇到对应场景就翻对应的手册。Agent Skills 干的就是这件事把重复性的、有固定套路的任务封装成 AI 助手可以自动识别并执行的技能模块。我最初接触这个概念的时候第一反应是“这不就是 prompt 模板吗”。实际用下来发现差别很大。Prompt 模板是你每次手动粘贴一段话而 Skills 是放在特定目录下、带有元数据描述、能被 Agent 主动发现和调用的结构化文件。它更像是一个插件系统而不是一段文本。目前围绕 Skills 的生态主要分几个层面一是 Anthropic 官方为 Claude Code 定义的 Skills 规范二是 OpenAI Codex 体系下的类似机制三是社区自发贡献的各种 Skills 仓库。这三者格式不完全一样但核心思路是相通的——用声明式的文件描述“什么情况下该做什么”让 Agent 自主决策调用。适合读这篇内容的人大概有三类第一类是已经在用 Claude Code 或 Codex 做日常开发的工程师想把手头的重复劳动自动化掉第二类是团队里负责工程效率的同学想给团队统一一套 AI 辅助规范第三类是对 Agent 架构感兴趣、想自己动手写 Skills 的开发者。不管你属于哪一类下面的内容都会从“为什么这么设计”讲到“具体怎么写、怎么调、怎么排错”。2. Skills 的整体设计与核心思路拆解2.1 为什么不是简单的 prompt而是独立文件很多人第一次接触 Skills 会有疑问我直接在对话里把要求说清楚不就行了为什么要单独搞一个文件体系这个问题的答案藏在“复用”和“发现”这两个词里。先说复用。你在一个项目里可能反复需要做同一件事比如“按照项目的 ESLint 配置检查并修复代码风格问题”。如果每次都在对话里重新描述一遍规则一是费 token二是容易漏掉细节三是不同的人描述方式不一样结果就不稳定。把它写成一个 Skill 文件之后规则是固定的任何人任何时间调用行为都一致。再说发现。Agent 在执行任务时会扫描可用的 Skills 列表根据当前上下文判断该不该调用某个 Skill。这个“判断”过程依赖的是 Skill 文件里的描述信息。如果你的描述写得清楚——“当用户要求修复代码风格问题时使用此技能”——Agent 就能在合适的时机自动触发。这是 prompt 模板做不到的因为 prompt 模板需要你主动想起来去用它。从架构上看一个 Skill 通常包含几个部分名称和描述用于被 Agent 发现、触发条件什么场景下激活、具体指令激活后执行什么操作、以及可选的辅助资源脚本、模板、参考文档。这个结构和传统的插件系统非常像区别在于插件的调用逻辑是代码写死的而 Skill 的调用逻辑是交给模型判断的。2.2 Claude Code 与 Codex 两套体系的差异目前市面上最主流的两套 Skills 实现分别来自 Claude Code 和 Codex。它们的设计哲学有细微但重要的差别选哪套取决于你的工作流。Claude Code 的 Skills 体系更偏向“文件系统驱动”。它约定了一个特定的目录结构比如.claude/skills/下面放各个技能的文件夹每个文件夹里有一个SKILL.md作为入口。这种设计的好处是直观你打开文件管理器就能看到所有技能增删改查都很方便。缺点是它和 Claude Code 这个工具绑定得比较紧迁移到其他环境需要做适配。Codex 这边的思路更偏向“配置驱动”。Skills 的定义往往和项目的配置文件结合在一起通过声明式的方式注册。这种方式在团队协作时更规范但对个人开发者来说上手门槛稍高一些因为你需要理解它的配置层级和继承关系。我个人的建议是如果你主要用 Claude Code 做日常开发先从它的 Skills 体系入手因为社区资源最多遇到问题好搜。如果你所在的团队已经在用 Codex 做统一的 AI 辅助开发那就跟着团队的规范走不要自己另起炉灶否则后期合并会很痛苦。2.3 一个 Skill 的生命周期理解 Skill 的生命周期有助于你在写的时候想清楚每个环节该注意什么。一个 Skill 从诞生到退役大致经历这几个阶段编写阶段你确定了一个需要自动化的场景开始写 Skill 文件。这个阶段最关键的是把触发条件写清楚太宽泛会导致误触发太窄又会导致该触发的时候不触发。注册阶段把写好的 Skill 放到约定的目录下或者在配置文件里注册。不同工具的注册方式不一样Claude Code 通常是放到目录里就自动识别Codex 可能需要在配置里显式声明。发现阶段Agent 在运行时扫描可用 Skills把名称和描述加载到上下文里。这个阶段要注意的是描述信息的长度太长会占用宝贵的上下文窗口太短又不足以让模型做出准确判断。调用阶段Agent 判断当前任务匹配某个 Skill读取完整的 Skill 内容并执行。这个阶段最常见的问题是 Skill 内部的指令有歧义导致执行结果不符合预期。迭代阶段用了一段时间之后你发现某些场景下 Skill 表现不好回来修改描述或指令。这是最容易被忽略的阶段但恰恰是让 Skills 越用越好用的关键。3. 核心细节解析与实操要点3.1 Skill 文件的目录结构与命名规范先看一个典型的 Claude Code Skills 目录结构这是我在多个项目里实际用下来比较顺手的组织方式项目根目录/ ├── .claude/ │ └── skills/ │ ├── code-review/ │ │ ├── SKILL.md │ │ └── references/ │ │ └── checklist.md │ ├── deploy-check/ │ │ ├── SKILL.md │ │ └── scripts/ │ │ └── verify.sh │ └── api-doc-gen/ │ └── SKILL.md每个技能一个文件夹文件夹名就是技能名用短横线连接的小写字母。这个命名习惯不是强制的但强烈建议遵守因为很多工具在解析时会做名称匹配大小写混用或者用下划线容易出问题。SKILL.md是入口文件必须存在。references/和scripts/是可选的辅助目录分别放参考文档和可执行脚本。我试过把参考文档直接写在SKILL.md里结果文件变得很长Agent 每次加载都要消耗大量 token。拆出来之后只在需要的时候读取效率高很多。注意目录名不要用中文或特殊字符。我踩过一次坑用中文命名了一个技能文件夹结果在某些终端环境下路径解析出错Agent 根本发现不了这个技能。后来全部改成英文小写加短横线再没出过问题。3.2 SKILL.md 的元数据怎么写才有效SKILL.md的开头通常有一段元数据区域用 YAML 格式写。这部分决定了 Agent 能不能在合适的时机发现你的技能。以我写的一个代码审查技能为例--- name: code-review description: 当用户要求审查代码质量、检查潜在 bug、或对某段代码提出改进建议时使用此技能。适用于 Python、JavaScript、TypeScript 项目。 ---这里name和description是两个最关键的字段。name要简短且唯一description要同时说清楚“什么时候用”和“用来干什么”。我见过很多人把description写成“这是一个代码审查技能”这种写法几乎没用因为 Agent 无法从中判断触发时机。好的描述应该包含触发场景的关键词比如“审查代码”“检查 bug”“改进建议”这样当用户的请求里出现类似表述时模型才能匹配上。还有一个细节description里不要写太泛的词比如“帮助用户”。这种词几乎出现在所有技能描述里等于没有区分度。要写具体的、有辨识度的场景词。3.3 指令部分的写法从模糊到精确元数据之后就是技能的具体指令。这部分是真正干活的地方写法直接决定执行效果。我的经验是把 Agent 当成一个聪明但对你项目一无所知的新人你需要交代的细节比你想象的多。举个例子我写过一个“生成 API 文档”的技能。最初的版本只写了一句“根据代码生成 API 文档”结果 Agent 生成出来的格式每次都不一样有时候用 Markdown 表格有时候用列表字段顺序也乱。后来我改成了这样## 执行步骤 1. 扫描 src/api/ 目录下所有以 .ts 结尾的文件 2. 对每个文件提取导出的函数和类型定义 3. 按照以下格式生成文档 - 函数名作为三级标题 - 参数列表用表格展示包含参数名、类型、是否必填、说明 - 返回值单独一段说明 4. 所有文档汇总到一个 API.md 文件中按文件路径排序改完之后输出就稳定了。这里的关键是把“做什么”拆解成“第一步做什么、第二步做什么”并且给出明确的格式要求。Agent 不需要你教它怎么思考但它需要你告诉它最终的产出长什么样。实操心得指令里尽量用“必须”“禁止”这样的强约束词少用“可以”“建议”。模型对强约束词的遵循度明显更高。比如“必须使用 TypeScript 严格模式”比“建议使用 TypeScript 严格模式”的执行率高很多。3.4 辅助资源的使用时机不是所有技能都需要辅助资源。判断标准很简单如果某部分内容只在特定情况下才需要就拆出去如果每次执行都要用到就留在SKILL.md里。references/目录适合放那些“查阅型”的内容比如代码规范清单、API 参考、常见错误对照表。Agent 在执行技能时如果判断需要参考这些内容会主动去读取。这样避免了每次加载技能都带上大段无关文本。scripts/目录适合放确定性的操作比如文件校验、格式转换、环境检查。这些操作用脚本执行比让模型生成代码再执行更可靠也更省 token。我通常会把脚本的调用方式写在SKILL.md里比如“执行scripts/verify.sh并检查退出码”。4. 实操过程与核心环节实现4.1 环境准备Claude Code 的安装与配置在写 Skills 之前得先把运行环境搭起来。Claude Code 的安装方式根据操作系统不同有差异下面是我在 Ubuntu 和 Windows 上分别试过的流程。Ubuntu 环境下推荐用官方提供的安装脚本。打开终端执行curl -fsSL https://claude.ai/install.sh | sh安装完成后需要配置 API 密钥。官方的方式是设置环境变量export ANTHROPIC_API_KEY你的密钥把这行加到~/.bashrc或~/.zshrc里避免每次开终端都要重新设置。如果你用的是第三方接入方式配置项会有所不同具体参考对应服务的文档。Windows 环境下如果你用的是 WSL流程和 Ubuntu 一样。如果直接用 Windows 桌面版下载安装包之后按向导走就行。需要注意的是Windows 下路径分隔符是反斜杠而 Skills 目录结构里用的是正斜杠配置的时候要留意。VS Code 用户可以直接装 Claude Code 的扩展装完之后在设置里填入 API 密钥然后在项目根目录创建.claude/skills/目录扩展会自动识别。注意国内网络环境下安装过程可能会遇到连接问题。我的经验是提前配置好镜像源或者使用代理工具此处指网络请求转发工具非其他用途具体配置方式参考你所使用工具的官方文档。不要在网上随便找来源不明的配置容易出安全问题。4.2 从零写一个可用的 Skill以“提交前检查”为例下面用一个完整的例子走一遍流程。场景是每次 git commit 之前自动检查代码风格、运行单元测试、确认没有调试代码残留。这个场景足够典型几乎每个项目都用得上。第一步创建目录mkdir -p .claude/skills/pre-commit-check第二步写SKILL.md--- name: pre-commit-check description: 当用户要求提交代码、执行 git commit、或检查提交前准备情况时使用此技能。适用于所有包含 package.json 的 JavaScript/TypeScript 项目。 --- ## 执行步骤 1. 检查是否存在未暂存的更改如果有提示用户先暂存 2. 运行 npm run lint如果失败输出错误详情并终止 3. 运行 npm run test如果失败输出失败用例并终止 4. 搜索暂存文件中是否包含 console.log、debugger、TODO 等标记 5. 如果以上全部通过输出“检查通过可以提交” ## 禁止事项 - 禁止自动执行 git commit只做检查 - 禁止修改任何源代码文件 - 如果 lint 或 test 命令不存在跳过对应步骤并提示用户第三步测试。在 Claude Code 里输入“帮我检查一下能不能提交”观察它是否自动调用了这个技能。如果没有触发检查description里的关键词是否和你的输入匹配。这个技能我用了大半年中间迭代过几次。最初的版本没有“禁止自动提交”这一条结果有一次 Agent 检查完之后直接帮我 commit 了虽然没造成什么损失但吓了我一跳。加上禁止事项之后就安全了。4.3 参数计算与条件判断的处理有些技能需要根据输入参数做不同处理。比如一个“生成组件”的技能用户可能指定组件类型函数组件还是类组件、是否带样式文件、是否带测试文件。这种场景下指令里要写清楚判断逻辑。我的写法是在SKILL.md里定义一个参数表参数名类型默认值说明name字符串无必填组件名称大驼峰type枚举functionfunction 或 classwithStyle布尔true是否生成样式文件withTest布尔false是否生成测试文件然后在指令里写“根据用户输入解析参数未提供的使用默认值。根据 type 的值选择对应的模板。”这样 Agent 就知道该怎么处理了。这里有个细节枚举类型的参数要把所有可选值列出来不要让模型自己猜。我试过只写“type 可以是函数组件或类组件”结果模型有时候生成functional有时候生成func导致后续判断出错。明确列出function和class之后就稳定了。4.4 多技能协作与优先级处理当项目里技能多了之后会出现一个任务匹配多个技能的情况。比如用户说“帮我审查代码然后提交”这同时匹配了code-review和pre-commit-check两个技能。这时候 Agent 怎么决定调用顺序目前的机制下Agent 会根据技能的描述和当前上下文做判断但这个判断不总是符合你的预期。我的做法是在技能描述里加入优先级提示比如在pre-commit-check的描述里加一句“此技能应在代码审查完成之后使用”。这样模型在规划步骤时会把顺序考虑进去。另一个做法是写一个“组合技能”把多个技能的调用逻辑串起来。比如创建一个review-and-commit技能指令里明确写“先执行 code-review 的步骤再执行 pre-commit-check 的步骤”。这种方式更可控但灵活性差一些适合流程固定的场景。5. 常见问题与排查技巧实录5.1 技能不触发怎么办这是最常见的问题。你写了一个技能但 Agent 在执行任务时就是不调用它。排查思路按以下顺序来第一检查目录位置。Claude Code 默认扫描项目根目录下的.claude/skills/如果你放到了其他位置它发现不了。确认一下路径是否正确。第二检查文件格式。SKILL.md的元数据必须是合法的 YAML开头的---和结尾的---都不能少。我遇到过因为缩进用了 Tab 而不是空格导致解析失败的情况排查了半天。第三检查描述关键词。把你平时触发这个技能时会说的话和description里的词对比一下。如果差异太大模型匹配不上。比如你描述里写的是“代码审查”但你平时说的是“帮我看下代码有没有问题”那就要把“看代码”“有没有问题”这些词也加进去。第四检查技能数量。如果一个项目里技能太多模型在发现阶段可能因为上下文限制而忽略部分技能。我的经验是单个项目控制在 10 个技能以内超过的话考虑合并或分层。5.2 技能触发了但执行结果不对这种情况通常是指令写得太模糊。排查方法是在技能执行后检查 Agent 的实际操作步骤和你在SKILL.md里写的步骤做对比看它在哪一步偏离了。常见的偏离原因有几个一是指令里有歧义比如“检查代码质量”这种说法不同模型理解不一样二是缺少边界条件比如没说明遇到错误时该怎么办三是格式要求不明确导致输出格式随机。解决办法就是前面说的把步骤拆细把格式写死把异常情况覆盖到。宁可写得啰嗦也不要留模糊空间。5.3 常见问题速查表问题现象可能原因排查方法解决方式技能完全不触发目录位置错误确认.claude/skills/路径移动到正确目录技能完全不触发YAML 格式错误用在线 YAML 校验工具检查修正缩进和符号技能完全不触发描述关键词不匹配对比用户输入和 description补充同义词触发后执行偏离指令有歧义对比实际步骤和预期步骤拆细步骤明确格式触发后执行偏离缺少异常处理检查是否有边界条件说明补充异常分支多个技能冲突优先级不明确观察调用顺序在描述里加优先级提示执行速度慢技能内容过长检查 SKILL.md 行数拆分到 references输出格式不稳定格式要求不具体检查是否有格式模板给出明确的输出示例5.4 几个我踩过的坑第一个坑是在技能里写了太多背景知识。我一开始写技能恨不得把整个项目的架构都塞进去结果SKILL.md写了五百多行加载慢不说模型还经常抓不住重点。后来学乖了技能只写“怎么做”背景知识放到references/里需要的时候再读。第二个坑是用技能做本该用脚本做的事。比如格式化代码这种确定性操作让模型生成格式化命令再执行不如直接写个脚本调用。模型适合做判断和生成不适合做重复性的确定性操作。第三个坑是忽略了技能的维护成本。技能写多了之后项目结构一变很多技能就失效了。我现在养成的习惯是每个季度过一遍所有技能把不再使用的删掉把需要更新的改掉。技能库和代码库一样需要定期清理。第四个坑是在技能里硬编码路径。我写过一个技能里面写死了src/components/这个路径后来项目重构组件移到了src/ui/components/技能就失效了。现在我会在技能开头加一步“确认项目目录结构”或者用相对路径加通配符。6. 技能库的扩展与团队协作6.1 从个人技能到团队规范个人用 Skills 和团队用 Skills考虑的东西完全不一样。个人用的时候你怎么顺手怎么来命名不规范、描述写得随意只要自己能触发就行。但团队用的时候这些都会变成问题。我们团队的做法是建立一个共享的技能仓库所有人写的技能都提交到这里经过 review 之后合并。Review 的重点是描述是否清晰、指令是否有歧义、是否和已有技能重复、是否包含敏感信息。合并之后每个人通过 git submodule 或者包管理工具同步到自己的项目里。这样做的好处是技能质量有保障坏处是流程变长了。对于快速试验性的技能我们允许个人先放在自己的.claude/skills/里用用顺了再提交到共享仓库。6.2 技能的分层组织当技能数量超过二十个之后平铺在一个目录里就很难管理了。我们按功能域做了分层.claude/skills/ ├── code-quality/ │ ├── lint-check/ │ ├── code-review/ │ └── test-coverage/ ├── deployment/ │ ├── pre-commit-check/ │ ├── build-verify/ │ └── release-notes/ └── documentation/ ├── api-doc-gen/ └── changelog-gen/这样组织之后找技能方便了权限控制也好做了。比如部署相关的技能只对特定角色开放代码质量相关的所有人可用。6.3 技能的版本管理技能也是代码应该纳入版本管理。我们用的是和项目代码一样的 git 流程每个技能一个分支改完之后提 PRreview 通过后合并。技能文件里会记录一个版本号方便追溯。版本号我建议用语义化版本比如1.2.0。主版本号在技能行为发生不兼容变化时递增次版本号在增加功能时递增修订号在修复问题时递增。这样团队成员在同步技能时能清楚知道这次更新会不会影响自己的使用。6.4 技能的效果度量怎么知道一个技能写得好不好我们用了几个简单的指标触发成功率该触发的时候触发了吗、执行准确率执行结果符合预期吗、使用频率有多少人在用。这些数据通过日志收集每个月看一次。触发成功率低的技能通常是描述写得不好执行准确率低的通常是指令有歧义使用频率低的可能是场景太窄或者有更好的替代方案。根据这些指标做针对性优化比凭感觉改要有效得多。7. 一些关于 Skills 生态的观察Skills 这个方向目前还在快速演进中。Claude Code 和 Codex 两套体系各有拥趸社区里也有不少人在做跨平台的适配层。我的判断是短期内不会出现统一的标准但核心概念——用结构化文件描述可复用的 Agent 行为——会稳定下来。对于开发者来说现在投入时间学 Skills 是划算的。即使将来换工具这套思维方式是通用的怎么把一个模糊的需求拆解成明确的步骤怎么让 AI 理解你的意图怎么设计可复用的自动化流程。这些能力不会因为工具变化而贬值。我目前的做法是保持关注但不追新。核心技能库稳定在十几个覆盖日常开发的主要场景。新出的工具和规范会看但不会立刻迁移等生态稳定一些再说。毕竟工具是拿来用的不是拿来折腾的。最后分享一个我最近在用的技巧把技能当成“给未来的自己写的备忘录”。你现在花十分钟写清楚一个技能三个月后你忘了当时的上下文但技能还在Agent 还能按你当初的意图执行。这个投入产出比比大多数效率工具都高。