Skill Is Not Document: Query-Conditioned Compatibility for LLM Agent Skill Routing

Zifei Wang, Wei Wen, Qiang Ji, Keyu Chen, Ruizhi Qiao, Xing Sun · arXiv 2606.03565 · 发表 2026-08-05
19 分钟阅读时长 7255字 4.35综合分 第 2 名08-06 AI Search 日报
目录 · 8 节1它到底在解决什么问题?2数据怎么造:拒绝记录从哪里来3新指标 Set-Compat:整组都要排在最前面4两阶段模型:召回负责找全,重排负责挑对组合5实验:哪些结论站得住6我认为它的局限7一个推荐/搜索团队可以怎么试8一句话结论和评价
相关 4新颖 5实用 4证据 5时效 4

做 agent 工具路由、skill 检索或者多路召回组合的人值得读这篇。它把一个常被忽略的事实讲清楚了:给 agent 召回 skill 时,单个 skill 相关还不够,召回的几个 skill 还得能在当前请求里一起用。论文的核心思想一句话:用大模型合成训练 query 时,模型会先拒掉一批“凑不成自然需求”的 skill 组合(论文叫 SKIP),这些拒绝记录平时被丢掉,作者把它们留下来,只交给 cross-encoder 重排模型去学,不交给双塔召回模型。在作者自建的 R3-Skill 基准上,重排后“整组 skill 都排进前几位”的比例从 28.12% 提到 33.27%;同样的拒绝记录如果当成双塔的难负样本,这个比例反而从 28.12% 掉到 21.58%。只有 0.6B 的召回模型 Hit@1 达到 72.07%,比 8B 的通用 embedding 模型高出近 10 个点。

它到底在解决什么问题?

先说 skill 是什么。它是一份可复用的能力说明,包含名字、简介和一段很长的正文(操作步骤、API 约束、示例代码),agent 读到它就知道怎么完成一类任务。R3-Skill 的 1 万多个 skill 合计 2,120 万 token,最长的一个有 31,571 个 token,不可能全部塞进 prompt,所以需要一个路由层先挑出少数几个。

难点在于,skill 召回回来是要被执行的,不只是被阅读。论文图 1 用了一个例子,我沿用它贯穿全文:

query需要的 skill示意的正确结果
q1:“把我们的工具打包发布,然后搭好发布流水线”Terraform 基础设施 + AUR 打包发布两个都要,缺一不可
q2:“给团队搭一套基础测试环境”只要 Terraform 基础设施AUR 打包发布应该压下去

表里的 AUR(Arch Linux 的社区软件仓库)打包发布,负责把软件打包上传到这个仓库。两个 query 下,它和 query 的文本相关度都不低。如果只按单个 skill 的相关度排序,q2 的前两位很可能是 Terraform 加 AUR 打包,agent 会被塞进一段用不上的指令。文档检索里多返回一篇相关文章通常无害,skill 路由里多返回一个就可能带来冗余或冲突的指令。

论文图 1:同样两个 skill,在 q1 下要一起用,在 q2 下 B 应该被压下去。看底部两个 ROUTE 框:区别不在 skill 本身,而在 query。
论文图 1:同样两个 skill,在 q1 下要一起用,在 q2 下 B 应该被压下去。看底部两个 ROUTE 框:区别不在 skill 本身,而在 query。

作者把这件事写成一个分解:整组 skill 都进前 K 的概率,约等于每个 skill 各自进前 K 的概率之积,再乘一个跟 query 有关的兼容性修正项 。 是这个 query 真正需要的 skill 集合。 恒等于 1 时,就退回到“各 skill 独立判断相关”的普通检索。这篇论文要补的,就是这个修正项的监督信号。

数据怎么造:拒绝记录从哪里来

整体流程见论文图 3:从 GitHub 爬 skill、去重、聚类、按近邻抽组合、让大模型判断写不写 query、专家复核、切分训练和测试。

论文图 3:R3-Skill 的数据流水线。上排从左到右是爬取 95,212 个 skill、去重到 10,246 个、聚成 40 个子簇和 8 个大领域、按近邻抽组合;下排是大模型标注 WRITE 或 SKIP、8 类拒绝原因统计、专家复核和切分。
论文图 3:R3-Skill 的数据流水线。上排从左到右是爬取 95,212 个 skill、去重到 10,246 个、聚成 40 个子簇和 8 个大领域、按近邻抽组合;下排是大模型标注 WRITE 或 SKIP、8 类拒绝原因统计、专家复核和切分。

为什么要按近邻抽组合?随机抽两个 skill,比如游戏联机加法律文书,一眼就知道凑不到一起,这种拒绝没有信息量。作者先用 BGE-M3 给 skill 算 embedding,用 KMeans 聚成 40 个子簇,再合并成 8 个大领域。两个 skill 的组合从同一个子簇里抽,三个 skill 的组合从同一个大领域里抽。这样抽出来的组合主题都很接近,但大模型仍然只接受了 56.3% 的两 skill 组合和 36.5% 的三 skill 组合。这说明主题相近远不等于能凑成一个自然的任务。

抽好组合后,大模型分两步输出。第一步判断这几个 skill 是否会被一个用户在同一段需求里自然地同时提出,标准是缺一不可、不是硬凑、现实中真有人这么问。判断为 WRITE(写出 query),就按六种用户口吻之一写一条 50 到 300 词(或字)的 query,并且不许出现 skill 的名字。判断为 SKIP(跳过),就写一句拒绝理由。“Code Review”和“Systematic Code Review”被拒,因为功能重叠,一个就够;“Rust 可靠性”和“Go 安全模式”被拒,因为一个请求不会同时用两种语言生态。

几个关键设置决定了这个基准能不能信:

设置内容为什么重要
规模10,246 个 skill,41,592 条 WRITE query,32,828 条 SKIP其中 15,791 条 query 需要两到三个 skill
语言方向en2en、en2zh、zh2en、zh2zh(skill 语言到 query 语言)中文 skill 只有 246 个原始条目,zh2en、zh2zh 各只有约 1,150 条 query
切分8,196 个训练 skill 和 2,050 个测试 skill 互不重叠模型没法靠记住测试 skill 得分
生成模型训练集用 DeepSeek-V4-Pro,测试集用 Qwen3-235B-A22B降低模型学到同一个生成器措辞的风险
人工复核测试集所有多 skill 标签由 9 位专家独立复核,初始分歧低于 5%测试标签可信,但 query 本身仍是合成的

拒绝理由被归成 8 类。en2en 的拒绝 71.7% 是领域不重叠,en2zh 有 56.0% 是“硬凑”(每个 skill 单看都合理,但放进同一个请求就不自然)。后面会看到,这个差别和重排模型在两个方向上的收益对得上。

新指标 Set-Compat:整组都要排在最前面

已有的指标里,Recall@K 看前 K 位覆盖了多少比例的需要的 skill;Comp@K 沿用 SkillRet 基准的定义,按论文的描述,它看前 K 位是否凑齐了整组需要的 skill。两者都允许整组 skill 散落在前 K 位的任何位置。作者另加了 Set-Compat,只在需要两个及以上 skill 的 query 上算:需要几个 skill,就看前几位;前几位恰好包含全部需要的 skill 才记 1,否则记 0。

是模型对 query 给出的排序, 是条件成立时取 1 的指示函数。用 q1 手算一下(示意):需要的是 Terraform 和 AUR 打包两个 skill,就只看前 2 位。排序是 Terraform、AUR 打包、Ansible,记 1;排序是 Terraform、Ansible、AUR 打包,Recall@3 仍是满分,但 Set-Compat 记 0。

为什么要这么严?agent 通常只加载最前面的几个 skill,多加一个就多占一段上下文,还可能带进冲突的指令。整组 skill 要到第 10 位以后才凑齐,Recall@15 看起来很好,对 agent 却没什么用。

两阶段模型:召回负责找全,重排负责挑对组合

R3 是常见的召回加重排结构。召回模型 R3-Embedding 从 Qwen3-Embedding-0.6B 初始化,从整个 skill 库里取 20 个候选;重排模型 R3-Reranker 从 Qwen3-Reranker-0.6B 初始化,对这 20 个重新打分。设计上的分工很明确:拒绝信号只进重排,不进召回。下面拆开讲。

召回:同一条 query 的几个正样本不能互当负样本

双塔训练常用 InfoNCE:一个 query 配一个正样本,batch 里其他 query 的正样本当负样本。多 skill query 有个坑。q1 需要 Terraform 和 AUR 打包两个 skill,如果这一步只把 Terraform 当正样本,而 AUR 打包恰好作为别的 query 的正样本出现在同一个 batch,它就会被当成 q1 的负样本推远。

作者的做法分两部分。主项照常算 InfoNCE,但把同一 query 的其他正样本(论文叫 sibling,即兄弟正样本)从分母里拿掉。另加一项,让每个兄弟正样本各自和负样本比一次,把 query 也往它们拉近:

是去掉兄弟正样本后的 InfoNCE, 是兄弟正样本的平均对比损失,,温度 。单 skill query 没有兄弟正样本,这个损失就退回标准 InfoNCE。难负样本用 Qwen3-Embedding-8B 离线挖:取它排在第 20 到 50 位、余弦相似度低于 0.85 的 skill。相似度设上限,是为了避免把其实也相关的 skill 当成负样本。

重排:拒绝伙伴拿 1 分,正确答案拿 3 分

重排训练还要用到被拒的组合。对每条 WRITE query,作者从它的正确 skill 所在的同一个聚类近邻区域里,取在被拒组合中出现过的 skill,叫它们 SKIP 伙伴。原文给出的挑选条件只有这两条:和正确 skill 同在一个近邻区域,并且出现在某个被拒组合里;并不要求它恰好和这条 query 的正确 skill 组成过被拒组合。它们和正确 skill 主题很接近,但被判过不该一起用。重排训练时,一个列表放 10 个候选:真正需要的 skill、SKIP 伙伴,以及 R3-Embedding 排在前面的其他候选。打分规则是需要的 skill 记 3,SKIP 伙伴记 1,其他记 0,再用 ListNet 训练:把这些分数做 softmax 当目标分布,让模型打分的 softmax 去逼近它。

手算一个列表(示意):2 个需要的 skill、2 个 SKIP 伙伴、6 个普通候选。,,,总和约 51.6。目标分布里,每个需要的 skill 约占 0.39,每个 SKIP 伙伴约 0.053,每个普通候选约 0.019。

这组数字说明一个容易误解的地方:SKIP 伙伴在训练里不是最差的负样本,而是排在正确答案之下、普通候选之上。这和 SKIP 的含义一致:它不是说这个 skill 不相关,只是说它在这个组合里不该一起出现。

为什么拒绝信号不能进双塔?

双塔给每个 skill 只算一个向量,所有 query 共用。以 AUR 打包为例:它在 q2 下是 SKIP 伙伴,InfoNCE 会把它的向量从 q2 推开;它在 q1 下是正样本,又会被拉向 q1。同一个向量要同时满足这两个方向,最后停在两股力量的折中点上,任何一条 query 的推开效果都被别的 query 的拉近抵消一部分。cross-encoder 没有这个问题,它每次把 query 和 skill 拼在一起重新计算,q1 下给 AUR 打包高分、q2 下给低分,彼此不冲突。

论文附录图 4:共享向量 e(s′) 在 q 下被推开(SKIP),在另一个 query 下被拉近(正样本),最终位置是两者的平衡点。看中间那个点:它被两个方向的箭头同时作用。
论文附录图 4:共享向量 e(s′) 在 q 下被推开(SKIP),在另一个 query 下被拉近(正样本),最终位置是两者的平衡点。看中间那个点:它被两个方向的箭头同时作用。

作者在附录里还分析了另外三种把 SKIP 放进双塔的损失写法,结论是都不如 InfoNCE。举一个:直接惩罚两个 skill 向量相似度的 BCE 损失,梯度方向和 query 无关,会让 Terraform 和 AUR 打包在所有 query 下都互相远离,连 q1 这种需要两者一起用的 query 也受影响。这部分只有推导,没有实验数字。

实验:哪些结论站得住

主结果在 R3-Skill 测试集上,重排都用同一份 R3-Embedding 前 20 候选(论文表 4,节选,单位 %):

模型Hit@1NDCG@10Recall@5Recall@10Set-Compat
BM256.048.829.9312.410.40
Qwen3-Embedding-8B(未微调)62.2973.0179.1384.9810.69
SkillRet-Embedding-0.6B46.7258.0464.4771.0111.88
R3-Embedding(0.6B)72.0781.6087.2291.7728.12
+ Qwen3-Reranker-0.6B68.0879.5486.4592.1217.82
+ SkillRouter-Reranker-0.6B67.9877.6582.5788.7724.36
+ R3-Reranker75.3981.9785.2389.9433.27

召回阶段,0.6B 的 R3-Embedding 比 8B 通用模型 Hit@1 高 9.78 个点,Recall@10 从 84.98% 到 91.77%。这说明针对 skill 全文和多正样本结构的训练,比把模型放大更管用。BM25 几乎完全失效,因为 query 被要求不出现 skill 名字,还有一半是跨语言的。

重排阶段,两个通用重排模型都把 Set-Compat 拉低了,Qwen3-Reranker 从 28.12% 掉到 17.82%。这说明只学“query 和单个文档是否相关”的重排模型,会把主题接近但多余的 skill 往前提,正好破坏组合。R3-Reranker 把 Hit@1 和 Set-Compat 都提上去了,代价是 Recall@5 从 87.22% 降到 85.23%,Recall@10 从 91.77% 降到 89.94%。也就是说,它把整组 skill 往前挪时,会把个别正确 skill 挤到后面。

关键的消融在论文表 7(单位 %):

配置改了什么Hit@1Set-Compat
A 召回用 8B 模型挖的难负样本(上线版本)72.0728.12
B 召回有 SKIP 伙伴时用它替换难负样本69.9321.58
C 重排不放 SKIP 伙伴72.3129.50
D 重排放 SKIP 伙伴,但随机配给别的 query75.1129.70
E 重排放 SKIP 伙伴,按原 query 配对(上线版本)75.3933.27

A 和 B 对比,说明 SKIP 当双塔负样本确实有害,和前面的推导一致。C、D、E 三行能把重排的收益拆开。从 C 到 D,Hit@1 提了约 2.8 个点,Set-Compat 几乎不动,这部分来自列表里多了一批难候选,跟配对对不对无关。D 和 E 的区别只在于 SKIP 伙伴放进哪条 query 的列表:E 放回挑出它的那条 WRITE query,也就是和它的正确 skill 同在一个近邻区域的那条;D 把同一批 SKIP 伙伴打乱后配给别的 query,并让 D 和 E 在语言方向、需要的 skill 数、候选相似度分布、skill 长度和训练中出现的次数上保持一致,所以两者唯一的差别就是配对对不对。从 D 到 E,Hit@1 只多 0.28 个点,Set-Compat 却多了 3.57 个点。这说明SKIP 伙伴只有和对应的 query 放在一起才教得会整组排序,放错了就只是一个普通的难候选。我按表 7 算了一下:R3-Embedding 到 E 的 5.15 个点 Set-Compat 提升里,约 3.6 个点来自正确配对,重排训练本身只贡献约 1.4 个点。

分语言方向的结果(论文表 5)也支持这个解释。en2zh 的拒绝多是“硬凑”,重排把它的 Set-Compat 从 18.97% 提到 25.64%,多 6.67 个点;en2en 的拒绝多是领域不重叠,双塔本身就能拉开距离,重排只多 3.46 个点。

迁移实验放在另一个独立构建的英文基准 SkillRet 上,它没有任何拒绝标注。R3-Embedding 的 NDCG@10 是 81.06%,比在 SkillRet 自己数据上训练的 SkillRet-Embedding 高 3.03 个点;加上 R3-Reranker 后到 83.87%,九个指标全部提升。通用 Qwen3 重排模型在这里同样拉低了所有 NDCG。这说明 R3-Reranker 学到的东西不只适用于自家基准。

我认为它的局限

第一,Set-Compat 绝对值仍然很低,而且小方向的数字不可靠。最好的系统也只有 33.27%,也就是三分之二的多 skill query,前几位凑不齐整组 skill。zh2en 从 45.45% 到 63.64%、zh2zh 从 50.00% 到 60.00% 这类数字,看起来像是十来条样本上的比例(这是我从数值反推的),作者自己也只把它们当参考。

第二,“该不该一起用”是大模型判的,不是执行结果。SKIP 来自 DeepSeek-V4-Pro 的一次判断,测试标签由专家复核,但没有任何实验让 agent 真的执行这些 skill,看少召回或多召回一个会不会让任务失败。query 也全是合成的,作者自己的泄漏审计显示 en2en 有 7.8% 的 query 包含 skill 名字的子串。

第三,重排换来 Set-Compat,牺牲了前几位的覆盖。Recall@5 降了约 2 个点,Comp@5 从 85.31% 降到 83.41%。如果下游 agent 能稳定加载 5 个以上 skill,单用 R3-Embedding 反而更合适,作者也这么建议。

一个推荐/搜索团队可以怎么试

  1. 先查自己的合成数据流水线有没有在丢拒绝记录。很多团队用大模型造 query 时,会让模型先判断组合是否合理;把 SKIP 和理由存下来,几乎没有额外成本。
  2. 在离线评测里加 Set-Compat,只算需要多个工具或多个结果的 query。如果现有重排模型让这个指标比纯召回还低,就说明它在把主题相近但多余的候选往前提,和论文里通用重排模型的表现一样。
  3. 重排训练用分级标签,正确答案、拒绝伙伴、普通候选分三档,先照抄论文的 3、1、0。同时跑一组“拒绝伙伴随机配给别的 query”的对照,确认收益来自配对,而不只是多了难候选。
  4. 不要把拒绝记录直接当双塔的难负样本。论文的 B 组已经给出反例;双塔继续用离线挖的难负样本,并处理好多正样本之间互当负样本的问题。

一句话结论和评价

这篇最有用的启发是:合成数据时模型说“这几个不该放在一起”,是一种依赖 query 的监督,只能交给能同时看到 query 和候选的模型去学。

维度评价
问题重要性高。skill 和工具库越来越大,召回一组能一起用的 skill 是 agent 的前置环节
方法创新性中。召回和重排都是常规结构,新意在保留拒绝记录,以及用消融说清它该放在哪一阶段
实验证据中高。表 7 的 C、D、E 对照设计得干净,还有跨基准迁移;但 query 是合成的,没有端到端执行
工程成本低。两个 0.6B 模型;重排 20 个候选每次请求最多约 9.2 万输入 token,对全库打分约 4,720 万
是否值得尝试值得。已经在用大模型合成训练数据的团队,几乎零成本就能拿到这份信号
适用场景agent skill 和工具路由,以及一次要返回一组互补结果的检索

读完这篇,你觉得

点一下即可,无需登录;再点一次撤回。只统计匿名次数,不记录你是谁。

讨论

欢迎补充实验细节、复现经验或不同看法。需 GitHub 登录。

正在加载讨论…