在检索增强生成(RAG)系统中,用户查询通常较短、歧义较多,而向量检索又依赖语义相似度进行召回。这会导致一种典型问题:检索结果中既包含真正相关的文档,也包含“看起来相似但实际不相关”的噪声文档。传统伪相关反馈(Pseudo-Relevance Feedback, PRF)通常假设 top-k 检索结果大多是相关的,并直接利用它们扩展查询;但在真实业务场景中,这一假设经常不成立。
“伪负向量增强查询”可以理解为:在向量检索过程中,利用大模型或检索日志识别出疑似不相关但语义接近的文档,将其作为“伪负向量”,用于修正查询表示、过滤噪声结果,并进一步提升召回质量。它不同于简单删除低分结果,而是把“形似神不似”的伪负样本转化为增强信号,使查询向量更贴近真实意图。
这一思路与近年来的查询增强、伪相关反馈、负样本学习、难负样本挖掘等方向密切相关。
二、技术原理
伪负向量增强查询的核心流程可以分为五步:
- 初始检索:对用户原始查询进行向量检索,得到 top-k 候选文档。
- 伪负判定:利用大模型、规则或日志反馈,判断哪些候选文档属于“伪负样本”。
- 伪负向量聚合:将伪负文档的向量聚合为“负方向信号”。
- 查询向量修正:从原始查询向量中减去伪负方向,得到增强后的查询向量。
- 二次检索与融合:使用增强查询向量重新检索,并与原始结果融合,得到最终文档集合。
用公式化方式表达,可以写作:
q_enhanced = normalize(q - α * pseudo_negative_direction)其中,q是原始查询向量,α是负向抑制系数,pseudo_negative_direction由伪负文档向量加权平均得到。这样做的直观含义是:让查询向量远离那些“容易误导检索”的语义区域,从而提升后续召回的纯度。
三、Python 实现
下面给出一套可运行的 Python 示例。为便于理解,示例使用随机向量模拟嵌入模型和向量库;实际工程中可以替换为sentence-transformers、BGE、GTE等嵌入模型,以及 FAISS、Milvus、Weaviate 等向量数据库。
importnumpyasnpfromtypingimportList,Dict,TupleclassPseudoNegativeQueryEnhancer:"""伪负向量增强查询器"""def__init__(self,alpha:float=0.3,pseudo_negative_threshold:float=0.5,max_pseudo_negatives:int=5,dim:int=128,):self.alpha=alpha self.pseudo_negative_threshold=pseudo_negative_threshold self.max_pseudo_negatives=max_pseudo_negatives self.dim=dim# 模拟文档库,实际应替换为向量数据库self.documents:List[Dict]=[]self.doc_vectors:np.ndarray=np.array([])defbuild_index(self,documents:List[Dict]):"""构建向量索引"""self.documents=documents vectors=[doc["vector"]fordocindocuments]self.doc_vectors=np.array(vectors,dtype=np.float32)defcosine_similarity(self,a:np.ndarray,b:np.ndarray)->float:"""计算余弦相似度"""norm_a=np.linalg.norm(a)norm_b=np.linalg.norm(b)ifnorm_a==0ornorm_b==0:return0.0returnfloat(np.dot(a,b)/(norm_a*norm_b))definitial_search(self,query_vector:np.ndarray,k:int=10)->List[Tuple[int,float]]:"""初始向量检索,返回 (doc_index, similarity)"""sims=self.doc_vectors @ query_vector/(np.linalg.norm(self.doc_vectors,axis=1)*np.linalg.norm(query_vector)+1e-8)top_k_idx=np.argsort(-sims)[:k]return[(int(idx),float(sims[idx]))foridxintop_k_idx]defidentify_pseudo_negatives(self,query:str,candidates:List[Tuple[int,float]],)->List[Tuple[int,float]]:""" 伪负样本识别: 实际工程中可替换为 LLM 判断、点击日志、用户反馈或重排模型打分。 这里采用简化规则:相似度处于中间区间且文本不包含查询关键词。 """pseudo_negatives=[]query_lower=query.lower()fordoc_idx,simincandidates:doc_text=self.documents[doc_idx]["text"].lower()# 简化判定:相似度不低,但缺乏关键语义重叠is_semantically_weak=query_lowernotindoc_text in_ambiguous_zone=self.pseudo_negative_threshold<=sim<=0.85ifis_semantically_weakandin_ambiguous_zone:pseudo_negatives.append((doc_idx,sim))# 限制伪负样本数量,避免噪声过大pseudo_negatives.sort(key=lambdax:-x[1])returnpseudo_negatives[:self.max_pseudo_negatives]defenhance_query(self,query_vector:np.ndarray,pseudo_negatives:List[Tuple[int,float]],)->np.ndarray:"""利用伪负向量修正查询向量"""ifnotpseudo_negatives:returnquery_vector/(np.linalg.norm(query_vector)+1e-8)negative_vectors=[]weights=[]fordoc_idx,siminpseudo_negatives:negative_vectors.append(self.doc_vectors[doc_idx])weights.append(sim)negative_vectors=np.array(negative_vectors)weights=np.array(weights)weights=weights/(weights.sum()+1e-8)pseudo_negative_direction=(weights[:,None]*negative_vectors).sum(axis=0)enhanced=query_vector-self.alpha*pseudo_negative_directionreturnenhanced/(np.linalg.norm(enhanced)+1e-8)defsearch_with_enhancement(self,query:str,query_vector:np.ndarray,k:int=5,initial_k:int=10,)->List[Dict]:"""伪负向量增强检索主流程"""# 1. 初始检索candidates=self.initial_search(query_vector,k=initial_k)# 2. 识别伪负样本pseudo_negatives=self.identify_pseudo_negatives(query,candidates)# 3. 增强查询向量enhanced_query_vector=self.enhance_query(query_vector,pseudo_negatives)# 4. 二次检索enhanced_candidates=self.initial_search(enhanced_query_vector,k=k)# 5. 返回结果results=[]fordoc_idx,siminenhanced_candidates:results.append({"id":self.documents[doc_idx]["id"],"text":self.documents[doc_idx]["text"],"similarity":round(sim,4),"is_pseudo_negative_filtered":any(doc_idx==pn_idxforpn_idx,_inpseudo_negatives),})returnresults# ------------------------------# 模拟数据与测试# ------------------------------defnormalize_vector(v:np.ndarray)->np.ndarray:returnv/(np.linalg.norm(v)+1e-8)defbuild_mock_documents()->List[Dict]:""" 构造一组具有语义干扰的模拟文档。 真实项目中应替换为知识库切片、向量嵌入和向量数据库。 """docs=[{"id":"doc1","text":"Python 异步编程中的 asyncio 事件循环机制"},{"id":"doc2","text":"Python 多线程与多进程在 IO 密集型任务中的区别"},{"id":"doc3","text":"Java 虚拟机垃圾回收算法与内存管理"},{"id":"doc4","text":"Python 装饰器原理与常见应用场景"},{"id":"doc5","text":"Python 批量图像处理脚本开发实践"},{"id":"doc6","text":"Python 控制台进度条与日志输出优化"},{"id":"doc7","text":"大模型 RAG 系统中的向量检索与重排策略"},{"id":"doc8","text":"Python 自动化运维中的系统监控脚本设计"},{"id":"doc9","text":"软件设计师考试中数据结构与算法高频考点"},{"id":"doc10","text":"Python 文件批量重命名与路径处理技巧"},]np.random.seed(42)dim=128fordocindocs:doc["vector"]=normalize_vector(np.random.randn(dim))returndocsdefmain():documents=build_mock_documents()enhancer=PseudoNegativeQueryEnhancer(alpha=0.35,pseudo_negative_threshold=0.45,max_pseudo_negatives=3,dim=128,)enhancer.build_index(documents)query="Python 批量图像处理自动化脚本"query_vector=normalize_vector(np.random.randn(128))print(f"查询:{query}")print("-"*60)results=enhancer.search_with_enhancement(query=query,query_vector=query_vector,k=5,initial_k=10,)forrinresults:print(f"[{r['id']}] sim={r['similarity']}"f"filtered={r['is_pseudo_negative_filtered']}|{r['text']}")if__name__=="__main__":main()四、代码解析
1. 初始检索
initial_search使用余弦相似度对查询向量与文档向量进行匹配。这是向量检索系统中最常见的第一阶段召回方式。
2. 伪负样本识别
identify_pseudo_negatives是整个方法的关键。它从 top-k 候选文档中筛选出“相似度不低,但语义匹配较弱”的文档。示例中使用了关键词缺失和相似度区间作为简化判定条件;生产环境中可以替换为:
- LLM 判断文档是否与查询真正相关;
- 用户点击、跳过、负反馈日志;
- 重排模型对相关性的打分;
- 历史误召日志挖掘。
3. 伪负向量聚合
enhance_query将伪负文档向量加权聚合,形成“负方向”。权重越高,说明该文档越容易误导检索,因此对查询向量的修正作用也越强。
4. 查询向量修正
修正公式为:
q_enhanced = normalize(q - α * pseudo_negative_direction)这里α控制抑制强度。α过大可能导致查询向量偏离原始意图,α过小则增强效果不明显。
5. 二次检索与结果返回
增强后的查询向量会重新参与检索。最终结果可以只返回二次检索结果,也可以与原始结果做 RRF 融合,以兼顾召回稳定性。
五、技术亮点
1. 把“噪声”变成“信号”
传统做法往往直接丢弃低分文档,但伪负向量增强查询会利用那些“看似相关、实际不相关”的文档。它们恰恰反映了查询与文档之间的语义边界,能够显著提升模型区分能力。
2. 不依赖完整训练流程
示例中的增强过程发生在检索阶段,不需要重新训练嵌入模型。实际系统中也可以将其作为检索前或检索后增强模块接入现有 RAG 流水线。
3. 与混合检索兼容
该方法可以与 BM25、向量检索、图谱检索、RRF 融合结合。例如先用多路召回获取候选集,再用伪负向量增强进行二次过滤和重排。
4. 工程可扩展性强
伪负样本识别模块可以替换为多种实现:
- 轻量规则:关键词、实体、领域标签;
- 重排模型:Cross-Encoder 打分;
- LLM 判别:让模型判断文档是否真正回答查询;
- 日志学习:利用用户负反馈持续优化伪负识别策略。
5. 适合复杂查询场景
当查询包含多个意图、专业术语或容易混淆的概念时,伪负向量增强能够帮助系统远离错误语义区域。例如查询“Python 批量图像处理”时,系统可以抑制与“Java 虚拟机”“软件设计师考试理论”等弱相关文档的干扰。
六、实验与评估建议
实际落地时,建议从以下指标进行评估:
| 指标 | 含义 | 关注点 |
|---|---|---|
| Recall@K | Top-K 召回率 | 是否找到更多相关文档 |
| NDCG@K | 排序质量 | 相关文档是否排在前面 |
| Precision@K | 前 K 条准确率 | 噪声是否减少 |
| 伪负识别准确率 | 伪负样本判断是否正确 | 是否误伤正样本 |
| 端到端回答准确率 | RAG 最终回答质量 | 是否提升生成效果 |
评估时应特别注意避免“过度抑制”。如果伪负识别模块过于激进,可能把真正相关的文档也排除掉。因此建议设置alpha、pseudo_negative_threshold、max_pseudo_negatives等参数的消融实验。
七、局限与改进方向
伪负识别依赖质量
如果伪负样本判断错误,增强反而会引入噪声。生产环境最好结合 LLM 判别、重排模型和用户反馈。α 参数需要调优
不同数据集、不同嵌入模型下,负向抑制强度差异较大。建议通过验证集自动搜索。查询漂移风险
若伪负方向过强,增强后的查询可能偏离原始意图。可以加入原始查询向量残差约束。可与 Query2doc、HyDE、MultiQuery 结合
伪负向量增强主要解决“远离错误语义”,而 Query2doc、HyDE、多查询扩展则负责“靠近正确语义”。两者结合有望进一步提升召回质量。可引入在线学习
长期来看,系统可以持续收集用户对检索结果的点击、跳过、差评行为,动态更新伪负样本池,形成闭环优化。
八、总结
伪负向量增强查询是一种面向 RAG 检索质量提升的增强策略。它通过识别并抑制“形似神不似”的伪负文档,使查询向量更加聚焦真实意图。该方法实现成本较低,可与现有向量检索、混合检索、重排和大模型生成模块灵活组合。对于企业内部知识库、工程文档检索、智能问答系统等场景,具有较好的实践价值。