
1. 为什么Agent需要技能而不是更多提示词1.1 从一次失败的提示词堆积说起做智能体工程化做到中期我踩过一个很典型的坑为了让Agent在特定场景下表现稳定我不断往系统提示词里加规则。第二版加了两条输出格式约束第三版补上了三个负面清单第四版又塞进去一段示例对话。结果提示词从2K涨到8K之后模型反而出现了很奇怪的行为漂移——旧任务开始变得不稳定同一个输入在不同轮次里给出完全不一致的处理逻辑。后来我接触到agent-skills这个方向才意识到问题根源我们一直在用上下文去承载能力但上下文是有限的、静态的、不可组合的。技能Skills的思路完全不同——它把Agent要掌握的每一项能力封装成一个自包含、可发现、可调用的文件夹。Agent平时只带一张技能清单真正要用到某件事时才加载对应的技能说明和脚本。这个思路不是简单的提示词模块化而是把Agent的能力从内嵌在系统提示里彻底转化为按需挂载的资产。这篇文章我打算结合自己从零搭建技能库的完整过程把agent-skills的核心机制、技能文件的标准结构、手写技能的实操步骤、以及我在工程落地过程中踩过的坑都梳理一遍。不管你是在做Claude、GPT这类大模型应用的Agent编排还是自己基于开源框架搭智能体这套方法都值得参考。1.2 技能、工具、插件三者的边界到底在哪社区里经常有人把Agent Skill、Tool工具、Plugin插件混着说它们在工程语境下确实有交叉但定位完全不同。我做个表格说明维度Tool工具Plugin插件Skill技能本质API能力入口软件能力扩展方法论过程封装载体函数/接口描述插件SDKSKILL.md 支撑文件触发方式模型决策后调用用户主动启用模型在对话中按需加载输出执行结果软件功能完整工作过程典型问题AI不会主动拆步骤能力绑定平台描述不清导致误用一个工具解决的是AI能不能做这件事的问题比如给你一个查天气的API而一个技能解决的是AI知不知道怎么把这件事做得像样的问题比如给你一套天气信息整理成穿衣建议的完整流程、判断规则和输出模板。技能本质上做的是三件事提供决策上下文、约束思考链路、固化产出标准。它不需要调用任何外部API却能让Agent在处理某个任务时按照你预期的路径走完流程。这一点是我在用了很久之后才真正理解的Skill不一定需要动手的能力它更多的是一种内化和外化的经验让模型不必从零开始想任务该怎么做。2. 技能的标准结构一个技能就是一个自包含的文件夹2.1 SKILL.md从哪来为什么要用MarkdownAgent需要一种能读懂的说明书来理解一个技能该怎么用。在agent-skills这个体系里核心文件约定为一个叫SKILL.md的Markdown文件。选Markdown而不是JSON或YAML是有原因的Agent的语义理解对自然语言最友好Markdown天然有标题、列表、代码块这些结构信号模型可以快速定位何时用和怎么用这两个最关键的信息块。Markdown可以内嵌代码示例这对给模型看特别重要。你可以在里面贴一小段输入输出示例模型马上能get到这个技能的工作模式。它是纯文本diff友好放Git里做版本管理、同行评审都很自然。SKILL.md的头部是一个YAML frontmatter用来登记技能的元信息。最核心的字段是name和description。这个description不是给你看的是给Agent的调度决策器看的——模型会先扫描所有技能的description判断当前对话是否命中某个技能。所以description的写法直接影响技能能被多大概率正确触发。2.2 一个技能目录里到底该放什么先看一个我实际在用的技能目录结构以代码仓库结构梳理这个技能为例skills/ repo-mapper/ SKILL.md scripts/ map_tree.py templates/ report_template.md reference/ common_ignore_patterns.md architecture_questions.md各部分的角色SKILL.md技能的主说明书。必须包含何时使用本技能、工作流程、关键规则、输入输出格式这几大块。scripts/需要执行的具体脚本。技能不一定要有脚本但如果这个技能需要读取文件、调命令、做数据转换就放在这里。templates/输出模板。比如要求Agent按某种格式输出报告、文档时模板文件可以让输出结构保持一致。reference/参考知识。这是给Agent在技能执行过程中按需读取的资料用来补充上下文而不是一开始就被全部吞进去。这样设计的好处是Agent在决定使用技能时最初读取的信息量是可控的。SKILL.md会告诉它如果需要更详细的忽略规则打开reference/common_ignore_patterns.md。这样技能内容可以做得非常丰富但对上下文的初始挤占又很小。关于这一点第四部分我会详细讲怎么控制上下文膨胀。2.3 description的措辞决定了Agent会不会在关键时刻想起你这是我认为整个SKILL.md里技术含量最高的一小段。description写得太泛Agent会在无关场景里误触发写得太窄Agent永远想不到用它。我的经验是一个好的description应该包含三层信息任务的典型触发场景、输入的主要特征、输出要达到的目的。举个例子同样描述一个代码评审技能比较差的写法代码审查技能用于review代码。这种描述在Agent的决策空间里几乎是隐形状态因为review代码这个表述太口语、太宽泛模型很难识别出当前这个需求是否应该调用它。我实际使用的写法负责对指定代码改动进行系统性审查识别潜在缺陷、安全隐患与性能风险。当用户提供git diff、PR链接或一段待审查代码且期望得到结构化审查意见时使用。输出结果包含严重程度分级、问题定位、修复建议。这里的关键词是git diffPR链接待审查代码——这些都是模型在对话上下文中容易捕捉到的实体而结构化审查意见严重程度分级则界定了输出形态让模型判断当前任务与技能的匹配度。3. 从零手写第一个技能发布说明转Changelog3.1 为什么第一个技能选Changelog生成对于一个刚接触agent-skills的人来说最好的练手项目应该满足三个条件输入容易获取、输出有明确标准、流程不需要外部系统依赖。发布说明转Changelog完美满足这三点。你只需要一段git提交记录就能完成完整的技能编写、调试和验证闭环。我们先看一下这个任务在没有技能时是什么状态。你让一个Agent根据git log生成Changelog模型通常能给你一个看起来合理的Markdown列表但细看你会发现版本号可能会被它自己编出来、日期格式不统一、分类逻辑随心所欲、删改commit信息。原因很简单——模型对这个任务的心智模型来自通用训练语料而不是你团队的实际规范。技能的价值在于把你对规范的定义固定下来让Agent变成一个不会偷懒的执行器。3.2 编写SKILL.md的实操与完整示例在技能目录下新建changelog-writer/SKILL.md。我的完整文件长这样--- name: changelog-writer description: 将零散的git提交信息或发布说明整理成符合团队规范的CHANGELOG.md。当用户提供git log文本、提交编号范围或要求生成、补充、修复Changelog时使用。 --- # Changelog Writer 这个技能用于把开发过程中的零散提交记录整理成结构化的CHANGELOG.md。 ## 核心规则 1. 分组规范按 Added新功能、Changed变更/破坏性更新、Fixed修复、Removed移除四组归类。 2. 版本号规则遵循语义化版本。破坏性更新必须升级Minor版本并优先列出。 3. 日期格式统一使用 YYYY-MM-DD。 4. 不臆造内容如果commit信息模糊使用 [待确认] 标记并在末尾向用户提问。 5. 合并同类项同一功能相关的多个commit自动合并为一条并在末尾附上主要PR编号。 ## 标准输入格式 用户提供以下内容时直接处理如果提供的是PR列表或发布说明先提取关键变更点再归类。 text git log --oneline v1.2.0..HEAD --no-merges工作流程收集输入源必要时向用户请求补充git日志范围。将每条记录按关键词预分类feat/add/feature 归入 Addedfix/bug/patch 归入 Fixedbreaking/refactor/change 归入 Changedremove/drop 归入 Removed。对分类结果做同义聚合去除重复条目。按严重程度排序Breaking Change 在最前其次 Added最后 Removed。输出完整的一版CHANGELOG.md包含版本号和日期。输出模板## [Unreleased] ### Added - 新功能A#PR号 ### Changed - breaking变更B#PR号 ### Fixed - 修复问题C#PR号 ### Removed - 移除模块D#PR号参考示例输入feat: add user profile page fix: correct typo in login form feat: add profile avatar upload refactor: change data loading to server-side for profile page期望输出### Added - 新增用户资料页包含头像上传能力#123#125 ### Fixed - 修正登录表单文案错误#124质量检查在返回任何输出前逐项检查[ ] 是否每一行都归类到四组之一[ ] 是否存在待确认项没有向用户提出[ ] 是否保留了原始PR编号[ ] 日期和版本号是否格式一致这里有几个设计细节值得展开 **核心规则区的不臆造内容**是最重要的一条。Agent有很强的补全倾向你只给它片段它可能脑补出并不存在的功能描述。明确告诉它标记待确认并提问它才会停下来而不是编。这也是Agent工程里常说的约束幻觉的刹车片。 **参考示例部分的输入对比**是给模型喂一个few-shot的例子。LLM在看过一个输入输出对照后对任务的理解会显著提升。这个示例不用多一段输入对应一段输出就够了。 **质量检查清单**是我建议大家从第一个技能起就养成的习惯。它相当于在技能末尾放一个自我校验钩子让模型在输出前先自检一遍。这个设计看起来简单但对输出质量的提升非常明显——因为模型的生成过程是序列式的如果能在最后一步强制它做一次checklist扫描很多低级错误会在生成阶段就被拦截。 ### 3.3 怎么测试技能是否真的被正确触发 写完SKILL.md只完成了第一步第二步是测试。我建议在专门隔离的会话环境或测试项目里做三组验证 1. **直接命中**给你一个明确的输入比如直接贴一段git log问帮我生成当前版本的Changelog。看Agent是否主动使用changelog-writer技能。 2. **间接命中**给一个模糊指令比如发布说明这块帮我整理下。看Agent能否从技能清单里召回正确的那个。 3. **负向测试**给一个完全无关的需求比如写一首关于数据库的诗。观察Agent是否错误触发了changelog技能。 测试时重点关注第三个场景。我发现很多技能误触发的原因都是description里的publish这个词——模型会把发布动态发布文章和发布版本混在一起。解决方式是在description里补充一句本技能仅适用于软件版本发布场景给决策器一个明确的排除条件。 ## 4. 技能库的工程化管理版本、测试与多Agent复用 ### 4.1 技能库怎么分区才不乱 技能数量一多管理就会乱。我的经验是把技能库分为三个区 - **builtin/**团队统一的标准技能所有人共享不允许个人随意改动。变更必须走评审。 - **community/**团队内分享但未经严格评审的技能可以作为builtin的候选。 - **personal/**个人调试中的技能方便实验不影响主工程。 分区的意义不只是目录好看更重要的是和Git权限、CI流水线绑定。比如builtin目录的改动需要至少一名其他成员的approvepersonal目录则可以随时自由提交。这个约定帮我避免了很多人为冲突——你不会想让一个同事刚实验到一半的技能漂到生产Agent里去。 ### 4.2 Git版本化与技能依赖的坑 一个技能自己是一个git仓库还是一整个技能库一个仓库两种模式我都试过。初期技能少时整个技能库一个仓库最方便git clone一次搞定但技能多到十几个后任何一个技能的改动都会让整个仓库的diff变得混乱Code Review时也很难聚焦。 后来我切到了单技能单仓库 主仓库用submodule管理的模式。每个技能repo里放一个SKILL.md、一个version.txt版本号遵循语义化版本。主仓库在一个manifest.json里记录各个技能的git地址和当前版本号 json { skills: [ { name: changelog-writer, version: 1.2.3, repo: gitinternal:skills/changelog-writer.git } ] }这个manifest就是技能的应用市场索引。Agent在启动时只读manifest拿到技能名单真正决策到某个技能时再从对应仓库加载SKILL.md和资源文件。依赖方面最大的坑是技能间的隐式依赖。比如你的changelog-writer技能里用了semver库而semver的解析逻辑在repo-mapper里维护——一旦两边不同步行为就会非常诡异。我的建议是技能内部需要的通用逻辑一律复制到该技能的scripts目录下不要跨技能共享函数。宁可有点代码冗余也要保证每个技能自包含、可独立运行。这也是一个技能就是一个自包含的文件夹这条原则最重要的理由。4.3 用自动化测试给技能上个保险Agent的行为有随机性所以技能测试我们不能像普通单元测试那样断言精确输出而是做关键行为断言。我用的是一套非常轻量的Python测试框架核心思路是这样的# test_changelog_skill.py from agent_runner import invoke_agent def test_changelog_direct_trigger(): result invoke_agent( skillchangelog-writer, conversation[ {role: user, content: git log --oneline v1.2.0..HEAD --no-merges}, ], ) assert ### Added in result.text assert ### Fixed in result.text assert 正确识别changelog输入 in result.trace def test_negative_no_trigger(): result invoke_agent( skillchangelog-writer, conversation[ {role: user, content: 帮我写首诗}, ], ) assert changelog-writer not in result.triggered_skills测试的重点有三断言输出结构里是否出现了关键分段标题说明技能被正确执行断言技能是否在正确的场景被触发decision trace断言负向场景是否被正确拒绝把这套测试挂到CI里每次技能库更新都会跑一遍回归。我强烈建议从第二个技能开始就同步写测试而不是等技能多了再补。Agent技能的一个特点就是改动一个SKILL.md的措辞可能连带影响其他技能的选择行为而人工回归很难发现这种隔山打牛的问题。4.4 多Agent复用时的配置隔离同一套技能库给负责客服的Agent和给负责代码生成的Agent用配置一定不能一刀切。因为manifest里所有技能都会进入Agent的决策候选列表即使有些技能跟它完全无关模型在扫描时也会消耗决策注意力。我的做法是在manifest里增加一个allowed_agents字段或者在Agent侧维护一个enabled_skills白名单skill_config: - name: changelog-writer enabled_agents: [release-bot, dev-assistant] - name: repo-mapper enabled_agents: [dev-assistant]白名单机制让每个Agent的候选技能保持在 5 到 10 个以内这是我认为兼顾决策效率和能力覆盖的最佳区间。一旦候选列表超过15个模型在技能选择上开始出现明显的不稳定误触发率显著上升。这个数字不是某篇论文给的而是我实测对比多个模型后的直观结论。5. 实测踩坑记录技能冲突、上下文膨胀与调用失灵5.1 两个技能抢活description冲突的真实案例有一次我给Agent配了changelog-writer和release-notes-generator两个技能。单独测试时它们各自表现很好结果一起上线后同一个发布相关的请求模型一会儿用changelog技能、一会儿用release-notes技能行为极其不稳定。排查链路是这样的我先去看两个技能的description发现都包含发布说明版本这些关键词语义重叠度非常高。我怀疑是候选列表排序问题把其中一个技能的description重写强调自己完全基于git提交记录把另一个强调基于PR描述与release管理平台数据。我把混淆场景的测试用例加进负向测试集确保模型在遇到PR列表和git log同时出现的情况下能明确走向正确的那一个。重新跑回归测试两个技能的选择准确率从约65%提升到了约90%。这个问题的根因不是技能不够多而是技能边界不够清晰。同类技能宁缺毋滥——如果你的几个技能描述之间需要用但是除了来区分那说明它们在模型眼里是同一个技能你需要的不是拆分而是合并或者明确划分输入特征。5.2 上下文膨胀技能元信息正在悄悄吃掉你的注意力有些刚入门的工程师习惯把非常详细的参考文档整篇内联在SKILL.md里。比如在repo-mapper技能里放了两千行的架构模式知识库每次都跟着技能一起被加载。这样做的结果是Agent的上下文里塞满了高密度但当前用不到的信息反而干扰了对用户直接意图的注意力。我解决这个问题的思路是分层加载。SKILL.md里只保留精炼的何时用、核心流程、关键规则、示例把长篇细节放到reference/或knowledge/目录并在SKILL.md里给模型一句明确的指导当需要了解具体的忽略规则时打开reference/common_ignore_patterns.md。这种按需读取的实践在对话中效果很好因为模型在资源不够时不会主动去翻文件但你告诉它需要时才打开某个文件它反而知道什么时候该主动查找。和人类的工作方式很像——你手上不会一直摊着整本操作手册但你知道手册在第几章需要时就翻。5.3 同一个技能换了个模型就失灵我在Claude环境下调试得非常顺滑的技能切到另一个开源模型上出现了明显的调用率下降和输出格式漂移。后来仔细分析发现问题不在于技能本身而在于不同的模型对指令的遵循习惯差别很大有些模型对负面清单不要做什么更敏感对正面指导反而执行得随意。有些模型在长文档里只能有效抓住前几个章节后面的大段规则基本被忽略。有些模型不太擅长自己触发打开reference文件这一步加载了主文件就完事了。我的应对方案是写技能时尽量用正面的、指令式的语言描述期望行为减少依赖负面清单来表达核心流程同时在任何重要规则前加上标题层级标记让模型更容易定位关键区块。真正需要区分模型行为的场景我会在技能里加一个平台适配段写明当你在X平台上运行时注意……而不是试图写一套浦适的指令。5.4 调试技能问题的通用排查链路这里我总结一下踩过多次坑之后沉淀出的排查链路如果技能表现不对我会按照这个顺序走步骤检查项典型结论1技能是否被触发没触发 → description与输入特征不匹配2如果不触发补全description中的触发场景关键词3触发后执行流程是否完整流程断裂 → SKILL.md的工作流步骤太模糊4输出是否达标输出不达标 → 核心规则或示例不足5输出结构是否每次一致不一致 → 输出模板未硬性约束6是否与其他技能冲突冲突 → 检查description重叠与Agent候选技能数量只要按这个链路走大多数问题都能在十分钟内定位到原因。这也是为什么我一直强调技能测试不能只看输出结果还要看触发路径。最后再说一个我个人的体会。很多人刚开始接触agent-skills时会倾向于把一个任务拆成很多个细碎的技能结果技能之间冲突不断管理成本反而比写提示词还高。技能应该对应一个有边界、有明确产出标准的工作方法而不是一个细小的动作。你不需要给每个API调用都建一个技能但你应该给怎么做一个合格的代码评审怎么按团队规范发布版本这类有方法论含量的任务建技能。技能的粒度拿捏准了整套体系才会越用越顺畅。我现在维护着一个二十多个技能的库日常新增和调试已经非常顺手这也是我觉得这个方向最值得投入的地方。