ColBERT — 让 BERT 检索既准又能扛大规模
是什么
ColBERT 是一种神经信息检索模型——给一句话查询,它从百万级文档库里挑出最相关的几篇。日常类比:像一个图书管理员,他不是把每本书读完总结成一句话再挨个比对,而是事先把每本书每页的关键词都做成小卡片,你问 ‘苹果手机售价’ 时,他用你这句话里的每个词去对所有小卡片,挑配得最齐的那本。
它解决的痛点是 2018 年 BERT 出世后检索界的两难:直接拿 BERT 拼查询和文档过一遍(cross-encoder)精度极高但慢到无法上线;把整篇文档压成一个 768 维向量(DPR)虽然能预先索引,但信息损失太多。ColBERT 用 late interaction 走了第三条路。
为什么重要
不理解 ColBERT,下面这些事都没法解释:
- 为什么 RAG 系统的检索阶段现在很多用 late interaction,而不是更老的 DPR 单向量
- 为什么 ColBERTv2 / PLAID / ColPali / SPLADE 这一整个流派全围绕 ‘token 级向量+轻量聚合’ 展开
- 为什么 ‘BERT 检索’ 不只 ‘把整段压成一个向量’ 这一种做法
- 为什么 ‘什么时候让查询和文档交互’ 是检索系统设计里最关键的一道开关题
核心要点
ColBERT 的全部巧思可以拆成 三步:
-
查询和文档各自独立过 BERT:不像 cross-encoder 把两者拼一起,ColBERT 让查询走一个 BERT、文档走另一个(共享权重),各自输出每个 token 的向量。这一步关键在 没有 cross attention,所以文档可预先编码并索引。
-
128 维投影:BERT 原生 768 维太大,加一层线性层压到 128 维。索引存储砍到原来的 1/6,精度几乎不掉。
-
MaxSim 打分:查询有 N 个 token,文档有 M 个。对查询的每个 token,去文档里找最像它的那个 token(max),打个分;N 个分加起来作为文档总分。
加分项:检索时用两阶段——faiss 对查询每个 token 找 top-k 文档候选(粗筛),再对小候选集做完整 MaxSim(精排)。
三种检索范式对比
| 范式 | 何时交互 | 速度 | 精度 | 可索引 |
|---|---|---|---|---|
| 单向量(DPR) | 不交互 | 极快 | 中 | 是 |
| late interaction | 编码后聚合 | 快 | 高 | 是 |
| cross-encoder | 编码时拼一起 | 极慢 | 极高 | 否 |
ColBERT 占据中间格子:比单向量精,比 cross-encoder 快,文档可预索引。
实践案例
案例 1:MaxSim 直观长什么样
查询 ‘苹果手机售价’(3 个 token,简化)。文档 ‘附近店里 iPhone 卖 5999’(6 个 token)。
q='苹果' → 文档里最像它的 token 是 'iPhone' → max sim = 0.85q='手机' → 文档里最像它的 token 是 'iPhone' → max sim = 0.92q='售价' → 文档里最像它的 token 是 '5999' → max sim = 0.78 总分 = 2.55注意 ‘苹果’ 和 ‘手机’ 都直接对上了 ‘iPhone’——它们没有被一个文档向量平均掉。这就是 late interaction 的精度来源。
案例 2:MS MARCO Passage Ranking 实测
| 模型 | MRR@10 | 延迟(ms/query) |
|---|---|---|
| BM25 | 18.7 | 62 |
| DocT5Query | 27.7 | 64 |
| DPR(单向量) | 31.4 | 12 |
| ColBERT | 36.0 | 458 |
| BERT-base reranker | 34.7 | 10700+ |
ColBERT 的 MRR 比 BERT reranker 还高 1.3 个点(因为能看更多候选),延迟低 20+ 倍。这是当时唯一兼得 ‘神经精度 + 可索引’ 的方案。
案例 3:为什么文档可预索引
cross-encoder 把 [CLS] q [SEP] d [SEP] 一起过 BERT,q 和 d 互相 attention,每来一条新查询都要重算全部文档。ColBERT 的 q 编码和 d 编码完全独立,没有 cross attention。所以文档的 M 个 128 维向量可以提前算好存进 faiss,查询时只算 N 个查询向量,O(N*M) 的 MaxSim 在 GPU 上飞快。
这就是 ‘late’ 的含义——查询和文档编码时不见面,只在最后聚合分数时见。
踩过的坑
-
索引大小爆炸:每个 token 一个 128 维向量,MS MARCO 8.8M 篇文档要 154GB。这是后来 ColBERTv2 用残差压缩压到 16GB 的直接动机。
-
MaxSim 的 max 不可导:训练时反向传不动。原文用 softmax 近似(带 temperature 参数)来过桥。这是机器学习里 ‘不可导用近似’ 的标准操作。
-
查询/文档长度受限:BERT 限 512 token,长查询要截断;长文档要切 chunk,跨 chunk 语义会断。
-
batch 内负样本敏感:训练用 in-batch negatives,batch 越大效果越好,但 GPU 显存吃紧时降 batch 会损失精度。
-
domain shift:在 MS MARCO 上训的 ColBERT 直接用到医学/法律/代码等领域时精度下降,需要 domain-specific finetune。
-
MaxSim 的求和不是平均:N 个查询 token 的 max sim 直接相加,意味着查询越长总分基线越高。论文里靠 ranking loss 抵消了绝对分数的影响,但若拿来做阈值过滤要小心查询长度归一化。
-
粗筛阶段的近似:faiss 对查询每个 token 做近似 ANN 搜索,可能漏掉 MaxSim 真正的 top 文档。原文经验是每个 token 取 top-1000 候选并取并集,再做精排。这个 1000 是工程超参,缩太小会丢回归。
适用 vs 不适用场景
适用:
- RAG 系统检索阶段(候选集 10K-10M,要求精度高于单向量但又不能用 cross-encoder)
- 查询和文档关键词匹配重要的场景(医学术语、法律条文、代码搜索、产品名)
- 可接受 100ms 量级延迟、能腾出几十 GB 索引空间的服务
- BEIR 类零样本跨领域检索基线
不适用:
- 极致低延迟(<10ms/query)→ 选 DPR 单向量
- 候选集很小(<1000)→ 直接 cross-encoder 全量打分
- 嵌入式设备 / 索引存储是硬上限 → 选 BM25 或 ColBERTv2 残差压缩版
- 需要可解释打分(业务规则要求)→ 选 BM25 + 神经 reranker
历史小故事(可跳过)
- 2018 年:BERT 出世,但拿来检索要么慢(cross-encoder)要么糙([CLS] 单向量)
- 2019 年:Facebook 推出 DPR,用 BERT 把查询和文档各压成一个 768 维向量。快但精度有限
- 2020 年:Khattab(斯坦福博士生)和 Zaharia(Spark / Databricks 创始人)在 SIGIR 提出 ColBERT,用 late interaction 同时拿到精度和速度
- 2021-2022 年:作者团队推出 ColBERTv2,用残差压缩把索引从 154GB 砍到 16GB
- 2023 年:Ben Clavié 写出 RAGatouille 把 ColBERT 系列做成 pip 包,三行代码起步
- 2024-2025 年:late interaction 思想扩展到视觉检索(ColPali)和稀疏检索(SPLADE),形成一整个学派
学到什么
- ‘什么时候交互’ 是检索设计的关键开关——early(拼一起过 BERT)/ late(各编码后聚合)/ no(单向量),三档对应三种 trade-off
- 保留 token 粒度+轻量聚合 是把 ‘大模型表达力’ 和 ‘索引可行性’ 兼得的通用模式
- 工程权衡可视化:精度 / 延迟 / 索引大小 是检索三角,没有银弹
- 不可导问题用近似过桥:MaxSim 的 max 反向传不动,softmax 加 temperature 是常见解法
- 为下游而设计的表示比通用表示更管用:128 维投影是为 MaxSim 而生,不是通用 embedding
- 预索引能力来自 ‘编码独立’:cross-encoder 慢的根源是查询和文档互相 attention,ColBERT 把这条边切断后立刻获得索引可行性。这条 ‘砍依赖换效率’ 的经验在系统设计里反复出现
延伸阅读
- 论文 PDF:ColBERT arXiv(12 页正文)
- 视频教程:Stanford NLP — ColBERT(Khattab 本人讲,60 分钟)
- 框架上手:RAGatouille 文档(pip install 三行代码起步)
- colbert-v2 —— ColBERT 的下一代,用残差压缩把索引从 154GB 砍到 16GB
- bert —— ColBERT 的 token 向量来源
关联
- bert —— 提供每个 token 的上下文向量,是 ColBERT 索引的原始材料
- colbert-v2 —— 直接后继,残差压缩 + 蒸馏,索引从 154GB → 16GB,精度还更高
- dssm-2013 —— 单向量稠密检索的开山祖,ColBERT 用 late interaction 改写其表达力上限
- drmm-2016 —— 早期把交互矩阵手工聚合,ColBERT 把这一步用 BERT + MaxSim 做得更彻底
- knrm-2017 —— 用核函数聚合交互信号,late interaction 是同一思想在 BERT 时代的延伸
- anserini-2017 —— 经典 BM25 检索基线,ColBERT 论文里的对照组
- transformer —— BERT 的底层架构,late interaction 直接利用其 token 级输出
- attention —— BERT 内部的核心机制,让每个 token 编码都包含上下文
反向链接
- ance-2020 —— ANCE — 让模型自己挖训练负例,对比学习的”自给自足”
- annoy —— Annoy — Spotify 的随机森林近似最近邻索引
- anserini-2017 —— Anserini — 把工业搜索引擎 Lucene 改造成学术 IR 实验台
- attention —— Attention Is All You Need
- bert —— BERT — 双向 Transformer 预训练
- bpr-2009 —— BPR — 用『i 比 j 更受欢迎』替代『i 是正例 j 是负例』
- cocondenser-2021 —— coCondenser — 让 BERT 的 [CLS] 在预训练就学会”代表整段话”
- colbert-v2 —— ColBERTv2 — 让向量检索既精又能扛百万文档
- doc2query-2019 —— doc2query — 让模型替文档预想”会被怎么搜”再写进倒排表
- dpr-2020 —— DPR — 用 BERT 双塔把检索从 BM25 时代拉进稠密向量时代
- drmm-2016 —— DRMM — 检索里的匹配是相关性不是语义相似
- e5-2022 —— E5 — 用海量”自然出现的文本对”训通用 embedding
- filip-2021 —— FILIP — 把 CLIP 的图文对齐细化到 token 级
- knrm-2017 —— K-NRM — 用核函数把交互矩阵变成可微排序信号
- ms-marco-2016 —— MS MARCO — 1 千万 Bing 真实查询喂饱神经检索的标准评测集
- replug-2023 —— REPLUG — 不动 LLM 一根毛,只把检索器调到它的”口味”上
- rm3-2001 —— RM3 — 让搜索引擎自己看一眼结果再重搜一次
- rocketqa-2021 —— RocketQA — 把稠密检索的训练拧到工业级
- splade-2021 —— SPLADE — 让神经网络学出稀疏向量,直接复用倒排索引
- vespa —— Vespa — Yahoo 检索 + 排序引擎