news 2026/8/27 2:40:49

Agent技能过百后调用命中率下降?元数据设计与路由策略实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent技能过百后调用命中率下降?元数据设计与路由策略实战

当 Agent 里的 Skill 数量超过 100 个之后,调用命中率会明显下降。这不是模型突然变笨了,而是我们把太多能力平铺在一起,让模型在每次决策时都要面对一个巨大的、彼此相似的候选集。最近我在维护一个 Agent 项目时,就遇到了这个现象:技能库从 30 个涨到 120 多个后,原先很多一次就能命中的调用开始频繁选错。同一个请求,有时候触发 A,有时候触发 B,偶尔还会调用一个看起来毫不相关的技能。后来我意识到,这已经不是一个提示词优化问题,而是一个信息架构和路由工程问题。

所以这篇文章不是教你怎么写单个 Skill,而是讨论一个更麻烦的问题:当 Skill 数量过百,Agent 该怎样保证调用命中率。我会从底层原因、元数据设计、路由策略、描述写法、测试方法和长期维护六个维度展开,尽量把这条路径讲透。

1. 先理解命中率为什么会在过百之后崩掉

很多团队的直觉是:Skill 越多,Agent 能力越强。这个直觉在十几个 Skill 的时候基本成立。但一旦数量过百,问题就不再是“能力不够”,而是“决策空间太大”。

1.1 模型选择 Skill 的过程,本质上是一次有约束的文本生成

要理解命中率,先要放下一个误解:模型并不是在“搜索”技能库,而是在生成下一个最合理的动作。

当你把所有 Skill 的描述都塞进系统提示词时,模型面对的是几百行文字。它需要在这些文字里找到与用户请求最匹配的一项,然后输出对应的调用指令。这个过程不是精确匹配,而是基于上下文的概率生成。

如果候选只有 10 个技能,模型几乎不会选错。因为每个技能的描述差异很大,用户请求和技能之间的关联很清晰。但当候选达到 100 个以上时,问题就不一样了:很多技能在“功能描述”上高度相似,比如“生成周报”“生成日报”“生成会议纪要”,单看描述都能对上“帮我把工作内容整理一下”这个请求,模型就会在几个相近选项之间摇摆。

这时候的命中率下降,不是模型能力退化,而是任务本身的判别难度上升了。

1.2 上下文过载后,相似描述会互相干扰

还有一个常被忽略的因素:上下文窗口和注意力机制。

系统提示词里的内容越多,每个 Skill 描述实际分到的注意力就越少。更麻烦的是,描述之间会互相干扰。比如 A 技能写了“生成 Python 脚本”,B 技能写了“执行 Python 代码”,C 技能写了“分析 Python 项目结构”。这三个描述放在一起,模型很难准确判断用户说“帮我写一段 Python 脚本”时应该调用哪一个。

从工程经验看,当技能总数超过 50 个后,继续往系统提示词里堆描述,收益会快速衰减;超过 100 个后,甚至会出现负面效果:模型更容易被无关技能带偏,或者为了“显得有用”而强行调用某个技能。

1.3 命中率下降的三种典型表现

在实际项目里,命中率下降通常不是突然归零,而是以三种形式出现:

  • 选错:用户请求是 A,Agent 调用了 B。比如要“创建任务”,它调用了“删除任务”。
  • 犹豫:模型先调用一个技能,结果发现不合适,又尝试另一个,反复横跳,浪费大量 token。
  • 幻觉调用:模型调用了当前 Skill 列表里不存在的技能,或者把两个技能拼在一起,产生一个错误指令。

这三种情况我都遇到过。最隐蔽的是第二种——它不会直接报错,但会让整个 Agent 的执行链路变得非常慢,而且用户会明显感觉到“这个 Agent 不稳定”。

注意:当命中率下降时,先不要急着优化单个 Skill 的描述。首先要判断是选错、犹豫,还是幻觉调用,因为这三类问题的解法完全不同。

2. 给 Skill 建立“可路由的元数据”,而不是写更多描述

很多人的第一反应是给每个 Skill 写更详细的描述。这个方向有问题。描述写得再长,如果模型需要在 100 个长描述里找答案,识别难度依然很高。

真正需要做的,是先给 Skill 建立一套可被路由的元数据。

2.1 先区分“使用说明”和“用于选择的检索信息”

一个 Skill 通常包含两部分信息:

  • 使用说明:这个技能怎么执行、有哪些参数、依赖什么环境。
  • 用于选择的检索信息:什么场景下应该调用它、什么场景下不该调用它、它和哪些技能容易混淆。

传统的 Skill 文件往往把这两部分混在一起。如果让模型直接读完整文件来做选择,信息量太大,而且很多执行细节对“选择”没有帮助。

我建议的做法是:单独维护一个 Skill 索引层,只保留和“选择”相关的字段。模型决策时先看索引,等确认调用后,再加载完整的 Skill 定义。

2.2 一个可落地的 Skill 元数据字段

下面是一组我在实际项目中使用的字段结构,供参考:

字段作用必填
skill_id技能唯一标识,建议用短横线命名,如generate-weekly-report
name人类可读名称,用于日志和调试
category技能所属分类,如reportcodedata_analysis
summary一句话描述,用于模型快速判断
trigger_examples典型触发请求示例,2 到 5 个即可
avoid_when明确说明什么情况下不要调用这个技能
dependencies依赖的工具、文件或前置条件
priority当多个技能匹配时,是否优先调用,可选值为normalhigh

重点是summarytrigger_examples。这两个字段直接决定模型能不能在候选列表里快速定位。

举个例子:

skill_id: generate-weekly-report name: 生成周报 category: report summary: 根据本周工作记录生成周报文档 trigger_examples: - 帮我写这周的周报 - 生成本周工作总结 avoid_when: 用户要求的是日报,或只要求整理数据,不需要生成叙述性报告 priority: normal

这样的结构比一段三百字的描述更容易被模型理解,也更适合后续做检索。

2.3 用分类和命名把决策空间压缩到 10 以内

元数据里最容易被忽略的是category。我强烈建议把 100 个 Skill 先归到不超过 10 个大类里,比如:

分类示例技能
report周报、日报、月报、会议纪要
code代码生成、代码审查、代码重构
data数据查询、数据分析、图表生成
document文档转换、文档摘要、文档翻译
automation任务创建、提醒设置、流程编排

分类的价值在于:当模型面对 100 个技能时,它很难选出正确的一个;但如果先判断“这是一个报告类需求”,再在 report 分类下的 10 个技能里选,压力就小很多。

实际操作时,可以把分类信息也放进系统提示词,或者作为路由逻辑的一部分。无论哪种方式,目标都是让模型不要直接面对全量技能。

3. 从“让模型自己猜”升级成“显式路由 + 检索召回”

如果说元数据是基础,那路由策略就是真正让命中率稳定下来的关键。

我不建议在技能数过百之后,还依赖“把所有描述塞进上下文,让模型自由发挥”的方式。更好的做法是让系统先做一轮筛选,再把少量候选交给模型决策。

3.1 轻量方案:两级分类路由

第一种方案不需要引入额外模型,利用规则和分类即可完成。

整体流程是:

  1. 先让模型判断用户请求属于哪个category
  2. 只把该分类下的 Skill 列表提供给模型。
  3. 模型在 10 个左右候选里做最终选择。

比如用户说“帮我把这份文档翻译成英文”,第一步先判断属于document,第二步把document分类下的所有技能描述给模型,模型再选具体是“文档翻译”还是“文档格式化”。

这个方案实现简单,效果提升也很明显。缺点是如果分类判断错了,后面再怎么选都是错的。所以分类层需要做得足够粗,确保大多数请求都能归到正确的类目下。

3.2 进阶方案:先向量检索,再让模型做最终选择

如果 Skill 数量继续增长,或者用户请求的表达方式非常多,两级分类可能会遇到瓶颈。这时候可以考虑引入检索增强。

基本思路是:

  1. 把所有 Skill 的summarytrigger_examples向量化,存入向量库。
  2. 用户请求进来后,先通过 embedding 检索出最相关的 top 5 到 top 10 个 Skill。
  3. 把检索结果连同原始请求一起交给模型,由模型做最终选择。

这套方案的好处是召回能力更强。用户即使换了说法,也能通过向量相似度找到相关技能。它也有代价:需要维护向量索引,需要处理检索失败的情况,还需要控制检索结果的多样性,避免 10 个候选全是同一个类型的技能。

我一般建议先做两级分类,等确实出现“分类正确但相似技能太多”的问题时,再叠加向量检索。不要一上来就追求复杂的检索系统。

3.3 兜底机制:强制确认和人工切换

无论路由策略多好,都无法保证 100% 命中。所以兜底机制非常重要。

一种常见的做法是:当模型选择某个 Skill 时,如果置信度不高,先向用户确认一下,而不是直接执行。

实际操作可以在提示词里加一个约束,比如:

如果你不确定用户请求匹配哪个技能,请列出最多两个候选,并询问用户。

另一种兜底是提供人工切换入口。比如 Agent 界面里显示当前命中的 Skill,用户可以手动指定其他 Skill。这个机制虽然看起来不够“智能”,但在生产环境里非常实用,它能避免错误调用带来的更大损失。

值得注意的是:单纯把候选列表从 100 减小到 10,命中率就能提升不少。这种提升不来自模型变强,而是来自决策难度降低。

4. 写 Skill 描述时,重点写“什么时候用”,而不是“能做什么”

很多 Skill 文件里会把“能做什么”写得很详细,比如“本技能支持多种格式、支持自定义模板、支持批量导出”。这些对使用阶段可能有价值,但对“选择”来说反而是噪音。

4.1 描述的核心任务:让模型判别,而不是让模型理解

在技能数量很多时,模型读取描述的目的只有一个:判断这个技能是否匹配当前请求。所以描述要写成“判别式”,而不是“解释式”。

换句话说,不要写“本技能可以生成一份内容详尽的周报,支持自定义时间范围、项目维度、人员维度……”,而应该写“当用户要求生成周报时使用。用户需要提供时间段和工作内容,或者提供工作记录文件”。

用更具体的话说:

  • 写得好的描述:用户提出 A 需求时调用
  • 写得不好的描述:本技能是用于生成周报的智能助手,能够帮助你高效完成……

识别标准很简单:把描述里的功能形容词全部删掉,如果句子依然能告诉模型“什么时候调用”,那就是一个合格的判别式描述。

4.2 写清楚“不要用它”的场景

大多数人在写描述时只会写“什么时候用”,很少写“什么时候不用”。在 100 个 Skill 的候选空间里,“什么时候不用”往往比“什么时候用”更能帮助模型排除干扰。

比如一个“文档摘要”技能,可以加上一局:

avoid_when: 如果用户只是要求翻译文档,不要调用本技能。

这看起来像废话,但在实际测试中,正是这种“排除性提示”能显著降低相似技能的混淆率。

我建议每个容易混淆的技能都写avoid_when。如果几个技能的trigger_examples有大量重叠,优先补全avoid_when,而不是继续加长summary

4.3 相似 Skill 的合并、拆分与区分约束

技能库里最容易出现的问题是:看起来不同的技能,实际服务的是同一类需求。比如“生成周报”和“生成工作小结”,用户可能觉得是一回事。

如果发现两个 Skill 的触发场景重叠超过 60%,可以考虑合并。合并后通过参数区分不同输出格式。比如统一成一个“工作汇报生成”技能,通过report_type: weekly|summary参数控制。

如果确实需要保留两个技能,就必须在描述中给出明确的区分点。比如:

  • A:用户要求“按周维度生成汇报”时调用。
  • B:用户要求“站在个人角度写一段简短总结”时调用。

这种显式区分,比让模型自己领悟“周报”和“小结”的区别可靠得多。

5. 用调用测试集衡量命中率,而不是靠几次功能测试

优化命中率这件事,最怕“凭感觉”。有时候你改了一版描述,测试几句话感觉变好了,但一上线又崩。原因是样本太少,而且没有覆盖到真实的坏case。

所以,Skill 数量过百之后,我强烈建议建立一套“调用级测试集”。

5.1 构建一个覆盖不同场景的测试集

测试集不需要很大,但必须覆盖几类关键场景:

  • 每个分类下至少 2-3 条典型请求。
  • 每个容易混淆的技能对至少 1 条“边界请求”。
  • 至少 5 条跨分类模糊请求,比如“帮我把这个数据整理成表格再写段说明”,可能同时涉及数据处理和文档生成。
  • 至少 3 条故意带噪音的请求,比如包含多层含义或模棱两可的表达。

测试集的价值在于,你可以通过反复运行同一个请求,观察 Agent 的调用结果是否稳定。如果同一条请求第一次调用 A,第二次调用 B,那就说明路由策略存在不稳定因素。

5.2 记录每次调用的完整链路

为了定位命中率问题,日志至少需要记录:

用户请求 模型分类结果(如果有多级分类) 检索候选列表(如果使用了检索) 最终选中的 Skill 执行结果或报错信息 耗时和 token 消耗

有了这些日志,你才能回答一个关键问题:模型选错,是检索阶段没有召回正确技能,还是召回了但最终选择错误?

排查顺序可以这样走:

  1. 复现一次失败调用,拿到完整日志。
  2. 检查检索阶段的候选列表里是否包含正确技能。
  3. 如果候选列表里没有,说明是检索或分类问题,要去调整召回逻辑。
  4. 如果列表里有但模型还是选错,说明是最终决策问题,要去优化描述和候选排序。
  5. 如果模型反复横跳,说明候选之间的区分度不足,需要增加avoid_when或合并技能。
  6. 如果模型直接调用了不存在的 Skill,说明提示词约束失效,需要检查输出格式限制。

这个排查链路能少走很多弯路。

5.3 用混淆矩阵找出容易打架的技能对

在测试集跑过一轮后,可以把结果做成一个简化版的混淆矩阵。横轴是应该调用的 Skill,纵轴是实际调用的 Skill。对角线上是命中,非对角线就是选错的情况。

比如你发现用户请求“写周报”时,有 3 次调用了“生成工作项列表”,有 2 次调用“生成项目进度同步”。这说明这两个技能和“写周报”之间存在较强的混淆,需要重点处理。

处理方式通常是两种:

  • 调整描述,让“工作项列表”明确排除“叙述性周报”场景。
  • 调高生成周报的优先级,或者把容易混淆的技能归到同一分类下,让模型先选大类,再细选。

6. 过百之后,不要忘记长期维护和准入门槛

Skill 数量过百,不是一次性建设,而是一个持续演进的过程。随着项目增长,你会不断新增技能,也会废弃旧技能。如果缺乏维护机制,命中率会再次下降。

6.1 新增 Skill 也要过“路由评审”

我见过很多项目,新增 Skill 时只验证“这一个技能能不能跑通”,完全不看它会不会和现有技能冲突。结果就是技能库越来越大,互相覆盖的也越来越多。

建议新增 Skill 时,至少回答三个问题:

  1. 用户请求在什么情况下会想到这个技能?
  2. 它和现有技能的重叠度有多高?
  3. 如果两个技能都匹配,模型应该如何区分?

如果第三个问题答不上来,说明这个新 Skill 还不够清晰,或者它应该作为现有技能的参数,而不是独立存在。

6.2 定期下线低命中率技能

每次跑完一轮调用测试,除了看哪些技能被错误调用,还要看哪些技能长期没有被调用。

如果一个 Skill 在过去 30 天内的调用次数为 0,或者命中率一直低于某个阈值,就应该标记为「低频」。低频技能保留在候选列表里,不仅不会提升体验,反而会增加模型的决策干扰。

处理方式有两种:直接归档,或者把它们从默认候选列表里剔除,改为通过搜索或用户显式指定才可用。归档不是删除,而是降低它们的“可见度”。

6.3 把 Skill 定义和路由策略拆成独立模块

最后一个建议是关于工程结构的。

不要把路由逻辑写死在某个 Agent 的 System Prompt 里。更合理的做法是:

  • skills/目录下存放每个 Skill 的完整定义。
  • skill_index.yaml存放用于选择的元数据索引。
  • router.pyrouter.ts等独立模块负责召回和排序。
  • Agent 启动时加载一次索引,请求进来时走路由逻辑,再调用具体 Skill。

这样做的价值在于,你可以单独测试、单独优化路由模块,而不需要重新调整 Agent 主流程。等 Skill 数量到几百个时,这套结构几乎是必须的。

说到底,Skill 数量过百后,Agent 调用命中率的问题,已经不是“这个模型强不强”的问题,而是“你有没有把决策空间管理好”的问题。真正有效的思路,不是让模型在庞大列表里大海捞针,而是通过元数据、分类、检索和测试,把正确的候选在正确的时间推到模型面前。

如果你的项目也走到了这一步,我的建议是先别急着调描述、加示例。先把所有 Skill 的元数据梳理出来,做一个最简单的分类路由,然后用一批真实请求去跑回归。你会发现,很多命中率问题的答案,其实早在你决定“把所有技能都塞进提示词”的那一刻就注定了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 2:39:47

小米玄戒O3芯片解析:3nm工艺与240亿晶体管背后的技术博弈

看到“240亿晶体管、3nm工艺,小米首款AI旗舰SoC玄戒O3亮相”这条消息时,我的第一反应不是“参数真高”,而是“这条路终于走到这一步了”。芯片不是装个壳就能出货的零件,尤其是旗舰SoC——它决定了手机的性能上限、功耗曲线、通信…

作者头像 李华
网站建设 2026/8/27 2:39:27

一键平面系统图:从标注到出图的工作流节点实战

居造标注这次推出的“一键平面系统图”模块,放在工作流里用才是完整形态。它不是简单地把平面图导出一张图,而是把构件标注、图层、图例规则、输出模板串起来,自动生成可用于施工交底、内部评审和归档的平面系统图。这篇文章适合正在做室内设…

作者头像 李华
网站建设 2026/8/27 2:37:52

League Director:免费的英雄联盟回放运镜与视频录制工具

League Director:免费的英雄联盟回放运镜与视频录制工具 【免费下载链接】leaguedirector League Director is a tool for staging and recording videos from League of Legends replays 项目地址: https://gitcode.com/gh_mirrors/le/leaguedirector 刚打完…

作者头像 李华
网站建设 2026/8/27 2:37:49

MATLAB元胞自动机森林火灾建模与GUI仿真

1. 项目概述:一个被低估的“森林求火”建模实战课“森林求火”这个词乍一听有点拗口,甚至让人下意识觉得是不是打错了字——其实它不是“救火”,也不是“纵火”,而是“森林火灾蔓延过程的数学建模与可视化求解”的简略表达。业内常…

作者头像 李华
网站建设 2026/8/27 2:35:53

【单片机课程设计/毕业设计】基于 ESP8266 的室内甲醛智能检测与远程 APP 控制装置设计 物联网架构下室内甲醛监测声光报警自动换气系统设计与实现(024604)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华