
做AI应用这一两年agent-skills这个词的出现频率越来越高。我最初注意到它是在整理团队Agent代码仓库的时候——一堆散落的工具函数、提示词模板、调用逻辑互相纠缠每次新项目都要重新拼一遍改一处接口能牵出一串报错。后来我们把“技能”当作一等公民来设计开发节奏立刻不一样了。这篇从我的实操经验出发聊聊agent-skills到底在解决什么问题、技能怎么拆怎么设计、落地时有哪些坑适合正在做Agent产品的开发者也适合想把自己项目里“能跑但不好维护”的智能体重构一遍的朋友。1. agent-skills到底在解决什么问题1.1 “万能Agent”是个伪命题能力边界才是真需求我见过太多人一开始搭Agent时脑子里想的是“一句话让模型把所有事都干了”。这个想法本身没有错但落到工程实现上几乎必炸。原因很简单真实任务不是只有一个而是一堆粒度不同、接口不同、权限不同的小任务。你今天希望Agent帮你查天气明天希望它写SQL后天希望它调内部CRM系统导出报表。如果你把这些需求全部塞进系统提示词里prompt很快会膨胀到几千行模型每次请求都要消化大量无关信息响应变慢、token变贵更麻烦的是改一个细节就要重新调优因为提示词之间会互相干扰。我踩过最典型的坑是把十几个工具tools的说明全部写进system prompt结果模型在简单任务上反而开始“选择困难”明明只需要调一个查询函数它非要先调用一个分析函数兜圈子。核心问题不是模型不够聪明而是能力没有结构化。这也是agent-skills出现的背景——它试图把“Agent会什么”这件事从模型的自由发挥里解放出来变成一套显式、可管理、可复用的能力单元。1.2 技能层是什么把经验、工具、规则打包成可复用单元先给一个我比较常用的定义技能skill是一个能让Agent稳定完成某个子任务的能力包它内部封装了触发条件、输入输出结构、执行逻辑、异常处理以及必要的提示词片段。它跟工具tool的区别在于工具通常指单个函数或API比如“查询订单接口”技能更接近任务语义比如“查询订单并生成用户可读的进度摘要”里面可能包含两个工具调用和一段结果整理逻辑。它跟工作流workflow的区别在于工作流是固定的多步编排适合流程不变的任务技能更轻量强调可组合、可复用同一个技能可以被多个Agent在多种场景下调用。举个例子。我之前做一个会议纪要产品早期是“调接口→拿转写文本→直接把文本丢给模型总结”效果很差。后来我们封装了一个“会议纪要结构化”技能内部做了三件事第一清洗转写文本删除语气词和重复片段第二按说话人分离内容第三抽取待办事项和决策结论。对外它只暴露一个函数generate_meeting_minutes(transcript_text, duration)。这个技能被产品里多个入口复用——实时会议、录音上传、历史会议补录全部走同一个技能。后来要改摘要风格只改技能内部的提示词片段所有入口同步生效。这就是技能层的价值它让能力有了边界也让能力可以沉淀。2. 技能拆解与设计怎么把任务变成一套技能2.1 从真实任务倒推技能清单而不是拍脑袋设计技能体系最容易犯的错误是“先定义后验证”——拿着一个理想化列表觉得Agent应该会写邮件、应该会做数据分析、应该会排查服务器日志然后照着清单吭哧吭哧写写完发现一半技能用不上另一半真正高频的需求压根没覆盖。我的做法是反过来的先收集真实任务再做聚类。具体分四步走第一步把过去一段时间里Agent收到的用户请求全部导出来没有线上数据就用测试用例凑至少准备两百条。第二步按“动作对象”拆解请求比如“帮我查一下昨天订单为什么失败”可以拆成“查询订单状态”和“分析失败原因”“把这份报告用英文发给客户”拆成“翻译报告”和“生成英文邮件”。第三步把同类的动作归并成一个候选技能统计每个候选技能出现频次用频次排序。第四步给每个候选技能标注三个属性调用频率、复用范围、实现成本。频率高、复用广、成本低的优先做频次低但成本高的先记入 backlog不急着动手。我当时用这个方法从产品入口的几千条真实请求里筛出一个技能清单最后第一版只做了六个技能覆盖了大约八成的请求量。剩下的长尾需求靠模型通用能力去兜底就够了。这个“二八原则”很重要。技能不是越多越好而是覆盖最核心的重复劳动。每一个技能都有维护成本技能数量失控会让索引和检索都变成负担。2.2 技能粒度怎么定拆到多大算正好技能粒度是整个设计里最难拿捏的部分。拆太粗技能内部会塞进一堆if-else每个分支都是不同业务场景模型根本分辨不清拆太细调用链变长Agent需要在一次任务里串五六个技能编排失败率直线上升。我通常用三条经验规则来判断粒度是否合适规则一一个技能应该能在一次调用中完成一个可验收的子任务。“可验收”的意思是执行完你明确知道结果对不对。比如“解析PDF并提取表格”是可验收的“分析这份合同”不是一个好技能因为“分析”太模糊要拆成“抽取合同条款”“识别风险点”“生成合同摘要”三个技能。规则二如果实现一个技能时需要大段条件分支来区分业务场景说明粒度偏大应该拆开。比如“处理文件”这个技能里面的逻辑可能分散成“文件转换格式”“文件压缩”“文件内容提取”它们不应该混在一起。规则三如果调用完一个技能还需要接着做三步以上的后续处理才能得到用户要的结果说明粒度偏小应该考虑合并或者提供上层组合技能。我做电商客服Agent时有一个典型案例。“查单”一开始拆成了三个技能查订单状态、查物流轨迹、查退款进度。看起来没问题实际上用户问“我的快递到哪了”时Agent要先判断属于哪类查询再决定调哪个技能这个判断本身就会出错。后来我合并成一个“查询订单全流程信息”技能内部自动路由到不同数据源对外参数只保留order_id和query_type效果反而稳了。粒度的判断不是纯理论问题最终标准是你希望模型在哪个层面做决策。把决策留在模型擅长的地方把执行收敛在技能内部。2.3 技能描述与参数设计让模型“一看就知道什么时候该用”技能设计里最容易忽视、但影响最大的其实是描述文字。因为在大多数Agent架构里不是你的代码决定什么时候调用技能而是模型根据技能描述做决定。描述写得差技能写得再好也没用。一个合格的技能描述至少要包含三层信息第一层什么时候用。直接写清楚触发场景比如“当用户询问订单配送进度、物流轨迹或预计送达时间时使用”。第二层什么时候不用。这一点很多人会漏掉但它非常关键。比如查物流技能里写明“不要用于查询历史订单状态历史订单请使用查询订单历史技能”能有效减少误调用。第三层需要哪些关键参数。描述里说明入参的格式和边界比如order_id必须是数字字符串query_type只能取status、logistics、refund三个枚举值。参数设计上我坚持一条尽量结构化拒绝自由文本。自由文本看起来灵活实际上会让参数抽取变成新的故障点。比如技能要接收“时间范围”我会定义成start_time和end_time两个ISO格式字符串而不是传一句“上周一到周三”让模型自己猜。下面是我常用的一个技能描述模板可以直接参考{ skill_name: query_logistics, description: 查询订单的物流轨迹与配送进度。当用户询问快递到哪了、什么时候送达、物流是否停滞时使用。不要用于查询订单金额、退款状态或历史订单信息。, parameters: { order_id: string, 必填, 订单编号纯数字字符串, query_type: string, 必填, 枚举值logistics / status / tracking_number } }注意description里的否定句我后面会专门讲为什么它值回票价。3. 技能实现与运行机制从定义到真实跑起来3.1 技能落地的三种常见形态怎么选技能定义只是设计文档真正落地主要有三种形态我分别踩过以后说说它们的适用范围。第一种纯Prompt技能。这种技能的“执行体”其实是一段指令模板模型拿到输入后按照模板处理文本不调用任何外部系统。适合文本分类、摘要、信息抽取、格式转换这类任务。优点是实现成本极低缺点是结果不稳定并且每次执行都会消耗token。我通常只用它来做轻量级文本加工比如清洗转录文本、把半结构化文本转成JSON。第二种代码技能。一个函数或API的封装内部可能有网络请求、数据库查询、外部SDK调用。Agent识别到需要这个技能后提取参数代码执行返回结构化结果。适合有明确数据源或系统接口的任务。这是最稳定、最可控的形态也是我主力使用的形态。缺点是需要写代码、需要维护技能变多之后工作量不小。第三种混合技能。内部既有代码逻辑也有Prompt调用。典型场景是先用代码调取原始数据再用模型做智能处理最后用代码格式化结果。比如前面说的“会议纪要结构化”就是混合技能代码负责转写清洗模型负责抽取待办和决策。这种形态能力最强但也最复杂建议等前两种跑通之后再上。选择标准只有一个看任务里“智能”的部分占多少。几乎没有智能含量、逻辑固定就写代码技能完全靠理解力和表达力就写Prompt技能既有数据操作又有语义理解就写混合技能。3.2 技能库的组织与检索技能超过20个之后怎么办技能少的时候怎么存都行全塞在一个文件夹里也能找到。但当技能数量超过二十个你一定会遇到“模型在决策时看不出该用哪个技能”的问题。我见过一个项目在系统提示词里列了四十多个技能说明结果是模型频繁选错甚至自创技能名。解决这个问题我在工程上分了三步走。第一步给技能建立目录结构按领域分域。比如skills/ ├── order/ │ ├── query_logistics.json │ ├── build_order_report.json │ └── handle_refund.json ├── content/ │ ├── generate_meeting_minutes.json │ ├── extract_action_items.json │ └── summarize_document.json └── data/ ├── query_sales_stats.json └── detect_anomaly.json分域不只是为了好看是为了后续检索。领域本身就是一种天然的标签。第二步写一个技能索引文件每个技能维护4个字段技能名、一句话说明、参数摘要、运行入口。这个索引文件可以在Agent初始化时只加载一次替代把全文塞进prompt的做法。第三步按需加载。不要让Agent一次性看到所有技能而是根据用户请求做语义检索只把最相关的3到5个技能注入上下文。这样可以大幅降低token消耗也降低模型选错技能的概率。我在技能检索上做过一个对比实验全量注入30个技能描述选对技能的成功率大概七成改成按请求检索后再注入相关技能成功率提升到九成以上。原因不难理解候选集越小决策越集中。3.3 一次技能调用的完整链路每一步都在做什么理解了技能形态和检索再看一次技能调用背后到底发生了什么。我用一个客服Agent“查物流”的例子走一遍完整链路。第一步用户输入“我昨天买的那个手机到哪了”。第二步Agent做意图识别。这一步没有调用技能只是让模型判断用户意图同时从用户上下文或数据库里补全可能缺失的参数。第三步技能匹配。系统用用户意图去技能库做检索召回query_logistics和query_order_status两个候选项经过评分后选出query_logistics。第四步参数抽取。模型从用户输入里提取order_id。这里有个细节用户可能没直接给订单号系统要先查询用户最近一笔订单拿到订单号才能进行下一步。第五步技能执行。代码函数被调用去物流系统拉取轨迹数据返回结构化JSON。第六步结果整理。原始物流数据是一串运单节点直接丢给用户显然不行。系统会把结构化结果拼成一段摘要再把摘要交给模型生成口语化回答。第七步上下文压缩。技能执行产生的原始JSON可能很长如果全量塞回对话上下文下一轮请求就会很臃肿。我的做法是只保留一个精简版本的执行结果摘要比如最终状态、当前位置、预计送达时间原始数据丢弃。这七步里最容易出问题的不是技能本身而是第四步参数抽取和第七步上下文压缩。参数抽取出错后面的技能执行根本跑不到上下文压缩做得太狠模型会丢掉回答所需的细节。压缩力度要反复试我当时是按“回答质量不下降”为基准一点点压缩出来的下限。4. 常见问题与排查技巧实录4.1 高频问题的排查思路速查技能系统跑起来以后真正磨人的不是写代码是问题排查。我把实际工作中遇到的高频问题整理成一个速查表每个问题都标注了排查顺序。常见问题现象优先排查方向常用解法模型不调用该调用的技能回答正确但绕过了技能走通用能力技能描述是否写清了触发时机在描述中补充明确的“当……时使用”句式模型调用了错误的技能逻辑通顺但执行错了动作候选技能之间描述是否有重叠在描述中写明“不要用于……”缩小检索候选集参数抽取错误技能执行返回报错或空结果参数schema是否足够结构化把自由文本参数改为枚举值增加参数校验技能执行超时技能卡住或接口迟迟不返回技能内部是否有重试和熔断机制给每个外部调用加超时和熔断失败时返回兜底文案模型不会使用技能返回结果技能执行成功但回答牛头不对马嘴返回结果是否过于原始、缺乏摘要在技能内部增加结果格式化步骤输出带语义摘要的结果技能调用链断裂一个技能的输出无法作为下一个技能的输入相邻技能的输入输出schema是否对齐设计技能时统一上下文数据模型用同一个中间格式传参这里我说一下表格里几个容易忽略的点。“模型不调用该调用的技能”这一条很多人第一反应是模型不行换更大模型。但绝大多数情况是技能描述里没有给出足够强的触发信号。模型决策时是读文字的它不会因为你起的技能名里有“query”就认为该调用它。描述里明确写“当用户询问……时使用”比什么技巧都管用。“不会使用技能返回结果”这一条根因通常是技能返回结果太重。我有一次让技能返回了一整张几十行的表格模型拿到之后找不到重点回答里开始编数据。后来改成在技能内部预先算好汇总指标模型只拿汇总数字去生成回答问题立刻消失。4.2 几个值得复用的工程技巧排查之外我再分享几个在真实项目中验证过、收益比较稳定的工程技巧。第一个技巧给每个技能写一个固定的“结果摘要器”。无论技能内部做了多复杂的处理对外统一输出三层结构status成功/失败/异常、summary供模型直接阅读的执行摘要、raw_data原始数据可选。模型优先读summary需要细节再下沉到raw_data。这个设计解决了大部分“模型不会用结果”的问题。第二个技巧权限校验放到技能层而不是UI层或Prompt层。我在一个内部工具里吃过亏当时权限校验写在页面上绕过页面直接调接口就能越权。后来把权限判断下沉到技能执行函数内部每次调用都校验用户身份和操作许可。技能不只是能力单元也应该是安全边界。第三个技巧为每个技能准备一个冒烟测试用例。所谓冒烟测试就是一组固定输入和期望输出每次技能改动后先跑一遍确保没有破坏核心链路。技能看似独立实际经常被多个场景复用一个细节改动可能影响所有入口。没有冒烟测试等于裸奔。我建了一个很大的回归用例集跑完一遍也就几分钟但拦住了大量线上问题。第四个技巧记录技能调用的token消耗。Prompt技能和混合技能会消耗模型token这个成本很容易被忽视。我在技能运行时挂了计数逻辑每调一次都会累加token数。一个月后看数据发现某个低频技能消耗的token比高频代码技能高出几倍因为它的输入输出很冗长。根据数据做优化比凭感觉砍功能靠谱。4.3 一个让我记忆深刻的踩坑案例说一个具体的案例。前段时间做一个报表生成技能需求是让Agent根据用户的一句话生成销售报表。初版设计得很简单技能接收时间范围和维度参数调数据接口返回表格。上线后问题不断。用户说“看下上周华东区的销售情况”模型正确调用了技能但返回结果是一张原始明细表整整几十行模型根本不知道用户想看的是汇总还是明细。用户又追问“为什么不总结一下”Agent才补了一段话。后来我重构了这个技能内部先自动生成三层数据——汇总指标、按维度拆解、明细列表——然后用Prompt挑选当前问题对应的展示层级最终输出一个带结论的摘要。重构之后用户问“上周华东区怎么样”技能直接回一句“华东区上周销售额环比增长8%主要是上海和杭州两个城市拉动”附上维度拆解表格。这个案例给我的教训很直接技能不能只做“取数”还要做“理解任务语义”。同样一个数据接口面对“怎么样”和“列出每条订单明细”要输出的内容完全不同。技能设计时就要考虑用户提出这个请求背后真正想要的东西。5. 一点真实体会与后续扩展技能体系不是一次设计出来的是跟着项目迭代长出来的。我第一版技能框架只有三个技能问题一大堆但因为骨架搭得对后面加技能只是往目录里放新文件、写清描述和参数整套机制不需要重写。这个“先搭骨架、再做深一两个技能、再横向扩展”的顺序我建议你直接复用。紧接着说一个一直想做的扩展技能市场。我们的技能库目前还是项目内共享但如果把技能描述、参数schema、测试用例打包成一个标准格式不同团队、不同项目之间就能互相交换技能。一个团队打磨好的物流查询技能另一个团队下载即可用这种复用效率会非常惊人。另一个扩展方向是跨Agent共享技能。我们现在每个Agent有独立的技能列表但很多基础技能是重叠的比如“时间格式化”“文本摘要”“数据校验”。把这些通用技能单独抽出做成一个共享层所有Agent按需引用维护成本能再降一截。多模态技能也在规划里。目前技能大多处理文本和结构化数据但实际需求里有很多图像理解、语音合成的场景。把多模态能力也封装成技能整个Agent能覆盖的任务范围会大很多。最后分享一个小技巧收尾。我要求团队每次新增技能时必须在描述里写一段“不要在什么时候使用”。这个约束看起来是多写几句话实际上逼着你去思考技能的边界到底在哪。写不出这段说明你自己都没想清楚这个技能的适用范围这种情况下等想清楚了再写代码也不迟。