1. 从"skills"这个模糊词说起:它到底指什么
第一次看到"skills"这个标题,加上项目正文和关键词都是空的,我其实是有点懵的。但结合热搜词里那一串——Agent Skills、Google Cloud、GKE、Genkit、claude agent skills、codex skills、skills开发、skills安装——基本可以锁定,这里说的不是泛泛的"技能"概念,而是围绕 AI Agent 的能力扩展机制,也就是给智能体"装技能"这件事。
打个比方。一个刚出厂的大模型,就像一个刚毕业的高材生,脑子好使,但没上过班。你让它写代码它能写,你让它查资料它能查,可一旦涉及"我们公司内部这套流程怎么走""这个特定工具怎么调""遇到这种报错该按什么顺序排查",它就抓瞎了。Agent Skills 要解决的,就是把这个"高材生"变成"熟练工"的问题——把特定领域的操作流程、工具调用方式、判断规则,打包成一个个可复用的"技能包",让 Agent 按需加载。
这套思路最近为什么火?因为大家发现,单纯堆参数、堆上下文,效果是有天花板的。你把一万字的操作手册塞进 prompt,模型可能只记住前两千字,中间还容易串味。而 Skills 的思路是按需加载、模块化组织:平时不占上下文,用到哪个技能就调哪个,用完就释放。这跟人脑的工作方式很像——你不需要时刻记住所有会的技能,只在需要拧螺丝的时候才想起"哦我会用螺丝刀"。
这篇文章我打算把"skills"这件事从头到尾拆一遍:它背后的核心机制是什么、一个技能包到底长什么样、怎么从零开发一个能用的 skill、装完之后怎么测试、以及我在实际折腾过程中踩过的那些坑。不管你是刚听说这个词想入门,还是已经写过几个 skill 但总觉得哪里不对,应该都能捞到点东西。
提示:本文讨论的 skills 特指 AI Agent 的能力扩展单元,不涉及任何其他含义。如果你搜到的是别的领域的内容,那可能不是同一回事。
2. 拆开一个 Skill 看内部:它凭什么能让 Agent 变聪明
2.1 Skill 的本质是一份"给模型看的说明书"
很多人第一次接触 skills,会以为它是什么高深的代码框架。其实剥开外壳,一个 skill 的核心就是一份结构化的说明文档,外加可选的辅助资源。它告诉模型三件事:这个技能是干什么的、什么时候该用它、具体怎么操作。
你可以把它理解成给新员工写的 SOP(标准作业程序)。一份好的 SOP 不会写"你要认真工作"这种废话,而是写"客户投诉时,先记录工单号,再查订单状态,如果超过 48 小时未发货,走加急流程"。Skill 也是这个逻辑——它把模糊的"你看着办"变成明确的"第一步做什么、第二步做什么、遇到什么情况走什么分支"。
那它和普通的 prompt 有什么区别?区别在于组织方式和加载时机。普通 prompt 是你每次对话都得把全部指令塞进去,又长又费 token。而 skill 是独立存放的,模型在判断"当前任务需要这个技能"时才把它读进来。这就好比你不会每天上班都背一遍员工手册,但需要报销的时候会去翻"报销流程"那一章。
2.2 元数据、指令、资源:三层结构各管什么
一个规范的 skill 通常分三层,我按重要性从外到内说。
最外层是元数据(metadata),一般包含技能名称、一句话描述、适用场景标签。这一层的作用是让 Agent 快速判断"这个技能跟我当前的任务搭不搭"。描述写得越准,模型选错技能的概率越低。我见过太多人这一层随便写,结果模型该用的时候不用、不该用的时候乱用,问题全出在这。
中间层是指令主体(instructions),也就是真正的操作说明。这里要写清楚步骤、判断条件、输入输出格式、边界情况怎么处理。这一层是 skill 的灵魂,写得好的指令能让模型表现得像干了十年的老手,写得烂的就是一堆正确的废话。
最内层是辅助资源(resources),比如参考文档、示例数据、脚本模板、工具定义。这些不是每次都要加载的,而是模型在执行过程中按需读取。比如一个"生成周报"的 skill,可能附带一个周报模板文件,模型需要时才去读。
| 层级 | 作用 | 常见错误 |
|---|---|---|
| 元数据 | 让 Agent 判断是否加载 | 描述太泛,导致误触发或漏触发 |
| 指令主体 | 定义具体操作流程 | 步骤跳跃、缺少分支判断 |
| 辅助资源 | 提供模板、示例、工具 | 资源过大,拖慢加载 |
2.3 为什么"按需加载"比"全塞进去"更聪明
这里得讲一个关键原理:模型的上下文窗口是有限资源,而且不是免费的。你塞进去的内容越多,模型处理每个 token 的成本越高,而且长上下文里模型对中间部分的注意力会下降——这就是所谓的"lost in the middle"现象。
Skills 的按需加载机制,本质是在做上下文预算管理。假设你有 50 个技能,每个技能平均 2000 字,全塞进去就是 10 万字,模型直接爆窗口。但按需加载的话,每次只调 1 到 2 个相关技能,上下文占用可能就几千字,又省又准。
这跟图书馆的逻辑一模一样。你不会把整个图书馆的书搬回家,而是需要哪本借哪本。Skill 的元数据就是图书馆的检索目录,指令主体就是书的内容,辅助资源就是书里夹的附件。
2.4 和传统函数调用、插件机制的区别在哪
有人会问:这不就是函数调用(function calling)或者插件吗?还真不太一样。
函数调用是模型决定调哪个 API、传什么参数,它解决的是"执行动作"的问题。而 skill 解决的是"知道该怎么做"的问题。举个例子,函数调用能让模型去查数据库,但"查数据库之前要先验证用户权限、查完之后要按什么格式整理结果"这些流程性知识,函数调用本身是不管的,得靠 skill 来提供。
插件机制通常和具体平台强绑定,换个环境就不一定能用。而 skill 更像是一种跨平台的约定,只要目标 Agent 支持读取这种结构化的技能描述,就能复用。这也是为什么最近 skills 生态能起来——大家发现这套东西可移植、可组合、可分享。
3. 从零开发一个能用的 Skill:我的完整流程
3.1 先想清楚"这个技能解决什么具体问题"
开发 skill 最容易犯的错,就是一上来就写指令,结果写出来的东西又大又空。我的习惯是先用一句话把技能的目标钉死。
比如"帮我处理数据"这种目标就是不合格的,太泛了。合格的应该是"把用户粘贴的 CSV 文本清洗成标准格式,去掉空行、统一日期格式、把金额列转成数字"。目标越具体,后面写指令越顺,模型用起来也越准。
我一般会问自己三个问题:这个技能输入是什么(用户会给什么)、输出是什么(期望得到什么)、中间有哪些判断分支(什么情况下走什么路)。这三个问题答清楚了,skill 的骨架就有了。
3.2 元数据怎么写才能让 Agent 精准命中
元数据里的描述字段,是模型决定"要不要用这个技能"的唯一依据。所以它必须同时满足两个条件:够具体,能区分;够简洁,不啰嗦。
我踩过的坑是:早期我把描述写得很宽泛,比如"用于处理各种文档任务"。结果模型只要碰到跟文档沾边的任务,不管三七二十一就加载这个技能,然后发现技能里的指令根本不匹配当前任务,白白浪费上下文。
后来我改成"当用户提供 Markdown 格式的会议记录,需要提取待办事项并分配负责人时使用"。这样模型一看就知道,只有"会议记录 + 提取待办"这个组合才该触发。描述里最好包含触发条件的关键词,比如输入格式、任务类型、期望输出。
注意:描述不要写成广告词。"本技能功能强大、支持多种场景"这种话对模型判断毫无帮助,反而增加误触发概率。
3.3 指令主体的写法:把"老手经验"翻译成步骤
这是最考验功力的部分。我的经验是:把自己当成在教一个聪明但完全不懂行的新人。聪明意味着你不用解释基础概念,不懂行意味着你不能跳过任何一步。
具体写法上,我推荐"编号步骤 + 条件分支 + 示例"的组合。先列主干步骤,然后在需要判断的地方插入"如果……则……否则……",最后给一两个输入输出示例。示例特别重要,因为模型对示例的模仿能力远强于对抽象规则的理解。
举个我写过的"日志分析"skill 的片段:
1. 读取用户提供的日志文本 2. 按行扫描,识别包含 ERROR 或 WARN 的行 3. 对每个错误行: - 如果包含 "timeout",归类为网络问题 - 如果包含 "null pointer",归类为代码缺陷 - 其他情况归入"待人工确认" 4. 按类别汇总,输出每类的数量和典型样例你看,这里没有一句废话,每一步都是可执行的。模型照着做,基本不会跑偏。
3.4 辅助资源怎么放才不拖后腿
辅助资源的原则是能少则少,能小则小。因为资源文件在加载时会占用上下文,放太多大文件,反而把技能本身的价值稀释了。
我通常只放三类东西:模板文件(比如输出格式的样板)、少量示例数据(帮模型理解输入长什么样)、工具定义(如果技能需要调用外部工具)。除此之外的东西,能不放就不放。
还有个技巧:把大资源拆成多个小文件,让模型按需读取。比如一个技能需要参考三种不同的规范文档,那就拆成三个文件,指令里写"如果需要处理 A 类情况,读取规范A.md"。这样模型只在真正需要时才加载对应文件,而不是一次性全读进来。
3.5 一个完整 Skill 的目录长什么样
说了这么多,给个实际的目录结构参考:
my-skill/ ├── skill.md # 元数据 + 指令主体 ├── resources/ │ ├── template.md # 输出模板 │ └── examples.md # 示例数据 └── tools/ └── tool-def.json # 工具定义(可选)skill.md是入口,模型先读它,判断要不要用。如果用,就按里面的指令执行,需要资源时再去resources/里拿。这个结构简单清晰,也方便分享和复用。
4. 装完不等于能用:Skill 的测试与调优
4.1 为什么"能跑通"和"跑得准"是两回事
很多人装完 skill,随便试一个例子,发现模型确实按步骤走了,就以为大功告成。但实际用起来才发现,换个输入就翻车。能跑通只说明语法没错,跑得准才说明逻辑对。
我一般会准备一组测试用例,覆盖三类情况:标准输入(最典型的场景)、边界输入(空值、超长、格式不规范)、干扰输入(看起来像但不该触发这个技能的任务)。三类都过了,我才认为这个 skill 基本可用。
4.2 我常用的三类测试用例设计
标准输入不用多说,就是正常用。边界输入是重点,比如用户给了一个空表格、给了一段乱码、给了一个超长的文本。这时候 skill 应该优雅处理,而不是直接崩掉或者输出一堆垃圾。
干扰输入最容易被忽略。比如我有个"代码审查"的 skill,结果模型碰到"代码解释"的任务也去加载它,然后按审查的逻辑输出一堆改进建议,用户其实只想知道这段代码在干嘛。这就是元数据描述不够精准导致的误触发。
| 测试类型 | 目的 | 典型用例 |
|---|---|---|
| 标准输入 | 验证主流程 | 格式规范的正常数据 |
| 边界输入 | 验证健壮性 | 空值、超长、乱码 |
| 干扰输入 | 验证精准度 | 相似但不该触发的任务 |
4.3 命中率低、误触发、输出跑偏的排查顺序
当 skill 表现不对时,我按这个顺序排查:
第一步,看是不是根本没触发。如果模型压根没用这个技能,问题在元数据描述——要么描述太窄,要么关键词没覆盖到。解决办法是把描述改得更贴近实际输入的表达。
第二步,看是不是误触发。如果模型在不该用的时候用了,问题还是元数据——描述太宽泛,或者和其他技能的描述有重叠。解决办法是加限定词,把适用场景收窄。
第三步,看是不是触发了但输出不对。这时候问题在指令主体。常见原因是步骤有歧义、缺少分支判断、或者示例和实际输入差距太大。解决办法是补分支、加示例、把模糊表述改成明确判断。
这个排查顺序很重要,因为不同层的问题要用不同的方法修。很多人一上来就改指令,结果发现根本是元数据没写对,白忙活。
4.4 迭代调优:从"能用"到"好用"的几轮打磨
一个 skill 从初版到稳定,我一般要迭代三到五轮。第一轮修明显的逻辑漏洞,第二轮补边界处理,第三轮优化描述精准度,第四轮精简冗余内容,第五轮根据实际使用反馈微调。
每轮迭代我都会记录"改了什么、为什么改、改完效果如何"。这个记录看起来麻烦,但当你同时维护十几个 skill 的时候,没有记录根本记不住哪个版本改了什么。而且这些记录本身就是宝贵的经验,下次写新 skill 能少走很多弯路。
5. 生态与工具链:skills 在不同平台上的落地差异
5.1 Google Cloud、GKE、Genkit 这条线怎么串
热搜词里出现了 Google Cloud、GKE、Genkit,这其实指向一条完整的落地链路。Genkit 是构建 AI 应用的框架,GKE 是跑容器的平台,Google Cloud 是底层基础设施。Skills 在这条链路上的角色,是让部署在云端的 Agent 具备可扩展的能力模块。
具体来说,你可以把 skill 打包成容器镜像,部署到 GKE 上,然后通过 Genkit 定义的接口让 Agent 调用。这样做的好处是技能可以独立更新、独立扩缩容,不用动主应用。比如你更新了一个"数据清洗"技能,只需要重新部署这个技能的容器,主 Agent 不受影响。
5.2 不同 Agent 平台的 skill 格式差异
目前 skills 还没有一个完全统一的标准,不同平台各有各的约定。有的用 Markdown 加 frontmatter,有的用 JSON 描述,有的直接在代码里注册。这就导致一个现实问题:为一个平台写的 skill,换到另一个平台可能要改格式。
我的应对策略是把技能的核心逻辑和平台格式分离。核心逻辑用纯文本写清楚,平台相关的部分(比如元数据的字段名、资源的引用方式)单独处理。这样迁移的时候,只需要改外壳,不用重写内容。
5.3 从社区找现成 skill 时怎么判断质量
社区里现在有不少分享出来的 skill,但质量参差不齐。我判断一个 skill 值不值得用,主要看三点:描述是否具体(泛泛而谈的直接跳过)、指令是否有分支判断(只有线性步骤的通常不够健壮)、是否附带测试用例(有测试的说明作者认真调过)。
另外还要看更新时间和反馈。一个半年没更新、也没人讨论的 skill,大概率是有坑没人填。反过来,如果一个 skill 有持续的 issue 讨论和版本迭代,那通常比较靠谱。
6. 那些没人告诉你的坑:我的踩坑实录
6.1 描述写太宽,模型到处乱用
这是我最早踩的坑。我写了一个"文本总结"的 skill,描述写的是"用于总结各种文本"。结果模型只要碰到跟文本沾边的任务,不管是要翻译、要改写、还是要提取信息,都先加载这个总结技能,然后按总结的逻辑去处理,输出完全不对路。
后来我把描述改成"当用户提供一篇超过 500 字的文章,明确要求生成简短摘要时使用"。触发范围一下子收窄了,误触发率大幅下降。教训是:描述里的每个词都在划定边界,边界越清晰,模型判断越准。
6.2 指令里藏了"隐含假设"
有次我写了个"生成 SQL 查询"的 skill,指令里默认用户给的表名是英文的。结果遇到中文表名的场景,模型生成的 SQL 直接报错。问题就出在我没把"表名可能是中文"这个假设写出来。
隐含假设是 skill 开发里最隐蔽的坑,因为你自己知道,就以为模型也知道。解决办法是写完指令后,找个完全不懂这个领域的人读一遍,看他能不能挑出"这里默认了什么"。挑出来的每一条,都要在指令里显式说明。
6.3 资源文件太大导致加载变慢
我曾经在一个 skill 里放了一个 5000 行的参考文档,想着"资料越全越好"。结果每次加载这个技能,上下文直接被占掉一大半,模型处理速度明显变慢,而且因为内容太多,模型反而抓不住重点。
后来我把那个文档拆成了五个小文件,按主题分开,指令里写清楚"处理 X 类问题时读 A 文件,处理 Y 类问题时读 B 文件"。加载速度回来了,输出质量也上去了。资源不是越多越好,而是越精准越好。
6.4 版本更新后旧 skill 突然失效
这个坑比较隐蔽。有次平台更新了 skill 的加载机制,我原来写的元数据字段名变了,结果所有旧 skill 全部失效。因为平时用得好好的,根本没注意到平台发了更新公告。
从那以后我养成了习惯:定期检查 skill 的运行日志,看有没有加载失败的记录。另外,重要的 skill 我会在本地留一份可运行的备份,万一平台出问题,能快速切换。
6.5 多个 skill 互相干扰怎么办
当你装的 skill 多了,会出现一种情况:两个 skill 的描述有重叠,模型不知道该用哪个,或者两个都用,输出混在一起。我遇到过"代码优化"和"代码审查"两个 skill 打架,模型一会儿给优化建议,一会儿给审查意见,输出很乱。
解决办法有两个:一是在描述里明确区分适用场景,比如"代码优化"写"当用户要求提升代码性能时使用","代码审查"写"当用户要求检查代码规范时使用";二是在指令开头加一句排他说明,比如"本技能只处理性能问题,不涉及代码风格"。这样模型判断起来就清晰了。
7. 我对 skills 这件事的真实看法
折腾了这么久 skills,我最大的感受是:它不是一个技术问题,而是一个表达问题。你能不能把一个领域的知识,拆解成模型能理解、能执行的步骤,这才是核心难点。技术框架、平台工具都是次要的,真正决定 skill 好不好用的,是你对那个领域的理解够不够深、表达够不够准。
另一个感受是,skills 的生态还在早期,标准不统一、工具不完善、坑也不少。但这恰恰是机会——现在投入去写、去试、去踩坑,积累下来的经验,等生态成熟了就是壁垒。我见过太多人等着"标准出来再动手",结果标准出来的时候,早动手的人已经攒了一堆可复用的技能库了。
如果你刚开始接触,我的建议是从一个小而具体的技能入手,别一上来就搞大而全的。写一个"把日期格式统一成 YYYY-MM-DD"这种小技能,跑通整个流程,理解每一层的作用,然后再逐步扩大。小技能踩的坑,和大技能是一样的,但修复成本低得多。
最后分享一个我自己的小技巧:每次写完一个 skill,先别急着用,放一天再回来看。隔一天再看,你会发现很多当时觉得"写得很清楚"的地方,其实有歧义。这个"隔夜检查"的习惯,帮我省下了大量后期调试的时间。