
大概从去年开始我手头好几个agent项目都撞上了同一堵墙单个任务里的function calling写得再顺一旦换一个场景、换一份数据格式整套逻辑就得推翻重来。直到我把“技能skills”这套抽象机制彻底想明白才意识到之前所谓的agent开发其实一直在用最原始的方式堆逻辑。这篇东西不打算写成文档就按我自己从原理到落地的完整过程来聊agent skills到底是什么、为什么它能把agent的能力做成一劳永逸的模块、一个技能从设计到上线的完整链路以及我实际踩过的坑和验证方法。如果你也在做agent开发或者正在纠结怎么让多个场景共用一套能力这篇应该能给你省下不少弯路。1. 从“工具调用”到“技能封装”Agent开发方式的转变先说个我一直以来的判断函数调用和技能压根不是同一个层级的东西。很多人把agent skills理解成“一组更复杂的工具函数”这是最大的误区。1.1 传统Function Calling的天花板早期做agent最标准的路子是给模型挂一堆函数描述让它根据用户意图去选择并调用。单看一次调用这套机制够用但项目一复杂问题就全都浮出来了。第一个是语义粒度太粗。我给模型暴露一个fetch_url_content的函数意图很明确但真到了需要“读完文章并提炼要点”这种复合任务模型就得自行编排多次调用而编排的逻辑散落在prompt里换一个任务就要重写一段。第二个是上下文负担太重。每个函数我们都要写详细的功能描述和参数说明模型每次交互都要把这些描述吃进上下文里。挂了二十个函数之后光函数描述就能吃掉几千token而且调用越频繁模型的注意力越分散出错率显著上升。第三个是复用性几乎为零。你在这个项目里精心调试好的“网页内容提取结构化输出”流程换到另一个项目里因为底层模型、prompt结构、调用约定都不一致整套东西直接作废。说白了之前我们做的都是“一次性代码”从来没把它当成可复用的能力资产。对就是“能力资产”这个词这是我后期才意识到的。函数调用本质是让模型去操作一个具体的执行单元而技能是一种可以被反复部署、跨场景迁移的封装能力。1.2 Skills机制到底带来什么变化Agent skills的核心思路是把“模型如何完成任务”一整段逻辑——包括前置检查、多步骤执行、结果格式化、异常兜底——打包成一个独立模块。模型只要识别到当前任务匹配某个技能的描述就直接调用这个模块不需要在对话里一步步重新编排。我做一个生活化的类比。函数调用像你雇了一个杂工你说“去把螺丝拧紧”他需要你自己交代用什么工具、拧几圈、拧完怎么检查。而技能是你雇了一个“空调维修专员”他自带全套工具和标准作业流程你只需要说“房间空调不制冷”他自己就知道要先检测电压、再看制冷剂压力、最后做清洁完事给你一份标准的检测报告。Skills带来的三个关键变化我总结如下任务执行从“边聊边想”变成“模块化调用”。模型先判断当前任务该用哪个技能然后整个技能作为一段独立逻辑执行不需要模型在上下文中逐步推演稳定性和速度都提升明显。技能描述被精简上下文占用大幅下降。技能库里每个技能只需要一段精炼的“何时使用”描述模型做选择时的负担比逐个阅读几十个函数描述小得多。多场景共享一套能力成为现实。同一个“网页信息提取”技能既可以用在舆情分析项目里也可以用在竞品调研项目里底层逻辑不变。2. Agent Skills的底层结构与运行机制光知道“它是个模块”还不够要把技能写好必须从根上理解它的组成和运行逻辑。一个完整的agent skill在我看来由三个层次组成描述层、交互层、实现层。2.1 一个Skill的完整组成描述层是技能库的“索引”也是模型决定“该不该用”的唯一依据。很多新手写技能描述一段话写得很简略结果就是模型在错误的场景下调用或者该调用的时候视而不见。我踩过的最典型一次一个“PDF表格抽取”技能我给模型的描述是“从PDF中提取表格数据”结果用户问“这个PDF里有没有关于营收的描述”时模型直接调用了它输出的却是无结构文本。如果描述里写明“仅用于需要结构化表格输出的场景若用户询问文本内容请勿调用”就不会发生这种事。交互层决定了模型怎么把自然语言请求翻译成技能能理解的参数。这里有个容易忽视的点交互层的输入输出格式一定要和描述层所说“何时使用”的场景匹配。比如一个“周报生成”技能输入参数如果你定义成“本周工作事项的JSON数组”模型就得做一次格式转换既增加出错概率也增加token消耗。合理的设计是直接接受自然语言段落内部的解析逻辑自己处理。实现层就是一个技能真正的执行代码。它不一定是Python或者JavaScript只要能跑就行。我的习惯是凡是涉及网络请求、文件读写的技能都用Python实现因为生态最全凡是涉及浏览器自动化的就直接调Playwright涉及大量文本重组的用JavaScript处理JSON反而更顺手。2.2 模型如何“发现”和“选择”技能理解了组成下一步要搞清楚系统是怎么从技能库里做选择的。这一块在我早期做开发时甚至没意识到它的存在——我以为模型是直接读所有技能描述然后从里面挑一个。但实际上技能数量一多全量加载根本不现实。让我把skill选择机制拆细一些。通常具备skills能力的agent框架会做两级路由第一级是技能索引也就是把所有技能的“触发条件”浓缩成一行行索引信息模型先扫一遍索引筛选出可能相关的3到5个第二级才是加载候选技能的完整描述结合当前对话上下文做精确匹配。如果项目用的是集中式技能库这个过程通常由宿主程序完成如果是分散式技能包这个“筛选”过程本质上就是一次模型推理调用。这也是我在实际项目中反复调整的一个点技能的“触发条件”写得越精确模型选对的概率越高。不要把触发条件写成“处理文档类任务”而要写成“当用户提供或引用一份Markdown/Word/PDF文档并要求转换格式、提取信息、汇总内容时使用”。这行字直接决定了你的技能是被准确命中还是被无关调用浪费掉。2.3 执行阶段的状态管理与错误恢复技能一旦被选中进入执行接下来考验的就是工程能力了。我在第一版技能里犯过一个低级错误技能执行是“一步到底”的一旦中途报错整个任务就死了模型不得不重新发起一次调用。我现在的做法是在技能内部做“分阶段状态追踪”。每个技能的执行都被拆成独立的阶段比如“参数校验→资源获取→核心处理→结果格式化”。每个阶段结束都输出一个结构化状态对象一旦某个阶段失败技能能直接返回“错误发生在哪个阶段、失败原因是什么、可以尝试的替代方案是什么”。模型收到这个错误反馈后不需要重新启动整个技能只需要针对失败阶段做修正或者换一条路径。这种设计带来的直接收益是我那套“网页内容抓取技能”的失败重试成本降低了大概四成。之前遇到目标网站反爬或者页面结构变化整个任务直接崩掉现在技能会在“资源获取”阶段识别出异常返回“页面结构已变化建议改用PDF版本”模型可以无缝切换策略。3. 完整实战开发一个可复用的Agent技能讲原理容易但真正动手写技能的时候还是会遇到一堆细节问题。下面我用一个我自己打磨过较完整的案例——“会议纪要与行动项提取技能”——走一遍完整流程从需求定义到调试通过每个环节说清楚为什么这么做。3.1 需求定义与边界划清写技能第一步不是写代码是画边界。当时团队里的需求是把每次客户会议的录音转成文字之后自动提炼出讨论主题、分歧点、决策和行动项并且要输出成固定格式的Markdown。边界我划了三条输入必须是已经转写好的会议文本技能本身不做语音转文字这就避免了我把外部ASR服务的耦合带进来输出格式严格固定需求方要求后续要直接导入电子看板工具所以Markdown结构不允许灵活发挥只处理内容本身不做参会人情绪分析、不做话题趋势预测这些属于“做了反而干扰核心功能”的噪音侧写。划好边界后最大好处在后面几个迭代里体现出来了——每当需求方提出“能不能顺便把每个人的发言次数统计一下”我都能明确回答“那个属于另一个技能不建议塞进来”。如果一开始不划界技能迭代几版之后就会变成一个大杂烩描述层没法写模型也会频繁误选。3.2 Skill描述决定“被调用成功率”的细节接下来写SKILL.md也就是那个技能描述文件。这一段的措辞水平直接决定模型能不能准确触发技能。我在第一版写的是# 会议纪要与行动项提取 从会议记录文本中提取讨论主题、决策和行动项输出Markdown格式。实测了大概20轮对话发现问题不少。最典型的问题是用户只是闲聊一句“下午的会你们觉得怎么样”时模型也会触发技能去提取。后来我把描述改成了带“触发条件”和“不适用场景”双段落的结构# 会议纪要与行动项提取 ## 何时使用 当用户直接提供一段会议转写文本或明确引用某次会议的文本记录并且要求从中整理出会议纪要、讨论结论、决策事项或后续行动项时使用本技能。 ## 何时不使用 如果用户只是普通聊天中提到“会议”“讨论”等词汇但没有提供任何文本也没有要求整理纪要不要调用本技能。 如果用户提供的是文章、博客或邮件正文而非会议转写文本请使用其他文本处理技能。改完之后误触发率肉眼可见地下降。道理很简单一个从真实需求里长出来的agent skills核心不只是“会做什么”更是“知道自己不做什么”。这行字并不起眼但它就是决定技能命中率的关键分水岭。3.3 核心实现与参数设计描述层解决“什么时候用”实现层解决“怎么把它做好”。这个技能的输入参数只有两个对话文本内容必填和可选的角色清单。参数我故意设计得这么少是为了降低模型在入口处做选择的负担。有些开发者喜欢给技能设计一堆可选参数以为这是灵活性其实技能在选择和执行时都要为每个参数做一次隐式推理参数越多越容易出偏差。我的原则是必填参数只保留“任务绝对绕不开的”其他的一律让内部逻辑自己判断。比如“这次会议有没有明确指定主持人”这类信息技能内部可以通过语义识别来推断根本不需要作为参数暴露给模型。实现层的核心逻辑我拆成了几个子函数split_by_topic把长文本按话题自然分段。这里我用的不是简单的分句切分而是基于段落结构加语义相似度做聚类。实际测试下来一份6000字的会议转写切出来5到7个话题块的效果是最好的。extract_discussion对每个话题块做“发言角色-观点立场-关键论据”三元组提取。这个阶段我强调模型输出必须使用固定的JSON schema不做任何自由发挥。generate_actions统一从全文里找“需要后续跟进”的表述并判定优先级和截止时间。优先级我采用三层标准硬性截止比如“下周三前给客户回复”、软性期望“尽快推进一下”、非紧急“后续有空收拾一下”。render_markdown把上面的结构化数据渲染成固定的Markdown格式。这里需要多提一下JSON schema的固化。我在第一版里用的是自然语言描述让模型自由输出结果格式经常飘有的输出用decesion拼错字段名有的优先级用小图标。后来我直接把输出结构写死成一个Pydantic模型在代码里声明字段类型、允许值、嵌套关系模型输出再做一次强制schema校验不符合就直接重试一次。从那以后输出稳定性从大概85%升到了接近100%。3.4 本地调试的完整流程技能写完之后不能直接上生产这一步最容易被忽略的坑是你以为模型对技能的理解和你一样实际上它理解的只是你描述层的那几行字。所以我所有技能的调试都是先跑“描述层测试”再跑“实现层测试”。描述层测试的做法很简单构造一组正向样本和负向样本正向样本是“应当触发技能”的对话负向样本是“不应当触发技能”的对话挨个丢给agent看模型选择是否正确。比如我准备过这些样例正向“这段会议文字里大家讨论了两个方案最后定了A方案张伟负责下周一前出报价帮我整理成会议纪要。”负向“哎对了你还记得上周说的那个会议吗后来怎么样了”——虽然提到了会议但只是闲聊回顾并没有提供文本。实现层测试就要把技能真正跑起来给一份真实的会议转写文本检查各个子函数的输出质量。我会重点盯两个指标一是结构校验输出能不能通过JSON schema校验二是语义校验比如行动项到底有没有把“负责人”和“截止时间”对应对。很多情况下负责人在正文里叫“张总”在行动项里变成“对方公司”这种模型很容易搞混必须靠真实样本一遍遍检查。4. 工具链与选型对比哪种Skills方案适合你原理和手写流程都过了一遍再来说选型。现在“skills”几乎成了各家agent框架的标配能力但不同方案之间的设计思路差异还是很大的选错了后面迁移成本极高。4.1 主流方案的横向对比我自己实际深度用过的有四类分别是闭源产品内置技能Claude Agent Skills这类、偏向代码生成场景的编码技能集Codex skills这类、开源agent框架的技能插件体系、以及完全自研的技能运行环境。这四类的定位完全不同。直接上对比表方案类型典型代表技能格式适用场景主要局限产品内置Claude Agent SkillsMarkdown描述脚本文件目录通用生产力任务、个人助理、内容处理平台绑定迁移成本高编码向技能集Codex Skills代码仓库CLI入口说明代码生成、仓库级任务重构偏开发场景通用任务支持弱开源框架插件各类agent框架的skill包遵循框架约定的脚本JSON多代理编排、复杂业务流依赖框架版本生态参差自研运行环境你自己定义的调用协议任意格式深度定制、企业级内部复用需要自己维护调度和存储从我自己的经验来说如果你做的agent主要跑在某个闭源产品生态里那直接用平台自带的skills格式是最省事的因为触发机制、上下文管理都被处理好了。但如果你像我一样需要把技能横跨多个平台复用就别被单一生态绑死尽早采用“技能目录 独立调用脚本”的自定义结构。4.2 从零搭建还是用现成平台那到底是自己从零搭一套技能运行环境还是用现成的下载平台我的看法是分阶段验证期一定用现成的规模化了再考虑自持。我在早期阶段从各类下载平台找过不少现成技能包那个阶段的收获主要是“看别人怎么设计技能描述”。很多优质技能包的SKILL.md写得极好触发条件明确、负面条件清晰、输入输出示例完整我后来自己写技能时大量借鉴了这种结构。这个阶段直接自己搭基础设施你还没理解技能设计的最佳实践大概率会把你现有的问题固化下来。等你的技能库规模超过20个、跨了3个以上业务域之后再开始自建一套“技能注册表版本管理运行时日志”的基础设施。到这个阶段你才真正理解需要什么不是“执行能力”本身而是技能迭代的观测能力。比如哪个技能触发频率最高、哪个技能经常在哪个阶段失败、哪个技能的描述值得优化这些数据才是资产。4.3 下载和复用他人Skills时的筛选标准这里单独说一句因为这部分的坑我踩得很重。第三方技能包的质量方差大得惊人一个好的技能包和坏的技能包表面看起来差别不大用起来天壤之别。我筛选技能包时重点看四个维度顺序也有讲究描述层有没有“何时不使用”段落。没有这个段落的技能包大概率是作者为了补任务临时写的连触发边界都没想清楚。有没有真实的输入输出示例。好的技能包一定有至少一组完整示例文件展示技能执行前后的数据形态。只有描述没有示例的技能执行结果几乎不可预期。依赖声明是否完整。技能包如果在描述里写了“依赖Python库beautifulsoup4”但没有提供requirements.txt或等价声明那它在你的环境里大概率跑不起来而且你找不到原因。更新记录和作者维护频度。这点我个人很看重因为这直接反映了技能包是被持续迭代还是写完了就扔。一个半年没更新的技能包在当前这个发展速度下基本等于废了。5. 测试评估与实战避坑指南最后这部分我不打算再讲设计理念了就分享测试和上线过程中真实遇到的问题。这些细节你在任何官方文档里都看不到但它们往往直接决定了技能能不能稳定跑在业务里。5.1 断言式测试和样本库机制技能类项目的测试和传统软件开发很不一样最大的难点在于“没有唯一正确答案”。两个同样优秀的会议纪要技能可能一个把“张伟负责”解析成负责人为“张伟”另一个解析为“张伟客户方”两者都不能算错但你没法用传统断言去判定谁更好。我的做法是建立了一套“字段级抽检”的评估机制而不是把整个输出拿来对比。比如行动项提取我关注的不是整篇纪要的措辞是否一致而是对每个行动项单独抽出来看负责人字段人员名是否真实出现在原文中、截止时间字段是否有明确原文依据、动作描述字段是否包含可执行的动词短语。逐字段校验过之后再算一个整体准确率。这个指标比看整篇文本的一致性有意义得多。样本库是另一个值得多提一嘴的机制。我从第一次做技能迭代开始就坚持给每个技能维护一套样本集里面至少20个真实输入输出对。每次改完描述层或者实现层我就把整套样本重新跑一遍确保旧行为没有被无意中改坏。这个机制在传统软件开发里属于基础中的基础但在agent开发里被大量人跳过了因为大家总觉得模型输出没法精确定制于是连回归测试都不做了。事实证明回归测试的价值不止于防退化它还是调优的催化剂——很多次我都是因为某个历史样本跑挂了才反推当前技能的哪个环节设计还不够稳。5.2 高频踩坑清单描述模糊、参数膨胀、上下文泄漏第一类坑是描述层写得太“像人话”缺少结构化信号。大部分初学者会写成“这个技能可以帮用户整理会议记录”但模型对这类自然语言的理解偏向宽泛极容易在无关场景误调用。我的解法是描述里必须出现具体的名词和动词组合像“会议转写文本”“行动项”“Markdown表格输出”这种越具象越好。第二类坑是参数无节制扩张。我见过一个网页爬取技能暴露了7个参数包括超时、重试次数、编码、代理、UA、Cookie、渲染方式。表面看是给用户全面的控制权实际上模型在生成这些参数时经常自相矛盾比如同时传了headlessTrue和rendertrue。正确的做法是大部分参数锁死在技能内部只暴露任务级参数。参数暴露越少模型越不容易出错。第三类坑是上下文泄漏。这种情况出现在同一技能里混合处理多个独立事务时比如一个“资料整理”技能前半段处理用户上传的PDF后半段又让模型总结本周的聊天记录。技能的设计逻辑混乱模型在执行时也容易把两个任务的语义搅在一起输出的整理结果里混着完全无关的信息。任何技能一次只处理一个语义域。5.3 性能与token消耗的优化最后说点关于效率和成本的实际经验。技能机制虽然减少了上下文占用但并不意味着token消耗天然就低实现时还是有几个烧token的点需要注意。一个隐蔽的开销是“无效重试”。当模型调用的技能在参数校验阶段就失败时有些框架会原样再抛给模型让模型“重新生成参数”这个重试过程往往一遍就是几百token。我的做法是在错误信息里直接给出“当前技能可接受的参数示例和格式”理想情况下模型第二次就能给出正确答案。另一个开销是“结果再加工”。技能把结果返回给模型之后模型经常觉得格式不够完美又开始自己改写一遍。要减少这类消耗技能本身输出的结果就要做到“模型无需二次编辑”的程度。会议纪要技能输出的Markdown我刻意做成了符合常见看板导入工具的默认格式模型收到之后看一眼就能直接输出给用户完全不需要动手改。我个人的经验是每次版本迭代之后观测“技能数调用/输出字符数”这个比值如果它在持续上涨多半是你技能内部的某处步骤在消耗大量中间token做低效转换赶紧查执行日志比盲目相信框架自带的统计工具要来得直接。到这一步围绕agent skills从原理框架到工程落地我把一整条链路里自己真正验证过的东西都翻出来了。技能机制厉害的地方不在某个单独的点而在于它逼着你用做产品的方式去想agent能力而不是用写临时脚本的方式去堆。哪怕你之前完全没接触过这个领域只要从边界清晰的小技能开始练手逐步优化描述层和实现层慢慢就能体会到为什么“skills”会成为agent开发里公认的新阶段。