别拿名次当分数:用Rerank做判定模型的失败复盘
发布时间:2026/11/4 8:52:51 锦皓数字建站

周六下午我盯着终端里的日志上面的数字难看得很。第 16 个实验跑完了F1 依旧在 0.6 附近晃悠。想了很久最后在技术群里认输“rerank 配小模型复现不了那个判定模型我投了。”不是标题党是真的输了。我手上这个任务很常见给定一个 query 和一段文档判断文档是不是真正满足这个 query——相关还是不相关通过还是不通过。本质是一个二分类判定模型不是召回也不是精排。约束是不能用大模型 API只能用开源小模型最好普通显卡就能转起来。当时我把主意打到了 rerank 头上。逻辑是这样的rerank 的核心是交叉编码器query 和文档拼在一起过 Transformer语义交互吃得很透在检索里的提分效果肉眼可见。它既然这么懂语义我为什么不直接拿它的分数当判定分数再配一个小模型做前置过滤纯开源、少标注、低成本这不就齐活了理想很丰满现实很打脸。两天16 个实验从 zero-shot 试到微调从阈值搜索试到分数校准甚至把高斯过程回归都用上了最好的成绩也离目标差一截。这篇文章不是教程是一个完整的失败记录我会把实验设计、核心现象和底层原因都拆开来讲。如果你也在打“用 rerank 做判定”的主意看完应该能少走两天弯路。1. 为什么我会想到用 rerank 做判定模型1.1 判定模型的本质要的是及格线不是名次判定模型的经典任务就是二分类或多分类输出的是一个“该样本属于哪个类、满足不满足条件”的绝对判断。拿我的任务举例判定“文档是否真正回答 query”模型面对的是 Ground Truth 标签它学习的最终目标是让“通过/不通过”的决策正确率最大化。这样的模型天然需要输出一个可以被比较的绝对测度——0.7 的通过概率和 0.3 的通过概率代表着两种不同的置信程度而且这两个数字在不同样本之间是可比的。rerank 呢它学的是相对序。训练数据长什么样某一次搜索里用户点了结果 A 没点结果 B所以 A 应该在 B 前面某次问答里文档 C 比文档 D 更贴合 query所以 C 排在 D 前面。它的优化目标是 NDCG、MRR 这类排序指标Loss 也是 pairwise 或者 listwise 的形式。模型关心的是候选集内部“谁在谁前面”根本不关心第二条文档绝对地“有多好”。我说得通俗一点。你高中班上有个同学你只知道他每次模考名次都在你前面但你不知道他总分是 650 还是 400也不知道 480 分算不算过一本线。rerank 就是那个只见过名次、没见过分数的考生。你把它拉来当“判定模型”问它“这条文档有没有资格及格”它只能给你一个相对位置的感觉不能给你一个绝对的分数。1.2 交叉编码器的“语义理解”给了人错误的安全感既然 rerank 有这个问题为什么我一开始还是想用它因为交叉编码器太诱人了。它把 query 和 doc 拼成一个序列过完整的 Transformerattention 可以同时看到 query 的每一个 token 和 doc 的每一个 token。对比双塔结构的 embedding 模型它理解的是真正的语义交互而不是两个向量的余弦相似度。在很多 RAG 评测里rerank 能把召回结果从 top-20 提升到 top-5效果非常猛。于是我会产生一种错觉这模型是真的“懂”语义的。既然懂那它输出一个分数我为什么不能把它当成置信度当时的思考特别顺滑分数高等于更相关等于满足要求分数低等于不相关等于不满足。这中间只差一个阈值。而阈值这种东西拿验证集一搜不就有了吗这个推理的危险之处在于它把“模型内部理解能力强”和“模型的输出具有绝对度量意义”划了等号。实际上交叉编码器理解语义很强但不代表它被训练成了一个绝对评分器。它的打分函数只要能维持相对顺序就完成任务了至于分数本身科学不科学、稳定不稳定训练目标根本不关心。1.3 任务约束为什么一开始绕开微调还有一个现实原因我没有大量标注数据。这次的判定任务人工标注样本一共几百条。几百条去微调一个 7B 模型大概率过拟合拿去微调 BERT 类模型效果倒是稳但当时心里预期是“应该用不上rerank 直接就够了吧”。这个误判直接导致我头两天在错误的方向上冲。另外还有一个来自行业氛围的推力。那段时间开源小模型讨论很热经常有人问“现在开源小模型有好用的么”。确实Qwen2.5、Llama-3.2 这些写摘要、做角色扮演、跑函数调用都已经有模有样。我心里难免会想小模型加一个聪明的 rerank强强联合判定任务还拿不下后来的事实是聊天好用和判断靠谱完全是两码事。2. 第一天的 6 个实验从直出到裸奔2.1 环境与基线配置有必要先交代一下环境方便你对照复现。两张 4090离线推理用 vLLM 起的小模型服务rerank 用的是 BGE 系列的 cross-encoder。候选小模型我测了 Qwen2.5-1.5B Instruct、Qwen2.5-3B Instruct、Qwen2.5-7B Instruct以及一个 DeBERTa-v3-base 做微调对照。数据统一走一套 prompt 模板你是一个严谨的判定模型。根据问题和文档判断文档是否真正回答了问题。 只能输出 yes 或 no不要输出其他内容。 问题{query} 文档{doc} 回答这里有个小细节我后来发现模型输出如果不做约束会给你一堆解释什么“文档提到了相关内容因此可以认为……”之类的。解析这些文本做判断比解析 yes/no 麻烦得多。所以实验里我做了 constrained decoding强制模型只能从 yes/no 两个 token 里选。用 vLLM 的 guided_decoding 或者 Outlines 库都能实现。这一点算是第一天最明确的收获生成式小模型做判定必须锁死输出空间否则它自己发挥起来你的解析逻辑根本跟不上。2.2 实验 1-4小模型直接判定的表现第一批实验就是让 1.5B、3B、7B 轮流上阵。结果很有意思也很有挫败感。1.5B 的 zero-shot 几乎等于乱猜验证集 F1 大概 0.52也就是比抛硬币好一点点。而且它特别喜欢说 yes一遇到“文档里沾了点边”的情况就放行。3B 稍好一点F1 将近 0.58但遇到否定句式、条件约束多的 query 就崩。举个例子query 是“哪些情况不能提取公积金”文档逐条列了提取条件3B 会抓住“公积金可提取”这几个词直接放行完全没看到“不能”这个否定。7B 明显正常多了F1 能到 0.67 左右。但离我预期的 0.85 还是差着一大截。这里我要说一句公道话7B 的表现让我看到开源小模型确实在进步但“好用”是相对的在严谨判定上它的稳定性依然不够。同一个样本你把 prompt 里“只能输出 yes 或 no”改成“请给出结论”它的判断就会飘。few-shot 也试了给 3B 塞了 5 个手工挑选的示例F1 勉强涨到 0.61但是换个示例顺序就掉到 0.55。这种方差让人觉得不踏实你根本不知道模型学会的是判断逻辑还是学会了模仿示例的格式和倾向。2.3 实验 5-6rerank 裸打分阈值问题直接暴露第一批的重头戏是 rerank 裸打分。我用 bge-reranker-v2-m3 给每条样本的 (query, doc) 算一个分数一开始按直觉设 score 大于 0 判定为相关。结果 F1 只有 0.60 出头比 7B 还差。于是我做了一件很自然的事在验证集上搜索最优阈值把 F1 拉到 0.64。到这里问题已经初见端倪。验证集最优阈值是 0.37可一旦换到测试集用同一个固定阈值F1 直接掉到 0.58。我第一反应是“阈值过拟合了”多搜几个区间、多搞点分位数总行吧后来才发现根本不是阈值的问题是分数本身不具备跨集稳定性。同样一句话在验证集上的分布和在测试集上的分布天差地别你搜出来的最优阈值只是那几百条样本的巧合产物。我把第一天的实验结果整理成了表。编号方法关键配置验证集F1现象1Qwen2.5-1.5B zero-shot固定模板 constrained decoding约0.52偏向yes判断接近随机2Qwen2.5-3B zero-shot同上约0.58否定句式、条件约束理解差3Qwen2.5-7B zero-shot同上约0.67相对正常稳定性仍差4Qwen2.5-3B few-shot5个示例约0.61示例顺序敏感方差大5bge-reranker-v2-m3score 0约0.60直接当判断分数不如预期6bge-reranker-v2-m3验证集最优阈值约0.64阈值切到测试集即失效第一天的结论表面上看起来是“阈值没选好、小模型不稳”但实际上已经藏着一个更深的问题rerank 的分数不是一个稳定的绝对度量。只是我当时的认知还不够把问题归结到阈值上于是有了第二天那一堆校准和融合实验。3. 第二天的 10 个实验校准、融合、微调、锚点能试的都试了3.1 实验 7-9分数融合与真正意义的微调第二天早上我先把最直觉的融合方案跑了一遍。小模型生成答案时本身有 logitsrerank 也有分数两个加权的想法非常自然。实验 7 就是让“小模型 logits 的 sigmoid 值”和“rerank 分数的 min-max 归一化值”做加权求和。权重从 0.1 到 0.9 网格搜索结果最好 F1 约 0.66。这个数字很令人沮丧融合的上限基本就是两个模型的 max加权没有创造出新的能力。接下来我开始怀疑一个一直没做的事微调。实验 8 是拿几百条标注数据微调 DeBERTa-v3-base 做二分类。结果它直接跑到 F1 0.78这个成绩比我前两天所有“聪明”方案都高。我当时脑子里只有一个想法分类任务就该用分类模型我在这儿跟排序模型较什么劲为了验证这个想法实验 9 用 Qwen2.5-3B 做了 LoRA 微调但这次不是生成式微调而是把模型最后一层换成了二分类头用交叉熵训练。F1 约 0.72低于 DeBERTa。数据量太少是一方面另一个原因我后面会讲生成式预训练模型的 representation 不一定适合直接接分类头它习惯的是“预测下一个 token”不是“把语义压到一个标签上”。3.2 实验 10-12锚点对比、特征化和多任务实验 10 是我当时觉得最有可能突破的方案锚点对比。既然 rerank 是学 pairwise 的那我就顺着它的训练方式走。固定一组人工挑选的正例锚点和负例锚点把待判定文档分别和正锚、负锚组成 pair用 rerank 分别打分两个分数的差作为判定依据。逻辑上讲如果文档和正锚的 pair 得分高那它应该更接近正类。这个方案在验证集上 F1 到了 0.66但有两个致命问题。第一锚点非常敏感换一组锚点分数差能到 0.08。第二它导致推理时间变成原来的倍数级每一条样本要跑两次 rerank线上请求的延迟根本顶不住。这种方案只能算实验室玩具不能落地。实验 11 我换了个思路不把 rerank 分数当最终判决而是当特征。把 rerank 分数、小模型给出的 logits、文档长度、query 与 doc 的 token 重叠数、关键词命中率等一起喂给一个逻辑回归。F1 到了 0.68虽然比裸打分好但也就那样。这至少说明rerank 分数里确实有判别信息但它需要被其他特征修正不能独当一面。实验 12 是更硬核的做法把 reranker 的 backbone 拿出来加一个二分类 head做多任务学习——一个 head 走原来的 pairwise 排序 loss一个 head 走 pointwise 分类 loss。F1 到 0.70。这个方案已经跟“用 rerank 做判定”关系不大了本质是用 rerank 模型的结构微调出一个分类模型。这也印证了一件事想要绝对判定能力就得用 pointwise 的监督信号去训不能指望 pairwise 预训练模型天生具备。3.3 实验 13-16校准、集成与最后的认输接下来的四个实验我开始跟“分数校准”死磕。实验 13 是动态阈值不是固定一个数而是按分数分布取分位数。效果跟固定阈值没有本质区别测试集该失效还是失效。实验 14 上了一个更有理论味道的方法对 rerank 分数做校准。先试了 isotonic regression效果一般因为校准样本太少。后来想到高斯过程回归——它在小样本、非线性映射场景下的拟合能力不错适合把“排序分数”这种形状不明的变量映射到“概率”上。校准完的分数确实看起来更平滑、更像概率了F1 却几乎没有提升。原因也简单校准只改变阈值不改变排名。排序模型还是那个排序模型校准只是给它穿了一件“概率”的外衣。实验 15 是集成。我把 bge-reranker-v2-m3、另一个开源的 cross-encoder、还有微调后的 DeBERTa 一起投票F1 到了 0.79。这个数字终于过了我自己拍脑袋定的 0.75 心理线但代价是部署三套模型延迟和成本直接爆炸。而且它已经彻底退出“rerank 配小模型”的框了真正托底的是那个微调分类模型。实验 16 是压垮我的最后一根稻草。我违规换了一个更大的模型跑同一条 pipelineF1 轻松到 0.84 以上任务难度完全可控。也就是说不是任务不可做不是我标注数据不够是“开源小模型 rerank”这个组合本身不具备稳定复现判定模型的能力。于是我认输了。第二天的实验结果我也整理了一下。编号方法关键配置验证集F1现象7logits score 加权融合权重网格搜索约0.66上限约等于两者max8微调 DeBERTa-v3-base二分类head约0.78分类模型直接碾压各种“聪明方案”9Qwen2.5-3B LoRA 二分类分类head CE约0.72数据少提升有限10正负锚点对比双次rerank约0.66锚点敏感、延迟翻倍11rerank分数做特征 LR手工特征约0.68分数有信息量但只能当特征12rerank backbone多任务pairwise pointwise约0.70实质已是微调分类模型13动态分位数阈值按分布取阈值约0.64不解决跨集失效14分数校准isotonic 高斯过程回归约0.65分数变平滑F1没变15多模型集成投票双rerank DeBERTa约0.79托底的是DeBERTa不是rerank16大模型同管线7B以上 / API约0.84任务可做路线错了4. 认输的底层原因排序分数与判定分数之间隔着一条认知鸿沟4.1 一个让我彻底明白的反直觉现象在讲数学之前先讲一个实验现象。有一次我在调试时拿同一条 (query, doc) 分别放进两个候选集里算 rerank 分数。第一个候选集里全是弱负例——那些明显不沾边的文档第二个候选集里塞了几个强负例——语义高度相似但没答到点上的文档。结果同一条样本在弱负例环境里得分 1.2在强负例环境里得分 2.8。这个现象当时看得我头皮发麻。如果 rerank 的分数真的是文档和 query 之间的绝对相关度那它不应该因为周围是谁而改变。但现实是它变了而且变化很剧烈。这说明它学到的更接近一个“相对竞争力”信号在一个都强的候选集里你再好也可能被压在下面在一个都弱的候选集里你再差也能出头。4.2 pairwise 与 pointwise两种优化目标两种世界观从训练目标来解释就更清楚了。排序模型用 pairwise loss 训练时样本是一个三元组 (q, d, d-)loss 只在“正样本得分是不是比负样本得分高”上有约束。只要 d 的分数大于 d-loss 就是 0模型完全没有义务告诉你d 的分数到底是 0.6 还是 0.9。于是经过训练之后模型内部可能把所有候选的分数都挤在一个狭窄区间里只需要通过微小的流动性区分相对次序。你硬要给这些分数设一个绝对阈值就像要求一个只打过“谁分数高谁赢”的人去当考官告诉他“80 分算优秀60 分算及格”——他根本没经历过绝对尺度怎么可能给得准判定模型则不同。pointwise 分类的目标是让预测的概率贴近真实标签每一条样本都独立施加约束学出来的分数自然具备绝对意义。一个是“我比他好”一个是“我到底够不够好”这就是 rerank 不能直接当判定模型的根因之一。4.3 校准为什么救不了排序分数也许你会说既然分数分布不稳定那我拿一批标注数据学一个校准函数把 score 映射到概率不就行了实验 14 已经证明这条路走不通原因有两层。第一层校准函数是固定的但排序分数的分布是随候选集漂移的。今天线上候选集平均质量是 0.6明天变成 0.8同一个文档的分数可能从 1.2 飘到 2.8。校准函数是在旧分布上拟合的到了新分布上当然失效。这就是为什么实验 14 中即使我用高斯过程回归把校准函数拟得再平滑F1 依然没有起色。第二层排序分数的非线性不是简单的单调变换。有时候强负例会把正例的分数压低但压低的幅度跟候选集里有多少个强负例有关不是单个样本能决定的。这导致校准问题本身就有点病构你要预测的目标是一个受周围样本影响的值又想拟合出一个与周围样本无关的全局函数这本身就矛盾。4.4 顺手聊聊开源小模型的“虚火”最后说回“现在开源小模型有好用的么”这个流行话题。我的结论是看场景。写代码、写摘要、做角色扮演Qwen2.5、Llama-3.2 这些确实好用。但做严谨判定它们的表现就像一个聪明但爱脑补的实习生——它能给你一个看似合理的答案却不能保证答案的边界稳定。尤其生成式模型它的输出是逐 token 采样的末尾的分类概率受 prompt 措辞影响极大。我把 prompt 里的“文档是否真正回答了问题”改成“文档是否与问题相关”1.5B 模型在 200 条样本上就有 30 多条结论翻转。这种敏感性在聊天场景里感受不明显在判定场景里是致命的。如果你非要让生成式小模型做判定我的建议是constrained decoding 锁死输出、多次采样取众数、在 prompt 里加清晰的判定标准。但这些只是缓解手段治不了“模型没有稳定绝对测度”的病根。5. 认输之后的替代路线以及这趟弯路的真实收获5.1 任务本质决定技术路线别跟 loss 对赌我现在会先问一个问题你的输出会被怎么使用如果这是一个“判断文档是否满足条件”的场景输出会被当作一个独立、可比的置信度来使用那请直接选 pointwise 分类模型比如微调 DeBERTa或者给 7B 模型加分类头做 LoRA。如果这是一个“把候选结果从好到坏排序”的场景用户只会看 top-k那 rerank 就是最合适的直接选它。两者的分界线不是模型规模而是优化目标。pairwise 模型永远不能替代 pointwise 模型就像你让一个教练只看“队伍排名”来判断“这支队伍有没有夺冠实力”排名能说明一部分问题但绝不等于绝对实力。5.2 如果你实在想用 rerank 做判定至少按这个姿势来我不拦着你踩坑但可以把坑填浅一点把 rerank 分数当特征不要当结果。喂给 LR、GBDT 这类模型跟其他特征组合效果会比裸分数好很多。用锚点对比时多做鲁棒性测试。换三组以上不同难度的正负锚点如果结果抖动超过几个点说明这个方案根本立不住。做分数校准时优先考虑分位数校准样本充足用 isotonic regression样本少可以尝试高斯过程回归。但要记住校准解决的是“分数形变”解决不了“分数漂移”。监控候选集分布。如果你线上的候选集质量和训练时不一致rerank 分数整体漂移几乎必然发生任何固定阈值和校准函数都会跟着失效。5.3 开源小模型的正确打开方式这次实验让我对开源小模型的定位有了更清晰的认识如果你有 7B 级别可用优先 7B别在 1.5B、3B 上硬撑。判定任务对语义边界的要求远高于聊天参数量的差距会直接体现在稳定性上。小模型最适合的场景是作为粗筛把明显不对的样本快速过滤掉把模糊样本送给精排模型或大模型。这个“粗筛加精判”的架构在成本和效果之间是最优解。几百条样本的小数据场景经典分类器往往比 LLM 更可靠。DeBERTa 微调在我的任务上赢了 Qwen2.5-3B LoRA原因就是它本来就是为判别任务设计的参数效率更高不容易过拟合。5.4 最后的一点个人体会如果把这次踩坑的经验压缩成一句话我会说别拿名次当分数。做技术选型之前先想清楚你要的是绝对判断还是相对排序。如果排错了后面再多的调参、校准、融合、蒸馏都是在给一个错误的地基添砖加瓦。当然也不能说一无所获。至少我确认了三件事开源小模型在判定任务上的边界在哪里、rerank 分数到底是个什么东西、以及未来遇到类似任务时我应该从哪里开始做。把这些写出来希望你能比我少跑两天弯路。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。