版权与内容来源声明
本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容,均在附表 A 中标注来源;引用官方原文保持原样,不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准,标注「待验证」的部分请以你本地环境实际输出为判断依据。本文不推荐任何不合规的软件获取方式,也不对任何收益结果作承诺。转载请注明出处。
第 1 章 三种做法分别在干什么
「向量检索慢」这句话,单独拎出来其实没法定性。慢是相对的:底库只有两千条时,最笨的办法也够快;底库到了两千万条时,任何办法都要认真算账。所以本文不打算先给结论,而是先把三种做法的机制摊开,再拿本机实测的数字去对照——先说清哪种做法在省什么、又在牺牲什么,最后才谈该选哪个。
1.1 先把两个词说成白话:向量和索引
向量,在这里指一串按固定顺序排好的数字。比如一段文字、一张图片,交给某个模型处理之后,会变成 128 个或 768 个数(本文实测用的是 128 维)。它的作用是让「像不像」这件事可以被计算:两串数字越接近,通常代表它们对应的内容越相似。
向量检索就是:把用户的问题也变成一串数字,然后去底库里找数字最接近的那几条。底库里每条内容都对应一个向量,所以「找最像的」翻译成计算,就是对底库里每一条都算一次相似度。
索引是另一回事。这个词在数据库里的意思是「为了少查几行而预先排好的结构」,书后面的索引页也一样——不翻全书,只翻一页。向量索引的思路完全一致:用一点预先的计算,换查询时少算几次。但它是拿什么换的,就决定了它会不会把结果找错。
1.2 三种做法:全部算一遍 / 只算几个簇 / 压缩后再算
下面三种,是业界最常见的三条思路。它们不是三个产品,而是三种「怎么少算」的回答方式。
第一种:暴力检索(Flat)。也叫全量检索。查询向量和底库每一条都算一遍距离,然后取最像的前几条。它没有任何近似,结果是精确的,代价是底库有多少条就算多少条。可以理解成「把整本书从头读到尾」。
第二种:粗聚类倒排(IVF 思路)。先给底库做一次聚类,再按簇建一张「簇号 → 条目编号」的名单,查询时只翻开其中几页。这里有两个词要解释:
- 聚类,就是按「数字长得像」把底库分成若干组,组数自己定(本文实测用了 64 组和 256 组)。
- 簇心,是一个簇里所有向量的平均值,可以把它当成这个簇的「代表」。新来一个向量,看它离哪个簇心最近,就归到哪个簇。
- 倒排这个词的意思是「反着建名单」:不是从每条内容去问它属于谁,而是从簇去列出「这个簇里都有谁」。
查询时的流程是:先算查询向量离各个簇心有多远,挑最近的几个簇,只在这几个簇里的条目上算相似度。挑几个簇,就是后面反复出现的nprobe。
第三种:乘积量化(PQ 思路)。它换了一个方向:不改「算哪些」,改「算得多贵」。做法是把一个长向量切成若干段(本文实测切成 8 段和 16 段),每一段单独做一次小聚类,然后用簇心编号代替这一段的原始数字。128 维、每维 4 字节的向量原本占 512 字节,变成 8 个编号之后只占 8 字节。查询时先算好一张「查询各段到各簇心」的对照表,再用查表求和的方式估出相似度。它算的距离是近似距离——不是真实距离,只是够用来排序。
1.3 三种做法对照表
| 做法 | 一句话在干什么 | 查询时算了多少条 | 拿到的距离 |
|---|---|---|---|
| 暴力检索(Flat) | 查询向量和底库每一条都算一遍 | 全部 2 万条 | 精确 |
| 粗聚类倒排(IVF 思路) | 先聚类,查询只翻最近的几个簇 | 只有被选中的那几个簇里的条目 | 精确,但可能整条漏掉真答案 |
| 乘积量化(PQ 思路) | 把向量切段,每段用簇心编号代替,压缩后再算 | 全部 2 万条,但每条只算很短的编码 | 近似 |
这张表里最关键的是最后两列的分工:倒排牺牲的是「会不会漏」,乘积量化牺牲的是「像得准不准」。后面所有数字,都是在给这两句牺牲标价。
第 2 章 本机实测:数据怎么来的、拿到了什么
2.1 实测设置
实测脚本与日志都在本机跑过,路径写在附表 A。设置如下:
- 环境:Windows 11,Python 3.13.14,numpy 2.5.2(这是本机装了的唯一相关包)。
- 底库规模:20000 条向量,每条 128 维,单精度浮点(
FP32)。查询 200 条,取最像的前 10 条,记为 Top10。 - 数据来源:固定随机种子
20261015生成的随机高斯数据,不是真实语料。这一点非常重要,第 3 章会专门交代它的影响。 - 两种向量都做了归一化,此时点积大小就等价于余弦相似度的高低,省去开方运算。
- 召回口径:Recall@10,即「近似做法给出的前 10 条」与「暴力检索给出的前 10 条」的重合比例。暴力检索自己和自己比,所以是 1.000,作为基准。
2.2 逐条实测结果
下表是日志里的原始输出,数字照抄、没有重算:
| 做法 | 平均单查询耗时 | Recall@10 | 索引体积 / 建索引耗时 |
|---|---|---|---|
| 暴力检索(Flat) | 0.915 ms | 1.000(基准) | 9.77 MB |
| 粗聚类倒排,64 簇 / nprobe=1 | 0.161 ms | 0.079 | 建索引 0.36 s |
| 粗聚类倒排,64 簇 / nprobe=4 | 0.740 ms | 0.228 | 建索引 0.36 s |
| 粗聚类倒排,64 簇 / nprobe=16 | 3.299 ms | 0.560 | 建索引 0.36 s |
| 粗聚类倒排,256 簇 / nprobe=1 | 0.044 ms | 0.043 | 建索引 0.78 s |
| 粗聚类倒排,256 簇 / nprobe=16 | 0.576 ms | 0.316 | 建索引 0.78 s |
| 粗聚类倒排,256 簇 / nprobe=64 | 3.412 ms | 0.668 | 建索引 0.78 s |
| 乘积量化 PQ,8 段 | 2.316 ms | 0.112 | 编码 8 字节/向量(原 512 字节,压缩 64 倍),建索引 3.46 s |
| 乘积量化 PQ,16 段 | 3.588 ms | 0.270 | 编码 16 字节/向量(压缩 32 倍),建索引 6.88 s |
举一个读表的方法:第 4 行「64 簇 / nprobe=4」的意思是——先聚成 64 个簇,每次查询挑最近的 4 个簇进去算。它比暴力检索快了(0.740 ms 对 0.915 ms),但召回只剩 0.228,也就是每 10 条正确结果里,平均只能找回来 2 条多。
2.3 建一次索引要花多少代价
查询耗时只是账的一半。另一半是「为了这份快,你提前付了什么」:
| 做法 | 建索引耗时 | 索引 / 编码体积 |
|---|---|---|
| 暴力检索(Flat) | 不需要建索引,查询时直接用原始向量 | 9.77 MB(就是原始向量本身) |
| 粗聚类倒排,64 簇 | 0.36 s | 原始向量 9.77 MB,另加一份簇号 |
| 粗聚类倒排,256 簇 | 0.78 s | 原始向量 9.77 MB,另加一份簇号 |
| 乘积量化 PQ,8 段 | 3.46 s | 8 字节/向量(原 512 字节,压缩 64 倍) |
| 乘积量化 PQ,16 段 | 6.88 s | 16 字节/向量(压缩 32 倍) |
这张表说明一件事:倒排没有省内存,它省的是计算量;乘积量化才真的省内存,但它要拿召回换。如果你的瓶颈是「机器放不下向量」,那么能帮你的不是倒排,而是量化这一类做法。
第 3 章 反直觉结论:在这个规模上,倒排可能还不如暴力
3.1 「快」是怎么换来的
先看最扎眼的一行:256 簇、nprobe=1 时,单查询只要 0.044 ms,比暴力检索的 0.915 ms 快得多。但同一行的召回是 0.043——找回来的 10 条里,平均只有不到半条是真的正确答案。第 4 行也一样:0.740 ms、召回 0.228。
这里的问题出在对比的对象不对等。暴力检索的 0.915 ms 是「把所有正确答案都找齐」的耗时;倒排的 0.044 ms 是「只翻了 1 个簇、漏掉大部分正确答案」的耗时。一个在完整交付,一个在交半成品。把这两个数字并排放在一起说「倒排快 20 倍」,是本文见过最常见的一种误读。
3.2 召回一旦要够,耗时立刻反超
那如果要求倒排把召回拉到能用的水平呢?看同一张表里 nprobe 拉高的两行:
- 64 簇、nprobe=16:召回 0.560,耗时 3.299 ms,已经比暴力检索的 0.915 ms 慢了好几倍。
- 256 簇、nprobe=64:召回 0.668,耗时 3.412 ms,同样比暴力检索慢。
也就是说,在本文这个 2 万条、128 维的规模上,倒排索引想拿到勉强能用的召回,付出的查询耗时反而不如直接全算一遍。这正是标题里「为什么慢」的答案之一:不是索引本身慢,而是「上了索引」这个动作在规模不够大时并不划算——它把一次简单的矩阵运算,拆成了「先算簇心距离、再按簇号捞候选、再逐条算」的好几步,多出来的调度开销,在小库上盖过了省下的计算量。
3.3 两条必须交代的前提
上面的结论必须带两个前提读,否则会误导人。
前提一:这是纯 numpy 实现、2 万条规模,耗时含 Python 层开销。本文没有安装 faiss、chromadb、sentence-transformers 这类工程级向量库(本机确实没装),所有代码都是脚本里用 numpy 直接写的。倒排那一段的查询循环是一条条 Python 循环(见第 6 章代码),每一条查询都要执行多次数组筛选和拼接,这些开销在工程级实现里会被压掉很多。所以本文的耗时数字只能用来做三种做法之间的相对对照,不能当作任何向量库的性能参考。
前提二:底库是随机高斯数据,没有簇结构。真实语料变成向量之后是有聚团的——同类内容会挤在一起,簇与簇之间有明显边界。而随机高斯数据是一片均匀的云,本来就没有「最近的几个簇」这回事。所以这里的召回天然偏低(0.043 到 0.668 这个区间),并不能说明倒排这套思路不行。
这两条前提合起来,指向本文真正想表达的判据:索引效果强依赖数据分布和你所处的规模。换成真实语料、换成更大的底库,上面每一个数字都会变,而且很可能变得对索引有利。所以在自己的库上「先量一遍」,比背任何一家的推荐参数都有用。
第 4 章 nprobe 与召回、耗时的三角关系
4.1 nprobe 是什么
nprobe是「每次查询翻几个簇」这个数字。nprobe=1就是只翻最像的那 1 个簇;nprobe=16就是翻最像的 16 个簇,在这 16 个簇里的全部条目上算相似度。
它同时牵着三根线:
- 翻得越多,越不容易漏。因为正确答案更可能在某个被你翻到的簇里,所以召回会往上走。
- 翻得越多,算得越多。候选条目随翻的簇数一起增长,耗时也会往上走。
- 翻得越多,越接近暴力检索。如果
nprobe等于簇数,那你翻完了所有簇,结果就和暴力检索一样——那时候索引就只剩开销、没有收益了。
4.2 三角关系表
把日志里的倒排行单独抽出来,nprobe的作用会非常直观:
| 簇数 | nprobe | 平均单查询耗时 | Recall@10 |
|---|---|---|---|
| 64 | 1 | 0.161 ms | 0.079 |
| 64 | 4 | 0.740 ms | 0.228 |
| 64 | 16 | 3.299 ms | 0.560 |
| 256 | 1 | 0.044 ms | 0.043 |
| 256 | 16 | 0.576 ms | 0.316 |
| 256 | 64 | 3.412 ms | 0.668 |
同一行横向看:耗时和召回是同涨同跌的。纵向比簇数还能看出第二层规律——256 簇在 nprobe 很小时(0.044 ms、召回 0.043)比 64 簇更快也更差,因为簇被切得更细,单个簇里的条目更少,翻一个簇更省,但也更容易漏。
4.3 三角不是线性的,所以要按召回底线反推
看 64 簇那一列:nprobe从 4 拉到 16,耗时涨了好几倍,召回只从 0.228 涨到 0.560。收益和代价的曲线不是一条直线,拐点出现得很早。这意味着「nprobe 越大越好」是错的——往后调,你花的是成倍的耗时,买回来的是越来越小的一截召回。
所以正确的用法不是「往上调」,而是反过来做:先定死召回底线,再往上加 nprobe 直到刚好达标就停手。为什么必须这样?因为召回底线是业务决定的事,耗时是机器决定的量——业务能接受多少漏检,是你能定死的;「多快算够快」则取决于当时有多少机器。从一个不稳定的量去反推一个稳定的量,本来就推不出稳定结论。
第 5 章 什么时候该用哪种:四个维度一张表
5.1 先问四个问题,而不是先选方案
选之前,先把自己这四个数问清楚。它们的作用不是给出一个正确答案,而是排除掉大部分根本不该考虑的方案:
- 数据量:底库一共多少条?这是决定「值不值得上索引」的第一道门槛。规模小的时候,索引的调度开销会盖过它省下的计算。
- 更新频率:每天新增、删除多少条?聚类和量化都是「要重建才生效」的结构,更新越频繁,重建成本越要算进去。
- 内存预算:原始向量能不能全部装下?装不下的时候,才轮到压缩类做法登场。
- 召回底线:最低能接受多少 Recall?这四个里唯一必须先定死的数。
5.2 决策表
| 维度 | 要问自己的问题 | 答案指向的做法 |
|---|---|---|
| 数据量 | 底库一共多少条 | 规模小(本文实测的 2 万条这一类)先跑暴力检索拿到基准,不急着上索引 |
| 更新频率 | 每天新增 / 删除多少条 | 更新频繁时先把「重建一次索引要多久」量出来(本文实测 0.36 s 到 6.88 s 不等),再决定用不用 |
| 内存预算 | 原始向量放不放得下 | 放不下,才轮到乘积量化这类压缩做法(本文实测可压到 8 字节/向量) |
| 召回底线 | 最低能接受多少 Recall | 先定死这条底线,再拿 nprobe 去凑它,而不是先定 nprobe |
表的读法是从上往下:第一行先把「要不要上索引」判掉,第二、三行再判「上了之后哪种能扛」,最后一行才是调参。顺序反了,就会变成先选了一个方案,再去找理由说服自己。
5.3 一句话版本
如果只能记一句:先量清自己处在哪个规模,再决定要不要上索引;决定要上之后,nprobe 和压缩比都不是越大越好,而是按召回底线反推出来的。
《LangChain + LangGraph + MCP 智能体开发实战》视频课:第 5 章给的是四种做法的取舍判据,如果你想把检索这一段真正跑起来再调,这套课从私有化部署、Embedding 到检索与 Agent 全流程都有对应章节。放在资料包里,扫码即可获取:
第 6 章 先量后调:把召回底线变成参数
6.1 六步流程
这套流程不需要向量库,一段 numpy 脚本就能跑完。关键是它每一步都在回答一个具体问题:
- 跑一遍暴力检索,计时间、存下每条查询的前 10 条结果。这一步同时给你两样东西:耗时基准,和作为标准答案的 Top10。
- 定召回底线。比如「至少要 0.9」,写下来,别放在脑子里。这条线决定后面什么时候停。
- 拿这个基准 Top10 去量所有近似做法。重合比例就是召回,不需要人眼判断对错。
- 从最小的参数往上加。nprobe 用 1 起步,簇数先试小档;每加一档记录一次「召回 + 耗时 + 体积」。
- 一达标就停手。第一次达到底线的那档参数就是答案,不要因为「再加一点可能更好」继续加。
- 换一批数据再跑一次。如果你的库会持续变(新增文档、换 embedding 模型),第 1 到 5 步要重跑,因为第 3 章那两条前提说了,结论强依赖数据分布。
第 6 步最容易被省掉,但它决定了这套参数能撑多久。
6.2 四段实测代码
下面四段都是从本机跑过的实测脚本里摘出来的,直接从实测日志里能对上结果。
第一段:建数据 + 暴力检索基准。
rng=np.random.default_rng(20261015)N=20000# 底库规模D=128# 维度Q=200# 查询条数TOPK=10base=rng.normal(size=(N,D)).astype(np.float32)queries=rng.normal(size=(Q,D)).astype(np.float32)base/=np.linalg.norm(base,axis=1,keepdims=True)queries/=np.linalg.norm(queries,axis=1,keepdims=True)t0=time.perf_counter()sim=queries @ base.T exact=np.argsort(-sim,axis=1)[:,:TOPK]t_flat=(time.perf_counter()-t0)/Q第二段:计算召回的完整口径。就是这段决定了后面每一行召回数字怎么来。
defrecall(approx_idx,exact_idx):hits=0fora,einzip(approx_idx,exact_idx):hits+=len(set(a.tolist())&set(e.tolist()))returnhits/(len(exact_idx)*TOPK)第三段:倒排的查询路径。注意它是逐条查询用 Python 循环处理的,这正是第 3 章提醒过的开销来源。
t0=time.perf_counter()approx=[]qcent=queries @ cent.T probe_order=np.argsort(-qcent,axis=1)[:,:nprobe]forqiinrange(Q):cand=np.concatenate([np.where(lab==c)[0]forcinprobe_order[qi]])iflen(cand)==0:approx.append(np.arange(TOPK))continues=queries[qi]@ base[cand].T approx.append(cand[np.argsort(-s)[:TOPK]])t=(time.perf_counter()-t0)/Q第四段:乘积量化的查询路径。核心是先查表、再求和,得到的是近似相似度。
t0=time.perf_counter()approx=[]forqiinrange(Q):qsub=queries[qi].reshape(M,sub)# (M, sub)lut=np.einsum("md,mkd->mk",qsub,cents)# (M, 256) 查表s=lut[np.arange(M)[None,:],codes].sum(1)# 近似相似度approx.append(np.argsort(-s)[:TOPK])t=(time.perf_counter()-t0)/Q第 7 章 边界、误区与待验证的部分
7.1 HNSW:另一种思路,但本文没有实测
除了上面三种,工程上还有一类做法是图结构索引,其中常被提到的是HNSW——一种把向量之间「谁离谁近」连成多层图结构、查询时沿着图往近处走的近似最近邻索引(人话:像在一张朋友关系图里问路,每次只问「你认识的人里谁离目标更近」,一层层往下走)。
它属于多数工程级向量库会提供的选项之一,但本文没有实测它:本机没有安装任何向量库,也没有一手来源可以核验它的默认参数与性能数字。所以这里只做概念性描述,它的具体参数默认值、性能表现一律标注「待验证」,本文不给任何数字。如果你的场景需要它,请以你所用库的官方文档为准。
7.2 三个常见误区
- 误区一:把「召回低的省时」当成「方案的提速」。倒排 nprobe=1 的 0.044 ms 和暴力检索的 0.915 ms 不是同一种交付,前者没把正确答案找齐。
- 误区二:默认 nprobe 越大越好。第 4 章的表已经说明,越往后收益越小、代价越大,超过某一点之后你还不如直接全算。
- 误区三:把别人库上的推荐参数直接搬过来。第 3 章那两条前提说明,簇结构和规模一变,最优参数就变。搬参数不如搬「先量后调」这套流程。
7.3 本文结论不适用于什么场景
- 不要拿本文的耗时数字去比任何向量库。这是纯 numpy 实现,含 Python 层开销,横向比三家库没有意义。
- 不要拿本文的召回数字判断某类索引「行不行」。底库是无簇结构的随机高斯数据,召回天然偏低,这是数据分布造成的。
- 不要在没有真实数据的情况下据此定参数。正确顺序永远是:抓一批有代表性的真实数据 → 跑第 6 章那六步 → 再定参数。
至于真实语料上三种做法的差距到底会拉开多少,本文没有实测,标注「待验证」。这也是后面还想补的一步:换一批有真实簇结构的向量,把同样的六步重跑一遍。
AI 大模型知识库(在线可查):第 7 章讲的是边界与待验证部分,如果想顺着检索、向量库这条线继续往下查,这个在线知识库按目录整理了 Agent 与检索相关的专题,浏览即可。放在资料包里,扫码即可获取:
附表 A:本文引用事实与出处对照表
| 事实 | 出处(文档名 + 发布方 + 链接) | 本文位置 |
|---|---|---|
| 全部实测数字:暴力检索 0.915 ms、召回 1.000、体积 9.77 MB;64 簇下 nprobe=1 为 0.161 ms / 0.079、nprobe=4 为 0.740 ms / 0.228、nprobe=16 为 3.299 ms / 0.560(建索引 0.36 s);256 簇下 nprobe=1 为 0.044 ms / 0.043、nprobe=16 为 0.576 ms / 0.316、nprobe=64 为 3.412 ms / 0.668(建索引 0.78 s);PQ 8 段为 2.316 ms / 0.112(建索引 3.46 s)、PQ 16 段为 3.588 ms / 0.270(建索引 6.88 s) | 本机实测(脚本路径):work/2026-10-15_向量索引实测.py与work/2026-10-15_向量索引实测.log;运行环境 Windows 11 / Python 3.13.14 / numpy 2.5.2;实测日期 2026-10-15。数字直接取自日志原始输出,未重算 | 第 2 章 2.2、第 3 章、第 4 章 4.2 |
| 实测设置:底库 20000 条 × 128 维、查询 200 条、Top10、固定随机种子 20261015、向量归一化后点积等价于余弦相似度排序 | 同上脚本(work/2026-10-15_向量索引实测.py第 16–27 行) | 第 2 章 2.1 |
numpy 2.5.2为本机实测环境版本;实测日志首行输出numpy = 2.5.2 | 同上日志(work/2026-10-15_向量索引实测.log第 1 行);本机 pip 环境实测 | 第 2 章 2.1 |
索引体积 9.77 MB 由底库张量的字节数换算得出(脚本按base.nbytes计算) | 同上日志(第 4 行输出「索引体积 = 9.77 MB」) | 第 2 章 2.2、2.3 |
| 乘积量化的压缩口径:单向量编码 8 字节(原 512 字节,压缩 64 倍)、16 字节(压缩 32 倍);建索引耗时 3.46 s / 6.88 s | 同上日志(第 11、12 行原始输出) | 第 2 章 2.2、2.3 |
| 召回口径 Recall@10 的计算方式为「近似 Top10 与暴力检索 Top10 的重合条数 ÷(查询数 × 10)」 | 同上脚本recall函数(work/2026-10-15_向量索引实测.py第 30–34 行) | 第 2 章 2.1、第 6 章 6.2 |
| 暴力检索(Flat)/ 粗聚类倒排(IVF 思路)/ 乘积量化(PQ 思路)三种做法的通行机制描述 | 本文对业界通行做法的归纳与重述;未逐字核验原始论文,具体论文出处与各家实现参数本文未作结论(截至 2026-10-15) | 第 1 章 |
| HNSW 为图结构的近似最近邻索引,属工程级向量库常见选项之一;本文未实测 | 待验证:本机未安装任何向量库,也未取得一手来源,故不核验其默认参数与性能数字(截至 2026-10-15 未作结论) | 第 7 章 7.1 |
| 本机未安装 faiss / chromadb / sentence-transformers 等向量库,故本文未做工程级向量库对照 | 本机 Python 环境实测(2026-10-15):未安装上述包,相关对照未运行 | 第 3 章 3.3、第 7 章 7.3 |
| 「真实语料上三种做法的差距会拉开多少」本文未实测 | 待验证:需换有真实簇结构的向量数据重跑第 6 章六步流程后才有结论 | 第 7 章 7.3 |
附表 B:术语速查表
| 术语 | 一句话解释 | 在本文哪里用到 |
|---|---|---|
| 向量 | 一串按固定顺序排好的数字,用来让「像不像」可以被计算 | 第 1 章 1.1 |
| 向量检索 | 把问题也变成向量,去底库里找数字最接近的几条 | 第 1 章 1.1 |
| 索引 | 为了少算几次而预先搭好的结构,像书后面的索引页 | 第 1 章 1.1 |
| 暴力检索(Flat) | 查询向量与底库每一条都算一遍距离,结果精确 | 第 1 章 1.2 |
| 聚类 | 按「数字长得像」把底库分成若干组 | 第 1 章 1.2 |
| 簇心 | 一个簇里所有向量的平均值,可当作这个簇的代表 | 第 1 章 1.2 |
| 倒排 | 反着建名单:从簇出发,列出这个簇里都有哪些条目 | 第 1 章 1.2 |
| nprobe | 每次查询翻几个簇;翻得越多,召回越高、耗时越长 | 第 1 章 1.2、第 4 章 |
| 乘积量化(PQ) | 把向量切段、每段用簇心编号代替,压缩后再算距离 | 第 1 章 1.2 |
| 近似距离 | 不是真实距离,只是够用来排序的估算值 | 第 1 章 1.2 |
| Recall@10 | 近似做法的前 10 条与暴力检索前 10 条的重合比例 | 第 2 章 2.1 |
| 归一化 | 把向量长度统一到 1,此时点积大小等价于余弦相似度高低 | 第 2 章 2.1 |
| HNSW | 把向量间的近邻关系连成多层图、查询时沿图往近处走的近似索引 | 第 7 章 7.1 |
写在最后:这篇用到的资料
写这篇文章时,把相关的官方文档和源码又翻了一遍,顺手也整理了几份配套的东西:
- 大模型学习路线图:从零基础到能自己动手做 Agent,按阶段说明每一步该学什么、哪些可以先跳过
- 《LangChain + LangGraph + MCP 智能体开发实战》视频课:7 个模块,从私有化部署、Embedding+RAG 到 MCP+Agent 全流程
- AI 大模型知识库(在线可查):Agent Skills 从入门到落地、Claude Skills 完全指南等专题,按目录浏览即可
- 640 套 AI 大模型行业报告 + 经典 PDF 书籍:看行业落地案例和别人怎么做的时候用得上
- 大模型零基础到精通教学视频:跟着敲一遍,比只读文档快得多
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「AI」,优先通过。
资料按「先路线、再动手、最后查漏」的顺序整理好了,建议先看学习路线那一份,照着它挑一条适合自己当前基础的路径再往下看。