
最近社区里agent-skills这名字出现的频率越来越高GitHub上各种技能库、模板仓库也越堆越多身边不少朋友第一反应都是先down下来看看然后就没有然后了。原因很简单光有一堆技能文件不知道这玩意儿到底怎么设计、怎么挂进Agent、怎么排查问题那它就只是一堆Markdown和脚本。这篇东西我想认真聊聊从一个实际做Agent应用的开发者视角把技能Skill系统的设计逻辑、落地步骤和踩坑过程完整拆开希望能帮正好卡在这个环节的朋友少走点弯路。1. Agent Skill不是Demo玩具它解决的是通用模型如何变成专项员工的问题1.1 技能系统在Agent运行链路中的位置很多人第一次接触agent-skills这个术语脑子里浮现的是提示词模板或工具列表这其实低估了它。在我的理解里技能系统不是Agent身上的装饰品而是决定它到底能不能稳定干活的核心骨架。可以把Agent的运行链路简化成四层模型层、编排层、能力层、资源层。模型层就是底层的语言模型负责理解和生成编排层是Agent的主循环决定下一步做什么能力层就是技能Skill和工具Tool所在的位置Agent在这里获取怎么做资源层是外部数据和API。大部分Demo项目死掉的地方就在能力层模型再聪明如果没有对应的技能支撑它就只能在原地打转靠通用推理硬撑着做一些低质量输出。我不太同意把技能简单归类为提示词工程的一部分因为它实打实地包含可执行代码、校验逻辑、输入输出规范和失败处理机制。一个标准技能单元本质上是触发条件 执行逻辑 输出契约的完整封装。1.2 技能与记忆、工具、子Agent的分工边界这几个概念特别容易混我干脆用一个比喻说清楚。工具Tool是手负责完成一个具体的动作比如调一次API、搜一次网页技能Skill是肌肉记忆负责把一串动作组合成稳定的行为模式记忆是档案柜存历史事实子AgentSub-agent是外包团队可以独立接活但需要管理和验收。具体例子你在做一个电商数据分析Agent。调商品详情接口是Tool把查销量→算增长率→对比竞品→输出周报这一整套流程打包成一个可复用的数据周报技能这是Skill。用户上次说每周一早上发报告这个事实存在记忆里。如果要同时分析十几个店铺主Agent忙不过来拆一个子Agent去做并行抓取这是Sub-agent。四者各管一段互相能协作但不能混着用。在agent-skills类项目里我看到最常见的误区就是把技能设计得无限复杂塞了一堆本该属于子Agent的逻辑。记住一条判断标准技能是确定性的流程子Agent是需要自主决策的任务。一个技能如果每次执行都要让模型疯狂思考那它就不是技能是没拆干净的半成品。2. 认真设计SKILL.md元数据是技能能被正确调度的前提2.1 一份可被机器理解与检索的技能元数据长什么样如果你打开过比较成熟的Agent技能框架社区里agent-skills项目普遍采用类似规范会发现每个技能目录下几乎都有一个SKILL.md文件。这个文件就是技能的简历Agent调度器靠它来判断这个技能是干什么的、什么时候该用、怎么用、有什么限制。我见过太多写得稀烂的SKILL.md整篇都是飘的描述里全是高效地智能地这种模型读了一脸茫然的词。元数据描述必须可机器检索、可语义匹配同时要包含足够的约束条件。下面这份是我个人比较推荐的字段结构字段必填说明示例name是技能名称全局唯一product_analysisdescription是一句话说明用途包含领域词和动作词分析产品销量趋势并生成对比报告trigger推荐触发条件支持关键词和语义描述当用户询问销量变化、周报、趋势分析时input推荐输入参数和格式product_ids: string[], period: stringoutput是输出格式和结构JSON包含summary和detail_data两个字段dependencies推荐依赖的工具、脚本或第三方库data_api, pandasversion是技能版本号1.2.0failure_modes推荐已知失败场景和兜底方案接口超时重试3次后返回缓存数据注意description和trigger这两项它们是调度器做匹配的最主要依据。写description时有个小技巧把它当作给另一个模型看的搜索摘要来写包含明确的领域名词和动作意图而不是写给人类看的用途介绍。比如生成周报三个字不如基于商品销量数据自动生成包含同比增长、环比增长和TOP10商品排名的周报摘要。2.2 触发条件与渐进式披露从指令匹配到语义路由技能调度有两种典型方式显式调用和隐式路由。显式调用是用户在对话中直接点名比如用数据分析技能看一下这个表简单粗暴适合技能数量少的场景。隐式路由是调度器根据用户意图自动选择合适的技能这才是真正体现agent-skills系统价值的地方。隐式路由的常见实现是Embedding语义检索把用户当前输入向量化和所有技能的description向量做相似度计算取top-k候选然后交给模型做最终裁决。这种方案的好处是技能数量增长时不需要频繁改动路由规则坏处是阈值调不好就会瞎匹配。**关于相似度阈值我自己实践下来的经验是设0.72左右比较稳。**低于0.7容易误召回模型会把毫无关系的技能当备选项浪费一轮推理高于0.8会导致召回率下降用户换一种问法就找不到技能。这个值不能拍脑袋定要根据你的技能库规模和真实对话样本来调。再看渐进式披露Progressive Disclosure。这个概念是防止技能信息一次性全灌进上下文导致token爆炸。设计思路是调度阶段只加载SKILL.md的description和trigger字段等确认调用后再加载完整的执行提示词和脚本依赖。用大白话说就是先看一眼简历觉得合适再让对方掏作品集。如果一开始就把所有技能的全量内容塞给模型20个技能就能吃掉几万token还容易让模型在决策时被无关信息干扰。2.3 元数据设计的常见返工点这一块我要专门列几个我自己返工过的教训第一技能描述里用了太多分支逻辑。比如当用户想分析销量但没给日期范围时默认取最近30天但如果今天是周一则默认取上一个完整自然周。这种条件逻辑不适合写在元数据里它应该写进主提示词元数据只负责告诉调度器这个技能能处理销量分析。第二name字段起得太随意。技能一旦超过20个命名混乱会让你连检索都做不了。建议用领域_动作格式比如sales_analyzecoupon_validate方便检索也能避免重名冲突。第三忘记维护依赖版本。技能里引用的脚本更新了但dependencies里的版本号没跟着变可能导致模型生成错误的调用参数排查起来非常痛苦。做技能库一定要像做软件包一样维护版本和变更日志。3. Skill与Tool的本质区别为什么光有Function Calling不够3.1 Tool是手Skill是肌肉记忆我刚做Agent那会儿觉得Function Calling已经很够用了无非是定义好函数模型自己决定调用时机。真正开始处理复杂任务才发现单靠Tool组合出来的Agent非常碎每一步都要模型重新规划中间偶发一个字段错误就前功尽弃。二者的核心差异在于封装粒度。Tool封装的是一次动作Skill封装的是一段流程及其相关的知识、模板、校验规则和异常处理。一件事情如果每次都需要模型用五六个Tool编排才能完成那就应该升级为Skill把编排逻辑固化下来让模型少做决策、多做执行。举个对比表格这个表也是我在给团队做内部培训时用的维度ToolSkill封装粒度单个API或函数多步骤流程及配套知识决策负担模型决定是否调用调度器匹配执行时模型只需填参数上下文占用参数列表较短包含提示词、示例、脚本占用量较大可复用性跨场景通用面向特定任务场景知识内嵌不含领域知识可内置行业规则、模板、约束失败处理返回错误码包含降级策略、重试逻辑、替代路径3.2 从单次调用到多步骤编排我们拿用户想给一批商品重新定价这个场景来说。用Tool方案模型需要先查当前价格、再算成本变化率、再查竞品价格区间、再套用定价规则、最后输出调整建议。每一步都是独立工具调用模型往返对话至少五六轮任何一步手滑都可能算错。用Skill方案定价调整被封装成一个技能内部已经写清楚流程读取商品列表、调用成本接口、计算利润率、比对竞品数据、应用定价规则、输出建议报表。模型只需要提供商品范围剩下的事都由技能完成。这个技能里还可以内置领域知识比如毛利率跌破10%时建议提价这类规则让输出更符合业务要求。3.3 什么时候不必建Skill什么时候必须建不是所有东西都要封装成技能这里我给一个流传于朋友圈的判断准则如果一个功能一个月用不到三次或者每次执行的步骤少于三步那就不值得做技能直接用Tool就行。相反如果满足以下任意两条建议升级为Skill同一个多步骤流程每周出现三次以上流程结果经常因为模型自由发挥而出现过大的质量波动新同事或新模型接手时需要培训才能稳定输出的工作我自己的项目里有个反例。早期我把发送邮件这种极简单的操作也封装成了Skill带了完整的提示词和校验模板结果技能加载时间比实际发信时间还长纯属浪费。后来把它降级回一个普通Tool反而清爽很多。技能是解决复杂复用问题的不是给所有操作贴金用的。4. 动手建一个真实技能抓取并结构化的网页内容提取Skill4.1 目录结构与文件职责空谈概念没意思我们直接上手搭一个技能。场景选得常见一点给定一个商品页URL自动抓取页面内容提取标题、价格、描述、规格参数并输出为结构化JSON。这个技能在很多价格监控、选品分析项目里都会用得到。技能目录结构我建议这样组织web_extract/ ├── SKILL.md # 元数据 触发描述 ├── prompt.md # 执行阶段加载的主提示词 ├── scripts/ │ ├── fetch_page.py # 页面抓取脚本 │ └── parse_markdown.py # 内容解析脚本 ├── examples/ │ └── sample_input.json # 输入示例 └── references/ └── fields_definition.md # 字段定义和取值规则SKILL.md写清楚这个技能做什么、输入输出格式prompt.md是给模型看的执行指南告诉它先跑哪个脚本、怎么解读脚本输出、最终按什么格式返回结果scripts目录放真正的执行代码examples和references用于给模型提供参考样例和字段规则。4.2 主提示词的分段写法prompt.md是整个技能的操作手册写法直接决定执行质量。分段写好过一坨长文本我习惯按这个结构组织# 任务目标 抓取指定商品页提取结构化商品信息。 # 执行步骤 1. 调用脚本python scripts/fetch_page.py --url [URL] --styles markdown 2. 对脚本输出的markdown内容按字段定义表提取信息 3. 若关键字段缺失标记为null不得编造数据 # 字段定义 - title: 商品标题取HTML title或主标题文本 - price: 价格只取商品价格剔除运费、优惠券等干扰信息 - spec: 规格参数键值对形式无规格则返回空对象 # 输出格式 仅输出JSON不要包含任何解释文字。 {title: ..., price: ..., spec: {...}}分段写的好处是模型执行时可以按步骤推进不会跳步字段定义明确后模型提取时不用自我发挥减少幻觉数据。我试过在输出格式里加了不要包含任何解释文字执行稳定度明显提升模型不会突然冒一句根据分析提取结果如下。4.3 引入外部代码与browser-use的整合网页抓取这个场景纯靠LLM自己去解析HTML是灾难必须配合外部的抓取工具。我目前用得比较顺手的是把browser-use这类浏览器自动化工具封装进技能的scripts目录。这样做的好处是能处理JavaScript动态渲染的页面普通requests抓不到的页面它也能搞定抓取前的cookies、headers、代理配置在脚本里全写死模型不用理解这些底层细节脚本出错时有稳定的错误信息返回给模型便于触发兜底逻辑脚本调用时主提示词只需告诉模型执行命令并读取输出文件就够。用这个方法我把原先经常失败的动态页面抓取成功率从不到五成拉到了九成以上。4.4 失败模式清单与重试策略再稳定的脚本也有翻车的时候关键是要把翻车处理逻辑写进技能里。我在这个技能里预埋了一张失败模式对照表失败现象可能原因处理策略脚本返回超时页面加载慢或反爬拦截重试1次更换user-agent头部关键字段为空页面结构变化或内容在登录墙后标记null不猜测附带说明原因输出不是合法JSON模型后处理出错自我修正一次去除说明文字重新解析页面检测为无商品标识商品已下架或链接失效返回下架状态允许上层决策跳过主提示词里加一条兜底指令发现失败时先根据策略表处理策略处理无效则原样返回错误信息。 这样可以防止模型在遇到异常时自由发挥出各种我认为大概是...的幻觉式输出。很多技能项目挂掉就是死在失败处理没有预案模型一旦慌张就开始编。5. 多技能调度与上下文管理最容易翻车的环节5.1 技能路由匹配策略与冲突处理技能数量超过十个之后调度就不再是给模型一个清单选一个那么简单了。我做项目时把路由设计改成两阶段第一阶段是召回。用Embedding把用户输入向量化和所有技能的description向量做相似度计算取top-5候选。第二阶段是精排。把候选技能的name、trigger、description、适用场景整理成一屏信息交给模型选择最合适的一个。模型看到的不是20个技能的完整列表而是5个高度相关的备选决策质量提升很明显。精排阶段特别要注意处理冲突情况。两个技能描述相似度高比如生成销售报表和生成运营分析报告模型容易选错。我的做法是在SKILL.md里增加一个override字段注明与xx技能的区别供精排阶段参考。比如运营分析报告可以写明侧重流量渠道和用户行为指标不含供应链库存字段模型一对比就能区分。5.2 上下文污染技能返回结果如何与主对话隔离技能执行通常会产生大量中间数据。有些抓取技能原始页面转成markdown之后动辄一两万token。如果这些数据全部回灌主对话上下文几轮之后整个Agent就废了——模型注意力被无关信息淹没回答质量断崖式下跌。我的经验是给技能输出做一个压缩层技能返回主对话的内容必须是提炼后的结构化摘要不能是原始数据。还是在网页提取技能上脚本抓完页面后先执行一层数据处理把有用的字段提取成JSON再让模型基于这个JSON生成最终回复。原始页面数据在技能内部消费完就丢弃不进主上下文。另外要严格用token预算控制技能加载。我给每个技能设了加载费用上限元数据和主提示词加起来不能超过一定量级超过就强制拆分。这相当于给技能加了瘦身KPI防止写技能时什么都往里塞。5.3 一组可复用的调度配置参考多技能管理的基础设施除了语义路由还需要依赖关系解析和并行调度。我目前常用的配置参考如下技能间依赖解析按依赖拓扑排序执行A技能需要B技能的输出时先执行B并行执行池互不依赖的抓取类技能可以并发跑注意接口限流和agent数量上限结果缓存同参数请求在短时间内视为幂等直接走缓存省一次完整执行失败熔断技能连续失败3次自动标记为不可用同时通知上层Agent改走替代路径这套配置写在一个独立的路由配置文件中不混进任何技能的SKILL.md。这样技能库的维护者只关心单个技能的自身质量路由和治理由平台层统一负责职责分离后两边都不容易乱。6. 实测中的高频坑token失控、空转循环与过度设计6.1 token失控隐藏的成本黑洞做技能系统最容易被忽视的就是token开销。技能元数据加载、主提示词加载、技能内部多轮脚本输出、模型后处理每一步都在消耗上下文空间。我曾经在项目里挂载了12个技能平均每轮用户对话光技能加载就吃掉一万多token成本翻了快三倍。控制token开销的办法拆开说有三条。第一是延迟加载前面提到的渐进式披露只给调度器看description。第二是把常用技能常驻、低频技能按需加载让最高频的几个技能省去反复加载的损耗。第三是精简技能内嵌示例每份示例都要有明确的作用解释没有肥肉的示例就应该删掉。6.2 空转循环Agent反复调用同一个失败的技能这个坑我印象太深了。有一个数据报表技能脚本因为接口返回格式变更一直在报错。模型第一次调用失败后没有停下来说明问题而是自动重试失败后又换了一种参数重试连续调了十几次同一个技能token烧掉不说任务荒废了很久。排查后发现在编排层缺少循环控制。解决方案我给两处一个是从系统层面做技能调用次数限制默认同一技能单任务最多调用3次超过就触发人工介入或切换技能另一处是在主提示词里加一条规则技能失败重试超过2次后停止操作并向上层汇报错误信息。双保险加持空转循环基本被堵死。6.3 过度设计什么时候Skill反而拖慢系统和有经验的Agent工程师聊技术方案聊到最后经常绕到一个话题现在的技能系统是不是太重了。我有过几次控制不住继续加技能的阶段营地里有十几个技能文件跑着结果发现真正被频繁调用且产生高价值的只有四五个剩下的都是当时头脑一热防患未然设计的。这些低频技能不仅占存储空间每次全量扫描还要拖慢调度速度典型的投入产出倒挂。现在我的策略很明确技能必须通过使用频率和效果指标双重验证才能保留先用普通工具和提示词叠加解决用完无脑建技能是陷阱。每隔一段时间做一次技能清单盘点删除或合并利用率低、效果差的技能保证库内每个技能都是能打能扛的。做技能系统这件事难的不是写一个技能而是设计出一套能长期运转的技能治理机制。我个人在实际操作中最深的体会是技能的价值不在多而在准调度的关键不在全而在省。写完这篇我接下来打算把技能的路由和上下⽂压缩逻辑单独抽成一个小库来沉淀让新项目从第一天开始就挂在成熟体系上而不是一次次从零做起。搞Agent应用的朋友如果正在憋技能库建议先花点时间把SKILL.md规范和调度预算敲定磨刀真不误砍柴功。