Agent 记忆检索中的混合搜索:Dense + Sparse 的底层权衡
拆解混合检索(Hybrid Search)在 Agent 记忆系统中的应用,从 BM25 和向量检索的互补原理出发,分析三种融合策略的工程取舍。
当 Agent 从长期记忆中检索相关信息时,本质上是在做一个跨模态的对齐问题——用户的查询是一段自然语言,而记忆中存的是不同粒度、不同时间、不同格式的记录。纯向量检索(Dense Retrieval)会丢掉精确匹配的信号,纯关键词检索(Sparse Retrieval)又捕不到语义相似度。于是大家都在做 Hybrid Search。
但"混合"这个词被用得太轻了。它不是一个函数调用就能解决的事,背后是对两种检索范式底层物理原理的理解和工程取舍。
BM25:在倒排索引里算概率
关键词检索的顶梁柱是 BM25。它的核心不是"匹配",而是在倒排索引上给每个词算一个权重。
公式拆到最底层:
BM25(t, d) = IDF(t) * TF(t, d) * (k1 + 1) / (TF + k1 * (1 - b + b * |d| / avgdl))
- IDF(t) 说的是:这个词在越少的文档里出现,它就越"重要"。一个罕见术语的出现比"的"/"是"有价值得多。
- TF(t, d) 说的是:在文档中出现次数越多越重要,但用 k1 做了饱和——出现 10 次不应该是出现 1 次的 10 倍,大概根号级的增长。
- b 控制了文档长度归一化:长文档天然有更高的 TF,b 参数让你决定要不要惩罚长文档。
BM25 的优势是精确——用户搜 "CVR prediction leakage",它知道 "leakage" 这个词在文档中出现过,而不在乎这个词的 embedding 在语义空间里挨着谁。它在 Agent 记忆系统里有个特别的用处:当 agent 想搜某个 API 的错误码或特定函数名时,BM25 完胜任何 embedding 模型。
它的痛点是语义哑巴——"数据泄露"和"leakage"在 BM25 眼里毫无关系。
Dense Retrieval:在高维球面上找近邻
向量检索的底层逻辑完全不同。它把查询和文档都投射到同一个高维空间,用余弦相似度或内积量距离。
关键物理事实:embedding 模型做的其实是"降维但不失去语义关系"——把一段文本的语义压缩到几百个浮点数里,让语义相近的文本在向量空间中彼此靠近。
它的优势是语义智能——"如何防止训练时用到未来信息"和"data leakage in time series"在向量空间里可能只隔了几度角。
痛点是精确失灵——搜 "get_user_info_v2()" 这个函数名,向量检索可能把它附近的语义邻居都捞出来,但精确匹配的反而是 BM25 才能保证。
融合策略:三种工程路线的权衡
混合不是简单地把两个得分加起来。三种主流路线各有适用场景:
1. 线性加权融合(Reciprocal Rank Fusion, RRF)
score = 1/(k + rank_dense) + 1/(k + rank_sparse)
每个检索器返回按排名计算的分数,然后相加排序。RRF 不关心原始分数绝对值,只关心排名位置。
优点:实现简单,两个检索器之间的 scale 差异不影响结果。
缺点:排名信息丢失了置信度——Dense 返回的第 5 条可能离第 4 条非常近,而 Sparse 的第 5 条可能已经断崖下跌了,RRF 分不出来这个区别。
适用场景:快速原型、对召回率要求不那么苛刻的 Agent 记忆查询。
2. 分数归一化融合(Min-Max / Z-Score)
把 Dense 得分和 BM25 得分各自归一化到同一量纲,然后加权相加:score = α * score_dense_norm + (1-α) * score_sparse_norm。
优点:保留了置信度差异——得分差距大的项会自然排在前面。
缺点:α 需要调参且在变化的数据分布上可能漂移。同一个 embedding 模型的得分分布会随着记忆库的增长而改变。
适用场景:中长期稳定的记忆库,有离线实验验证 α 的机会。
3. 级联检索(Cascade)
先用 BM25(开销小)粗筛出一个候选集,再用 Dense Retrieval 在候选集上做精排。
在 RAG 系统里这个模式很常见。
优点:计算成本可控——不需要对所有文档计算 embedding 相似度。
缺点:漏召回——如果 BM25 第一轮就把正确文档淘汰了,后面的精排再强也救不回来。
适用场景:记忆库非常大(百万级以上)且 BM25 就能覆盖大部分精确匹配的场景。Agent 短期记忆通常达不到这个量级,不太适用。
工程上的细节陷阱
- BM25 参数不是通用的:k1=1.2, b=0.75 是 TREC 语料上调出来的。Agent 记忆库的文档长度分布(短则一行日志、长则完整的 reasoning trace)可能需要重新调。b 过大会惩罚长文档,让长思考链排在很后面。
- Dense + Sparse 的延迟差异:BM25 基于倒排索引,O(1) 查找计算几千个候选;向量检索需要 ANN(近似最近邻)搜索,在 HNSW 图结构上走 log(n) 复杂度。两者天然不同步,级联方案里 BM25 往往是瓶颈——索引在内存中所以不是,但如果 BM25 返回的候选集太大,下游排序也会变慢。
- 索引更新策略:Agent 记忆不断写入,BM25 的倒排索引增删改容易,但 embedding 索引(如 HNSW 图)的增量更新会破坏图结构。实践中需要写一个"重建调度"而不是实时插入。
混合检索不是 silver bullet。它解决的是"Agent 记忆系统中,语义理解和精确匹配可以并存"这个工程问题。选哪种融合策略,取决于你的 Agent 是更常回忆事实陈述(需要精确),还是更常做类比推理(需要语义)。
在自研 Agent 框架的记忆模块里,我最终选择了 RRF + 可配置权重——不为别的,就因为 Agent 的记忆查询模式在不断变化,需要一套灵活到可以随时调整优先级的机制。
评论
发表评论