假设你是一座“城市个性档案馆”的馆长,馆里存放着全城每位市民的“性格画像卡”。每张卡片上是一串数字,代表这个人的幽默感、责任心、冒险精神等特质在多个维度上的打分。忽然有一天,用户来找你:“帮我找出和这位姑娘性格最像的 10 个人。”如果卡片按姓名笔画排列,你得把全部卡片摊在地上,一张张人工比对——全城上千万张卡片,这得比对到猴年马月? Qdrant 就是为这种“找相似”而生的智能匹配档案馆。它是当前最流行的开源向量数据库之一:用一串“数字画像”(向量)表示每条数据,用相似度尺子(余弦、点积、欧氏距离)衡量两条数据多像,再用 HNSW 分层索引让“翻遍全城”变成“快线直达”。它还能给画像贴业务标签(载荷),支持“先圈定人群再谈神似”的过滤检索;用分片和副本保证海量数据与故障场景下的高可用。 这篇文章会带你从零认识 Qdrant:先理解向量与相似度,再上手集合、点、索引、过滤、优化、高可用,最后用 Python 亲手搭一个迷你向量库。学完它,你就看懂了当下大模型应用中最热门的“检索底座”。
一句话价值:掌握 Qdrant,你就掌握了 RAG、语义搜索、智能推荐的检索底座——这是大模型落地时代最抢手的工程能力之一。
目录
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
基础概念:先给每个对象画一张“数字画像”
老馆长上任后学的第一件事,是如何给市民“画画像”。他把一个人浓缩成 8 个分数:幽默感、责任心、冒险精神、表达欲……每一个分数都是一个维度。有了这 8 个分数,一个人就可以被看作 8 维空间里的一个点。画像画得越准,后面找“神似”就越靠谱。
在 AI 世界里,“画画像”这个动作叫嵌入(Embedding),画出来的数字列表叫向量(Vector)。文本、图片、音频都能被嵌入模型变成向量。Qdrant 不关心你的画像怎么画出来的,它只负责两件事:把画像保管好(存储),并快速找到“长得最像”的画像(检索)。这就需要一把尺子来度量相似度。
Qdrant 在创建集合时通过 distance 参数选择尺子。最常用的是余弦相似度:只看两个向量的方向是否一致,忽略它们的长度;点积适合用户偏好打分的推荐场景,数值越大越相关;欧氏距离衡量每个维度上的绝对差距,适合图像、音频等“整体差异”更重要的场景。三种尺子各有适用场景,选错会让检索结果失真。
想象相亲时,你不关心对方家境(向量长度),只关心三观方向是否一致——这就是余弦相似度的哲学。它天然适合语义文本检索:同一句话换个说法,向量方向依然接近;而欧氏距离更像“户籍距离”,一丁点数值波动都会被放大。
- 分子内积运算把两个向量对应位置的数值相乘再全部相加,衡量两张画像在每一个特质维度上的“同向程度”。
- 分母模长之积分别对每个向量求“长度”,即把各维度平方求和再开方,作用是消除画像“整体幅度”的影响。
- 整体比值内积除以两个模长之积,得到落在 [-1,1] 之间的“方向贴合度”,与向量长度无关。
集合与点:档案馆里的登记册与卡片
档案馆场地有限,馆长把市民按职业片区分类,每个片区立一个大柜子,柜子里的登记册就叫“集合”(Collection)。打开任意一本册子,每一页就是一位市民的画像卡,Qdrant 里称之为“点”(Point)。
一张画像卡由三部分构成:ID 是卡片的唯一编号;向量是那串数字画像,负责“像不像”的计算;载荷(Payload)是贴在卡片上的便签,记录年龄、职业、城市等业务属性,负责条件筛选。创建集合时必须声明向量维度 size 和距离度量 distance,其中 size 必须与你使用的嵌入模型输出维度完全一致,否则数据写入直接报错。
集合是逻辑容器,底层由多个分段组成,数据先写小段再定期合并。集合级别还能配置分片数、副本数、HNSW 参数;Qdrant 甚至允许一个点携带多个命名向量(如稠密向量与稀疏向量并存),为混合检索铺路。载荷不像关系表那样有固定 schema,随写随加,想按某个字段过滤时再给它建索引即可。
登记册和画像卡设计好后,档案馆的骨架就搭好了。但真正的考验还在后面:如何在千万张卡片里,不翻遍全馆就找到最像的一张?这就要请出下一节的“快捷地铁网”。
- 逐维差值把两个向量每个维度相减,得到每个“性格特质”上的差距,差距越大说明该特质越不像。
- 平方求和把所有维度的差距平方后加总,避免正负抵消,同时放大较大差距的权重。
- 整体开方对平方和开根号,得到一个正的“空间直线距离”,数值越小表示两张画像越接近。
近邻搜索:HNSW 的“快捷地铁网”
馆长请来一位交通工程师,给画像卡设计了一张“地铁图”:每张卡片是一个车站,相似的卡片之间连上轨道。此外再修几条“快线”——快线上的站点极少、站距极大,一列快车可以瞬间从城南窜到城北;地面层则是密如蛛网的慢线,负责站点间的精细比对。搜索时先坐快线到达目标区域,再换慢线精确定位。
这就是 HNSW(分层可导航小世界图)的直觉,Qdrant 默认使用它作为向量索引。HNSW 借鉴了跳表的分层思想:高层的节点稀疏、连接更长,负责“远跳”定位;底层的节点密集、连接更短,负责“精查”打分。搜索从顶层入口出发,逐层下行,最终落到最底层给出 Top-K。
使用 HNSW 时,构建期有 m 和 ef_construct 两个关键参数:m 控制每个节点最多连接多少条边,越大图越稠密、内存越大;ef_construct 控制构建时考察的候选邻居数,越大索引质量越高、构建越慢。查询期则由 ef_search 控制候选列表大小,越大召回越准、延迟越高。需要说明的是,HNSW 是近似最近邻(ANN),并非 100% 精确;数据量小或要求绝对精确时,可以指定 exact: true 走暴力精确搜索。
从“翻遍全城”变成“快线直达 + 慢线精查”,这正是 HNSW 能让 Qdrant 在亿级向量上于几十毫秒内返回结果的原因。
- 层号 kk 表示节点被分到的层高,k 越大代表该节点位于越稀疏的高层,越接近“快线”入口。
- 衰减因子 p^k每高一层,入选概率按比例缩减,因此层越高节点越少,这是“快线站少”的数学来源。
- 归一化系数 (1-p)保证所有层的概率之和为 1,使层高成为一个合法的概率分布。
过滤检索:先圈定人群,再谈神似
用户又加需求了:“我要找和她性格最像的 10 个人,但只限养猫、住在城南、25 到 35 岁之间的。”馆长意识到,光“神似”不够,还得先“圈定人群”。
这在 Qdrant 里叫“过滤 + 搜索”:先用贴在画像卡上的便签(载荷)圈定候选人群,再在圈定的人群内做向量相似检索。过滤表达式由逻辑操作符组合而成:must 表示必须满足,should 表示满足则加权,must_not 表示排除——像给检索加了一份“硬性要求清单”。
过滤要快,依赖两件事。第一,给常用的载荷字段建索引,让“圈人”本身不慢;当过滤条件很强时,Qdrant 会先缩小候选集再算向量距离,省掉大量无效计算。第二,更进一步做混合搜索(Hybrid Search):同一段文本既用稠密向量捕捉语义,又用稀疏向量捕捉精确关键词,两路得分再用加权求和或 RRF 融合,兼顾“懂意思”和“抠字眼”。
先“圈定猫奴片区”,再在片区内谈“性格神似”——过滤检索让向量搜索从大海捞针变成池中捞鱼。
- 排序位置文档 d 在第 r 路检索结果中的名次,名次越靠前数值越小,1 表示最相似。
- 倒数加权名次越小得分越高,加常数 k 是为了防止除零,并压低第一名带来的巨大差距,常用 k=60。
- 多路求和对稠密、稀疏两路分别求倒数再相加,两路都靠前的文档总分最高,从而同时兼顾语义与关键词。
优化策略:给档案馆瘦身提速
档案馆的卡片越积越多,仓库快放不下了。馆长发现,很多数字的精度根本没人较真:“幽默感 0.876”和“幽默感 0.874”在实际匹配中毫无区别。那何不把小数都“四舍五入”成 0~255 的整数?
这个思路就是标量量化(Scalar Quantization)。Qdrant 可以把 float32 向量压缩成 8 位无符号整数(uint8),内存占用直接降为原来的四分之一。为了弥补精度损失,查询时可以配合 oversampling(多取一些候选)和重打分(用原始浮点向量对候选重新排序),让精度损失降到最低。
优化并不只有量化。规划容量时用内存估算公式 N×D×4 字节,能提前判断一台机器装不装得下;分段(Segment)机制让新数据先进入小段快速写入,定期与老段合并,避免频繁重建;调参时把 m、ef_construct、ef_search、量化四件套按“召回率-延迟曲线”组合选择,而不是无脑拉满。
瘦身之后,同样的仓库能塞下 4 倍画像卡,查询速度反而更快——这就是“用一点点精度换一大截成本和速度”的工程智慧。
- 归一化比例分子表示数值 x 在某一维度取值范围内离下限的距离,除以范围宽度后得到 [0,1] 的比例。
- 放大与取整把比例乘以 255 再向下取整,得到 0~255 之间的整数等级,这就是“四舍五入驻扎”的核心步骤。
- 内存收益每个数从 4 字节变成 1 字节,整体内存降为原来的四分之一,是性价比最高的压缩方式。
高可用架构:让档案馆永不闭馆
档案馆开张后不能打烊。馆长的对策像银行:多开柜台分流(分片)、每家网点存双份账本(副本)、每天营业结束把账本封存归档(快照)。这样哪怕一个网点失火,其他网点照样营业。
Qdrant 的分片把集合按点 ID 哈希分布到多个分片上,写入和检索自动并行,容量可以横向扩展。副本因子可设为 2 或 3,每个分片保留多份拷贝,任一节点故障,请求自动切换到健康副本。快照则把整个集合备份下来,用于灾难恢复或环境迁移。
数据写入时,Qdrant 通过 WriteOrdering 控制一致性等级:weak 只要主副本确认就返回,速度最快但极端情况下可能丢数据;medium 等主副本确认并推进复制;strong 等所有副本确认,最安全但写入延迟最高。分布式集群模式下,节点的加入、探活与元数据由 etcd 协调管理。
多馆区、双账本、日归档,让档案馆的可用性从 99% 飙升到 99.9999%,代价是写入要多等几次副本确认——这正是所有分布式系统都要面对的一致性权衡。
- 单节点可用率 a例如 a=0.99 表示某台机器一年约 99% 的时间可用。
- 单节点失效率1-a 即单台机器宕机的概率,例如 1%。
- 多副本指数效应r 个副本全部同时失效的概率是 (1-a)^r,系统可用率就是 1 减去该值;副本越多,可用率越接近 100%。
工程落地:让档案系统跑进真实业务
档案馆的一切准备就绪,最后一个问题:怎样把它接入城市的日常业务,让市民真正用起来?
最典型的落地是 RAG(检索增强生成)——给大模型配一个“外接记忆”。流程是:把企业文档切块(chunk)→ 用嵌入模型转成向量 → 批量写入 Qdrant;用户提问时,先把问题转成向量,在 Qdrant 里检索 Top-K 相关片段,把这些片段拼进提示词,再交给大模型生成带出处的答案。Qdrant 在其中扮演“记忆中枢”,决定了大模型“记得牢不牢、答得准不准”。
工程落地还要管住三件事:一是用好 Python 客户端(qdrant-client),批量 upsert 比逐条写入快一个量级;二是提前做内存规划,按估算公式为向量预留余量,并监控写入速率与延迟;三是把召回率、P99 延迟、分片状态纳入监控告警。数据量不大时,可以直接用 Qdrant Cloud 托管,一键建集群、免运维、专注业务。
至此,档案馆完成了从“收藏”到“服务”的转身。向量、索引、过滤、优化、高可用……这些零件组合起来,就是今天 AI 应用背后那个随时待命的记忆中枢。
- 相关文档集合relevant 是人工标注的、与查询真正相关的文档集合,是评估的“标准答案”。
- 检索返回集合retrieved_k 是向量搜索返回的前 k 条结果,是系统给出的“候选答案”。
- 交集与比值用返回结果中命中相关文档的数量,除以相关文档总数,衡量“该捞上来的到底捞上来多少”。
AI 应用场景
企业知识库 RAG 问答
阶段:检索增强生成(RAG)
解决的问题:传统关键词搜索无法理解同义表述,员工搜“报销流程”找不到标题为“费用申请制度”的文档;大模型直接作答又容易凭空编造。Qdrant 将文档切片向量化,先做语义召回拿到 Top-K 上下文,再让大模型基于真实资料作答并附出处。
具体案例:某大型券商把 10 万份制度文档切片为 80 万条记录存入 Qdrant,客服机器人回答准确率从 61% 提升到 89%,平均响应时间从 3 秒降到 0.6 秒。
电商“猜你喜欢”向量召回
阶段:推荐系统的召回排序(Recall & Rank)
解决的问题:传统协同过滤冷启动差,基于类目标签的召回无法理解“轻薄+通勤+防晒”这类组合语义。Qdrant 用用户与商品的嵌入向量做 Top-K 相似召回,再把候选交给精排模型。
具体案例:某服饰电商对 500 万商品做图像与文本双模态嵌入,用 Qdrant 在约 5ms 内完成百万级向量的 Top-50 召回,点击率提升 23%。
内容平台语义去重
阶段:数据清洗与内容质量治理
解决的问题:搬运、洗稿产生的近似重复文章,用 URL 或哈希根本去不掉。Qdrant 用内容嵌入向量的相似度阈值判断“是否近似重复”,再批量删除,为平台节省大量审核人力。
具体案例:某资讯平台每天接收 200 万篇投稿,用 Qdrant 查询每篇文本向量最相似的历史文章,余弦相似度大于 0.92 即判定为重复,去重率达 31%。
Python 演示
"""Qdrant 迷你演示: 玩具向量库实现余弦相似度 Top-K 检索"""import math def text_to_vector(text): """玩具版嵌入: 把字符哈希到 8 个桶, 得到 8 维向量""" vec = [0.0] * 8 for ch in text: vec[ord(ch) % 8] += 1.0 return vec def dot(a, b): return sum(x * y for x, y in zip(a, b)) def norm(v): return math.sqrt(sum(x * x for x in v)) class MiniQdrant: """山寨 Qdrant: 只实现 upsert 与相似度查询两个核心接口""" def __init__(self): self.points = {} self.next_id = 1 def upsert(self, vector, payload): """写入或更新一个点, 返回自动分配的 ID""" point_id = self.next_id self.next_id += 1 self.points[point_id] = {"vector": vector, "payload": payload} return point_id def query(self, vector, top_k=3): """返回与 vector 最相似的 top_k 个点(含得分与载荷)""" scored = [] for point_id, p in self.points.items(): denom = norm(vector) * norm(p["vector"]) cos = dot(vector, p["vector"]) / denom if denom > 0 else 0.0 scored.append((cos, point_id, p["payload"])) scored.sort(key=lambda item: item[0], reverse=True) return scored[:top_k] def main(): db = MiniQdrant() docs = ["智能客服机器人", "机器学习模型", "奶茶配方研究", "户外运动装备", "量子计算入门"] for text in docs: db.upsert(text_to_vector(text), {"title": text}) query_text = "AI 算法工程师" results = db.query(text_to_vector(query_text), top_k=3) print("查询:", query_text) for score, point_id, payload in results: print(" #%d %s 相似度=%.4f" % (point_id, payload["title"], score)) if __name__ == "__main__": main()
vec[ord(ch) % 8] += 1.0玩具版“嵌入”:把每个字符按哈希分到 8 个维度桶里,模拟真实嵌入模型输出向量。cos = dot(vector, p["vector"]) / denom if denom > 0 else 0.0一行实现余弦相似度公式:内积除以两个模长之积。scored.sort(key=lambda item: item[0], reverse=True)全库暴力排序取 Top-K;生产环境数据量大时由 HNSW 索引代替这一步。db.upsert(text_to_vector(text), {"title": text})对应 Qdrant 的 upsert 接口:向量与载荷一起写入集合。if __name__ == "__main__":可执行入口,保证脚本可以直接用 python 运行。
常见误区
误区刚开始我把 Qdrant 当关系型数据库用,总想先定义好字段结构再写入,结果发现创建集合只需要向量大小和距离度量,业务字段根本不用提前声明。
正解Qdrant 的集合只规定向量维度 size 和距离度量 distance。业务属性存放在载荷(Payload)中,随点写入、随时新增,不需要预定义 schema;如果要按某字段过滤,只需给该字段建索引就能提速。这就像档案馆先立柜子,卡片上贴多少张便签、写什么内容都随你,不必事先规定便签格式。
为何常见:关系型数据库“先建模后写入”的思维惯性太强,而向量数据库主打灵活的半结构化存储,两者设计哲学根本不同。
误区我以为既然叫“最近邻搜索”,那返回的 Top-K 一定是全库最相似的 k 条,一条都不会错。
正解HNSW 是近似最近邻(ANN)算法,它用“分层图 + 贪心下降”快速逼近,牺牲少量召回率换取对数级的速度。追求精确时可以用 exact: true 精确搜索,或调大 ef_search 提升召回;评估检索质量要用 Recall@k 这类指标,而不是盯着单条结果看。
为何常见:“近似”二字藏在全称里,文档默认索引又是 HNSW,不深入读文档很难意识到它不是暴力精确检索。
误区嵌入模型输出 1536 维还是 768 维,我觉得越大越能表达语义,于是盲目选择大维度。
正解维度越高表达力越强,但内存按维度线性增长(N×D×4 字节),而且高维空间存在“维数灾难”——距离区分度反而变差。正确做法是结合嵌入模型能力、数据量、内存预算综合选择,必要时用降维或量化控制成本。
为何常见:“信息越多越好”的直觉与高维空间反直觉的几何性质相悖,只有踩过内存的坑才会醒悟。
误区既然向量库既能存数据又能检索,那我还用 MySQL 干什么,全部迁过来就好了。
正解两者是互补关系。交易型业务(订单、账务)仍然需要关系型数据库的事务与强一致性;向量库擅长的是“语义相似检索”,通常由业务方先算好向量,再交给 Qdrant 做召回。它们配合而非替代,就像档案馆和账房各司其职。
为何常见:新技术宣传常让人误以为“我可以替代一切”,忽视了事务、聚合、权限等传统数据库擅长且向量库并不擅长的能力。
误区既然 ef_search 越大召回越准,那我直接把线上参数拉满,既准又快,何乐不为。
正解ef_search 越大,HNSW 搜索过程中考察的候选越多,召回率确实提升,但延迟会显著上升,高 QPS 场景下容易打爆 CPU。工程上要按 P99 延迟与召回率的平衡点来定,通常先用离线数据画出“召回率-延迟曲线”,再确定上线参数。
为何常见:调参时只盯着单个指标提升,忽略了延迟和资源成本这些隐形成本,属于典型的“局部最优”思维。
面试题
Q1. Qdrant 中一个“点”(Point)由哪三部分构成?
- A.向量、索引、载荷
- B.ID、向量、载荷← 正确答案
- C.ID、索引、集合
- D.向量、集合、分片
答案:B。点的三要素是 ID(唯一编号)、向量(数字画像)和载荷(业务便签)。索引是集合层面的结构,不是点的组成部分。可以想象一张画像卡:编号管身份,数字管相似,便签管筛选。
Q2. 创建 Qdrant 集合时必须指定哪两项配置?
- A.向量大小与距离度量← 正确答案
- B.分片数量与副本因子
- C.索引类型与载荷字段
- D.量化方式与压缩比例
答案:A。向量大小 size 必须与嵌入模型的输出维度一致,距离度量 distance 决定“像不像”的算法。分片、副本、索引都有默认值,属于可选配置;载荷字段根本无需预定义。就像立柜子前先确定卡片尺寸和比对标准。
Q3. 余弦相似度计算结果的取值范围是?
- A.[0, 1]
- B.[-1, 1]← 正确答案
- C.[0, 255]
- D.(0, +∞)
答案:B。余弦相似度是两个向量夹角的余弦值,方向完全一致时为 1,完全相反时为 -1,无关时为 0。它只衡量方向是否一致,与向量长度无关,所以不会取到超过 1 的值,更不会是负无穷。
Q4. 关于 HNSW 索引中 ef_search 参数,说法正确的是?
- A.控制图中节点的最大连接数
- B.控制索引构建时使用的线程数
- C.控制搜索时候选列表的大小← 正确答案
- D.控制量化压缩的等级数量
答案:C。ef_search 控制查询时动态扩展的候选列表大小,值越大召回越准、延迟越高;控制连接数的是 m,影响构建质量的是 ef_construct。候选列表越大,相当于地铁搜索时愿意多逛几个站,找到目标概率更高但更耗时。
Q5. 标量量化后,向量从 float32 压缩为多少位整数?
- A.4 位无符号整数
- B.8 位无符号整数← 正确答案
- C.16 位有符号整数
- D.32 位有符号整数
答案:B。标量量化把每个维度映射到 0~255 的整数等级,也就是 8 位无符号整数,内存从 4 字节降为 1 字节、整体降为四分之一。就像把小数画像四舍五入成整数评分,省库容但保留大致相似度。
Q6. 关于 HNSW 与精确搜索的对比,正确的是?
- A.精确搜索在数据量大时更快
- B.HNSW 在数据量大时更有优势← 正确答案
- C.两种方式召回率完全相同
- D.HNSW 不需要占用额外内存
答案:B。精确搜索是暴力计算,复杂度 O(n),数据量大时极慢;HNSW 借助分层图把检索复杂度降到近似 O(log n),因此数据量越大优势越明显。HNSW 是近似算法,召回率略低于精确搜索,且需要额外内存存储图结构。
Q7. 副本数 r=3、单节点可用性 a=0.99 时,系统可用性约为?
- A.99.00%
- B.99.90%
- C.99.99%
- D.99.9999%← 正确答案
答案:D。按公式 A = 1 - (1-a)^r 计算:1 - 0.01^3 = 0.999999,即 99.9999%。三个副本同时宕机的概率只剩百万分之一。副本就像多存几份账本,只要有一份完好,档案馆就能继续营业。
Q8. Qdrant 支持的距离度量方式有哪些?
- A.余弦相似度← 正确答案
- B.点积相似度← 正确答案
- C.欧氏距离← 正确答案
- D.曼哈顿距离
答案:ABC。Qdrant 支持余弦、点积和欧氏三种距离度量,曼哈顿距离不在支持列表内。三种尺子各有适用场景:余弦看方向、点积看偏好、欧氏看绝对差距,创建集合时通过 distance 参数选定。
Q9. 关于 Qdrant 过滤检索,说法正确的有?
- A.过滤条件可组合 must/should/must_not← 正确答案
- B.载荷字段可以建立索引加速过滤← 正确答案
- C.过滤发生在所有距离计算完成之后
- D.过滤可以与向量检索同时完成← 正确答案
答案:ABD。must、should、must_not 是过滤表达式的三个逻辑操作符;给常用载荷字段建复合索引能显著加速过滤。Qdrant 会先做过滤再计算距离,而不是全部算完再筛,因此 C 错误。先圈定人群再谈神似,正是它的核心优化思路。
Q10. 关于混合搜索(稠密+稀疏)的说法,正确的有?
- A.稠密向量擅长捕捉深层语义← 正确答案
- B.稀疏向量擅长精确关键词匹配← 正确答案
- C.混合搜索必须关闭所有过滤条件
- D.多路结果可用排名融合公式合并← 正确答案
答案:ABD。稠密向量把文本映射为低维实向量,能理解“同义改写”;稀疏向量按词表计数,擅长“抠字眼”。混合搜索把两路得分用加权或 RRF 融合,且可以同时叠加过滤条件。C 说法没有依据,过滤与混合搜索是正交能力。