
skills这个词在最近的LLM应用开发圈子里热度已经快压过prompt工程了。如果你在一个Agent相关项目的评审会上听到把XX能力做成一个Skill对方说的不再是简历上的技能清单而是一套能让模型按需调用、可复用、能共享的能力模块。我见过太多团队把几百条prompt模板堆进系统提示词里结果输出质量每况愈下改一行描述就要全局回归。Skills这套思路之所以值得花时间研究是因为它把提示词从一个不可测试、不可组合的文本片段变成了有边界、有元信息、有工具绑定、可以被模型主动选用的软件单元。这篇文章不聊空概念直接拆解Skills背后的底层逻辑以及怎么从零手写一个能稳定跑在生产环境里的Skill。适合正在做Agent、工作流编排、AI功能落地的人参考也适合那些prompt资产已经多到没法维护的团队找到一条结构化出路。1. Skills鲜为人知的分层真相它不只是prompt模板1.1 先划清边界Skills、Tools、RAG和工作流到底什么关系很多人把Skills理解成高级prompt或者工具调用的壳子这其实窄了。我习惯用一个分层模型去看**Tools工具**是原子能力比如查天气、发邮件、执行SQL它是一个可以被调用的函数本身不知道什么场景下该用。**RAG检索增强生成**解决的是知识从哪来的问题它给模型提供外部资料片段。**Workflow工作流**是确定性的流程编排每一步做什么、顺序如何由开发者写死。**Skills技能**是介于工具和工作流之间的那一层——它描述了什么时候用、怎么拆解任务、需要哪些工具、按什么顺序调用、输出什么格式。用一个生活化的类比Tools是一把螺丝刀RAG是一张说明书Workflow是流水线上机械臂固定的动作路径而Skills是一位熟练技工脑子里装一个书架的完整思路。这位技工接到书架任务能自己决定先看说明书还是先量尺寸能自己决定用螺丝刀还是电钻过程中的判断和动作组合就是Skill。理解了这一层你就会明白为什么单独的function calling做得再好Agent的表现仍然不稳定。因为function calling只解决了某个工具怎么调的问题没有解决这个任务该拆成哪几步、每步该不该调工具、结果如何校验的问题。Skills补的正是这一环。1.2 路由—加载—执行三层结构模型怎么知道该用哪个技能一个成熟的Skill体系在运行时其实是一个三层结构路由层模型读到一份技能清单每一条包含技能名称、一句话描述、适用场景、触发条件。它会判断当前用户请求匹配哪个技能。加载层确定命中后把该技能的完整模板、说明、相关代码或资源加载进上下文。注意这一步做到了按需加载而不是把所有技能一股脑塞进系统提示词。执行层模型按照技能内的步骤说明逐步执行期间可以调用工具、引用数据、输出结构化结果。我见过不少团队把几十个技能的全部描述直接写进System Prompt认为这样模型知道的更多结果实测效果很差。原因在于模型的选择压力过大、无关文本稀释注意力而且上下文成本随着技能数量线性上涨。正确的做法是路由层只保留精简的索引完整细节等命中后再注入。1.3 为什么是现在指令遵循能力与上下文窗口的拐点这项模式能成立离不开两个前提。一个是大模型的指令遵循能力已经强到可以理解复杂的约束条件——如果模型连当用户表达出差意图时先检查预算再推荐航班这种带条件分叉的指令都执行不稳Skill的任务模板就没有生存土壤。另一个是上下文窗口变大之后加载一个完整技能描述不再挤占正常对话空间实用性才真正落地。换句话讲Skills是模型能力曲线和工程需求曲线交叉后的产物。三四年前大家把prompt写得再精巧模型面对多步拆解任务依然容易迷路今天的模型配合Signal级的分步引导才让技能化封装有了可重复执行的价值。2. 从零构建一个可用Skill差旅管理案例全拆解2.1 一个Skill的最小目录少了哪个都会出事我不推荐上来就设计一个巨型规范但下面的目录结构是我维护了多套技能仓库后沉淀下来的底线travel_booker/ ├── SKILL.md # 技能主描述包含元信息、触发条件、执行步骤 ├── requirements.txt # 该技能依赖的Python包 ├── scripts/ │ └── search_flights.py # 调航班查询接口的脚本 ├── reference/ │ └── airlines_policy.md # 差旅政策参考比如只允许经济舱 └── assets/ └── output_schema.json # 输出结果的结构化Schema这里面最容易忽略的是requirements.txt。很多Skill在开发环境中跑得好好的部署到生产容器里突然报错查到最后都是因为依赖没有跟着技能一起锁定版本。你要么用Docker镜像把技能做成独立环境要么至少保证每个技能目录里有明确的依赖清单否则可复用就会变成不可复制。2.2 SKILL.md的写法任务模板加输入输出契约SKILL.md是整个Skill的核心它通常分为两大块。开头是YAML格式的元信息我一般至少包含以下字段name: travel_booker description: 根据用户的出差目的地、日期和预算完成航班与酒店查询与预订推荐。 when_to_use: 用户提到出差、订机票、订酒店、行程安排、报销差旅等需求时。 tools: [search_flights, search_hotels, book_ticket] version: 1.2.0不要小看这段元信息。description和when_to_use是路由层判断该不该用这个技能的全部依据。我见过有人把description写成处理差旅相关事宜结果用户问出差补贴标准是多少也被路由到这个技能后面的执行步骤根本没有答补贴的逻辑效果自然崩。元信息之后是主体部分我建议按目标—步骤—约束—输出四段式来写目标这个技能帮用户完成什么说清楚成功的标准。步骤给出一二三四步操作序列每步要明确判断什么、调用什么、得到什么。约束明确什么不能做。比如不得预订超出预算的酒店、不得在用户未确认时下单。输出定义输出格式最好引用Schema文件。差旅场景的简化版步骤可以是这样## Steps 1. 提取用户的出发地、目的地、日期与预算如信息缺失主动追问不要猜测。 2. 调用 search_flights 查询经济舱航班按总价从低到高排序。 3. 若往返票价总和超出预算提示用户并给出最接近预算的方案。 4. 生成候选方案列表包含航班号、起降时间、价格与航司。 5. 等待用户明确确认后再调用 book_ticket严禁提前出票。写到这里你可能觉得这不就是一份流程文档吗对本质确实是一份给模型看的流程文档但它的价值在于把判断节点、工具调用、约束规则揉进了同一个上下文里。模型照着执行就不容易在某个分支上自由发挥。2.3 从一次真实调试看步骤设计的颗粒度我之前调试过一个内部的知识整理Skill起初步骤写的是分析用户提交的文档并生成摘要结果模型给出的摘要时好时坏。后来我把步骤改成1. 识别文档类型技术方案、会议纪要、周报。 2. 提取作者、日期、核心结论、待办事项四类信息。 3. 将待办事项按负责人分组缺少负责人时标记为unassigned。 4. 输出JSON格式摘要字段与output_schema.json保持一致。改完之后效果立刻稳定。这说明了一个关键规律步骤的颗粒度要细到模型不需要做开放性创意决策的程度。生成摘要本身是一个抽象任务但把抽象任务拆成具体的四类信息提取动作后模型的执行方差就大幅下降了。2.4 命名和描述模型不是搜索引擎它靠语义匹配给Skill起名要遵循动词加对象的模式比如search_codebase、generate_weekly_report、check_invoice_risk。不要用utility、general_helper这种连开发者自己都说不清用途的名字。描述部分要写什么时候用而不是是什么。check_invoice_risk的描述写成用户要求审核发票合规性或检查发票风险时就明显优于发票检查工具。因为路由层本质上是语义匹配只有描述贴近用户的自然表达模型才能精准命中。3. 让Skill真正跑起来加载、调用与测试的三板斧3.1 用前缀注入还是按需注入取决于你的延迟预算加载策略上有两种常见做法。一种是前缀注入把技能索引或轻量级描述常驻在上下文里命中后立即激活适合对延迟敏感、技能数量不多的场景另一种是延迟加载先让模型用普通方式回答像搜索引擎一样召回候选技能再二次拼装上下文适合技能库庞大的场景。我个人的经验是技能数量在10个以内时前缀注入完全够用且实现简单超过30个时一定不要全量注入否则每次请求都背着几十份技能说明成本和延迟都不可控。主流Agent框架里的做法通常是索引在前详情在后索引就几十个字详情几千字后者按需追加。3.2 搭一个最小测试台比你想的更重要我在给任何Skill写第一行执行逻辑之前一定会先搭一个最小测试台。它不需要什么复杂框架核心就三件事准备一批测试输入normal case、edge case、非法输入各若干条。调用模型执行该Skill。比对输出是否符合预期Schema。测试用例怎么设计我以差旅Skill为例说明场景输入期望结果正常场景下周三去上海出差预算1500帮我订个酒店返回酒店列表价格不超过1500缺省追问帮我订机票追问出发地和日期不直接执行非法输入帮我订个火箭去火星说明无法预订并给出替代建议超预算预算500订北京市区酒店提示预算不足推荐郊区选项这套测试台我通常会沉淀成一份test_cases.json放进技能目录里。别小看这一步——当你调整技能描述后只需要重跑一遍测试集就能发现哪些行为被改歪了。没有测试台做回归技能迭代基本靠玄学。3.3 多个Skill协作调度顺序和优先级怎么定当用户的一个请求会命中多个Skill时需要在路由层设计优先级。我常用的策略是特异性优先越具体、越垂直的技能优先级越高通用技能兜底。比如用户说帮我安排出差行程差旅预订Skill应该优先于通用日历Skill被选中因为前者是更精准的意图匹配。另一种情况是Skill内部依赖另一个Skill此时可以把依赖关系显式声明在元信息的depends_on字段里。例如travel_booker依赖search_flights这个工具型技能那么在加载时就要确保被依赖方先就绪避免执行到一半才发现工具未注入。3.4 上下文占用控制控制成本的小窍门Skill的完整描述可能几千字如果一次请求中命中两三个上下文压力不小。我的技巧是给SKILL.md分层公共部分触发条件、输入输出契约完整保留内部大段的参考材料、政策文档单独放在reference/目录等模型确认要执行某一步时再作为工具的结果返回。比如航司政策文档根本不需要在加载时读取等模型生成候选方案、需要对比政策再做合规筛选时再把这个文档作为检索结果注入。这一套按需拿取的思路能让单个技能的实际上下文成本下降40%左右。4. Skill体系化的四大工程问题4.1 版本管理Skills也需要语义化版本一旦Skills数量多起来版本混乱是必然的。同一份技能在A项目里是v1.0在B项目里已经改到v1.3而模型的生产环境还在用v1.0的行为这种情况我踩过太多次。推荐的做法是在SKILL.md的frontmatter里维护version字段同时用Git管理整个skills仓库。每改一次描述或工具映射升一个patch版本改变输入输出契约升minor版本。真正发布到生产环境时锁定技能版本号像锁定依赖包版本一样严格。4.2 权限与安全工具绑定不是绑得越多越好给Skill挂工具时要克制。很多技能最后失败不是功能不够而是工具太多导致模型在中间步骤犹豫不决甚至调用错误的工具。安全方面的底线有两条技能只能调用它声明过的工具运行时层面要做白名单校验。高风险动作下单、删除、发送消息必须拆成独立步骤且要求用户二次确认。我在生产环境里见过最危险的案例是一个会议纪要整理的Skill为了方便绑定了发送邮件的权限某次模型误判用户意图直接给全组群发了草稿邮件。这个事故之后我们定的铁律是每个Skill的工具权限必须最小化高风险动作一律半自动。4.3 团队协作谁维护、如何评审、如何淘汰Skill不是写完就一劳永逸的。我建议每个Skill都要有明确的owner类似代码模块的维护者。评审时重点看三件事描述与触发条件是否清晰、执行步骤是否可测试、工具依赖是否最小化。更关键的是淘汰机制——如果一个Skill连续30天没有命中记录就要审视它是不是已经过时。没有淘汰机制技能库最终会腐烂成一堆互相冲突的规则。4.4 共享生态从内部沉淀到社区复用Skills最大的想象力在于生态共享。一个团队沉淀出的高质量Skill理论上可以被另一个组织复用。跨团队复用时要额外关注两件事一是外部工具的认证信息不能写死在技能里要通过环境变量或配置中心注入二是描述中的行业术语要保留通用性别用只有内部人才懂的黑话。能翻译成通用表达的Skill才是可传递的资产。5. 我在生产环境踩过的五个深坑5.1 过度封装导致模型选择困难最开始我做技能库时恨不得把每个细小的动作都封装成Skill结果几十个技能同时挂载模型的命中准确率反而暴跌。用户说帮我订酒店它能同时匹配三个描述相似的技能。后来我学会了聚合把相似功能合并成一个技能用内部步骤分支来处理不同细类。同一件事能用内部判断解决就不要拆成两个外部技能。5.2 文件膨胀拖慢加载有个技能我为了追求完整把参考资料、历史案例、FAQ全部写进主文件文件直接膨胀到三万字符。每次命中这个技能光加载就要多花几百毫秒。正确的做法是把静态知识放进reference/目录执行过程中遇到瓶颈再动态检索。Skill应该是一个会干活的人不是一本百科全书。5.3 命名模糊让模型用错Skill我写过叫document_processor的技能描述是处理文档相关需求。结果它成了万金油用户让翻译文档也触发它让提取表格也触发它让总结PDF也触发它实际跑起来每件事都干不好。后来拆成translate_document、extract_tables、summarize_pdf三个技能命中率立刻提升。命名和描述的模糊是路由层最大的敌人。5.4 输入校验缺失造成连环崩溃某个Skill接收用户输入的日期字符串我默认它是YYYY-MM-DD格式结果模型从对话中提取日期时返回了3月15号下游工具直接崩溃。从那以后我在Skill执行步骤里增加了一个前置校验环节提取日期并归一化为YYYY-MM-DD无法解析时询问用户。看似多了一步却避免了90%的异常情况。5.5 上下文污染SysPrompt里堆太多技能描述这是最隐蔽的坑。初期我把所有技能的完整说明都拼进系统提示词以为这样模型什么都会。实际上无关技能的描述会稀释注意力还容易让模型在不同技能之间来回横跳。改成索引在前、详情按需加载的方案之后效果立竿见影不仅输出更稳定单次调用的token消耗也明显下降。最后分享一个我自己的体会Skills这套模式真正难的从来不是写一份SKILL.md而是学会克制——克制工具的数量克制描述的长度克制封装的粒度。与其一次铺开二十个技能不如把最常用的三个打磨到不假思索就能用对的程度再逐步扩展。技能库就像工具箱高手不是工具最多的那个人而是每样工具都知道该什么时候拿出来、怎么用对。