当用户丢给你一份 10 万字的《2026年企业报销规范.pdf》,大模型的 Context Window(比如 8K 或 32K)瞬间就会被撑爆。你不可能把 10 万字全塞进 Prompt 里让大模型去算自注意力。
这时候,我们就必须给 Agent 装上 "海马体(外挂记忆库)",也就是 RAG(检索增强生成)。
向量数学与相似度度量
一、 物理映射:文本是如何变成高维坐标的?(Bi-Encoder 视角)
在算数学公式之前,你必须先在脑海中建立起物理坐标系。
当你调用 OpenAI 的 text-embedding-3-small 接口时,你传给它一句话:"苹果现任 CEO 是谁"。
大模型(这里特指专门用于提取特征的 Bi-Encoder 双编码器模型 )经过几十层 Transformer 的计算,不输出文字 ,而是输出一个长度为 1536 的浮点数数组(Float Array)。
V query = [ 0.012 , − 0.045 , 0.887 , ... , − 0.102 ] \mathbf{V}_{\text{query}} = [0.012, -0.045, 0.887, \dots, -0.102] Vquery=[0.012,−0.045,0.887,...,−0.102]
这 1536 个数字到底是什么?
你可以把它想象成一个拥有 1536 个坐标轴的超高维宇宙。
- 第 1 个维度可能代表"是否与科技相关"
- 第 2 个维度可能代表"是否与水果相关"
- 第 3 个维度可能代表"是否带有疑问语气"
- ...(实际上维度是极其抽象的隐式语义,人类无法直接命名)
每一句话,在这个 1536 维的宇宙中,都是一个带有方向和长度的箭头(向量)。
当你把公司 10 万字的文档切成 1000 个段落,全部变成向量存入数据库(如 Milvus/Pinecone)后,RAG 的本质问题就变成了极其纯粹的几何学问题:在 1536 维空间里,哪几个文档向量离我的 Query 向量最近?
二、 几何学的审判:为什么必须用 Cosine 相似度?
在向量数据库里,计算"远近"有三种最核心的数学尺子。我们一个个拆解,看看工业界为什么做出了特定的选择。
1. 欧氏距离 (Euclidean Distance / L2 距离)
这是我们在初中数学里学的两点之间的直线距离。
在多维空间中,向量 A \mathbf{A} A 和 B \mathbf{B} B 的 L2 距离公式为:
L 2 = ∑ i = 1 n ( a i − b i ) 2 L2 = \sqrt{\sum_{i=1}^{n} (a_i - b_i)^2} L2=i=1∑n(ai−bi)2
- 致命缺陷(维度灾难) :在低维空间(比如 3 维),欧氏距离很好用。但在 1536 维空间里,会发生一种叫做"高维空间诅咒(Curse of Dimensionality)"的物理现象------所有的点到彼此的欧氏距离都会趋于相同。
- 语义失真 :如果向量 A \mathbf{A} A 是一句极短的话("苹果公司"),向量 B \mathbf{B} B 是一篇 5000 字的长文。由于 B \mathbf{B} B 包含的信息量极大,它的向量长度(Magnitude) (即模长 ∥ B ∥ \|\mathbf{B}\| ∥B∥)往往会非常大。即使它俩在语义方向上完全一致,巨大的长度差异也会导致 L2 距离极大,从而被错误地判定为"不相关"。
2. 余弦相似度 (Cosine Similarity) ------ 现代 NLP 的灵魂度量
既然长度会造成干扰,我们干脆抛弃长度,只看方向!
这就是余弦相似度的核心思想:衡量两个向量在多维空间中的夹角 θ \theta θ。
数学推导如下:
两个向量的点积(内积)几何定义是 A ⋅ B = ∥ A ∥ ∥ B ∥ cos ( θ ) \mathbf{A} \cdot \mathbf{B} = \|\mathbf{A}\| \|\mathbf{B}\| \cos(\theta) A⋅B=∥A∥∥B∥cos(θ)。
稍微移项,我们就得到了你给出的那个极其优美的公式:
similarity = cos ( θ ) = A ⋅ B ∥ A ∥ ∥ B ∥ \text{similarity} = \cos(\theta) = \frac{\mathbf{A} \cdot \mathbf{B}}{\|\mathbf{A}\| \|\mathbf{B}\|} similarity=cos(θ)=∥A∥∥B∥A⋅B
- 物理意义 :分母 ∥ A ∥ ∥ B ∥ \|\mathbf{A}\| \|\mathbf{B}\| ∥A∥∥B∥ 的作用是**"强行把两个向量的长度缩放到 1(单位化)"**。不管你是一万字的长文,还是三个字的短句,只要你们讨论的是同一个核心语义(方向相同),夹角 θ \theta θ 就趋近于 0 ∘ 0^{\circ} 0∘, cos ( 0 ∘ ) = 1 \cos(0^{\circ}) = 1 cos(0∘)=1(极度相似)。如果方向完全垂直, cos ( 90 ∘ ) = 0 \cos(90^{\circ}) = 0 cos(90∘)=0(毫不相关);方向完全相反, cos ( 180 ∘ ) = − 1 \cos(180^{\circ}) = -1 cos(180∘)=−1(语义对立)。
3. 内积 (Inner Product / Dot Product) ------ 工程师的终极黑魔法
公式极其简单,就是对应维度相乘后求和:
Dot Product = A ⋅ B = ∑ i = 1 n a i b i \text{Dot Product} = \mathbf{A} \cdot \mathbf{B} = \sum_{i=1}^{n} a_i b_i Dot Product=A⋅B=i=1∑naibi
重点来了!这是一个资深 AI 架构师必须懂的性能优化技巧!
计算 cos ( θ ) \cos(\theta) cos(θ) 时,每次都要算分母的平方根运算(求模长),在几十亿级的数据量下,这会让 CPU/GPU 的算力直接爆炸。
如何解决?在存入数据库之前,提前把所有向量"归一化(Normalize)"!
如果我们在获取 Embedding 时,强行让所有的向量长度 ∥ A ∥ = 1 \|\mathbf{A}\| = 1 ∥A∥=1, ∥ B ∥ = 1 \|\mathbf{B}\| = 1 ∥B∥=1。
那么,余弦公式的分母就永远是 1 × 1 = 1 1 \times 1 = 1 1×1=1!
此时,内积(Dot Product)在数学上绝对等于余弦相似度(Cosine Similarity)!
A ⋅ B = cos ( θ ) ( 当 ∥ A ∥ = ∥ B ∥ = 1 时 ) \mathbf{A} \cdot \mathbf{B} = \cos(\theta) \quad (\text{当 } \|\mathbf{A}\| = \|\mathbf{B}\| = 1 \text{ 时}) A⋅B=cos(θ)(当 ∥A∥=∥B∥=1 时)
工业界现状 :当你调用 OpenAI 的 text-embedding-3 API 时,它返回给你的 Float Array,已经是经过归一化处理的单位向量了 。因此,在配置你的向量数据库(如 Milvus / Qdrant)时,官方强烈建议你把距离度量标准配置为 Inner Product (IP),而不是 Cosine。因为算内积的 CPU 周期远小于算余弦,能极大提升 QPS(每秒查询率)。
三、 把向量数学嵌入 RAG 的物理流转
现在,RAG 在微观层面的数据流已经彻底清晰了:
- 入库阶段(Offline):你把文档切块,发给 Embedding API。返回的归一化浮点数组,被存入向量数据库。
- 查询阶段(Online):用户发来 Query,宿主程序拦截它,同样发给 Embedding API 变成归一化向量。
- 暴力计算(Brute-force Search) :向量数据库拿 Query 向量,去和库里的一百万个文档向量,做 100 万次内积运算(Dot Product)。
- Top-K 召回:数据库把内积得分最高(最接近 1)的前 5 个文档文本返回给你的 Java 宿主程序。
- 强塞入上下文 :宿主程序把这 5 个文档作为
Observation,塞进while循环的状态机 Prompt 里,大模型瞬间拥有了"记忆",输出精准答案!
但这里埋下了一颗巨大的工程地雷:
在上面第 3 步里,我说数据库要做"100 万次内积运算"。如果你的库里有 10 亿 个文档呢?每次查询都要做 10 亿次 1536 维的浮点数乘法求和?哪怕是最顶级的 GPU 也会当场卡死。
这就是HNSW 算法 诞生的原因。
传统检索与现代检索算法
在真实的工业级 RAG 架构中,检索分为两派:
- 古典派(稀疏检索 Sparse Retrieval) :以 BM25 为绝对王者的精确词频匹配算法。
- 现代派(稠密检索 Dense Retrieval) :以 HNSW 为绝对霸主的向量近似最近邻(ANN)图索引算法。
如果你只懂向量检索,你的 Agent 在遇到用户查询特定的"订单号(TX-9982)"或"特定的专业术语"时,会大概率产生幻觉(因为 Embedding 模型会对无语义的数字或生僻词抓瞎)。只有把这两者结合,你才能构建出无懈可击的系统。
我们直接切入这两种算法的底层数学与数据结构!
第一座山:BM25 (Best Matching 25) ------ 词汇统计学的极致巅峰
不要以为大模型时代,基于词频的算法就过时了。目前在 ElasticSearch 和所有主流搜索引擎中,BM25 依然是不可撼动的默认基石。它不需要任何 GPU,仅靠 CPU 计算词频就能达到极其恐怖的检索精度。
BM25 本质上是老一代 TF-IDF (词频-逆文档频率) 算法的"究极魔改版"。
假设用户的 Query 是 Q = "苹果 公司 CEO" Q = \text{"苹果 公司 CEO"} Q="苹果 公司 CEO",你的文档库里有一篇文档 D D D。BM25 是如何计算 Q Q Q 和 D D D 的相关性得分的?
它的完整数学公式如下(深呼吸,我们逐个变量拆解):
Score ( Q , D ) = ∑ i = 1 n IDF ( q i ) ⋅ TF ( q i , D ) ⋅ ( k 1 + 1 ) TF ( q i , D ) + k 1 ⋅ ( 1 − b + b ⋅ ∣ D ∣ avgdl ) \text{Score}(Q, D) = \sum_{i=1}^{n} \text{IDF}(q_i) \cdot \frac{\text{TF}(q_i, D) \cdot (k_1 + 1)}{\text{TF}(q_i, D) + k_1 \cdot \left(1 - b + b \cdot \frac{|D|}{\text{avgdl}}\right)} Score(Q,D)=i=1∑nIDF(qi)⋅TF(qi,D)+k1⋅(1−b+b⋅avgdl∣D∣)TF(qi,D)⋅(k1+1)
1. 核心部件一:IDF (Inverse Document Frequency) ------ 衡量词汇的"含金量"
公式里的 IDF ( q i ) \text{IDF}(q_i) IDF(qi) 是用来给 Query 中的每个词打底分(权重)的。
- 如果 q i q_i qi 是"公司",在 10 万篇文档里出现了 9 万次。这说明"公司"是个烂大街的词,毫无区分度,它的 IDF 值会极其接近 0。
- 如果 q i q_i qi 是"CEO",只在 100 篇文档里出现过。这个词极其稀有且关键,它的 IDF 值会非常巨大。
- 底层物理意义 :BM25 算法极其聪明地让
罕见词主导了最终得分,自动屏蔽了无意义的废话。
2. 核心部件二:TF (Term Frequency) 与 k 1 k_1 k1 饱和度 ------ 抑制"水军刷屏"
如果文档 D D D 里,"苹果"出现了 1 次,得 1 分;那如果有人为了作弊,在一篇垃圾文档里写了 100 次"苹果",这篇文档的得分应该翻 100 倍吗?
绝对不行!这就是公式中 TF ( q i , D ) \text{TF}(q_i, D) TF(qi,D) 以及常数 k 1 k_1 k1(通常设为 1.2 到 2.0)的作用。
- 底层物理意义 :BM25 引入了一个非线性饱和曲线 。当"苹果"出现第 1 次时,得分暴涨;出现第 5 次时,得分增加变缓;出现第 100 次时,得分几乎不再增加(趋于一个极限值 k 1 + 1 k_1 + 1 k1+1)。这就彻底粉碎了靠无限堆砌关键词来骗取相关性的可能。
3. 核心部件三:长度惩罚系数 b b b 与文档长度惩罚
公式分母里有一串极其精妙的算式: 1 − b + b ⋅ ∣ D ∣ avgdl 1 - b + b \cdot \frac{|D|}{\text{avgdl}} 1−b+b⋅avgdl∣D∣
- ∣ D ∣ |D| ∣D∣:当前文档的总字数。
- avgdl \text{avgdl} avgdl:整个数据库里所有文档的平均字数。
- b b b:长度惩罚系数(通常设为 0.75)。
- 底层物理意义 :如果一篇文档长达 10 万字,它哪怕只靠概率,也很容易命中"苹果"和"CEO"这两个词。如果不做惩罚,长文档会永远霸占搜索结果。
这个算式的作用是:如果你的文档长度 ∣ D ∣ |D| ∣D∣ 远远大于平均长度 avgdl \text{avgdl} avgdl,分母就会变大,导致最终得分被狠狠地压缩。这迫使系统去寻找那些短小精悍、且词汇密集命中的高质量文档。
阶段总结:BM25 把词频统计、罕见度权重、反作弊和长度惩罚全部揉进了一个没有超参数需要训练的解析解公式里。它在查找特定名字、型号、代码时,是极其精准的"狙击枪"。
第二座山:HNSW (Hierarchical Navigable Small World) ------ 高维空间的空间折跃门
现在,回到我们在上一节遇到的绝望问题:如果库里有 10 亿个 1536 维的向量。每次查询如果都做 10 亿次内积计算(暴力搜索 Brute-force),哪怕你的 Agent 跑在 H100 集群上也会超时死机(时间复杂度 O ( N ) O(N) O(N))。
我们需要一种数据结构,能在几毫秒内,不遍历所有点,直接在 10 亿个点中"空降"到离目标最近的区域。
HNSW 是如何把时间复杂度从 O ( N ) O(N) O(N) 暴力压缩到近乎 O ( log N ) O(\log N) O(logN) 的?它融合了两个极度硬核的计算机科学概念。
步骤 1 的前置理论:Skip List(跳表)的一维魔法
设想你要在一条有 1000 个站点的单行线地铁上找第 800 站,如果一站一站停,你需要走 800 步。
什么是跳表?就是建立多层快车道!
- 第 0 层(底层):站站停的慢车(包含所有 1000 个点)。
- 第 1 层:每隔 10 站停一次的快车(只有 100 个点)。
- 第 2 层(顶层):每隔 100 站停一次的特快车(只有 10 个点)。
查询过程 :你坐顶层特快车,瞬间到达第 700 站和第 800 站;然后降级到第 1 层,坐快车;最后降级到底层,精确找到目标。这就是一维空间里的 O ( log N ) O(\log N) O(logN) 查找。
步骤 2 的前置理论:NSW (Navigable Small World) 的高维拓扑网
在一维直线上建跳表很简单,但在 1536 维的宇宙里,没有绝对的"前后"之分!
于是数学家们提出了 NSW(可导航小世界图)。
它在多维空间里把向量当成图的节点,然后让每个节点与其物理距离最近的几个节点(比如最近的 16 个点)通过"边(Edges)"连起来,形成一张错综复杂的蜘蛛网。
- 贪婪路由算法(Greedy Routing) :当你的 Query 向量进入这张网时,你随便找一个起始点空降。然后你环顾四周,看看当前点连着的 16 个邻居里,哪个离目标点更近?如果是 A 更近,你就立刻"跳"到 A。不断重复这个过程,直到你走到一个点,发现它周围的所有邻居都没有它自己离目标近,这个点就是局部最优解(近似最近邻)。
步骤 3 终极融合:HNSW 的三维空间图层叠加
NSW 还有一个致命问题:如果 10 亿个点都在一张网上,你的图会变得极其密集,贪婪路由依然会绕远路。
HNSW 的天才之举,就是把 NSW(多维网状图)和 Skip List(分层跳表)彻底融合!
HNSW 在内存里构建了一个令人惊叹的多层立体高维图结构:
- Level 0(最底层):包含了所有的 10 亿个向量节点。它们彼此连接,极其密集。
- Level 1 到 Level N(向上递增):按照指数级衰减的概率(比如每往上一层,节点数量减少 90%),随机抽取底层的节点往上提拔,在上一层重新建立稀疏的网状连接。
- Level Max(最高层):可能只有区区十几个极其孤立的节点,作为**"宇宙级传送门"**。
HNSW 的极限查表物理全过程(感受这几毫秒内发生的魔法):
- 空降顶层:用户的 Query 向量首先被空降到最高层(Level Max)的唯一入口点。这里只有寥寥几个点跨越了极其遥远的多维空间。
- 顶层贪婪搜索:在这个极度稀疏的图里算几次距离,瞬间定位到最高层里离 Query 最近的那个节点。
- 空间降维穿梭(Drop Down):以刚才找到的节点为锚点,直接垂直降落到**下一层图(Level Max - 1)**中。
- 逐层逼近:在每一层中,以进入该层的锚点为起点,继续执行贪婪路由,找到该层最近的点,然后再降层。
- 底层的精细清扫:当降落到包含了 10 亿个节点的最底层(Level 0)时,系统已经站在了离 Query 极度接近的"家门口"。此时在极小的局部范围内再做一次贪婪搜索,最终命中!
工程结论 :HNSW 放弃了"100% 绝对精确的全局最优解"(它是一种 ANN,Approximate Nearest Neighbor 近似算法),但换来的是即使在百亿规模的高维向量库中,也能稳定将查询耗时压制在 10 毫秒 级别。这就是为什么目前业界所有的向量数据库(Milvus、Pinecone、Qdrant、Faiss)底层全都是 HNSW 算法。
Agent 架构师的终局抉择:Hybrid Search (混合检索)
现在你掌握了双剑:
- BM25 是一把手术刀,极其精准地命中用户的特定关键词,不会偏离。
- HNSW 是一张大网,通过 1536 维的高维折跃门,瞬间捕获语义相似但用词完全不同的文档(比如用户搜"薪资",能命中写着"酬劳"和"报酬"的段落)。
在现代顶尖的 Agent 架构里,我们绝对不会只用一种。我们会用多路召回:
- 宿主程序收到用户 Query。
- 并发开启两个线程:
- 线程 A:把文本扔进 BM25 倒排索引,召回 10 篇文档。
- 线程 B:把文本 Embedding 化,扔进 HNSW 向量索引,召回 10 篇文档。
但是,BM25 给出的分数可能是 15.8,而 HNSW 给出的内积得分是 0.85。两套完全不同维度的数学打分,在宿主程序里该怎么融合并选出真正的 Top 5 喂给大模型呢?
这就必然引出整个 RAG 架构里的最后一道门神------Reranker (重排器,Cross-Encoder 交叉编码器)。
这一步非常关键!它直接决定了你的大模型会不会被一堆乱七八糟的干扰文档带偏而产生幻觉。
Rerank(重排)机制
在刚才的推演中,你的宿主程序并发调用了 BM25(词频检索)和 HNSW(向量检索),各召回了 10 篇文档。现在,你的内存里躺着 20 篇候选文档,但分数完全无法直接比较:
- BM25 给文档 A 打了
24.5分。 - HNSW 给文档 B 打了
0.88分(内积)。
怎么融合?业界有两种绝对核心的做法:一种是纯数学的"粗排",另一种是基于深度学习的"精排"。我们把这两层窗户纸全部捅破!
第一层防线:RRF (Reciprocal Rank Fusion) ------ 倒数秩融合算法
当分数维度不同时,最优雅的数学解法是抛弃绝对分数,只看排名(Rank)!
这就是 RRF 算法。它的公式极其精简,却被所有主流商业搜索引擎(如 Elasticsearch 8.x)奉为圭臬:
S c o r e RRF = 1 k + R a n k BM25 + 1 k + R a n k HNSW Score_{\text{RRF}} = \frac{1}{k + Rank_{\text{BM25}}} + \frac{1}{k + Rank_{\text{HNSW}}} ScoreRRF=k+RankBM251+k+RankHNSW1
- R a n k Rank Rank:文档在各自召回列表中的名次(第 1 名就是 1,第 2 名就是 2)。
- k k k :一个平滑常数(业界经过无数次 A/B 测试,通常定死为
60)。 - 底层物理意义 :如果文档 A 在 BM25 排第 1,但在 HNSW 连前 10 都没进;而文档 C 在两边都排第 3。代入公式计算,文档 C 的总得分会反超文档 A!RRF 算法极其凶悍地偏袒那些在两套完全不同的底层逻辑(词频 + 语义)中都表现优异的"双料优等生"。
经过 RRF 粗排,这 20 篇文档被重新排序。但这还不够!大模型的上下文极其珍贵,我们需要选出最精准的 Top 5。这就必须请出镇山之宝------Cross-Encoder(交叉编码器)。
终极防线:Bi-Encoder 与 Cross-Encoder 的物理维度降维打击
1. 为什么 Bi-Encoder(双编码器 / 向量召回)精度有限?
你之前调用的 text-embedding-3 或者 BGE-m3 模型,全都是 Bi-Encoder 。
它的物理流转是双线并行的:
- 离线时 :文档 D D D 独自进入 Transformer,算出自注意力,输出一个 1536 维的向量 V d \mathbf{V}_d Vd。
- 在线时 :用户的 Query Q Q Q 独自进入 Transformer,算出自注意力,输出一个 1536 维的向量 V q \mathbf{V}_q Vq。
- 最后一步 :在数据库里,用简单的点积或余弦公式 (极其廉价的计算)计算两者的分数: S = V q ⋅ V d S = \mathbf{V}_q \cdot \mathbf{V}_d S=Vq⋅Vd。
致命缺陷(Late Interaction 晚期交互) :
在 Transformer 进行那几十层极其复杂的 Q , K , V Q, K, V Q,K,V 矩阵计算时,Query 和 Document 是物理隔离的! Query 里的 Token 从未和 Document 里的 Token 发生过任何点积碰撞。它们只是各自被压缩成了一个高度抽象的 1536 维向量,最后才用一个极其简陋的点积公式见了一面。这导致大量极其微观的上下文语义在"压缩成向量"的过程中永久丢失了。
2. 为什么 Cross-Encoder(交叉编码器 / Reranker)精度极高?
如果你调用过 BAAI 的 bge-reranker-v2-m3 模型,这就是目前开源界最强的 Cross-Encoder。
它的物理流转极其暴力。它根本不生成什么 1536 维的向量,而是直接把 Query 和 Document 拼接成一个超级长句子,一次性塞进 Transformer!
输入的物理形态长这样:
[CLS] 苹果现任 CEO 是谁? [SEP] 蒂姆·库克自 2011 年起担任苹果公司首席执行官... [SEP]
奇迹发生的瞬间(Early Interaction 早期交互) :
在这张巨大的 Q ⋅ K T Q \cdot K^T Q⋅KT 注意力矩阵中,Query 里的"CEO"这个 Token 的 Query 向量,会直接、物理地 去和 Document 里的"库克"、"首席执行官"的 Key 向量做高维点积!
Query 和 Document 在第一层网络就已经彻底水乳交融,逐字逐句地进行了极其深度的语义对齐和逻辑推理。
经过几十层这样的深度纠缠,最后在最顶层的 [CLS] Token 上,接一个简单的线性分类器,输出一个 0 到 1 之间的浮点数,代表这篇文档完美回答这个 Query 的概率(比如 0.985)。
3. 为什么 Cross-Encoder 绝对不能用来建索引?(数学灾难)
既然 Cross-Encoder 这么无敌,为什么我们不直接用它去搜那 10 亿篇文档?
算一笔账:
- Bi-Encoder :离线把 10 亿篇文档变成向量存起来。线上 Query 来时,只需过 1 次 Transformer 变成向量,然后数据库做 10 亿次极快的点积。耗时:10 毫秒。
- Cross-Encoder :因为它必须把 Query 和 Document 拼在一起才能算,所以你无法在离线时预先计算任何文档的特征! 线上 Query 来时,你必须把 Query 分别和 10 亿篇文档拼在一起,把庞大的 Transformer 神经网络完完整整地运行 10 亿次 !耗时:大约需要 30,000 年(即使你有一万张 A100 显卡也要算几天)。
这就是现代 RAG 架构的终极妥协与艺术:漏斗模型。
RAG 检索链路的"工业级漏斗"大一统
现在,你已经具备了俯瞰整个 RAG 检索管线(Retrieval Pipeline)的上帝视角。一条能扛住千万并发、零幻觉的企业级 Agent 检索链路,物理流转如下:
- 海量全库(10 亿级):躺在硬盘和数据库里。
- 第一道漏斗(多路召回,10 毫秒级) :
- Agent 的宿主程序收到用户 Query。
- 触发 BM25 引擎(找包含特定字眼的,极快),召回 Top 100。
- 触发 HNSW 向量引擎(找 Bi-Encoder 语义相似的,极快),召回 Top 100。
- 第二道漏斗(RRF 粗排,1 毫秒级) :
- 宿主程序在内存中运行 RRF 公式,把这 200 篇文档去重、根据排名融合,筛选出毫无争议的 Top 20。
- 第三道漏斗(Cross-Encoder 精排,200 毫秒级) :
- 把 Query 和这 20 篇文档拼接到一起,发给 Reranker 大模型(如 BGE-Reranker)。
- Transformer 执行深度注意力计算,给这 20 篇文档打出极其精准的
0~1概率分。 - 截取分数最高、绝对能回答用户问题的 Top 5 文本块(Chunks)。
终局 :宿主程序将这精挑细选的 5 个文本块,作为 Observation,悄悄塞进 Agent 的 messages 数组里,发给最终的生成大模型(如 DeepSeek-Chat 或 GPT-4)。大模型看着这 5 块绝对精准的记忆,完美地吐出无幻觉的答案。