【RAG实战】同一个检索策略打天下?我用4种自适应策略让每种问题都找到最优路径

系列文章:本篇是第 2 篇 / 共 4 篇

项目地址GitHub - RAG_Agent_project

前情提要第 1 篇 - 架构设计与双层 Pipeline


[引言]

上一篇讲到 BM25 FAQ 短路层,60% 的简单问题在那里就解决了。但剩下 40% 的问题进入 RAG 管道之后,还有一个很尴尬的现实:

同一种检索方式,对不同问题的效果差距非常大。

"什么是决策?" —— 直接检索就能命中。 "请分析管理学中各流派决策理论的异同" —— 太抽象了,直接检索召回率很低。 "比较一下泰勒和法约尔的管理思想" —— 涉及多个子话题,一次检索覆盖不全。 "管咋学啊背不下来" —— 口语化,教材里根本没有这种表述。

如果只用一种检索策略,总有一类问题的效果会很差。所以我设计了 4 种策略,让 LLM 自动判断问题类型、选择最优路径。


4 种策略分别解决什么问题

先上全景表,后面一个一个拆:

策略适用场景工作原理
直接检索概念明确、表述清晰标准混合检索 + Reranker 精排
HyDE抽象、理论性、比较类LLM 先生成"假设性答案",用答案去检索
子查询拆分复杂多部分问题LLM 拆分子问题 → 分别检索 → 合并去重
回溯简化口语化、模糊表述LLM 转化为精确学术问题再检索

策略选择器:规则优先,LLM 兜底

# rag_qa/core/strategy_selector.py
class StrategySelector:
    def select(self, query: str) -> str:
        # 第1步:规则优先(O(1) 关键词匹配,毫秒级)
        if any(kw in query for kw in ["比较", "对比", "区别", "异同"]):
            return "子查询检索"
        
        # 第2步:LLM 分类(temperature=0.1)
        result = self.llm.invoke(strategy_prompt(query))
        strategy_map = {
            "A": "直接检索",
            "B": "假设问题检索", 
            "C": "子查询检索",
            "D": "回溯问题检索"
        }
        return strategy_map.get(result, "直接检索")  # 失败默认直接检索

这里的设计思路和意图识别一样:规则优先 + LLM 兜底。包含"比较/对比/区别"等关键词的直接走子查询,省一次 LLM 调用。LLM 分类失败时默认回退到直接检索 —— 因为直接检索是最安全的策略,至少不会出错。

给 LLM 的 Prompt 也很简洁:

你是一个检索策略分类器。根据用户问题选择最合适的检索策略:
A. 直接检索 - 问题表述清晰,关键词明确
B. 假设问题检索 - 问题抽象、理论性强
C. 子查询检索 - 问题包含多个子话题
D. 回溯问题检索 - 问题口语化、模糊
​
用户问题:{query}
只回答 A/B/C/D

HyDE:与其用问题检索,不如先生成一个"假答案"

HyDE (Hypothetical Document Embeddings) 是这 4 种策略里最巧妙的一个。

def hyde_search(query: str):
    # 1. LLM 生成假设性答案
    hypothetical_answer = llm.generate(hyde_prompt(query))
    # prompt: "假设你是一位管理学教授,请针对以下问题给出一个简要回答:{query}"
    
    # 2. 用假设答案的 embedding 去检索
    results = vector_store.hybrid_search(hypothysical_answer)
    
    # 3. Reranker 精排(注意:rerank 时仍用原始 query)
    return reranker.rerank(query, results)

为什么 HyDE 有效? 举个真实例子。

用户问:"各流派决策理论的异同"

直接用这个问题去检索,关键词是"流派"、"决策理论"、"异同" —— 但教材中的表述是"古典决策理论"、"行为决策理论"、"理性决策模型"。关键词对不上,召回率低。

HyDE 生成的假设答案会包含:"古典决策理论假设完全理性...行为决策理论引入有限理性概念...两者在假设前提、分析方法上存在差异..." —— 这些教材关键词被假设答案"补全"了,用假设答案去检索,召回率大幅提升。

但有个坑:Reranker 精排时必须用原始 query,不能用假设答案。因为假设答案是 LLM "编"的,可能包含错误信息,用它精排会把不相关内容排到前面。


子查询拆分:大问题拆成小问题,各个击破

def subquery_search(query: str):
    # 1. LLM 拆分子问题
    sub_queries = llm.generate(subquery_prompt(query))
    # prompt: "将以下问题分解为简单的子问题,每行一个"
    # 例如: "比较泰勒和法约尔" → 
    #   "泰勒科学管理理论的核心要点是什么"
    #   "法约尔一般管理理论的核心要点是什么"
    #   "泰勒和法约尔管理思想的主要区别是什么"
    
    # 2. 并行检索每个子问题
    all_results = []
    for sq in sub_queries:
        results = vector_store.hybrid_search(sq)
        all_results.extend(results)
    
    # 3. 按 parent_id 合并去重
    merged = deduplicate_by_parent_id(all_results)
    
    # 4. Reranker 精排(用原始 query)
    return reranker.rerank(query, merged)

为什么要按 parent_id 去重? 多个子问题可能检索到同一个父块下的不同子块。如果不去重,同一个父块的内容会被重复送给 LLM,浪费 token 且可能让 LLM 过度关注这部分内容。

子查询拆分的 Prompt:

你是一个问题分解器。将以下复杂问题分解为2-4个简单的子问题。
要求:
1. 每个子问题应该是一个独立的、可检索的知识点
2. 每行一个子问题
3. 不要包含原问题中未提及的假设
​
用户问题:{query}

回溯简化:把口语翻译成教材语言

这是最"接地气"的一个策略。

def backtracking_search(query: str):
    # 1. LLM 将口语转化为学术问题
    academic_query = llm.generate(backtracking_prompt(query))
    # prompt: "将以下口语化问题转化为精确的学术问题"
    # 例如: "管咋学啊背不下来" → "管理学课程的学习方法和记忆技巧有哪些"
    # 例如: "决策那个玩意儿到底啥意思" → "管理学中决策的定义和内涵是什么"
    
    # 2. 用转化后的问题去检索
    results = vector_store.hybrid_search(academic_query)
    
    # 3. Reranker 精排(用原始 query)
    return reranker.rerank(query, results)

回溯简化的 Prompt:

你是一个学术问题改写器。将以下口语化的问题转化为精确的学术问题。
要求:
1. 使用管理学专业术语
2. 保持原意不变
3. 只输出改写后的问题,不要解释
​
用户问题:{query}

4 种策略实际表现对比

维度直接检索HyDE子查询回溯
LLM 调用次数011+1
检索次数11N1
延迟最低中等较高中等
适用场景关键词明确抽象理论多话题复合口语化
核心优势补全关键词覆盖面广术语对齐

实际跑下来的分布:直接检索覆盖约 50%,HyDE 约 20%,子查询约 15%,回溯约 15%。策略选择器本身的 LLM 调用延迟约 200ms,相比后续检索+生成的 2-5 秒基本可以忽略。


小结

本篇拆解了 4 种自适应检索策略。核心要点:

  1. 策略选择:规则优先 + LLM 兜底,失败默认直接检索

  2. HyDE:用假设答案补全关键词,提升抽象问题的召回率

  3. 子查询:拆分后并行检索,按 parent_id 去重

  4. 回溯:口语→学术术语对齐

下一篇进入检索层内部 —— BGE-M3 双向量混合检索 + WeightedRanker 融合 + BGE-Reranker Cross-Encoder 精排 + 父子块上下文恢复,这是整个系统检索质量的核心。

项目地址GitHub - jlu55404-art/RAG_Agent_project: RAG问答系统 · GitHub

有帮助欢迎 Star 支持!问题评论区交流~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值