☰
Agent Skills技能体系实战:从定义、构建到治理
2026/10/14 8:25:36 网站建设 项目流程

打开任何一个AI开发者社区,agent-skills这个词最近都在以肉眼可见的速度刷屏。但我的体感是:真正把它聊透的人不多。多数帖子停在“展示一个炫酷技能”,少数帖子停在“我们应该给Agent装技能”,至于技能怎么定义、怎么入库、怎么防止技能之间互相打架,很少有人说清楚。我自己把一个内部工具项目改造成基于技能体系的Agent之后,最大的感受是:模型本身并没有变聪明,但系统整体变得可靠了,调试成本也降了一个量级。这篇文章不聊概念,只聊我实际动手时踩过的问题、定过的规则和最终沉淀下来的做法。

1. “agent-skills”热议背后,真正要解决的是什么问题

很多人第一次听到“Agent Skills”时,第一反应是:这不就是给模型写Prompt吗?或者,这跟Function Call有什么区别?我有段时间也这么想,直到我连续拆了十几个任务后才发现,技能层解决的东西跟Prompt和工具函数都不太一样。

1.1 模型会思考,但不会“干活”:意图与行为之间缺一个工业层

大模型本质上是一个概率性的文本生成器。你给它一段输入,它回一段输出,中间没有稳定的“执行”保证。你可以让模型写出一个Python函数,但你没法保证它每次都能写对;你可以让模型模仿一个工作流,但它每轮都可能发明新的写法。这在Demo阶段无所谓,一旦要把Agent接进真实业务流程,问题就放大了:同一个“整理会议纪要”的诉求,模型上一次返回的是JSON,这一次可能返回的是带星号的Markdown,下一次干脆在回复里夹了一段“好的,我来帮你整理”。

技能层做的事情,就是在这条“意图到行为”的通路里,插入一个有边界、有协议、有校验的中间层。技能的职责不是替模型思考,而是把那些已经被验证过“这么做能成”的动作片段固化下来。模型只负责判断“现在该调用哪个技能”和“给技能填什么参数”,具体怎么做,由技能里的执行体接管。

打个生活化的比方:模型像大脑,技能像双手。大脑负责决定“我要倒水”,双手负责执行“拿杯子、开壶盖、倾斜倒水”这套标准动作。没有技能的模型,相当于每次倒水都要重新研究一遍手该怎么动,偶尔还会把水洒得满桌都是。

1.2 提示词工程为什么解决不了“复用”问题

在技能体系出现之前,大家普遍的做法是把所有指令塞进一个System Prompt,或者做一个超长的提示模板。这种方法在单个任务上有效,但一旦任务数量上来,问题就非常明显:

第一,代码层面无法复用。同样一段“把用户输入拆成结构化字段”的逻辑,写进A任务的Prompt里是一份,写进B任务的Prompt里又是另一份,改一处要全局找。第二,不可测试。Prompt没有固定入口,你没法给它配一组回归用例。第三,上下文被大量占用。你每轮对话都要把“遇到XX情况请按XX格式输出”重复灌给模型,真正留给用户问题分析的空间被压缩。第四,行为不稳定。同一个Prompt在不同轮次、不同上下文里的表现可能存在很大差异,因为模型会在长指令里“挑重点”。

技能层把这些指令从“自然语言描述”变成了“可执行的代码或严格的模板 + 结构化输入输出协议”。指令被固化,行为边界被收紧,模型要做的事情从“理解并遵守长文指令”变成“选择技能并填参数”。后者的成功率,远远高于前者。

1.3 什么样的项目才值得引入技能体系

这不是说所有项目都应该上技能。我自己判断项目是不是需要技能体系,主要看四条标准:

  • 任务是否可枚举:如果用户请求是完全开放、没有边界的闲聊,那么技能体系帮不上忙;但如果是“写周报、查库存、发报价单”这类有限集合,就值得做。
  • 是否存在高频重复的动作片段:比如每次处理工单都要先做意图分类,每次生成周报前都要先聚合数据源,这些片段重复出现,才有“沉淀”的价值。
  • 是否需要多人协作和持续维护:一个人写的脚本自己心里有数,但一个三人以上的团队维护几十个Agent任务时,没有统一接口几乎寸步难行。
  • 是否需要审计和回滚:业务场景要求你知道某条结果是由哪一步、哪个版本产生的,技能库的版本体系可以追溯。

如果你的项目只是做一个几百行内的脚本、演示Demo、或者一次性数据清洗,那完全可以直接写Prompt。技能层是为“从玩具到工具”这一跨越准备的。

2. 一个技能的四件套:名字、描述、输入协议、执行体

我在花了两周时间把第一个技能库搭起来之后,最大的教训是:很多人把技能想得太简单,以为就是“一段提示模板 + 一个函数名”。但真正能长期稳定运行的技能,必须是一个完整单元。

2.1 先分清“技能”和“工具函数”的区别

工具函数(Function)回答的是“怎么做一步操作”,比如“执行SQL查询”“调用翻译API”。技能(Skill)回答的是“怎么完成一个业务流程环节”,比如“把客户的英文邮件转成结构化工单”。一个技能内部往往要调用多个工具函数,还要包含触发条件、参数清洗、结果校验和失败降级。

我见过一个团队把“生成销售周报”做成了技能,但它内部其实包含:读取CRM数据、聚合上周指标、对比目标值、生成自然语言摘要、按模板排版五个动作。这五个动作如果拆成五个独立工具让模型自己编排,模型大概率会在某一步漏掉对比目标值,或者生成摘要时格式不对。技能的价值就是把这五个动作编排逻辑固定下来,对外只暴露一个入口:输入销售数据,输出周报正文。

2.2 技能描述怎么写,模型才不误用

这是整个技能设计里最容易被低估的地方。技能描述是模型选择技能时唯一能看到的“说明书”,写得太泛,模型什么都往这个技能塞;写得太窄,模型该用的时候不用。

我后来总结出一个公式,每个技能的description必须包含三块:

  • 正向触发条件:什么场景下应该考虑调用本技能。要写业务场景,而不是写处理动作。
  • 反向排除条件:什么时候坚决不能用本技能。负例比正例更能帮模型避开误用。
  • 前置数据要求:调用前,哪些字段必须已经就绪。

举个例子,“会议纪要整理技能”的描述,我是这么写的:

name: meeting_minutes_formatter description: > 当用户提供一段会议录音转写文本,并希望整理为会议纪要、待办事项或决策记录时, 使用本技能。适用场景包括:周会、项目同步会、客户沟通会。 不适用于:用户只要求摘要单句话、要求生成会议邀请邮件、或输入内容并非会议转写。 前置要求:transcript字段必须包含完整的转写文本,长度不少于50字。

这段话看着啰嗦,但实测下来,模型误用率下降了非常明显。原因是它把“摘要”和“会议纪要整理”这两个动作边界划清楚了。很多初版描述只写“整理会议内容”,结果模型把“帮我总结一下这个文章”也路由到了这个技能上。

2.3 输入输出协议比执行体更关键

我早期犯过一个错:把大量精力花在执行体怎么写,却忽略了输入输出协议。后来真正跑业务才发现,80%的故障都出在边界上:模型传进来的参数缺失、字段类型不对、输出结果没有通过校验就直接入库。

一个技能必须有结构化的输入Schema和输出Schema。输入用JSON Schema约束,输出不仅要声明结构,还要写一段校验逻辑。校验逻辑建议包含两个层面:结构层面(字段是否存在、类型是否正确)和业务层面(数值是否在合理范围、枚举值是否合法)。业务层面的校验才是真正防脏数据的关键。比如“生成报价单”技能,输出里总金额字段是数字,但校验时还要检查总金额是否等于各项之和,否则模型算出个错误总和就会进入审批流。

2.4 一个最小可用的技能长什么样

这里给一个简化版示例,结构可以直接抄。以“邮件摘要技能”为例:

name: email_summary_extractor description: > 提取原始邮件正文中的关键信息,生成结构化摘要。 适用于用户提供完整邮件内容并要求总结要点/提取待办。 不适用于短于20字的碎片消息,不适用于需要自动回复邮件的场景。 input_schema: type: object required: [raw_email, sender] properties: raw_email: type: string description: 邮件完整正文 sender: type: string description: 发件人标识 output_schema: type: object required: [summary, action_items, urgency] properties: summary: type: string action_items: type: array items: type: string urgency: type: string enum: [low, medium, high]

执行体则是一个Python函数,内部先调一次大模型抽取关键字段,再用pydantic校验输出,不合法就自动重试一次,重试仍失败就返回统一错误结构。这些细节写着繁琐,但正是这套“协议 + 校验 + 重试”的组合,把技能成功率从“碰运气”拉到了“可接受”。

3. 从零搭技能库:从四条业务线里“榨”出技能的过程

设计技能最忌讳拍脑袋:坐在电脑前凭空想“这个场景应该有个技能”。真正的技能库是长在业务日志里的。我搭技能库时,做了一套还算系统的提炼方法,你可以直接照搬。

3.1 先扒任务日志,别凭感觉设计

我把过去三个月内Agent跑过的所有任务日志拉出来,一条一条扫。重点找三类东西:

第一,高频出现的动作片段。比如很多任务里都有“先判断用户意图,再分配优先级”这一步,这个片段就是一个技能候选。第二,被反复修订的提示段落。如果有一段指令在十几个任务里被以几乎相同的形式复制粘贴,那就说明它应该被固化。第三,频繁失败的操作步骤。日志里模型经常在某一步格式不对或逻辑遗漏,这不是模型笨,而是这一步缺少确定性引导,正是技能要补的位置。

我统计下来,四条业务线的日志里浮现出了大约四十几个候选片段,但真正值得做成技能的只有一半左右。判断标准很简单:这个片段在过去一个月里,每周都被用到至少五次,才配得上一份专属技能。

3.2 按“频次 × 成本 × 复用潜力”排序,先做头部

候选技能不可能一次性全部实现,得排优先级。我用的打分公式是:

优先级 = 调用频次 × 失败代价 × 复用潜力

调用频次直接数,失败代价按“该步骤出错后对下游的影响”打分(比如生成进账单就比生成摘要影响大),复用潜力看这个技能能否被多个业务线共用。一次算下来,排在最前面的往往是“结构化工单拆分”“周报指标聚合”“公告合规检查”这类基础动作,而不是花哨的业务能力。

先做头部技能的收益是:技能库建立的第一周就能覆盖大约六成的重复工作。这个正反馈很重要——团队看到技能真能减少扯皮,后面推进就顺畅不少。

3.3 命名空间与版本管理:早定规矩,后面少吵架

技能库一旦超过二十个,命名混乱就是灾难。我定了一套命名规则:业务域.动作.对象。

比如crm.quote.build_pdf、crm.invoice.send_reminder、analytics.report.weekly_aggregate。这套规则最大的价值不是好看,而是天然形成分组。模型在路由时也能通过前缀快速缩小选择范围;运维在排查时也能一眼看出某个技能属于哪个业务域。

版本管理也很重要。每个技能定义文件里必须带version字段,执行体改动时同步升版本,并且在变更说明里记录“改了什么、为什么改”。我见过不记录版本的结果:一个技能改了两版后,输出字段从user_name变成了username,下游解析直接断裂,查了半天才发现是技能悄悄改了协议。

3.4 给每个技能配一张“测试卡”

这个习惯救了我很多次。我要求每个技能在入库时,必须带一张测试卡,包含四类用例:

  • 成功用例:典型场景下,预期输出是什么样的。
  • 失败用例:输入不完整或条件不满足时,技能应该返回什么错误。
  • 边界用例:空值、超长文本、极端数值。
  • 易混用例:最容易跟其他技能混淆的输入,验证模型能正确路由。

哪怕是最简单的技能也要配。原因后面会细说,这里先记住一句:Agent系统的风险,往往不是“会不会用”,而是“在边界处做选择时选得对不对”。

4. 技能化改造前后,我这边的数据对比

光说“技能好”没有说服力,我把改造前后的实测数据放出来。这是我在自己项目里跑的相对结果,数据集不大,但趋势已经很能说明问题。

4.1 测试怎么设计

我从业务线里随机抽了20个真实任务,覆盖工单分类、周报生成、客户邮件摘要、报价单制作、数据异常排查五类。同一个任务分别用两种方案跑:A方案是旧的“巨型Prompt + 自由发挥”模式,B方案是“技能路由 + 结构化执行”模式。模型用同一个版本,温度设置一样,每个任务各跑三遍,取中位数或多数结果对比。

4.2 关键数据对比

指标A方案(纯Prompt)B方案(技能化)变化
任务整体完成率55%82%+27个百分点
输出格式合格率70%100%大幅改善
单任务Prompt token消耗基准值约降低37%减少
单次失败平均排查时长约2小时约30分钟明显缩短
需要人工介入比例30%12%大幅下降

完成率提升在意料之中,但有两个数字比我预想的更突出。一个是token消耗下降37%,原因是原本每轮都要重复注入的冗长指令,现在被压缩成“技能名 + 参数”,模型不需要在上下文里反复“阅读理解”。另一个是排查时长压缩,这个不完全是技能的功劳,更多来自统一错误结构——失败时返回的错误不再是模型即兴写下的一句话,而是一个带错误码、带缺失字段说明的结构体,顺着查就是几分钟的事。

4.3 比数字更重要的三个体验变化

数字之外,有三个方面很难用表格衡量,但实际工作流改善巨大。

第一个是调试体验。以前模型输出不对,你要从头读一遍Prompt,猜它是在哪一步理解偏了。现在是先看路由记录:它选了哪个技能、填了哪些参数。如果选错了技能,问题在描述层;如果参数填错了,问题在提示词或者Schema设计;如果执行体报错,问题在代码层。三层边界清晰了,调试就等于按图索骥。

第二个是稳定性。技能化之后,同样输入的多次运行结果几乎一致。这不是因为模型不随机,而是因为技能执行体把随机部分限定在了一个很小的生成范围内(比如只生成摘要正文,不生成格式和流程)。业务方终于敢把Agent输出接进正式流程。

第三个是新同学上手快。新同事不需要理解业务的全貌,只需要看技能清单,就能知道系统“会什么、不会什么”,排查问题时直接定位到对应技能。

5. 技能库膨胀与冲突:新问题清单及排查思路

技能化的过程不是一路顺风的。跑到第三个月,技能库膨胀到接近四十个,新问题开始冒头。这里把我踩过的几个典型坑完整写出来,特别是那个真实的排查链路,希望你碰到类似情况时不必重新走弯路。

5.1 先看现象:从“串技能”到“选择困难”

危险迹象通常不是技能报错,而是任务结果“不对劲但能跑”。典型症状有三类:第一是串技能,用户明明要周报,系统却跑出了会议纪要的结构;第二是选择困难,技能多了以后模型开始在日志里反复尝试调用多个技能,最终返回“无法确定使用哪个技能”;第三是沉默失效,模型觉得哪个技能都不完全匹配,就绕过技能库直接自由发挥。

这三个症状的根源几乎都指向同一个地方:技能描述之间的边界不够清晰,或者技能数量超过了模型在当前上下文中的分辨能力。

5.2 一次真实的排查链路:“周报技能”和“会议纪要技能”打架

我当时遇到一个具体问题:让Agent生成“上周工作周报”,结果输出里混进了“本次会议待办事项”的片段。第一反应是模型抽风,但连续复现三次后,我决定按链路排查。

第一步查路由日志。日志显示模型确实调用了analytics.report.weekly_aggregate,但返回结果中混入了meeting_minutes_formatter的输出片段。这说明两个技能在同一轮任务中都被执行了。

第二步查两个技能的描述。问题一下就暴露了。周报技能的描述里写了“适用于包含本周工作总结、下周计划、风险点的汇报材料”,会议纪要技能的描述里写了“适用于整理会议讨论内容、待办事项和结论”。而用户输入的周报请求里包含了“上周例会讨论的三个事项”,两个描述对“事项”二字的覆盖面产生了重叠。模型认为例会事项也该走会议纪要。

第三步修复。我没有选择修改提示词让模型“更聪明”,而是直接给两个技能加了互斥描述:周报技能增加“内部不得包含待办执行细节,事项只做摘要级别引用”;会议纪要技能增加“仅当输入为原始会议转写文本时使用,不接收周报请求”。同时给周报技能的输出Schema增加了一个校验规则:如果结果里出现了action_items字段,判定结构不合法,自动重试。

第四步回归。改完跑测试卡里的易混用例,确认周报请求不会触发会议纪要技能,然后全量回归一遍所有技能,确保没有引入新问题。全程大概用了半天,但如果一开始没有路由日志和测试卡,这个问题的排查时间至少翻三倍。

5.3 过时技能怎么处理:冷却与归档

业务规则会变,技能也会过期。最坑的是,模型不知道技能里的规则已经过期,还会照常调用它输出旧格式的结论。我这里的办法是给每个技能增加生命周期状态:active、cooling、archived。

规则变更后,不要把技能直接删除,先改成cooling状态,在描述里注一句“当前业务规则已变更,本技能不再使用”,观察一到两周。期间如果模型还频繁调用,说明有业务路径仍然依赖它,需要回头梳理依赖;如果几乎不再被调用,就转入archived。归档不是删除,保留定义和执行体,方便版本追溯。

5.4 回归测试与质量门禁:防止改A坏B

技能规模上来以后,最怕的是改了A技能,结果B技能的调用链路被波及。这里的根源往往不是代码层面的依赖,而是描述层面的语义重叠——A技能的描述改动后,模型把本该给B的任务路由给了A。

所以回归测试必须全量跑,不能只跑你改的那个技能。我现在的流程是:任何技能变更触发后,自动跑一遍所有测试卡,只要有一个失败就阻断发布。这个门禁一开始会觉得麻烦,但它是技能库能长期膨胀而不失控的底线。

6. 技能协同的正确姿势:三种编排模式与一条底线

单个技能解决单件事,但真实业务是复杂流程。这一层我到很后期才真正理顺,前期因为乱编排踩了不少坑。下面是我最终保留的三种模式。

6.1 链式编排:A的输出就是B的输入

适合有严格先后顺序的流程。比如报价单制作:先调用crm.quote.fetch_context拉取客户与项目信息,再把结果作为crm.quote.build_pdf的输入。链式编排要注意的是每两个技能之间的数据结构必须对齐,否则断层的地方又要靠模型自由发挥。

我的做法是在技能库里定义“输出契约”:每个技能的输出Schema同时标注“可能对接的下游技能”。这一步不做,编排就全靠运气。

6.2 路由编排:先分类,再分发

适合入口庞杂、单个请求可能涉及多个技能域的场景。比如统一客服入口,先调用一个intent_classifier技能把用户请求分类,再根据分类路由到对应技能。注意分类技能本身也要被当成普通技能治理,不能因为是“分类器”就给特殊待遇。

6.3 并行拆分:多个独立技能同时执行

适合互相没有依赖、最后需要汇总的技能组。比如生成项目周报时,同时调analytics.report.weekly_aggregate聚合数据、调crm.ticket.summary统计工单、调hr.leave.calendar拉取请假记录,最后合并成一份报告。并行编排的坑在共享状态:多个技能如果同时写同一个上下文变量,会出现互相覆盖。我的对策是每个技能只能用自己输入的独立字段,汇总动作单独用一个merger技能完成。

6.4 底线:能写死的工作流,别让Agent自由发挥

这是我最想强调的一条。技能体系有一个诱惑:因为模型会自动编排,所以设计者容易偷懒,把本该固定的流程也交给模型临场发挥。实际上,凡是业务规则已经明确、步骤顺序固定的流程,都应该用外部工作流写死,只在需要判断和生成的地方开放Agent能力。

我见过一个反例:某团队把“审批通过后自动发送通知”也交给Agent编排,结果模型某次在审批未通过的时候自作主张发了通知。这不是模型坏,而是设计上把确定性动作交错了对象。Agent技能的下限,应该由流程引擎兜住。

7. 最后几个不写进文档的小技巧

真正把技能体系维护大半年之后,有几个心得不会写进正式文档,但特别值得分享。

第一个是测试卡里多写失败用例,而不是成功用例。Agent出问题几乎都出在边界和异常上,成功路径反而很少翻车。我后来给每个技能配的用例里,失败和边界用例占到七成。

第二个是技能描述里一定要写负例。正面描述写得再漂亮,模型也容易过度泛化;一句话负例“不适用于什么”,往往比三句正向描述更有用。

第三个是统一错误结构。所有技能在失败时都返回一个带错误码、错误阶段、缺失字段的错误体。这套结构看起来像基础设施,但它决定了你排查问题的速度上限。

第四个是定期做技能健康度检查。我每两周跑一遍全量测试卡,把通过率下降的技能标红,优先排查。很多问题在变成线上故障之前,其实已经先在测试卡里露出了苗头。

你自己动手做Agent时,会发现真正把它从概念Demo推向可用状态,拼的不是模型多聪明,而是这层“技能层”打理得多干净。它不性感,但可靠。这大概就是agent-skills这个词背后最值得花时间的地方。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询