1. 从“每次都要重新教AI”说起:Agent-Skills到底在解决什么
如果你用AI Agent干过稍微复杂点的活,大概率经历过这种崩溃:昨天刚调教好的代码审查流程,今天开个新会话,它又变回那个只会说“好的,我来帮你看看”的客套机器。你不得不把项目规范、命名习惯、测试要求、提交格式再复述一遍,像极了每天早上都要重新给新员工做入职培训。
Agent-Skills要解决的就是这件事。它的核心思路非常朴素:把“你希望AI怎么干活”这件事,从每次对话里的临时指令,变成一份可复用、可版本管理、可被Agent自动加载的标准化文件。这个文件通常叫SKILL.md,放在约定的目录里,Agent在启动或执行特定任务时会主动读取它,然后按照里面定义的流程、约束和工具调用来工作。
说白了,它给AI装了一本“岗位操作手册”。你不再需要靠记忆和重复来维持AI的行为一致性,而是把工作方式沉淀成文档,让Agent每次上岗前先翻手册。
这套机制适合谁?三类人最该关注。第一类是重度使用AI编程助手的开发者,比如用Codex、Claude Code这类工具做日常开发的人,Skill能让代码风格和审查标准固定下来。第二类是需要AI执行重复性专业流程的从业者,比如测试工程师、数据分析师、专利检索人员,把固定套路写成Skill比每次写长提示词靠谱得多。第三类是想搭建多Agent协作系统的人,Skill是Agent之间传递“工作契约”的天然载体。
关键词里出现的SKILL.md、skill-creator、codex skill、agent skill,本质上都指向同一个东西:用结构化的Markdown文件来定义Agent的行为边界和操作流程。下面我会从文件结构、编写方法、加载机制、实战踩坑几个层面,把这件事讲透。
2. SKILL.md的文件结构:一份能被Agent读懂的操作手册长什么样
2.1 为什么是Markdown而不是JSON或YAML
很多人第一反应是:定义配置为什么不用JSON?答案在于Agent读Skill的方式和人读文档是一样的。大语言模型对Markdown的解析能力远强于对嵌套JSON的理解,尤其是当Skill里需要包含自然语言的判断逻辑、示例、边界说明时,Markdown的段落和列表结构更接近模型的训练分布。
JSON适合传参数,Markdown适合传意图。Skill要传递的是“在什么情况下做什么、为什么这么做、做到什么程度算完成”,这些内容用JSON写会变成一堆难以维护的字符串拼接,用Markdown写则天然清晰。
2.2 一个可用的SKILL.md骨架
下面是我在实际项目中反复调整后沉淀下来的结构,你可以直接拿去改:
# Skill: 代码审查助手 ## 触发条件 当用户提交代码diff或要求review时激活。 ## 前置检查 - 确认diff非空 - 确认目标分支为feature/*或hotfix/* - 若diff超过500行,先要求拆分 ## 执行流程 1. 逐文件读取变更,标注新增/修改/删除 2. 按以下优先级检查: - 安全漏洞(硬编码密钥、SQL拼接) - 逻辑错误(边界条件、空指针) - 性能问题(N+1查询、无索引扫描) - 风格问题(命名、注释缺失) 3. 每个问题给出:文件:行号、问题描述、修复建议、严重等级 ## 输出格式 使用表格汇总,严重等级用P0/P1/P2标注。 ## 禁止事项 - 不修改代码,只提建议 - 不对未变更的文件发表意见 - 不评价业务逻辑合理性这个骨架的关键在于:触发条件让Agent知道什么时候该用这个Skill,执行流程让它知道按什么顺序做,禁止事项划定了行为边界。三者缺一不可。
2.3 触发条件的写法直接决定Skill会不会被误用
我见过最常见的翻车场景是:Skill写得很详细,但触发条件写得太宽泛,导致Agent在不相干的场景下也加载它。比如写“当用户提到代码时激活”,结果用户只是问“Python和Java有什么区别”,Agent也把代码审查Skill拉出来跑一遍。
触发条件要具体到动作+对象+上下文。对比一下:
| 写法 | 问题 | 改进 |
|---|---|---|
| 用户提到代码 | 太宽泛 | 用户提交diff并要求审查 |
| 处理数据时 | 模糊 | 用户上传CSV并要求清洗或分析 |
| 写文档 | 不明确 | 用户要求生成API文档且提供了接口定义 |
触发条件本质上是给Agent一个判断依据,让它自己决定“这个Skill现在该不该上场”。写得太松,Agent会过度触发;写得太紧,该用的时候用不上。
2.4 执行流程要写成“可执行步骤”而不是“原则性描述”
另一个高频错误是把执行流程写成价值观宣言。比如“仔细检查代码质量”“确保输出准确”——这种话对Agent没有任何指导意义,它本来就会说自己会仔细。
有效的执行流程必须是可操作、可验证、有顺序的。每一步都应该能让Agent判断“我做完这一步了吗”。比如“逐文件读取变更”比“理解代码变更”好,因为前者有明确的完成标志,后者没有。
我在写流程时有个习惯:每写一步就问自己,如果让一个新人照着做,他能不能不追问就执行下去。如果不能,说明这步还不够具体。
3. 用skill-creator把重复劳动变成可复用资产
3.1 skill-creator的工作逻辑
skill-creator这类工具的核心价值不是帮你写Markdown,而是帮你从已有的对话记录或操作日志中提取出可复用的模式。它的典型工作方式是:你给它一段你和Agent的完整交互记录,它分析出其中的重复步骤、固定约束、输出格式要求,然后生成一份SKILL.md草稿。
这比从零手写高效得多,因为很多工作方式你自己都没意识到是“可沉淀的”。比如你可能每次都会要求Agent“先列大纲再写正文”“代码块要标注语言”“不要用‘总之’开头”,这些散落在对话里的约束,skill-creator能帮你归拢成一份正式Skill。
3.2 从对话记录到Skill的提取过程
假设你有一段和Agent协作写技术文档的对话,里面你反复做了这些事:要求先确认读者背景、要求每个概念配一个生活类比、要求代码示例必须能直接运行、要求结尾不要总结。skill-creator会把这些提取成:
# Skill: 技术文档写作 ## 触发条件 用户要求撰写面向特定读者的技术说明文档。 ## 前置确认 - 读者技术背景(新手/有经验/专家) - 文档用途(教程/参考/决策依据) - 篇幅预期 ## 写作约束 - 每个核心概念必须配生活化类比 - 代码示例必须可直接运行,标注语言类型 - 禁止使用“总之”“综上所述”等总结性开头 - 段落不超过6行 ## 输出结构 按“问题场景→核心概念→操作步骤→常见错误”组织。这个过程的关键是你要提供足够多的交互样本。只给一两轮对话,提取出来的Skill会很单薄;给十轮以上,模式才会稳定浮现。
3.3 手动打磨比自动生成更重要
skill-creator生成的草稿只能算半成品。我实测下来的经验是:自动提取能覆盖70%的显性约束,但剩下30%的隐性判断需要手动补。比如“什么时候该追问用户”“遇到矛盾需求时怎么取舍”“输出长度怎么控制”,这些决策逻辑很难从对话记录里自动归纳,需要你自己想清楚后写进去。
我的做法是:先用skill-creator生成初稿,然后拿三个真实任务去测试。如果Agent在执行时出现犹豫、跑偏、或者反复确认,就说明Skill里缺少对应的判断规则,补上再测。通常迭代三轮左右,Skill就能稳定工作。
3.4 Skill的版本管理容易被忽略
Skill一旦开始被多个Agent或多个项目引用,就需要版本管理。我建议把SKILL.md放在Git仓库里,每次修改都走commit,并在文件头部加一个版本号和变更说明:
<!-- version: 1.3 --> <!-- changelog: 增加对TypeScript项目的类型检查规则 -->这样做的好处是,当Agent行为出现异常时,你可以快速定位是不是某次Skill修改导致的。没有版本管理的Skill,改着改着就变成一锅粥,最后没人敢动。
4. Agent加载Skill的机制与多Skill协作的冲突处理
4.1 Agent是怎么“看到”Skill的
不同平台的加载机制有差异,但核心逻辑大同小异:Agent在启动时会扫描指定目录下的SKILL.md文件,把内容读入上下文,然后在后续对话中根据触发条件判断是否激活某个Skill。
这里有个关键细节:Skill内容会占用上下文窗口。如果你放了二十个Skill,每个两千字,那就是四万字的固定开销,还没开始干活上下文就满了。所以Skill不是越多越好,而是要精简、合并、按需加载。
我通常把Skill分成两类:常驻Skill(比如代码规范、输出格式)放在默认加载目录,按需Skill(比如特定框架的迁移指南)放在子目录,由Agent根据任务类型主动请求加载。
4.2 多个Skill同时触发时的优先级问题
这是实际使用中最容易出乱子的地方。假设你有一个“代码审查Skill”和一个“安全审计Skill”,用户提交了一段涉及加密操作的代码,两个Skill都满足触发条件,Agent该听谁的?
我的处理方案是在Skill里显式定义优先级和互斥关系:
## 优先级 本Skill优先级为P1。当与安全审计Skill同时触发时, 先执行安全审计,再执行本Skill的常规检查。 ## 互斥 本Skill与“快速原型Skill”互斥,若用户明确要求快速验证, 则跳过本Skill的完整流程。这种显式声明比让Agent自己“权衡”靠谱得多。模型在多个指令冲突时,行为是不确定的,你不把规则写死,它就会随机选一个。
4.3 Skill之间的数据传递
多Skill协作时,上一个Skill的输出往往要作为下一个Skill的输入。比如“需求分析Skill”输出的用户故事,要传给“测试用例生成Skill”。这时候需要在Skill里定义清楚输出格式和接口约定。
我的做法是在Skill末尾加一个“输出契约”段落:
## 输出契约 输出必须为JSON格式,包含以下字段: - stories: 数组,每个元素含id、title、acceptance_criteria - priority: P0/P1/P2 - dependencies: 依赖的其他故事id列表下一个Skill在触发条件里写明“当接收到符合上述契约的JSON时激活”,这样两个Skill就能串起来。没有契约的Skill协作,基本靠运气。
4.4 加载失败的常见原因
Agent没按预期加载Skill,通常逃不出这几个原因:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| Skill完全不生效 | 文件路径不对或文件名不是SKILL.md | 检查目录结构和大小写 |
| 偶尔生效偶尔不生效 | 触发条件太模糊,模型判断不稳定 | 收紧触发条件,加具体关键词 |
| 生效但行为不对 | Skill内容有歧义或自相矛盾 | 逐段读,找冲突表述 |
| 多个Skill打架 | 缺少优先级声明 | 加优先级和互斥规则 |
我踩过最坑的一次是文件名写成了skill.md(小写),在某些区分大小写的系统上直接不加载,排查了半天才发现。这种低级错误建议一开始就用脚本校验。
5. 实战中那些文档不会告诉你的坑
5.1 Skill写得太细反而会限制Agent的判断力
新手容易犯的错是把Skill写成流水线作业指导书,每一步都规定死。比如“第一步输出A,第二步输出B,第三步输出C”。结果遇到稍微不同的输入,Agent就卡住了,因为它不知道该不该变通。
好的Skill应该在关键决策点给规则,在执行细节给空间。比如“必须检查安全漏洞”是规则,“用什么方式检查”可以留给Agent自己选。我通常会在Skill里加一句“在不违反上述约束的前提下,可根据实际情况调整执行顺序”,给模型留一点自主权。
5.2 中文Skill的编码问题
关键词里出现了skill编码193、skill编码247这类词,我理解是指Skill文件的字符编码。这里有个实际坑:如果SKILL.md里包含中文,务必确保文件是UTF-8编码,且Agent的读取环境也支持UTF-8。我遇到过在Windows环境下用GBK保存,Agent读出来全是乱码,触发条件完全匹配不上。
建议在文件头部加一个编码声明,或者在团队内统一规定所有Skill文件必须UTF-8无BOM。这个细节很小,但出问题时很难排查。
5.3 测试Skill是否生效的最小验证方法
写完一个Skill,不要直接上复杂任务测试。用一个最小可验证案例先跑通:构造一个明确满足触发条件的输入,看Agent是否按Skill定义的流程执行。比如代码审查Skill,就提交一个只有三行、包含一个明显问题的diff,看它能不能按格式输出。
最小验证通过后,再逐步增加复杂度:多文件diff、边界情况、冲突Skill同时触发。这样出问题时你能快速定位是Skill本身的问题还是任务复杂度的问题。
5.4 Skill的维护成本被严重低估
一个Skill写出来只是开始,后续的维护才是大头。项目规范变了、工具升级了、团队约定调整了,Skill都得跟着改。如果Skill数量多,维护成本会指数级上升。
我的建议是:控制Skill总数,优先合并同类项。比如“Python代码审查”和“Java代码审查”可以合并成一个“代码审查Skill”,用条件分支处理不同语言。Skill数量控制在十个以内,维护起来才可持续。
5.5 不要用Skill做它不擅长的事
Skill擅长的是固定流程、明确约束、可复用模式。它不擅长的是需要实时判断、依赖外部状态、高度依赖上下文的任务。比如“根据用户情绪调整回复语气”这种事,写成Skill效果很差,因为情绪判断本身就不稳定,写死的规则反而会让回复变得机械。
判断一个任务该不该做成Skill,我的标准是:如果这个任务你每次都要跟Agent说同样的话,那就值得做成Skill;如果每次说的话都不一样,那就不值得。
6. 从单Skill到Skill体系:让AI真正记住你的工作方式
6.1 个人Skill库的搭建思路
当你有了三五个稳定可用的Skill之后,就该考虑体系化的问题了。我的做法是按领域分目录,按使用频率分加载层级:
skills/ ├── core/ # 常驻加载 │ ├── output-format/SKILL.md │ └── code-style/SKILL.md ├── dev/ # 开发时按需加载 │ ├── code-review/SKILL.md │ └── test-gen/SKILL.md ├── docs/ # 写文档时加载 │ └── tech-writing/SKILL.md └── domain/ # 特定领域任务加载 └── patent-search/SKILL.md这样组织的好处是,Agent可以根据当前任务类型只加载相关目录,避免上下文被无关Skill占满。
6.2 Skill与提示词的边界
很多人会混淆Skill和系统提示词。简单区分:系统提示词定义Agent的身份和通用行为准则,Skill定义具体任务的执行方式。系统提示词说“你是一个严谨的工程师”,Skill说“审查代码时按P0/P1/P2分级并输出表格”。
两者配合使用效果最好。系统提示词给基调,Skill给具体操作。不要把什么都塞进Skill,也不要把具体流程写进系统提示词。
6.3 团队协作中的Skill共享
如果是团队使用,Skill需要有一个共享机制。我们团队的做法是建一个Git仓库专门放Skill,每个人可以提交PR修改,合并前需要至少一个人review。review的重点是:触发条件是否清晰、执行流程是否可操作、有没有和现有Skill冲突。
另外,团队Skill要有一个“负责人”制度,每个Skill指定一个人负责维护,避免出现“大家都觉得该改但没人改”的情况。
6.4 持续迭代:把每次踩坑都变成Skill的更新
最后分享一个我坚持了很久的习惯:每次Agent行为不符合预期时,不要只在对话里纠正它,而是回头看看Skill里缺了什么规则,补进去。这样你的Skill库会随着使用越来越完善,Agent也会越来越“懂你”。
比如有一次Agent在生成测试用例时漏掉了异常分支,我没有只是说“你漏了异常情况”,而是打开测试生成Skill,在检查清单里加了一条“必须覆盖正常、边界、异常三类输入”。下次它就不会再漏了。
这个习惯的长期回报非常高。半年下来,我的Skill库已经覆盖了日常工作中80%的重复性任务,新开一个会话,Agent基本能直接进入工作状态,不需要我再做“入职培训”。
提示:Skill的价值不在于写得多漂亮,而在于能不能稳定地让Agent按你的方式工作。先跑通一个最小Skill,再逐步扩展,比一上来就设计完美体系要务实得多。