今年圈子里关于 AI 工作流的词换得特别快但“skills”是少有几个让我愿意停下来重新整理思考方式的词。过去我写提示词本质上是在写一次性对话模板——同一个任务的规则改了我就要打开聊天记录从头翻一遍把旧逻辑一条条挑出来替换时间长了自己都分不清哪条还在生效。后来我把这类可复用的流程封装成了技能包用工程化的思维去管理 AI 的行为边界再回头看之前的方式简直是在拿便利贴管理一个项目。这篇文章不是来普及“什么是技能包”的而是想分享我自己从零搭一个可用技能包的完整过程包括怎么定文件结构、怎么设计输入检查、怎么处理模型乱编的问题以及一个技能在真实使用中如何从 v1 迭代到 v3。如果你正在调试 Agent 应用或者发现自己反复把同一套要求粘贴给大模型这篇文章应该正好能解你的燃眉之急。1. 为什么我最终放弃了“更长的提示词”转而把技能当成一个小项目来管理1.1 提示词是聊天话术技能是可交付的模块在早期阶段我处理任务的方式是写一段尽可能详细、尽可能防呆的提示词。比如让 AI 把会议纪要整理成任务清单我会在提示词里写“你是项目经理请提取所有决策、下一步行动、负责人、截止日期并按重要程度排序……”看起来没问题但用两周就会发现这类提示词有几个根本性缺陷。第一没有结构。所有规则挤在一段话里模型的注意力被摊薄。第二没有校验。对方甚至没有会议纪要就让我处理模型还是会被硬生生生成一份把幻觉当事实输出。第三没有版本管理。我已经忘记当前这段提示词是哪天改的更不知道上一版和这一版的差异到底改变了什么。当我开始用“技能”的视角来看待这个任务时一切突然清晰起来。所谓技能就是将一个特定任务的完整解决方案打包包括任务定义、输入的前置条件、处理规则、参考资源、输出格式以及可选的脚本。它本质上是一个拥有自己目录结构的小项目和一段写在聊天框里的文字是两种维度的东西。1.2 拆解后的整体收益确定性、边界和复用性封装技能之后我首先察觉到的是确定性的提升。以前同一个需求在不同会话里回答质量忽高忽低现在技能包把规则固定下来了模型可以在“给定的边界里”做偏移而不是自由发挥。其次是边界控制。技能包可以主动拒绝而非硬着头皮回答。手动调用好友在客服场景会根据输入的文明程度给出灵活答复不该处理的内容会明确说“不处理”这个逻辑在技能里是显式编码的不依赖模型那一刻的灵光。最后是复用性。这个技能在 A 项目里调通的规则只要把目录复制到 B 项目微调几个字段就能直接用。我发现这句话说得毫不含糊真正线上跑了三个月后才敢这样写。现在我把高频业务场景拆成了大约七个技能搜索、排序、转换的通用逻辑在几个项目里同时生效维护成本反而比当初维护提示词还低。2. 拆解“会议纪要转任务清单”实例一个最小可用技能包的完整解剖我以自己最常用的“meeting-to-todo”技能为例展示一个技能的目录是怎么长出来的。这个技能的目标很单一给模型一段会议纪要原文输出一份可执行的任务清单包含责任人、截止日期、关联上下文并明确标注哪些是决策、哪些只是闲聊结论。如果你自己动手做过类似的事情下面这些目录结构你可以直接借鉴。2.1 技能的文件结构不只是 SKILL.md而是分层逻辑meeting_to_todo/ ├── SKILL.md ├── assets/ │ ├── decision_template.md │ ├── ambiguity_rules.md │ └── categories.yaml ├── scripts/ │ ├── extract_owners.py │ └── export_markdown.py └── tests/ ├── case_01_normal.md ├── case_02_no_owner.md └── case_03_vague_verbs.md初次看到这里你可能会觉得小题大做。但一个技能的核心并不只是指令文本而是“规则 参考资源 代码 测试”的组合。把静态资源放到 assets 下让模型按需读取把复杂转换逻辑放到 scripts 下让精确的计算交给代码而不是模型的语言直觉把代表性输入放到 tests 下每次改技能先跑一遍回归。这是我在实际执行中总结出的“职业技能包”最佳实践。2.2 定义一个强制输入门能拒绝的任务别硬做SKILL.md 的开头部分最重要的是触发条件和输入校验规则name: meeting-to-todo description: 将原始会议纪要进一步转换成结构化的任务清单仅适用于包含明确讨论内容与结论的文本。 input_gates:缺少“会议主题”或“参会人”字段时直接拒绝不生成内容。如果待办事项中没有包含负责人则不能推断负责人应放入“待认领”分组。如果行动动词模糊例如“讨论一下”“跟进”必须标记为“待明确”不得自行脑补具体动作。这三条看起来简单但实际挽救了无数次输出质量。模型在训练时被鼓励“有话可说”所以很容易在信息不全时自动脑补。技能包要反向给模型一个合法路径当输入不满足条件时说出“无法处理”是一件正常的、确定的事情而不是失败。我还发现写拒绝规则时比写生成规则更有效。原因是输出形式的想象空间太大你穷举不完模型会怎么组织话术但输入门往往只有几个核心前提提前用规则卡死它们整体质量就稳了大半。2.3 处理逻辑格式化的步骤而不是一大段“让 AI 随便发挥”在 SKILL.md 中我给模型描述的是一套流程不是故事先识别文本中的“决策”“行动项”“风险项”“未决问题”四类内容。对每个行动项提取“责任人”“期望完成时间”“关联上下文”。将责任人缺失的项目归入“待认领”区。按优先级对行动项排序紧急且重要 紧急 重要 常规。使用 assets/decision_template.md 作为输出模板不得脱离模板格式。这里的意图是压缩模型的决策空间。我不要求它思考什么是重要的我直接给定排序规则我不让它自由输出表格我给它一个标准模板。这不是为了限制创造力而是为了限制不确定性。在一次内部测试中我把同一条会议纪要分别用“自由提示词”和“技能包”跑五遍前者输出了三种完全不同的格式和两个不同的责任人人选后者五遍的差异只剩时间排序上的细微偏差。2.4 脚本层的存在意义把精确操作交给确定性代码我更进一步的建议是如果任务里有“从文本中提取日期并换算相对时间”“按 Excel 列做重命名”“生成特定数据结构的 JSON”这类操作不要指望着模型用“语言能力”硬写格式应该直接在 skills 里带一个 Python 脚本让主流程先调用模型做信息抽取再调用脚本做结构化转换。在我的 meeting-to-todo 技能里extract_owners.py 负责把“负责人建议由王强和张萌共同处理”这类自由文本拆成两个 owner 字段并去重。模型对“从一长串句子中找出人名”已经很擅长但把它转成规范的 JSON脚本更稳定。执行顺序是先由模型读取全文输出一个中间 JSON再由脚本对中间 JSON 做后处理。两层配合一个技能才算完整。这种“模型做语义理解脚本做确定性转换”的分工应该成为技能设计的基本常识。它能有效降低最终输出的语法错误率。因为我反复观察过当模型被要求一次性输出一个复杂的结构时它偶尔会在第 37 个字段后面突然漏掉一个引号或者把数组嵌套错一层。有了脚本做语法校验和重写这类低级错误几乎绝迹。3. 我的技能从 v1 到 v3 的演化版本管理救了我的工作效率3.1 v1所有规则硬编码成超长提示词的阶段最早版本的 meeting-to-todo 其实是没法在多个场景里复用的。为了覆盖客服记录、研发周会、产品评审会三种场景我把规则全部堆进一个提示词里。这样做的直接后果是当研发场景里需要强调“技术债是否记录”时客服场景的规则也会被同时激活导致输出里莫名其妙多了一行“客户情绪维度”。当时我想当然地以为把规则写得足够全模型就会按需选用。但事实是模型在一个长提示词里不会做严格的“场景路由”它在局部上下文里更倾向遵循字面顺序后续规则会对前面的行为产生干扰。这个阶段给了我很惨痛的教训一行提示词的改动可能影响另外六条规则的效果回归测试靠肉眼根本做不完。3.2 v2把资源文件拆出来的阶段v2 是我用工程思维重构的开始。我把每一种会议类型拆成一个独立的资源文件assets/meeting_type_engineering.mdassets/meeting_type_customer.mdassets/meeting_type_product.md主 SKILL.md 不再写场景细节只写“根据输入中的会议类型字段选择对应资源文件中的规则执行”。这一步的改动让我意识到技能的灵魂不在于“让模型看到所有信息”而在于“让模型只看到当下任务需要的那部分信息”。上下文不是越多越好相关才重要。同时我把动态部分从规则中剥离。以前“最近一次代码评审是在 3 月前”这种信息已经写进了提示词新版本里我改用脚本去读取真实的项目日历数据再注入上下文。这样技能包不再是封闭的死文件而是一个能感知环境数据的活动系统。3.3 v3路由能力与回滚机制的阶段v3 解决的是“选择哪套规则”这件事。我引入了两层机制第一层是元技能专门负责判断输入属于哪一类会议并返回对应的子技能名第二层是子技能间的隔离每个子技能只处理自己那一类会议的逻辑。最终调用关系是这样的外层的 meeting-to-todo 技能接收到输入后先做分类再委托给 engineering_todo、customer_todo 或 product_todo 之一。每个子技能都以独立版本存在互不覆盖。这个版本的回滚体验最好当冲动更新 customer_todo 后发现问题时一行命名的语义化版本切换就可以回到上一个版本而不会拖累 engineering_todo。这一步之后我把技能当成了一个正式维护的代码库有主分支、有 tag、有变更记录。4. 评估一个技能包的好坏我只看这四个指标4.1 拒绝率比准确率更值得关注大多数人评估提示词会看它答得准不准我却更关注它在不该回答时有没有拒绝。一个技能包如果对残缺输入硬生生给结论准确率再高也是虚高因为它在臆测。实际操作中我会给技能加一个统计口每次调用时把“正常完成”“拒识”“降级处理”三种结果写入日志。如果一个技能在正常业务里的拒绝率超过 15%它不是太保守就是我定义的前置条件与真实输入已经不匹配了。这时候应该调整输入门而不是简单放宽规则。比如我早期对客服技能设置了“必须包含订单号才能处理退款”结果大量用户只发了截图没有订单号拒绝率达到 40%。我把前置条件改成“包含订单号或清晰的订单截图信息”之后拒绝率降到 5%输出质量没有明显下降。这个例子清楚说明拒绝是防御机制不是最终目的什么时候拒绝、什么时候放行需要拿数据说话。4.2 可追溯性能不能定位每条输出背后的规则依据技能包的输出往往会“看起来合理”这是语言模型最危险的地方。为了对抗这种危险性我在模板里强制要求每个行动项后面跟一个“依据来源”字段记录这条结论来自会议原文的哪一句。这让输出变得可审计。以前的提示词输出是一锅粥现在每条输出都能溯源到输入文本的某个位置。当用户质疑某项结果时我不会凭感觉辩护而是可以明确指出来源。这个指标评估的其实是技能包是否真正“基于输入做处理”而不是借着输入的由头开始编故事。4.3 错误提示是否对用户有操作指引我见过太多技能在输入不满足时只回一句“无法处理”用户并不知道该补什么。好的错误提示应该像接口文档里的错误码明确说明缺了什么字段、应该去哪个位置补、补完后重新调用的方法是什么。我们从上到下设计技能时会默认用户熟悉内部结构这大错特错。真实用户根本不理解你的输入门是什么。因此我在 SKILL.md 里为每种拒绝条件都配置了“user_message”告知文案但这几乎是在做产品设计了。实际上我采取了更轻量的办法用单独一行列出“常见拒绝原因与修改建议”模型可以根据具体情况选择最接近的提示返回给用户。这种细节不花什么时间收益却非常显著。4.4 回归测试一技能一库修改后必须跑完测试集技能包如果更新频繁而缺乏回归测试就是在裸奔。我的做法是在 tests 目录下放五到十个典型输入每个测试文件附带一个 expected_output 摘要。修改技能后先跑一遍所有用例观察哪些输出产生了计划外变化。这里的经验是不要只看对错还要看差异。有一次我调整了排序规则原以为只会影响紧急项的位置结果所有正常项全部被降级还多了一条“重要且紧急”的标记。如果没有回归测试这种隐性破坏可能要上线几周后才被用户察觉。技能包本质上是另一种软件组件那它的质量守护方式也必须软件化。5. 从手动调用到技能路由正确使用顺序与常见陷阱5.1 不要第一天就引入 Agent 自动选技能遇到一个新需求时大部分人的第一反应是“让 Agent 自己判断应该调用哪个技能”。我劝你先停一停。如果一个技能连手动调用的效果都不稳定给它再强的路由也是把一个脆弱的基础放大成混乱的系统。我个人的推进路径是先在脚本里显式调用某个技能跑通单一场景。观察五到十次真实业务输入统计拒绝率和输出可追溯率。只有当单一技能调用成功率稳定在 90% 以上才考虑让路由层介入。等到你准备引入路由时要给每个技能写足够清晰的 name 与 description 字段。这部分看似不起眼却是模型选择技能的唯一直观依据。如果 description 写得太抽象比如“处理文字”模型会在多种情况下都选中它如果写得太具体比如“仅处理带时间戳的英文会议纪要”它又会错过机会。我把描述写成“将中文会议纪要转换为责任人明确的任务清单适用于研发/客服/产品三类会议当输入不是会议纪要时应拒绝”这段描述显著提高了路由命中率。5.2 命令空间冲突技能多了以后最先炸的地方技能数量超过十个后最常见的问题不是单个技能质量下降而是技能之间边界重叠。比如我既有“summary-and-export”又有“meeting-to-todo”两者都可以输出工作总结结果路由经常把会议纪要转发给 summary 技能产出一堆不分责任人的大白话。我的解决办法是在技能描述中加入“同类型任务边界”的说明例如在 summary 技能里写一句话“如果你需要从会议纪要中提取行动项并分配负责人请调用 meeting-to-todo而不是本技能。”这实际上是把路由决策的信息直接放进模型可见的描述里成本极低效果立竿见影。5.3 对不同模型的技能适配别迷信一次编写到处使用训练和推理方式不同模型对命令的遵从度也不同。我在调一个技能时发现对模型 A 有效的 rule 顺序在模型 B 上效果会打折。原因可能是模型 B 对长文本尾部的注意力分布不一样。现在我会在技能包里额外增加一个“model_tuning.md”记录本技能在不同模型下的参数调节建议。例如我自己的 meeting-to-todo 技能里model_tuning.md 会写明如果基于高指令遵从模型排序规则可以直接放在主流程如果基于低指令遵从模型建议将每一步显式拆开并附上示例否则它会跳过中间的判断直接套用输出模板。这类经验单独靠提示词无法承载必须作为技能的一部分沉淀下来。5.4 噪音输入与兜底策略最后一道防线即使技能设计得再完善生产环境里总会出现你没见过的极端输入。应对方式不是在规则里无限堆砌分支而是设置兜底策略。我常用的兜底有两条输出顶部强制要求模型自我检查“本次输出是否完全基于输入中的信息”如果没有依据需要显式标注“推测内容”对置信度低的字段统一标记为“unknown”而不是让模型选择一个看似合理的默认值。兜底策略更像是一种“安全气囊”保证模型在不确定时依然不会越过诚实边界。我之前有过太多因为没设兜底而生成的漂亮事故报告——每条信息看起来合理却没有一条能指出具体来源。加了这几条兜底之后类似的问题几乎绝迹。6. 最后几个基于我实际经验的收尾建议如果你正准备开始搭第一个技能包我最大的建议是先选一个“重复出现、规则明确、输出格式稳定”的小任务把它独立封装而不是一上来就去覆盖一个杂乱的大型工作流。小任务更容易观测效果也更容易在早期建立对技能包的信心。我最初的 meeting-to-todo 就是从单文件提示词开始的一步步拆成目录结构整个过程花了两周但收益用了两年。关于是否要用框架的问题我的看法是框架可以帮你管理加载和路由但技能的设计逻辑仍然得自己搭。不要被框架预设的目录限制了你的思考技能包最值钱的部分从来不是文件放在哪而是你如何定义输入门、如何组织处理逻辑、如何用脚本兜住模型的误差。最后再分享一个小技巧每次新技能上线后的第一周记得保留所有真实输入输出样本。这些东西是下一版优化的最佳素材。我每次改技能第一件事就是重新翻一遍上周的日志看看模型在哪类输入上频繁触发兜底策略再去调整规则顺序。时间一长你的技能包会像老员工的工艺手册一样越磨越顺手。
阅读完成 · 觉得有帮助?