别拿rerank当判定器:16组实验后的技术复盘 你可能以为标题里的“认输”是句自嘲我写这篇复盘时是真的把两天的实验记录翻出来又看了一遍。两天16组实验全在围绕一个搭法打转拿开源rerank的语义匹配能力去给一个小模型当“判定器”的拐杖最后没有一组实验能同时满足三个条件——阈值可用、跨场景稳定、延迟可控。如果你也动过“用rerank改一改就能做判定”的念头这篇博文至少能帮你省下两天的时间。我先把话说清楚本文不否定rerank在检索排序里的价值我要聊的是它在“判定模型”这个身份下的四个隐蔽坑、四种失败路线以及认输之后我重新规划方案时的正确思路。1. 为什么我会被“rerank 小模型”这个组合吸引1.1 业务场景和约束当时的需求来自一个内部系统给定一段文本判断它是否“达标”。这里的达标可能是“这条用户反馈是否真的在描述故障”“这个候选答案是否真的覆盖了问题要点”“这段文档描述是否与目标功能相关”。这类任务不算复杂但要求模型本地部署、可审计、可人工复核还不能调外部的大模型接口。算力上限大概就够跑一个几百M的交叉编码器或者更小一点的单塔分类器。这种约束下大多数人第一反应是微调一个BERT类小模型做二分类。但问题在于初始化标注数据很少几个主题下翻来覆去只有几百条可用。业务方又给了一个很紧的时间预期于是我想找一个“不需要大量标注也能立马上手”的方案。rerank模型进入视野几乎是必然的它的输入是query和doc输出是一个相关分我的判定任务也可以包装成“标准描述”和“待判定文本”让模型去给两者的匹配程度打分。这个包装太自然了自然到我当时觉得这条路几乎就是为这个需求量身定做的。1.2 把判定问题偷换成匹配问题的诱惑判定和匹配在数学上当然有交叉但它们的评价体系完全不同。匹配问题关心的是“这对文本是否指向同一件事”判定问题关心的是“这段文本本身是否达到了某个标准”。举个例子你拿一句“这台机器运行时有异响”去匹配“机器故障描述”rerank会给出一个很高的相关分。但如果判定标准是“故障描述中必须包含故障代码或发生时间”那这句话就是不合格的——相关但不是达标。这种差异在第一次实验里就会暴露但我在做第一组实验之前被一个更诱人的假设冲昏了头既然开源rerank模型在公开榜单上表现那么强它内部一定已经学到了非常细的语义判断能力我只要把“判定标准”写成一个query它的语义匹配能力就能迁移到判定任务上。相当于我把一个训练有素的检索高手请来让它换个岗位当质检员。我当时甚至设计了三层用法后来16个实验里每一个都逃不出这三层用法直接拿rerank的score当判定分数人工定一个阈值做二分类拿rerank当老师给无标注数据打伪标签训练一个小模型小模型做初筛rerank在候选集上精排用排序结果反推判定结论。这三条路我后来全走了也全碰了壁。壁不是撞在“模型不够强”上而是撞在“rerank这个物种的工作逻辑”上。1.3 我当时设想的三种用法先说第一种用法也是最省事的一种把一个中大型的cross-encoder型rerank模型加载进来把判定标准固化成一段描述文本然后把待判定内容作为候选文档传进去模型吐出分数。这么做的好处是完全不需要标注坏处我在后面细说但它在路线上最吸引人。第二种用法更工程化用rerank给大规模无标注语料打标生成一个伪训练集然后用这个小模型上线。这样可以把推理成本从几百M降到几十M也方便塞进在线链路。第三种用法是把两条路拼起来小模型先做一轮快速打分把最可能不达标的样本过滤掉剩余候选交给rerank精排最终按精排分数做阈值判断。听起来很稳但实际跑起来后问题一个接一个。2. rerank的两个本性注定它不适合当判定器2.1 排序损失背后的“相对分数”陷阱rerank模型在训练时用的是pairwise或listwise排序损失目标是把正样本排到负样本前面。这种训练方式让模型学到的本质是“相对顺序”而不是“绝对标准”。说得更直白一点它知道A比B更像正样本但它并不知道A本身算不算合格。这个差异在推理时会带来一个特别隐蔽的现象分数分布会随输入批次漂移。如果某一次输入了一批整体质量很高的文本rerank会给其中一多半都打高分如果某一次输入的全是低质文本它也会硬生生挑出几个“相对较好”的给高分。因为训练时它从来没有被要求对齐一个绝对好坏的分界线。我后来用一个生活类比给同事解释这件事选美比赛的评委能给20个选手排出名次但你让他站在海关查验通道里决定“每个人是否可以过关”他就懵了。他擅长的是“谁比谁好看”不是“谁达到了过关标准”。判定模型要求的是后者rerank擅长的是前者。2.2 分数分布偏移在A域调的阈值到了B域就成摆设这个坑我踩得最实。第一组实验里我用一个开源rerank模型对某一种类型的文本打分拿验证集调出来的阈值在测试集上表现还不错F1能做到0.75上下。可当我把它平移到另一个文本类型上同一个阈值直接让F1跌破0.5。原因不复杂rerank的分数本身就不是概率它没有被校准过。不同领域下的文本匹配分天然分布就不一样。这个领域下0.6可能已经算强相关换一个领域0.6可能只是中等相关。你必须在每个新领域重新标数据、重调阈值那你费劲做“不用标注”的方案就已经破产了一半。我后来尝试过用温度缩放、等渗回归这些校准手段去修正分数效果在当时那一批数据上还可以但换一个分布又失效。校准器永远追不上分布漂移因为rerank的训练信号里根本没有绝对标准它不会主动让自己对齐一个稳定的语义零点。2.3 更致命的一点它根本不会面对“否命题”这一点是我跑完第四组实验才完全想透的。检索和排序任务里负样本通常都是“不太相关”的样本很少会精细构造“高度相关但就是不达标”的样本。而判定任务真正困难的部分恰恰是这些负样本。举个例子判定“这段回答是否完整告知了退款流程”一个回答可能是“退款申请在订单详情页具体金额取决于支付方式”——这句话和退款流程高度相关但它并没有告知完整流程它只是提到了一部分。这种样本对排序模型来说是“不错的正样本”因为它在语义上和退款强相关排名时它会排到很多无关文本前面。但对判定模型来说它是一个必须被拒掉的困难负样本。rerank的负采样策略从一开始就没有为这种场景准备过它看到“相关”就容易给高分你要的却是“达标”。这一条直接击中了我整个方案的根基不是微调能救的不是调阈值能救的是工具本身的工作逻辑就不匹配。3. 16组实验全记录哪些值得跑哪些是白耗3.1 实验矩阵总览我把16组实验分成四条路线每条路线四个实验。下面这个表是我在复盘时重新整理的结果列写的都是最终结论不包含中间调参过程。路线实验行为典型做法最终结果A. 现成rerank直接判定A1~A4不同架构体量的开源rerank模型0-shot打分按阈值分类单域可看跨域崩溃全程失败B. 小模型微调 rerank信号B1~B4小模型分类器输入拼接rerank分数特征或不加特征直接用伪标签微调伪标签错误被放大训练信号不可靠C. rerank构造训练集C1~C4用rerank从无标注语料里筛正负样本再训练小模型调整筛选阈值和自训练轮数数据质量提升有限瓶颈在小模型容量本身D. 小模型初筛 rerank精排级联D1~D4小模型先过一遍排序阶段上rerank按位置和分数联合决策性能最高的一组但稳定性不达标延迟上升明显看这张表你可能会说路线D不是“性能最高”吗为什么不继续调因为“性能最高”和“可用”之间差着一整个工程化距离我下面把每条路线的关键实验细节拆开讲。3.2 路线A拿现成rerank直接当判定器A组实验的做法很简单加载开源rerank权重构造一个判定query然后把待判定文本当doc传进去。我试了不同参数量级的模型从小几十M到几百M到接近1B的都有。第一个发现是分数分布严重坍缩。几乎所有文本的score都挤在一个很窄的区间里正负样本之间的区分度比我想象中低得多。这说明模型虽然能给出相对排序但它并不像分类器那样天然地给“达标”和“不达标”留出隔离带。第二个发现更让人头疼同一个模型在两个领域上的最优阈值差距很大。我在A领域用验证集调出一个阈值F1是0.76觉得很开心换到B领域同样的代码同样的阈值直接掉到0.47。这个过程让我彻底意识到0.76的成绩并不是“模型会判定”而是“阈值恰好在那个领域碰对了”。我还试过加一层校准器想让这条路线变得可用结果前面已经说了校准器在校准域有效跨域依然是摆设。A组四组实验结论统一现成rerank可以当排序器但绝对当不了判定器。3.3 路线B小模型微调 rerank伪标签/特征既然直接用不行我想能不能把rerank当成一个“信号源”喂给真正能被微调的小模型。B组实验做了两件事一是把rerank的分数作为额外特征拼进小模型分类器里二是直接把rerank打好的0/1伪标签当训练目标。加特征这条路的问题在于小模型很快会把rerank分数当成最重要的特征学到的其实是“复读rerank的判断”但rerank的判断本身就不稳定特征通道像一个哈哈镜把错误也一起放大了。伪标签训练的问题更本质。我拿了五万条无标注记录用rerank打分后按阈值切出伪标签再用一个小型Transformer模型去拟合。训练loss还挺正常但拿到人工复核的样本上一测错误全部集中在那些“语义相关但不达标”的困难负样本上。因为这些样本在rerank眼里本来就被判成了正样本伪标签直接把错误固化下来小模型再去拟合这不靠谱的标签等于在垃圾标注上做梯度下降。我中间还尝试过只取rerank置信度最高的样本当伪正例置信度最低的当伪负例把中段模糊样本丢掉确实能提升一点训练集质量。但训练出来的小模型上限就这么高一旦面对中段困难样本它根本没法产生rerank完全不具有的判断力。小模型不是大模型的压缩包它是另一套容量更有限的机器。3.4 路线Crerank构造训练集小模型重学C组实验是B组的延伸版区别在于我不直接让rerank打伪标签了而是用“配对挑选”的方式构造数据。具体做法是每一条标准描述配上若干条文本让rerank选出“哪一条最符合标准”然后把这些排序结果展开成pairwise训练数据去训练一个小型排序模型。这组实验其实比B组科学一点因为rerank的排序能力比绝对打分能力靠谱。问题出在另一个地方我训练出来的小模型在其中一个领域上达到了可用水平但在另一个看起来分布差不多的领域上依然崩掉。两个领域在词表重合度、句式复杂度上都接近模型表现差距却非常大。这时候我意识到问题已经从“训练数据构造方式”转移到了“小模型容量本质”。容量有限的小模型在单一分布内可以拟合得很好但它的表征空间根本没有足够的自由度去同时容纳多个判定标准。它不是不愿意学是真的学不下那么多套隐式规则。C组还有一个额外发现如果我不断用更高质量的困难负样本去强化数据小模型的分数确实会往正确的方向挪但每次挪动都会在另一个子维度上产生回退。顾此失彼这就不是一个数据工程能补完的问题。3.5 路线D小模型初筛 rerank精排的级联方案D组是当时所有人的直觉选择小白模型快速粗筛掉明显不合格的rerank在幸存者里做出精细排序然后根据排序位置和分数联合判断。这组实验效果最好在单个数据集上确实接近业务可用的底线但它有三个让我最终放弃的问题。第一是延迟。我原本指望小模型初筛能砍掉80%的计算量但实际数据里“看起来明显合格”和“看起来明显不合格”的样本比例远低于理论假设大量样本还是得走到rerank这一步。上线后平均延迟比单模型翻了将近三倍。第二是两级系统的阈值标定。小模型初筛阈值、rerank精排阈值、两个模块置信度不一致时的兜底策略这三层参数在跨域之后全部要重新调。每换一个领域就是一套新的标定流程这不叫方案成熟这叫工程陷阱。第三才是最关键的D组的成绩上限并没有高到值得付出这些复杂度。我把它的最好成绩和另一条对比路线放在一起比过那条路线是用一个中等规模的开源大模型对同样的数据进行“生成式判定”效果稳定超出实时性也行。也就是说我费了那么大劲做的级联系统实际上是在用19世纪的办法解决21世纪的需求。4. 认输的核心依据以及复盘后的正确路线4.1 让我决定停止的三个指标两天跑完16组实验我给自己定了三条硬指标只要三条同时不满足就停止投入。第一条是跨域稳定性。任何一个方案至少要在两个以上不同分布的文本类型上都达到可用的F1而不是一个域好一个域崩。这条直接砍掉了路线A和C。第二条是阈值标准可维护。上线之后如果每换一次领域都要重新标数据调阈值那系统的维护成本会随时间线性上涨这条砍掉了路线B和D的工程化可能性。第三条是延迟可控。级联方案里小模型加精排的双重开销让平均延迟无法接受而它换来的性能提升又不足以覆盖延迟代价。三条一交叉结论已经很明显这个架构方向本身就不对不是可以靠继续堆实验救回来的。我不太喜欢“坚持就能成功”这种叙事。在工程里发现方向性错误并及时停止和把一件事做完做对同等重要。两天16个实验我真正收获的不是“失败的经验”而是一张清晰的排除清单。4.2 复盘后我认为值得做的路线认输当晚我重新列了三条路都是基于这次排雷后的认知修正。如果允许在线请求我会首选开源大模型做“生成式判定”。不是让它简单输出一个“是/否”而是要求它先输出判定结论再输出理由理由里必须引用原文片段。生成式判定的好处是它天然要面对“否命题”你再告诉它标准的边界它能给出可解释的判断。对量化后的开源模型做一次轻量LoRA效果通常比通用的rerank方案稳定得多。如果必须纯本地小推理我不会再让模型独立做最终判定。我会把任务拆开小模型负责做“廉价特征的抽取和召回”把候选文本里的关键实体、关键词、时间信息等先结构化规则负责核对硬性条件只把那些规则对不齐、语义模糊的少量样本交给一个中等规模的交叉编码器精排。rerank在这个架构里仍然有一席之地但它只负责排序候选不再负责“判定达标”。如果数据非常垂直还有一个值得先试的方案用大量领域内无标注文本对基座模型做继续预训练再在少量标注上微调。可能有人觉得小模型无标注预训练收益太小但我在其他项目里见过的案例是领域数据能带来比通用基础模型明显更准的判定结果。这个路线和rerank无关它是先让模型真正理解这个领域的语言再谈判定的问题。4.3 一个更高维度的认知判定器是“标准”不是“相似度”复盘到最后我脑子里留下一个非常简洁的判断相似度模型回答的是“像不像”判定模型回答的是“达没达标”。这两件事在低难度样本上看起来很像在困难样本上完全不同。搜搜索引擎在乎的是“相关”内容审核系统在乎的是“合规”客服工单系统在乎的是“是否有效解决”。一旦判定标准涉及边界、例外、条件组合那么任何基于匹配分数的方案都会失灵因为它没法学“标准”只能学“相似”。这是数据分布决定的不是模型结构决定的换更大的rerank也改变不了这个底层逻辑。想清楚这一点之后我觉得这两天的时间也不算白花。至少下一次再有人跟我说“用rerank改一改就能做判定模型”的时候我可以很明确地告诉他你会得到一份可复现的失败报告。而如果你也想快速验证这类思路我建议第一天上午先做一件事——手工标注300条困难样本用小模型硬训一个baseline再拿这个baseline去对比你心里的“高级方案”。很多时候那个朴素baseline就已经站在终点了。