简介
本文介绍多向量搜索技术(如ColBERT)作为提升RAG召回结果相关性的解决方案。与传统单向量嵌入不同,多向量方法通过保留token级别的细粒度信息,利用MaxSim算法计算查询与文档间的相似度。文章详细展示了在PostgreSQL中实现ColBERT rerank的完整流程,包括数据编码、索引构建和查询优化。实验证明,该方法在多个BEIR数据集上显著提升了搜索效果(NDCG@10最高提升约25%),不仅适用于文本检索,还可扩展到视觉文档理解等场景。
多向量 | 另一种提升召回结果相关性的解决方案
RAG严重依赖向量搜索, 但是有一个漏洞, 可能导致搜索出来的结果并不理想, 原因是相似性!=相关性.
业界的解决办法是混合搜索( 即: 向量(语义)搜索 + 全文检索 + 模糊查询等 + rerank )
其实还有一种解决办法: 多向量搜索.
目前向量搜索结果不理想的根本原因是:
- query
句子/段落 embedding与 库内句子/段落 embedding的相似性
换句话说, 段落由句子组成, 句子由token(词组)组成, 然而embedding对应的是token(词组)聚合后的向量值.
那么能不能直接使用token(词组)的向量值进行搜索, 减少信息的丢失呢?
能, 但是数据量太大了, 一句话可能包含很多个token, 一段话就更多了. 使用token搜索时会产生笛卡尔积式的搜索.
有没有可能加速呢?
这就是将介绍的 vectorchord maxsim 算子.
以下内容翻译自: https://blog.vectorchord.ai/supercharge-vector-search-with-colbert-rerank-in-postgresql
使用 PostgreSQL 中的 ColBERT rerank 增强向量搜索
传统的向量搜索方法通常使用句子嵌入来定位相似内容。然而,通过池化token嵌入来生成句子嵌入可能会牺牲token级别的细粒度细节。ColBERT通过将文本表示为token级别的多向量(而非单个聚合向量)来克服这个问题。这种方法利用token级别的上下文后期交互,使ColBERT能够保留更细微的信息,并比单纯依赖句子嵌入的方法提高搜索准确率。
ColBERT 结构(摘自原始论文)
如上图所示,ColBERT 将每个文档/查询编码为一个token向量列表(数组),并在查询期间计算 MaxSim。
Token 级的后期交互计算需要更高的算力和存储空间。这使得在大型数据集中使用 ColBERT 搜索变得极具挑战性,尤其是在低延迟至关重要的情况下。
一种可能的解决方案是将句子级向量搜索与token级后期交互重排序相结合,从而利用近似向量搜索的效率和多向量相似性搜索的高质量。
多向量(即向量数组)方法不仅限于纯文本检索任务,它还可以用于视觉文档理解. 参考此文 。对于多模态检索模型,像ColPali和ColQwen这样的先进模型直接将文档图像(pdf,扫描文本等)编码为多向量,并表现出比 OCR 转文本方法更强大的性能。
本博客将演示如何使用 PostgreSQL 扩展插件 VectorChord 和 pgvector 进行 ColBERT 重新排序。
教程
假设我们已经有了文档,让我们创建一个表来存储所有文档:
import psycopg from pgvector.psycopg import register_vector class PgClient: def __init__(self, url: str, dataset: str, sentence_emb_dim: int, token_emb_dim: int): self.dataset = dataset self.sentence_emb_dim = sentence_emb_dim self.token_emb_dim = token_emb_dim self.conn = psycopg.connect(url, autocommit=True) with self.conn.cursor() as cursor: cursor.execute("CREATE EXTENSION IF NOT EXISTS vchord CASCADE;") register_vector(self.conn) def create(self): with self.conn.cursor() as cursor: cursor.execute( f"CREATE TABLE IF NOT EXISTS {self.dataset}_corpus " "(id INT BY DEFAULT AS IDENTITY PRIMARY KEY, text TEXT, " f"emb vector({self.sentence_emb_dim}), embs vector({self.token_emb_dim})[]);" )这里我们创建了一个包含句子级嵌入和token级嵌入的表。
有许多嵌入 API 和开源模型。您可以选择适合您用例的模型。
对于标记(token)级嵌入:
from colbert.infra import ColBERTConfig from colbert.modeling.checkpoint import Checkpoint class TokenEncoder: def __init__(self): self.config = ColBERTConfig(doc_maxlen=220, query_maxlen=32) self.checkpoint = Checkpoint( "colbert-ir/colbertv2.0", colbert_config=self.config, verbose=0 ) def encode_doc(self, doc: str): return self.checkpoint.docFromText([doc], keep_dims=False)[0].numpy() def encode_query(self, query: str): return self.checkpoint.queryFromText([query])[0].numpy()ColBERT 模型默认生成 128 维向量。
插入数据:
class PgClient: ... def insert(self, documents: list[str]): with self.conn.cursor() as cursor: for doc in tqdm(documents): sentence_emb = sentence_encoder.encode_doc(doc) token_embs = [emb for emb in token_encoder.encode(doc)] cursor.execute( f"INSERT INTO {self.dataset}_corpus (text, emb, embs) VALUES (%s, %s, %s)" (doc, sentence_emb, token_embs) )对于向量搜索部分,我们可以使用VectorChord构建高性能的RaBitQ索引:
class PgClient: ... def index(self, num_doc: int, workers: int): n_cluster = 1 << math.ceil(math.log2(num_doc ** 0.5 * 4)) config = f""" residual_quantization = true [build.internal] lists = [{n_cluster}] build_threads = {workers} spherical_centroids = false """ with self.conn.cursor() as cursor: cursor.execute(f"SET max_parallel_maintenance_workers TO {workers}") cursor.execute(f"SET max_parallel_workers TO {workers}") cursor.execute( f"CREATE INDEX {self.dataset}_rabitq ON {self.dataset}_corpus USING " f"vchordrq (emb vector_l2_ops) WITH (options = $${config}$$)" )为了加快索引构建过程,我们可以利用外部质心(即k-means的聚集点)构建。更多详情,请参阅“在 VectorChord 中构建外部质心的优势和步骤” 。
现在,我们可以查询 PostgreSQL:
class PgClient: ... def query(self, doc: str, topk: int): sentence_emb = sentence_encoder.encode_query(doc) with self.conn.cursor() as cursor: cursor.execute( f"SELECT id, text FROM {self.dataset}_corpus ORDER BY emb <-> %s LIMIT {topk}" ) res = cursor.fetchall() return res为了支持MaxSim重新排名(rerank),我们需要创建一个函数:
class PgClient: def __init__(self, url: str, dataset: str, sentence_emb_dim: int, token_emb_dim: int): ... self.conn.execute(""" CREATE OR REPLACE FUNCTION max_sim(document vector[], query vector[]) RETURNS double precision AS $$ WITH queries AS ( SELECT row_number() OVER () AS query_number, * FROM (SELECT unnest(query) AS query) ), documents AS ( SELECT unnest(document) AS document ), similarities AS ( SELECT query_number, document <=> query AS similarity FROM queries CROSS JOIN documents ), max_similarities AS ( SELECT MAX(similarity) AS max_similarity FROM similarities GROUP BY query_number ) SELECT SUM(max_similarity) FROM max_similarities $$ LANGUAGE SQL """)现在,我们可以对向量搜索检索到的文档进行重新排序:
class PgClient: def rerank(self, query: str, ids: list[int], topk: int): token_embs = [emb for emb in token_encoder.encode_query(query)] with self.conn.cursor() as cursor: cursor.execute( f"SELECT id, text FROM {self.dataset}_corpus WHERE id = ANY(%s) ORDER BY " f"max_sim(embs, %s) DESC LIMIT {topk}" (ids, token_embs) ) res = cursor.fetchall() return res评估效果
我们在多个BEIR数据集上测试了此方法。
结果如下:
| 数据集 | 搜索NDCG@10 | rerankNDCG@10 |
|---|---|---|
| fiqa | 0.23211 | 0.3033 |
| quora | 0.31599 | 0.3934 |
这表明 ColBERT rerank 可以显著增强向量搜索的结果。
所有相关的基准代码都可以在这里找到。
未来工作
向量搜索和全文搜索结合 ColBERT rerank 功能可以进一步提升性能。我们还开发了 PostgreSQL BM25 扩展插件。
如何系统的学习大模型 AI ?
由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。
但是具体到个人,只能说是:
“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。
这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。
我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。
我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
一直在更新,更多的大模型学习和面试资料已经上传带到CSDN的官方了,有需要的朋友可以扫描下方二维码免费领取【保证100%免费】👇👇
01.大模型风口已至:月薪30K+的AI岗正在批量诞生
2025年大模型应用呈现爆发式增长,根据工信部最新数据:
国内大模型相关岗位缺口达47万
初级工程师平均薪资28K(数据来源:BOSS直聘报告)
70%企业存在"能用模型不会调优"的痛点
真实案例:某二本机械专业学员,通过4个月系统学习,成功拿到某AI医疗公司大模型优化岗offer,薪资直接翻3倍!
02.大模型 AI 学习和面试资料
1️⃣ 提示词工程:把ChatGPT从玩具变成生产工具
2️⃣ RAG系统:让大模型精准输出行业知识
3️⃣ 智能体开发:用AutoGPT打造24小时数字员工
📦熬了三个大夜整理的《AI进化工具包》送你:
✔️ 大厂内部LLM落地手册(含58个真实案例)
✔️ 提示词设计模板库(覆盖12大应用场景)
✔️ 私藏学习路径图(0基础到项目实战仅需90天)
第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。