Adaptive RAG 技术详解:从 Query 分类到智能检索策略


各位技术爱好者们,大家好!今天我要向大家隆重介绍一个我自己开发的项目:一个使用 Streamlit 搭建的通用自适应 RAG (Retrieval-Augmented Generation,检索增强生成) Demo 应用。受到 fareedkhan-dev/all-rag-techniques 项目的启发,我希望通过一个简洁的(不依赖于langchain和其他复杂库函数)实用的、可交互的应用,让大家更直观地理解 Adaptive RAG 的魅力,并体验更智能、更精准的问答系统。

如果不了解fareedkhan-dev/all-rag-techniques 项目的可以查看我之前的文章:

告别 LangChain 和 FAISS?手把手教你玩转 21 种 RAG 技术,这个硬核项目不容错过!

告别“一招鲜”,迎接“自适应”的 RAG

传统的 RAG 系统,往往采用固定的检索和生成策略,面对各种各样的问题,难免显得有些“力不从心”。例如,对于事实性问题,我们可能希望系统快速定位到关键信息;而对于分析性问题,则需要系统进行更深度的语义理解和推理。

Adaptive RAG 的核心思想在于 “因材施教” —— 根据用户问题的类型,动态调整检索策略和生成方式,从而提供更贴合需求、质量更高的答案。我的这个 Streamlit Demo App,正是为了展示这一理念而生。
image.png|500

项目亮点: 从“分类”到“自适应”的 RAG 流程

我的 Demo App 也致力于揭示 RAG 技术的内在逻辑,不依赖于复杂的python库,如LangChain 和 FAISS。我使用了 Streamlit 框架来构建用户界面,专注于RAG逻辑的实现,在 RAG 的核心实现上,我尽量保持了代码的清晰性和可读性,以及前端的过程处理的直观和详细。下面我们看看核心代码:

  • 智能 Query 分类 (Intelligent Query Classification): 这是自适应 RAG 的“大脑”。App 首先会对用户提出的问题进行分类,判断其属于 事实性 (Factual)分析性 (Analytical)观点性 (Opinion) 还是 情境性 (Contextual) 等类型。

    def classify_query_ollama(query: str, model: str = OLLAMA_CLASSIFY_MODEL) -> str:
        """Classifies the query using a local Ollama model."""
        # ... (与 Ollama 连接和错误处理代码) ...
    
        system_prompt = f"""You are a query classification expert. ... (分类指令) ..."""
        user_prompt = f"User Query: \"{query}\"\n\nClassify this query."
    
        try:
            response = ollama_client.chat(
                model=model,
                messages=[
                    {'role': 'system', 'content': system_prompt},
                    {'role': 'user', 'content': user_prompt}
                ],
                options={'temperature': 0.1} # 低温度,保证分类的确定性
            )
            raw_category = response['message']['content'].strip()
            # ... (类别提取和验证代码) ...
            return extracted_category
    
        except Exception as e:
            # ... (错误处理代码) ...
            return "Factual" # 分类失败时,默认使用事实性策略
    
    

    代码特点与优势: 我使用了 Ollama 本地模型比如qwen2.5:7b来进行 Query 分类。相较于远程 API,本地模型具有 更高的隐私性更低的延迟。 以及使用了deepseek api来进行检索生成。
    image.png|500
    classify_query_ollama 函数的核心逻辑在于构建合适的 System Prompt, 指导 Ollama 模型准确地将用户问题划分类别。低温度 (temperature=0.1) 的设置,保证了分类结果的 一致性和可靠性

  • 自适应检索策略路由 (Adaptive Retrieval Strategy Routing): 根据 Query 分类结果,App 会选择不同的检索策略。目前,我定义了四种基本的检索策略,分别对应四种 Query 类型:factual_retrieval_strategyanalytical_retrieval_strategyopinion_retrieval_strategy, 和 contextual_retrieval_strategy

    def adaptive_retrieval(
        query: str,
        query_type: str,
        vector_store: SimpleVectorStore,
        bm25: Optional[BM25Okapi],
        all_chunks: List[Dict[str, Any]],
        k_vector: int, k_bm25: int, k_final: int,
        user_context: Optional[str] = None
    ) -> List[Dict[str, Any]]:
        """Selects and executes the retrieval strategy based on query type."""
    
        strategy_map = {
            "Factual": factual_retrieval_strategy,
            "Analytical": analytical_retrieval_strategy,
            "Opinion": opinion_retrieval_strategy,
            "Contextual": contextual_retrieval_strategy,
        }
        retrieval_function = strategy_map.get(query_type, factual_retrieval_strategy)
    
        try:
            results = retrieval_function(
                query=query,
                vector_store=vector_store,
                bm25=bm25,
                all_chunks=all_chunks,
                k_vector=k_vector, k_bm25=k_bm25, k_final=k_final,
                user_context=user_context
            )
            return results
        except Exception as e:
            # ... (错误处理代码) ...
            return []
    

    代码特点与优势: adaptive_retrieval 函数充当了 策略路由器的角色。它根据 query_type 动态地调用不同的检索函数。虽然目前 Demo App 中的 factual_retrieval_strategy 等函数还仅仅是简单的 Hybrid Search,但这个框架已经为未来 更复杂的自适应检索逻辑 预留了扩展空间。例如,针对分析性问题,我们可以设计更精细的子查询分解或关系抽取策略;针对观点性问题,可以引入情感分析来提升检索效果。

  • Hybrid Search (融合检索): 在检索层面,我采用了 Hybrid Search 策略,融合了 向量检索 (Vector Search) 和 关键词检索 (BM25)。

    def hybrid_search(
        query: str, vector_store: SimpleVectorStore, bm25: Optional[BM25Okapi],
        all_chunks: List[Dict[str, Any]], k_vector: int, k_bm25: int, k_final: int
    ) -> List[Dict[str, Any]]:
        """Performs hybrid search using vector similarity and BM25, with Reciprocal Rank Fusion."""
        # ... (获取 Query Embedding 代码) ...
        vector_results = vector_store.search(query_embedding, k=k_vector) # 向量检索
        bm25_results = search_bm25(bm25, query, all_chunks, k=k_bm25) # BM25 关键词检索
        fused_scores = reciprocal_rank_fusion([vector_results, bm25_results], k_param=RRF_K) # 互惠排名融合
        fused_ranked_ids = sorted(fused_scores.keys(), key=lambda x: fused_scores[x], reverse=True)
        # ... (根据融合排名选择最终 Chunk 代码) ...
        return final_chunks
    

    代码特点与优势: Hybrid Search 结合了语义向量检索和关键词检索的优点,提升了检索的召回率和准确率reciprocal_rank_fusion (互惠排名融合) 算法被用于有效地融合两种检索结果,确保排名靠前的结果既具有语义相关性,又兼顾关键词匹配度。

  • 自适应 Response 生成 (Adaptive Response Generation): 类似于检索策略,Response 生成阶段也根据 Query 类型,采用了不同的 System Prompt

    def generate_adaptive_response(
        query: str,
        query_type: str,
        context_chunks: List[Dict[str, Any]],
        generation_model: str = "deepseek-chat",
        use_ollama_for_generation: bool = False
    ) -> Tuple[Optional[str], Optional[str]]:
        """Generates response using a selected prompt based on query type."""
        # ... (准备 Context 代码) ...
    
        prompts = {
            "Factual": f"{base_instruction} Focus on extracting the specific fact requested.",
            "Analytical": f"{base_instruction} Provide a reasoned analysis, comparison, or summary ...",
            "Opinion": f"{base_instruction} Identify and report the opinions or sentiments expressed ...",
            "Contextual": f"{base_instruction} Use the provided context to answer the question, considering it might relate to previous interactions ...",
        }
        system_prompt = prompts.get(query_type, prompts["Factual"]) # 根据 Query 类型选择 System Prompt
    
        final_prompt_content = f"""{system_prompt}
    
    Context:
    {context}
    {'... (context truncated)' if truncated else ''}
    
    Question: {query}
    
    Answer:"""
    
        # ... (调用 LLM 生成 Response 代码 - DeepSeek 或 Ollama) ...
        return generated_text, source_info
    

    代码特点与优势: 针对不同类型的 Query,定制 System Prompt,指导 LLM 更好地理解用户意图,并生成更符合预期的答案。例如,对于事实性问题,Prompt 强调 “提取事实”;对于分析性问题,则引导 LLM 进行 “分析和总结”。 用户可以灵活选择使用 DeepSeek API (默认) 或 本地 Ollama 模型 进行 Response 生成。

Demo App 亮点总结:

  • 自适应 RAG 流程: 完整演示了从 Query 分类到自适应检索和生成的 RAG 流程。
  • 本地 Ollama 支持: Query 分类和 Embedding 生成都可使用本地 Ollama 模型,保障隐私和低延迟。
  • Hybrid Search 融合检索: 结合向量检索和关键词检索,提升检索效果。
  • 可扩展的架构: 策略路由和自适应 Prompt 的框架,为未来更复杂的自适应 RAG 策略预留了空间。
  • Streamlit 交互界面: 简洁易用,方便用户上传文档、提问和查看结果。

适用人群与应用场景

我认为这个 Demo App 特别适合以下人群:

  • RAG 技术学习者: 希望通过实践理解 Adaptive RAG 原理的开发者。
  • AI 应用开发者: 希望探索如何构建更智能、更灵活的 RAG 系统的工程师。
  • LLM 爱好者: 对 RAG 技术和 LLM 应用感兴趣的技术爱好者。

快速上手,体验 Adaptive RAG

如果你也想亲身体验 Adaptive RAG 的魅力,或者想深入了解代码实现细节,欢迎联系作者并亲自运行这个 Demo App!
adap-检索1.gif|500

image.png|500

未来展望

虽然目前的 Demo App 还比较基础,但我计划在未来继续完善它,例如:

  • 更精细的检索策略: 针对不同 Query 类型,实现更高级的检索算法。
  • 对话历史支持: 引入对话上下文理解,实现真正的 Contextual RAG。
  • 更多模型集成: 支持更多的本地 LLM 和 Embedding 模型。
  • 更完善的评估指标: 加入客观评估指标,量化 Adaptive RAG 的性能提升。

我希望这个 Demo App 能够成为大家学习和探索 Adaptive RAG 的一个起点。 欢迎大家 关注这个项目,提出宝贵的意见和建议,一起推动AI技术的发展!


如果大家比较感兴趣,后期考虑将优化后的完整代码进行开源。

如果有想尝鲜的朋友可以后台私信或者点击喜欢作者。

希望这篇博文草稿对您有所帮助!
相关文章:

告别繁琐配置!这款免费开源的 AsrTools,让语音转文字效率飞起!

Auto-Deep-Research:告别昂贵的Deep Research,拥抱开源的AI助手!

MCP,你的大模型USB通用接口 - 向来如此便对吗的文章 - 知乎

Crawl4AI进阶:AI 时代的智能网页信息提取利器 - 向来如此便对吗的文章 - 知乎

Crawl4AI: 赋能AI用户的开源智能网页爬虫与数据提取 - 向来如此便对吗的文章 - 知乎

9大AI智能体联袂复盘,揭秘华尔街投资大师的投资策略 - 向来如此便对吗的文章 - 知乎

每天分析一个开源项目:olmOCR,让 AI 帮你读懂“天书”! - 向来如此便对吗的文章 - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值