# Summary
**重排序是用一个「新模型」重新计算 query 和 doc 的相关性分数**
## 在搜索中的位置
用户查询
→ Embedding检索 + [[ElasticSearch、ES]](召回阶段)
→ **Reranker(精排阶段)**
→ Top结果
## 原理
```python
# 拼接后一起编码
input_text = "[CLS] query [SEP] doc [SEP]"
score = reranker(input_text) # 直接输出相关性分数
# 优点:query 和 doc 充分交互,精度更高
# 缺点:必须在线计算,慢(只能处理几十到几百个候选)
```
# Cues
[[双塔模型(Bi-Encoder)、粗召回(粗排)]]
# Notes
## 一、与双塔模型(Bi-Encoder)的区别
**双塔模型(用于召回)**:
```python
# 分别编码,可以离线计算
query_vector = encoder(query) # [1, 768]
doc_vector = encoder(doc) # [1, 768]
score = cosine_similarity(query_vector, doc_vector) # 点积
# 优点:速度快,支持百万级检索
# 缺点:query 和 doc 独立编码,交互不足
```
**Cross-Encoder(用于重排序)**:
```python
# 拼接后一起编码
input_text = "[CLS] query [SEP] doc [SEP]"
score = reranker(input_text) # 直接输出相关性分数
# 优点:query 和 doc 充分交互,精度更高
# 缺点:必须在线计算,慢(只能处理几十到几百个候选)
```
## 二、CLS 和 SEP 是什么?
这是 **BERT 类模型的特殊标记符号**,可以把它们理解为"标点符号",帮助模型理解文本结构:
**`[CLS]`** - Classification Token (分类标记),> 就像看一篇文章,标题写着"[总结]",你知道这里会给出整体结论
- **位置**: 永远放在**最开头**
- **作用**: 像一个"总结者",模型会把整段文本的**综合信息**都汇聚到这里
- **输出**: Reranker 最后就看这个位置的输出来判断相关性分数
**`[SEP]`** - Separator Token (分隔符) > 就像聊天时用 "---" 分隔不同话题
- **位置**: 放在**不同部分之间**
- **作用**: 告诉模型"这是两个不同的东西,别混淆"
- **类似**: 中文的顿号、分号
---
## 实际例子
假设你搜索 **"北京天气"**,候选文档是 **"今天北京多云转晴"**
```python
# Reranker 实际看到的输入:
"[CLS] 北京天气 [SEP] 今天北京多云转晴 [SEP]"
# 模型内部处理:
# 1. [CLS] 的位置会综合理解整个句子
# 2. [SEP] 告诉模型: 前面是query,后面是文档
# 3. 最后输出 [CLS] 位置的分数 → 比如 0.92 (很相关!)
```
---
## 为什么需要这些标记?
|场景|不用标记|用了标记|
|---|---|---|
|**区分部分**|"北京天气今天北京多云" <br> 😵 模型分不清哪是query|"[CLS]北京天气[SEP]今天..." <br> ✅ 清楚知道结构|
|**获取分数**|不知道看哪个位置的输出|直接看[CLS]的输出|
---
## 核心要点
- `[CLS]` = 开头的"总结位置",输出最终分数
- `[SEP]` = 中间的"分隔符",区分 query 和 doc
- 这是 BERT 训练时就定好的**约定俗成**,就像 HTTP 协议里的 `GET`、`POST` 一样
___
你碰到的是经典的 “交叉编码器(cross-encoder)用于排序 / Learning-to-Rank 的训练数据构造” 的变体——也就是用 BERT(query, doc) 联合建模并输出打分的那一类监督学习问题。
下面我把能直接用、样式清晰的训练数据格式、常见标签策略、负样本采样、损失函数与工程实践要点都列出来——并给出具体的 JSON/伪码样例,方便你直接落地。
一、常见的数据格式(3 种主流)
1. Pointwise(点式)
每条样本是一个 (query, doc, label),label 是标量(binary/graded/score)。
示例(JSONL):
```
{"query":"如何做披萨?","doc":"披萨做法:先准备面团...","label":1}
{"query":"如何做披萨?","doc":"苹果派的做法:先...","label":0}
```
训练时用回归或分类损失(如二分类交叉熵或 MSE / regression loss)。
2. Pairwise(对式 / 三元组)
每条是 (query, positive_doc, negative_doc) 或 (query, pos, negs[]),目标是 score(q,pos) > score(q,neg)。
示例:
```
{"query":"python 列表去重","positive":"使用 set 去重的示例代码...", "negative":"如何写一个 C++ 类?"}
```
常用损失:hinge loss、pairwise cross-entropy(BPR)等。
3. Listwise(序列式 / 多候选)
每条是 (query, candidates=[{doc,label}, ...]),标签可以是 0/1 或 0/1/2/3(分级)。训练时把同一 query 的所有候选一起做 softmax + cross-entropy(更直接优化排序指标)。
示例:
```
{"query":"南京旅游必去","candidates":[
{"doc":"中山陵介绍...", "label":2},
{"doc":"附近的餐馆列表...", "label":1},
{"doc":"股票行情今天...", "label":0}
]}
```
二、标签类型(怎么标注)
• Binary(0/1):相关 / 不相关。标注简单,常用在 QA、FAQ 场景。
• Graded(0..3/4):不相关 / 低相关 / 中等 / 高相关。对排序更细腻,有助于 listwise loss。
• Soft labels(概率/分数):来自自动模型(如 cross-encoder 给出的分数)或多个标注者的平均分,用于蒸馏训练。
三、负样本(非常关键)
• 随机负(Random):简单但效果有限。
• in-batch negatives:把 batch 内其他 doc 当负样本,训练效率高。
• hard negatives(困难负样本):用 BM25 / 现有 bi-encoder / heuristic 筛出的高相似但不相关的 doc,训练效果大提升。
• 动态挖掘:训练中周期性用当前模型检索再更新负样本(在线挖掘)。
四、输入格式与截断(工程细节)
• 把 query 和 doc 拼接:[CLS] query [SEP] doc [SEP](或使用 tokenizer 的 encode_plus(query, doc))。
• 截断策略:通常把 max_length 分配给 doc(truncation='only_second'),保证 query 完整。
• 可以加入额外特征(点击次数、bm25 score)作为额外的输入 head,但大多数情况下先用文本本身即可。
五、常用损失及训练策略
• Pointwise:binary CE 或回归 MSE。
• Pairwise:hinge loss max(0, margin - s(pos)+s(neg)) 或 pairwise CE(BPR)。
• Listwise:softmax over candidates(给每个候选计算 exp(s)/sum(exp(s)))然后用 cross-entropy 使 ground-truth 在分布中概率最高——这个在多候选、同 query batch 非常好用。
• In-batch softmax / InfoNCE:把整个 batch 的所有 docs 作为 negatives,常用于对比学习与蒸馏。
六、具体样例(二种常见训练数据 JSONL)
七、训练时的具体实现思路(伪码)
`loss = F.cross_entropy(scores, labels)`
八、数据规模与标注成本建议
• 小规模实验:每个 query 10~100 个候选、上万条 query(数万—十万样本)可见明显效果。
• 生产级:十万—百万级 query + 每 query 多个候选,且结合自动挖掘的 hard negatives。
• 标注:优先做高质量的正例 / hard negatives;多个标注者交叉检查以减少噪声。
九、常见实践与技巧
1. 先用 bi-encoder+ANN 做召回,再在召回 top-K 上做 cross-encoder 精排(训练 cross-encoder 用上面 listwise/pairwise 数据)。
2. 训练数据来源:用户点击/点击-未点击信号(implicit feedback)、人工标注(explicit relevance)、现有交叉模型的打分(蒸馏软标签)。
3. 蒸馏:用强 cross-encoder 给 bi-encoder 生成软标签,或用 cross 的分数作为训练目标提升 bi-encoder。
4. 评估:在 dev 上用 Recall@K、MRR、NDCG、以及 downstream RAG 的生成质量一并评估。
5. 样本平衡:注意绝大多数负样本会导致训练不稳定,使用 in-batch + hard negatives 更稳妥。
6. 标签噪声处理:对人标结果做一致性校验,或给每条样本加权(more confident sample weight)。
十、我可以直接给你的东西(你选一项我马上给)
• A. 可运行的数据生成 + HuggingFace transformers 脚本(从 JSONL 到 DataLoader,再到训练 loop,含 listwise softmax 示例)。
• B. 标注指引模板(用于告诉标注员如何标注 0/1/2/3、示例与边界情况)。
• C. 负样本挖掘与 hard negative mining 的实现示例(BM25 + bi-encoder 混合采样脚本)。