1. 先泼盆冷水:Skill 数量与 Agent 智商不成正比
1.1 我见过最离谱的“技能全家桶”
先讲一个真实的场景。某团队在内部系统里接入 Agent 时,产品经理兴冲冲地列出了二十多个“必备技能”:查工时的、查 OKR 的、查会议室状态的、生成周报的、翻译邮件摘要的、自动给客户打标签的……理由也很充分:每个业务部门都觉得自己那点操作如果不变成技能,Agent 就“不完整”。
结果跑了两周,问题全冒出来了。最典型的是 Agent 会花十几秒“思考”,然后不确定该调哪个技能;有时候明明只是问一句“这周会议室紧张吗”,它能连环触发三个技能,最后给你返回一个风马牛不相及的排期表。后来我们做了一次埋点统计,二十多个技能里,真正在一周内被成功触发超过 10 次的只有 4 个,剩下十几个要么从未触发,要么每次触发都是误判。
这不是个别现象。我自己也踩过类似的坑,总想把 Agent 的能力边界撑大一点,于是不断往里塞技能包。装的时候有多爽,用的时候就有多痛。核心原因其实不难理解:Agent 的决策通道是有限的,每一个技能都在跟“直接回答”这条路抢资源。技能太多,模型每走一步都要做一次“要不要调用工具”的判断题,误判率自然就上去了。
1.2 模型的基础推理能力被“技能噪音”掩盖
很多人忽略了一件事:大模型本身已经内置了大量常识性能力。你问它“今天适合穿什么”,它不需要一个“天气穿衣建议技能”才能回答;你让它把一段话改得更委婉,它也不需要“邮件润色技能”。这些技能本质上是把模型已经会做的事情封装了一层,不但没有新增能力,反而增加了决策负担。
我习惯用“噪音”这个词来形容这种状态。一次对话中,系统把可用技能的名称、功能说明、参数格式、示例用法全部塞进上下文,模型相当于一边开车一边看十几块广告牌。它必须“无视”大部分广告牌才能专心开车,但这是有认知成本的。实测中,技能描述总长度超过一定阈值之后,模型对基础问题的回答质量会明显下降,尤其是那些需要多步推理的任务。
更隐蔽的问题是,技能的存在会改变模型的回答倾向。明明用户问的是一个开放性问题,模型因为检测到“这个技能的关键词沾边”,就会优先走工具调用路线,而不是直接组织语言回答。绕了一大圈,最后给出的结果反而更机械、更模板化。结论很扎心:技能不是越多越好,有时候少到极致,Agent 反而更聪明。
2. 一份 Agent Skill 失效的三种典型病理
2.1 描述性失语:模型根本不知道什么时候该用它
我复盘过大量“永远不被触发”的技能,发现它们有一个共同点:描述写得像招聘 JD,而不是使用说明书。
举个例子。某团队给 Agent 配了一个“项目风险预警技能”,技能的 description 写的是:“用于识别项目中可能存在的风险因素,并提供风险管理建议。”看起来没毛病,但模型面对用户真实提问时,根本不知道触发它。因为用户不会说“请进行风险管理”,用户会说“这个需求下周做不完怎么办”。如果技能描述里没有出现“延期”“做不完”“没时间”这类自然表达,模型在意图匹配阶段就把它跳过了。
我后来把这条描述改成:“当用户提到项目可能延期、资源不足、需求变更、团队抱怨时间不够等情况时,使用本技能分析风险并给出应对建议。不要用于解释概念或写科普说明。”触发率立刻翻了接近三倍。说明问题不在技能本身,而在描述是否完成了“从用户口语到工具调用”的翻译。描述性失语是大多数技能无效的第一大原因,也是最容易被修复的原因。
2.2 成本黑洞:技能文档先吃掉一半上下文
第二个病理更现实:上下文预算被技能说明蚕食。现在的 Agent 应用通常把技能描述、参数 Schema、示例片段全部注入系统提示词里。单个技能消耗几百 token 听起来不多,但十个技能就是几千甚至上万 token。如果 Agent 还需要读取用户数据、历史记录,那留给真正推理的空间就被严重压缩。
我做过一个对比:同一个 Agent,在技能包里只保留 2 个核心技能时,处理一段 3000 字中文材料并输出摘要,整体响应质量稳定;当技能包膨胀到 15 个之后,同样的问题出现了明显的“记忆衰减”——它开始遗忘材料前半部分的内容。这当然不是模型真的失忆,而是上下文窗口被无关技能描述占满,有效信息被挤出了注意力范围。
更坑的是,很多技能描述里还塞了大量“防御性提示”,比如“不要把这个技能用于 X 场景”“如果用户没有明确要求,请不要调用”。这些内容看似严谨,其实是双重负担:一方面占 token,另一方面会增加模型的理解歧义。最好的技能说明,是让模型在 1 秒内看懂触发条件;而不是让它读完一篇小论文再决定动不动手。
2.3 相互打架:多个技能同时触发导致死循环
多个技能之间互相干扰,是我见过最让人血压升高的场景。一个 Agent 同时挂着“日历管理技能”和“任务调度技能”,用户说“帮我安排下周五的评审会议”。结果模型先调用日历技能创建了日程,又调用任务调度技能生成了一堆待办,最后还试图用“邮件通知技能”给参会人发邀请。三个技能各做了一部分,但没有一个把整件事闭环。
更离谱的是技能之间的循环调用。有的 Agent 支持技能内部再调用其他技能,一旦 A 技能的输出格式触发了 B 技能的入口,B 又依赖 A 的返回值,就会在同一个任务里来回切换四五次。每次切换都要消耗 token,还可能因为参数格式不匹配直接报错。用户看到的结果就是:Agent 思考了很久,然后说“抱歉,我遇到了一些问题”。
这类问题很难从单个技能的代码里看出来,必须从“技能组合”的层面做排演。我后来定了一条规矩:新增任何技能之前,先画一张技能触发关系表,标注哪些技能可以串行、哪些技能绝不能同时出现。宁可个别场景多一步人工操作,也不要让 Agent 在多个技能之间反复横跳。
3. 我是怎么给已有技能做“健康检查”的
3.1 从触发率报表里找“僵尸技能”
给技能做体检,第一步不是看代码,而是看报表。如果 Agent 平台支持日志分析,我会重点拉三个指标:触发次数、调用成功次数、调用结果使用率。触发次数表示模型判断“该用技能”的次数;调用成功表示工具本身没报错;结果使用率表示最终回答里是否真的采纳了技能返回的数据。
三者的差距很能说明问题。一个技能如果触发次数很高但结果使用率很低,说明模型评估错了场景;如果触发次数极低,说明描述和用户的真实表达不匹配;如果调用经常失败,那就要检查工具接口是否稳定,或者参数映射是否合理。连续观察两周,基本能把“僵尸技能”找出来——它们占着上下文,却从未贡献过价值。
我还有一个个人习惯:每个技能都要设置独立的日志标记。这样不仅能看整体触发率,还能定位到具体是哪一类用户问题触发的。标签维度包括触发前缀、用户问题长度、调用耗时等等。没有这些数据,后面所有的优化都只能靠拍脑袋。
3.2 用 1 个问题判断是否值得重构
面对一个表现不佳的技能,我建议只问一个问题:去掉它,用户会明显觉得缺了某样东西吗?
如果答案是不确定,那就先别急着删,而是做一个“隐藏测试”:把技能从配置文件里注释掉,跑一周。很多团队不敢用这种“减法测试”,怕用户投诉。但我做过几次之后发现,真正被用户感知的功能缺失非常少。因为大多数技能只是锦上添花,而用户最常用的核心路径,往往只有一两条。
隐藏测试结束后,把有技能和无技能两段时间的用户反馈对比一下。如果没有任何人提到某个功能“消失了”,这个技能就可以彻底移除了。如果确实有反馈,再把技能加回来,同时按照更严谨的触发条件重新设计。这套方法周期长,但比拍脑袋决策可靠得多。
3.3 技能评估打分表
为了方便判断一个技能是去是留,我整理了一张打分表。每次评估技能,都会从以下几个维度打分,单项 1~5 分,总分低于 15 分的技能直接列入淘汰候选:
| 评估维度 | 打分逻辑 | 权重说明 |
|---|---|---|
| 触发准确率 | 触发后是不是总能匹配用户意图 | 核心指标,误触发越少越好 |
| 结果使用率 | 返回数据是否真的被写进最终回答 | 防止模型“用了等于没用” |
| 上下文成本 | 技能描述+Schema 实际占用 token 数 | 成本越高,要求越严苛 |
| 接口稳定性 | 外部服务超时、报错频率 | 不稳定接口等于给 Agent 埋雷 |
| 可维护性 | 参数变更是否需要频繁改代码 | 频繁改动会导致描述失真 |
这张表看起来简单,但比“感觉这个技能有用”要客观得多。尤其是“可维护性”这项,很容易被忽略。很多技能的接口只改了一个字段名,原本的文档就全废了。与其维护一堆脆弱连接,不如让 Agent 用最朴素的方式解决问题。
4. 实操:把拖后腿的技能改成真正有用的技能
4.1 裁剪前的准备工作
确定要保留哪些技能之后,不要直接动手改,先把准备工作做完,否则很容易改出一堆新问题。
第一步是梳理用户最常问的 20 类问题。可以从客服工单、群聊记录、搜索日志里拉,目标不是列全用户需求,而是找出覆盖度最高的几类。接着对这 20 类问题做一次“无技能基线测试”:让 Agent 在完全没有技能的情况下回答,看哪些问题能答好,哪些问题答得不行。答得不好的那一类,才是真正值得用技能去补的缺口。
我见过最普遍的错误是反向操作:先写了技能,再去找什么问题配它。这样相当于“有了锤子看什么都像钉子”,技能的触发范围会被强行扩大,最终表现反而更差。正确的顺序一定是“缺口在前,技能在后”。准备工作的最后一步,是给每个候选技能写一句“任务声明”,比如:“本技能只解决会议室预订确认,不做日程建议。”这句话会直接变成技能描述的第一句。
4.2 重新设计技能说明的三段式写法
我以为稳妥的技能说明,应该分成三部分:触发条件、执行边界、输出要求。缺一不可,但顺序可以按平台习惯调整。
触发条件部分,要写用户可能怎么说,而不是写技术概念。比如“当用户提到‘订个会议室’‘哪个房间有空’‘下午开会有地方吗’等表达时,使用本技能”。用自然口语覆盖高频说法,模型在意图匹配时命中率会明显提高。执行边界部分要写明“不做什么”,比如“不要主动推荐会议室之外的地点,不要修改已有日程”。这不是防御性废话,而是给模型划定清晰的决策边界,防止工具自由发挥。
输出要求部分最关键,但最容易被写坏。不要写“请输出友好且专业的回复”,这没有任何约束力。要写“只返回会议室编号、时间段和预订状态,一句话说明是否成功,勿包含思考过程”。明确的结构化要求,能让 Agent 的回答更稳定,也更容易被后续程序解析。三段式写完之后,建议把说明压缩到 300 token 以内;超过这个长度,大概率是因为混入了无关内容。
4.3 用显式开关避免误触发
有些技能本身很稳定,但就是容易在错误的场景里被误触发。比如数据分析技能,用户只不过说了一句“我感觉这数据不太对”,模型就可能直接调用技能去跑 SQL,结果因为权限不够报错。这种情况不能怪模型,只能怪技能的触发条件太宽松。
我会给这类技能加一个“显式开关”:要求的触发语句更严格,必须包含明确指令,比如“请用数据分析技能查看数据”“帮我统计一下”“跑一遍分析”。如果用户只是表达情绪,模型就应该用普通对话能力回应,而不是动用工具。这个改动会让技能的触发率下降,但成功率会显著上升。
另外一个有效手段是把高成本技能的优先级调低。如果模型需要在“调用数据分析技能”和“直接回答”之间选择,我宁愿它先尝试直接回答;只有当回答需要精确数字或者跨表查询时,才选择调用工具。调整优先级不会让技能失效,而是让它从“天天抢戏”变成“关键先生”。
5. 一组对比实验结果:同一任务,开技能与不开技能
5.1 测试任务设计
光说不练没有说服力。我挑了一个内部测试集来对比“满技能版 Agent”和“极简版 Agent”的差异。测试集包含 12 类常见任务,每类任务准备 10 条真实用户问题,一共 120 条。问题覆盖日常问答、数据查询、流程安排、文案改写、多步信息整合等场景。
实验分成三组:第一组挂 12 个技能,包括日程、天气、订单查询、邮件起草、风险预警等;第二组只挂 3 个被验证为“高触发、高使用率”的技能;第三组不挂任何技能,纯靠模型基础能力。三组使用同一个模型版本、同一份系统提示词和完全相同的输入顺序,尽可能排除变量干扰。评估标准也提前定好:回答准确率、任务完成度、平均响应时长、上下文 token 开销。
坦白讲,一开始我预想的结论是“极简版大于满技能版”,但我没想到差距会那么大。尤其在多步信息整合任务里,满技能版经常因为中途调用一次无关工具,导致后续步骤断掉。极简版反而能一路走到底。
5.2 典型结果
简单汇总几个关键数据(虚构测试数据,仅作讨论):
| 指标 | 满技能版(12 个技能) | 精简版(3 个技能) | 无技能版 |
|---|---|---|---|
| 总体成功率 | 64% | 83% | 78% |
| 数据查询类准确率 | 88% | 91% | 52% |
| 开放问答类准确率 | 61% | 80% | 86% |
| 平均回答耗时 | 8.2 秒 | 5.4 秒 | 4.1 秒 |
| 平均 token 单次 | 5400 | 3300 | 2100 |
数据查询类任务里,无技能版输得很彻底,因为模型记不住某个内部系统的状态,必须有工具做支撑。开放问答类任务里,满技能版明显被拖累,本来能直接生成的回答,非要先思考一遍工具切换再输出,准确率反而最低。最让我意外的是精简版:它在两类任务里都拿了不错的分数,尤其在整体成功率上最高,达到了 83%。
结论并不复杂:技能要解决的是“模型靠内部知识无法单独完成”的问题,而不是代替模型做它本来就擅长的事。数据查询离不开技能,开放问答则应该让模型自由发挥。把所有技能无差别塞给 Agent,只会让它在不该调用工具的地方消耗时间和注意力。
5.3 对结果的理解
有人可能会问:既然无技能版在开放问答里得分最高,是不是干脆把所有技能都删了?我认为不是。因为真实业务里有很多必需操作,比如“查询订单状态”“提交工单”“触达外部系统”,没有技能,模型根本完成不了。所以那个 52% 的数据查询准确率就是代价。
实验最值得关注的是满技能版和精简版的差距——两者拥有的工具能力几乎一致,满技能版只是多了 9 个“低频技能”。这些低频技能没有在任何一次测试里帮上忙,却稳定地拖慢了响应速度。也就是说,技能包的边际收益下降得比想象中快得多。前面 1 个技能带来的能力提升非常明显,到第 5 个技能时基本持平,第 10 个往后就开始负优化。
这给我一个很实际的操作指引:如果团队时间有限,与其优化每一个技能的实现细节,不如先砍掉一半低频技能。一次减法带来的效果,可能比重写十个技能描述还明显。
6. 我最后留下哪些技能,以及避坑清单
6.1 目前仍保留的几类技能
经过几轮清理,我现在给内部 Agent 保留的技能,大致只分三类。
第一类是“数据访问型”。系统内的订单、库存、项目状态等数据,模型不可能靠训练知道,必须通过工具读取。这一类技能是刚需,需要保证接口稳定,并且描述要写得特别具体,细化到参数名和返回字段。第二类是“外部动作型”,例如提交审批、创建日程、发送通知。它们必须被执行,但触发门槛要高,最好加上用户二次确认环节,防止误操作。第三类是“格式转换型”,例如把一段文本转成特定结构、从非结构化内容里抽取字段。这类技能适合场景固定、输出标准化的任务。
其余那些“知识科普型”“写作润色型”“脑暴建议型”技能,我基本都不挂了。不是它们没用,而是模型的基础能力已经足够好,挂上去只会增加噪音。我现在的原则是:如果一次对话中,用户最直接的感受就是“对话变顺畅了”,那技能配置就做对了。
6.2 避坑清单
最后分享一份避坑清单,都是我实际踩过之后整理出来的。希望你在给 Agent 配技能时能少走几步弯路。
- 不要为了“完整”而配技能。先把用户高频问题和能力缺口对齐,再决定加什么。
- 不要用抽象描述写技能说明。触发条件要写用户原话,执行边界要写“不做什么”。
- 不要放过低频技能。连续两周触发率低于 10 次的技能,优先隐藏并观察。
- 不要只盯触发率。结果使用率才是最终价值的体现,触发率高但结果不用,等于一场空。
- 不要让技能互相嵌套。除非有充分测试,否则 A 技能调 B 技能很容易变成死循环。
- 不要把完整工具文档塞进技能描述。精简到只保留调用所需的最小信息量。
我给 Agent 配置技能的经验,说白了就是“少即是多”。早期我也迷恋那种动辄几十个技能的能力清单,好像技能数量代表了 Agent 的战斗力。但现在我更看重每一次调用的确定性:这个技能可能很慢,可能很笨,但只要它被触发,就一定要给出对用户有用的结果。这一件事做到了,技能就算没白配;做不到,删掉反而是最优解。