RAG技术全景图2025:从青铜到王者的10种实现方式

58 阅读20分钟

你有没有遇到过这种崩溃的情况:

公司要做个AI知识库,你信心满满地用LangChain搭了个RAG系统,结果:

  • 用户问个稍微复杂点的问题,AI就开始"我不太确定"
  • 文档明明有答案,检索却找不到相关的片段
  • 多轮对话刚到第三轮,AI就把之前说的全忘了
  • 老板问"我们上季度销售额多少",AI答"抱歉我无法获取实时数据"

然后你百度了一圈,GitHub翻了三页,最后发现......

RAG根本不是你想象的那种"文档检索+LLM"的简单拼接!

今天咱们就来彻底搞懂2025年RAG的所有玩法,从基础的Naive RAG到前沿的Agentic RAG,保证你看完就能在公司里当RAG专家。


先打个比方:为什么RAG比你想的复杂?

RAG就像你在海底捞等位拿的那个号码牌。

你以为的RAG:

把文档塞进向量库 → 用户提问 → 检索相关内容 → LLM回答

实际的RAG:

用户问"你们公司2024年Q3的销售政策是什么?"

简单RAG:检索到"2024"、"销售"、"政策"这些关键词,但找到的是2024年Q1的旧政策

高级RAG:理解了"Q3"这个时间概念,找到了对应的时间范围,还关联了相关政策变更的历史记录

看出差距了吗?


RAG技术演进路线图

先给你一张全景图,让你知道自己在哪个段位:

段位技术方案特点适用场景
🥉 青铜Naive RAG简单粗暴,能跑就行Demo演示、简单问答
🥈 白银Advanced RAG混合检索+重排序生产环境基础版
🥇 黄金Modular RAG模块化设计,可插拔中大型项目
💎 铂金Self-RAG自我判断何时检索复杂推理任务
👑 钻石Corrective RAG自动纠错和修复高准确性要求
🏆 王者Agentic RAG智能体驱动,会主动行动企业级复杂应用

下面一个个来拆解。


1. Naive RAG(青铜段位)- 新手的第一个坑

这是什么: 最基础的RAG实现,就是把文档切成chunks,向量化后存进向量数据库,检索时用相似度找最相关的几个chunks。

# ❌ 很多人的第一版实现(包括三个月前的我)
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings

def naive_rag(query, documents):
    # 简单粗暴地切分文档
    texts = [doc.page_content for doc in documents]
    
    # 直接向量化
    embeddings = OpenAIEmbeddings()
    vectorstore = FAISS.from_texts(texts, embeddings)
    
    # 检索最相关的3个片段
    docs = vectorstore.similarity_search(query, k=3)
    
    return "\n".join([doc.page_content for doc in docs])

为什么这玩意儿会坑你:

  1. 语义漂移:文档切得太碎,上下文丢失严重
  2. 检索精度低:只看相似度,不考虑时序、重要性等因素
  3. 无语义理解:"Q3"和"第三季度"在它看来是完全不同的词
  4. 冷启动问题:新文档进来需要重新整个向量化

适用场景:

  • 文档结构简单,问题都是事实性查询
  • 对准确性要求不高,做个demo给老板看
  • 你刚接触RAG,想先跑个"Hello World"

2. Advanced RAG(白银段位)- 职场必备技能

看到Naive RAG的问题后,聪明人开始优化了。核心思路:在检索前、检索中、检索后都加料

2.1 检索前优化:查询改写

# ✅ 查询扩展 - 让搜索更全面
def query_expansion(query, llm):
    prompt = f"""
    将以下查询扩展为3个相关的搜索查询,覆盖不同角度:
    原始查询:{query}
    
    返回格式:
    1. [扩展查询1]
    2. [扩展查询2]
    3. [扩展查询3]
    """
    expanded_queries = llm.invoke(prompt)
    return [query] + parse_queries(expanded_queries)

# 用户问:"Python性能优化"
# 扩展后:
# 1. Python性能优化
# 2. Python代码加速技巧
# 3. Python内存优化方法
# 4. Python并发编程提升性能

2.2 检索中优化:混合检索

# ✅ 混合检索 - 关键词 + 语义双保险
from langchain.retrievers import BM25Retriever, EnsembleRetriever

def hybrid_search(query, documents):
    # BM25:基于关键词匹配(擅长精确匹配)
    bm25_retriever = BM25Retriever.from_documents(documents)
    bm25_retriever.k = 5
    
    # 向量检索:基于语义相似度(擅长理解意图)
    vector_retriever = FAISS.from_documents(
        documents, embeddings
    ).as_retriever(search_kwargs={"k": 5})
    
    # 组合两种检索器,用RRF算法融合结果
    ensemble_retriever = EnsembleRetriever(
        retrievers=[bm25_retriever, vector_retriever],
        weights=[0.4, 0.6]  # 语义检索权重稍高
    )
    
    return ensemble_retriever.get_relevant_documents(query)

为什么要混合?

想象一下:用户搜"React Hooks"

  • 纯向量检索可能返回"Vue Composition API"(语义相似但不是用户要的)
  • 纯关键词检索可能漏掉"useState和useEffect的使用技巧"(没有精确匹配Hooks)
  • 混合检索:两个都能找到,互补短板

2.3 检索后优化:重排序

# ✅ 重排序 - 让最相关的排在最前面
from sentence_transformers import CrossEncoder

def rerank_results(query, documents, top_k=3):
    # 使用交叉编码器重排序
    cross_encoder = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
    
    # 计算每个文档与查询的相关性分数
    pairs = [[query, doc.page_content] for doc in documents]
    scores = cross_encoder.predict(pairs)
    
    # 按分数排序,取top_k
    scored_docs = list(zip(documents, scores))
    scored_docs.sort(key=lambda x: x[1], reverse=True)
    
    return [doc for doc, score in scored_docs[:top_k]]

重排序的骚操作:

  • 初筛用便宜的向量检索,召回100个候选
  • 精排用贵但准的交叉编码器,从100个里选出最好的5个
  • 成本和效果的完美平衡

3. Modular RAG(黄金段位)- 大厂的选择

当RAG系统变得复杂时,大厂们把它拆成了模块,像搭乐高一样灵活组合:

# 🏗️ Modular RAG - 像搭乐高一样灵活组合
class ModularRAG:
    def __init__(self):
        # 查询理解模块
        self.query_analyzer = QueryAnalyzer()
        
        # 多种检索模块,按需选择
        self.retrieval_modules = {
            "semantic": SemanticRetriever(),      # 语义检索
            "keyword": KeywordRetriever(),        # 关键词检索
            "time_aware": TimeAwareRetriever(),   # 时间感知检索
            "graph": GraphRetriever(),            # 图谱检索
            "hybrid": HybridRetriever()           # 混合检索
        }
        
        # 后处理模块
        self.reranker = CrossEncoderReranker()
        self.context_compressor = ContextCompressor()
        
        # 路由器:决定用哪些模块
        self.router = QueryRouter()

    def process(self, query):
        # 1. 分析查询类型
        query_type = self.query_analyzer.analyze(query)
        
        # 2. 路由器决定使用哪些检索模块
        selected_modules = self.router.route(query_type)
        
        # 3. 并行执行多个检索策略
        all_results = []
        for module_name in selected_modules:
            results = self.retrieval_modules[module_name].retrieve(query)
            all_results.extend(results)
        
        # 4. 重排序 + 去重
        reranked = self.reranker.rerank(query, all_results)
        
        # 5. 上下文压缩(去掉冗余信息)
        final_context = self.context_compressor.compress(query, reranked)
        
        return final_context

模块化的核心优势:

  • 可插拔设计:需要新的检索策略?加个模块就行
  • 动态路由:根据问题类型自动选择最优的检索组合
  • 并行处理:多个检索策略同时跑,取最优结果
  • 易于维护:每个模块独立,改一个不影响其他

查询路由的实现思路:

class QueryRouter:
    def route(self, query_analysis):
        """根据查询分析结果,决定使用哪些检索模块"""
        modules = []
        
        # 如果涉及时间,加入时间感知检索
        if query_analysis.has_time_constraint:
            modules.append("time_aware")
        
        # 如果是实体关系查询,加入图谱检索
        if query_analysis.is_entity_relation:
            modules.append("graph")
        
        # 如果包含专业术语,加入关键词检索
        if query_analysis.has_technical_terms:
            modules.append("keyword")
        
        # 默认都加语义检索
        modules.append("semantic")
        
        return modules

4. Self-RAG(铂金段位)- 会思考的RAG

核心理念:不是所有问题都需要检索!

你问ChatGPT"1+1等于几",它需要去检索文档吗?显然不需要。Self-RAG就是让AI自己判断什么时候该检索,什么时候直接回答。

# 🧠 Self-RAG - 会自我判断的RAG
class SelfRAG:
    def __init__(self, llm, retriever):
        self.llm = llm
        self.retriever = retriever

    def process(self, query):
        # 步骤1:判断是否需要检索
        need_retrieval = self._should_retrieve(query)
        
        if need_retrieval:
            # 步骤2:检索相关信息
            docs = self.retriever.get_relevant_documents(query)
            
            # 步骤3:评估检索结果的相关性
            relevant_docs = self._filter_relevant(query, docs)
            
            if relevant_docs:
                # 步骤4:基于检索内容生成答案
                answer = self._generate_with_context(query, relevant_docs)
                
                # 步骤5:验证答案是否被检索内容支持
                if self._is_supported(answer, relevant_docs):
                    return answer
                else:
                    # 答案不被支持,重新生成
                    return self._regenerate(query, relevant_docs)
            else:
                # 检索结果不相关,直接用LLM回答
                return self._generate_without_context(query)
        else:
            # 不需要检索,直接回答
            return self._generate_without_context(query)

    def _should_retrieve(self, query):
        """判断是否需要检索"""
        prompt = f"""
        判断回答以下问题是否需要检索外部信息:
        问题:{query}
        
        如果问题涉及:
        - 具体的数据、时间、地点
        - 最近发生的事件
        - 专业领域的细节
        - 公司内部信息
        那么需要检索。
        
        如果问题是:
        - 常识性问题
        - 简单计算
        - 通用概念解释
        那么不需要检索。
        
        回答:需要检索 或 不需要检索
        """
        result = self.llm.invoke(prompt)
        return "需要检索" in result.content

Self-RAG的三个关键判断:

  1. Retrieve Token:要不要检索?
  2. ISREL Token:检索结果相关吗?
  3. ISSUP Token:生成的答案有依据吗?
用户问:"Python是什么?"
→ 判断:常识问题,不需要检索
→ 直接回答

用户问:"我们公司上季度的KPI完成情况?"
→ 判断:涉及具体数据,需要检索
→ 检索 → 验证 → 回答

5. Corrective RAG(钻石段位)- 自我纠错的RAG

核心改进:检索到错误内容也不怕,系统会自动修复!

# 🔧 Corrective RAG - 会自我修复的RAG
class CorrectiveRAG:
    def __init__(self, llm, retriever, web_search=None):
        self.llm = llm
        self.retriever = retriever
        self.web_search = web_search  # 备用的网络搜索
        self.quality_evaluator = RetrievalQualityEvaluator()

    def process(self, query, max_attempts=3):
        for attempt in range(max_attempts):
            # 1. 检索
            docs = self.retriever.get_relevant_documents(query)
            
            # 2. 评估每个文档的质量
            evaluated_docs = []
            for doc in docs:
                score = self.quality_evaluator.evaluate(query, doc)
                evaluated_docs.append((doc, score))
            
            # 3. 根据评估结果分类
            correct_docs = [d for d, s in evaluated_docs if s == "correct"]
            ambiguous_docs = [d for d, s in evaluated_docs if s == "ambiguous"]
            incorrect_docs = [d for d, s in evaluated_docs if s == "incorrect"]
            
            # 4. 决定下一步行动
            if correct_docs:
                # 有正确的文档,直接生成答案
                return self._generate_answer(query, correct_docs)
            
            elif ambiguous_docs and not incorrect_docs:
                # 只有模糊的文档,尝试知识精炼
                refined_docs = self._refine_knowledge(query, ambiguous_docs)
                return self._generate_answer(query, refined_docs)
            
            else:
                # 检索结果不靠谱,启动纠错机制
                if attempt < max_attempts - 1:
                    # 尝试查询改写
                    query = self._rewrite_query(query)
                    continue
                else:
                    # 最后一次尝试:用网络搜索兜底
                    if self.web_search:
                        web_results = self.web_search.search(query)
                        return self._generate_answer(query, web_results)
                    else:
                        return "抱歉,没有找到相关信息"

    def _rewrite_query(self, query):
        """查询改写:换个方式问"""
        prompt = f"""
        以下查询没有找到好的结果,请改写成更容易检索到答案的形式:
        原查询:{query}
        
        改写要求:
        1. 保持原意
        2. 使用更通用的词汇
        3. 拆分复杂问题
        
        改写后的查询:
        """
        return self.llm.invoke(prompt).content

class RetrievalQualityEvaluator:
    def evaluate(self, query, doc):
        """评估检索结果的质量"""
        prompt = f"""
        评估以下文档对于回答查询的有用程度:
        
        查询:{query}
        文档:{doc.page_content}
        
        评估标准:
        - correct:文档直接回答了查询,信息准确可靠
        - ambiguous:文档部分相关,但信息不完整或需要补充
        - incorrect:文档与查询无关或信息错误
        
        评估结果(只回答correct/ambiguous/incorrect):
        """
        result = self.llm.invoke(prompt).content.strip().lower()
        return result if result in ["correct", "ambiguous", "incorrect"] else "ambiguous"

Corrective RAG的纠错流程:

用户提问 → 检索文档 → 质量评估
                         ↓
              ┌─────────┼─────────┐
              ↓         ↓         ↓
           正确      模糊      错误
              ↓         ↓         ↓
          直接生成   知识精炼   查询改写
                         ↓         ↓
                      生成答案   重新检索
                                   ↓
                              还是不行?
                                   ↓
                              网络搜索兜底

6. Adaptive RAG(钻石段位)- 因人而异的RAG

核心理念:不同用户、不同场景,用不同的策略!

# 🎯 Adaptive RAG - 自适应的RAG
class AdaptiveRAG:
    def __init__(self, llm, retriever):
        self.llm = llm
        self.retriever = retriever
        self.strategies = {
            "simple": self._simple_strategy,      # 简单问题
            "complex": self._complex_strategy,    # 复杂问题
            "multi_hop": self._multi_hop_strategy # 多跳推理
        }

    def process(self, query, user_context=None):
        # 1. 分析查询复杂度
        complexity = self._analyze_complexity(query)
        
        # 2. 选择对应策略
        strategy = self.strategies.get(complexity, self._simple_strategy)
        
        # 3. 执行策略
        return strategy(query, user_context)

    def _analyze_complexity(self, query):
        """分析查询复杂度"""
        prompt = f"""
        分析以下查询的复杂度:
        查询:{query}
        
        复杂度分类:
        - simple:单一事实查询,如"Python是什么"
        - complex:需要综合多个信息,如"比较React和Vue的优缺点"
        - multi_hop:需要多步推理,如"A公司CEO的母校在哪个城市"
        
        复杂度(只回答simple/complex/multi_hop):
        """
        return self.llm.invoke(prompt).content.strip().lower()

    def _simple_strategy(self, query, user_context):
        """简单策略:直接检索+生成"""
        docs = self.retriever.get_relevant_documents(query, k=3)
        return self._generate(query, docs)

    def _complex_strategy(self, query, user_context):
        """复杂策略:多角度检索+综合"""
        # 扩展查询,获取更多视角
        expanded_queries = self._expand_query(query)
        
        all_docs = []
        for eq in expanded_queries:
            docs = self.retriever.get_relevant_documents(eq, k=2)
            all_docs.extend(docs)
        
        # 去重 + 重排序
        unique_docs = self._deduplicate(all_docs)
        reranked_docs = self._rerank(query, unique_docs)
        
        return self._generate(query, reranked_docs[:5])

    def _multi_hop_strategy(self, query, user_context):
        """多跳策略:分解问题,逐步推理"""
        # 分解问题
        sub_questions = self._decompose_query(query)
        
        # 逐个回答子问题
        intermediate_answers = []
        for sq in sub_questions:
            docs = self.retriever.get_relevant_documents(sq, k=2)
            answer = self._generate(sq, docs)
            intermediate_answers.append({"question": sq, "answer": answer})
        
        # 综合所有中间答案,生成最终答案
        return self._synthesize(query, intermediate_answers)

    def _decompose_query(self, query):
        """将复杂问题分解为子问题"""
        prompt = f"""
        将以下复杂问题分解为可以独立回答的子问题:
        问题:{query}
        
        子问题列表(每行一个):
        """
        result = self.llm.invoke(prompt).content
        return [q.strip() for q in result.split('\n') if q.strip()]

Adaptive RAG的适应维度:

维度简单模式复杂模式
检索数量3个文档10+个文档
查询扩展不扩展多角度扩展
重排序可选必须
推理步骤单步多步
响应时间慢但准

7. Graph RAG(钻石段位)- 理解关系的RAG

2024-2025年的大热门! 用知识图谱增强RAG,让AI理解实体之间的关系。

# 🕸️ Graph RAG - 知识图谱增强的RAG
class GraphRAG:
    def __init__(self, llm, vector_store, graph_db):
        self.llm = llm
        self.vector_store = vector_store
        self.graph_db = graph_db  # Neo4j、NetworkX等
        self.entity_extractor = EntityExtractor()

    def build_knowledge_graph(self, documents):
        """从文档构建知识图谱"""
        for doc in documents:
            # 1. 提取实体
            entities = self.entity_extractor.extract(doc.page_content)
            
            # 2. 提取实体间的关系
            relations = self._extract_relations(doc.page_content, entities)
            
            # 3. 添加到图数据库
            for entity in entities:
                self.graph_db.add_node(entity.name, entity.type, entity.properties)
            
            for relation in relations:
                self.graph_db.add_edge(
                    relation.source, 
                    relation.target, 
                    relation.type
                )

    def retrieve(self, query):
        """图谱增强的检索"""
        # 1. 从查询中提取实体
        query_entities = self.entity_extractor.extract(query)
        
        # 2. 在图谱中查找相关实体和关系
        graph_context = []
        for entity in query_entities:
            # 获取实体的邻居节点(1-2跳)
            neighbors = self.graph_db.get_neighbors(entity.name, depth=2)
            # 获取相关的关系路径
            paths = self.graph_db.get_paths(entity.name)
            graph_context.extend(neighbors + paths)
        
        # 3. 传统向量检索
        vector_results = self.vector_store.similarity_search(query, k=5)
        
        # 4. 融合图谱上下文和向量检索结果
        combined_context = self._merge_contexts(graph_context, vector_results)
        
        return combined_context

    def _extract_relations(self, text, entities):
        """提取实体间的关系"""
        entity_names = [e.name for e in entities]
        prompt = f"""
        从以下文本中提取实体之间的关系:
        
        文本:{text}
        实体列表:{entity_names}
        
        返回格式(每行一个关系):
        实体1 | 关系类型 | 实体2
        
        例如:
        马云 | 创立 | 阿里巴巴
        阿里巴巴 | 总部位于 | 杭州
        """
        result = self.llm.invoke(prompt).content
        return self._parse_relations(result)

Graph RAG vs 传统RAG的对比:

用户问:"马云创立的公司的总部在哪?"

传统RAG:
→ 检索"马云""公司""总部"相关文档
→ 可能找到很多不相关的内容
→ 答案可能不准确

Graph RAG:
→ 识别实体:马云
→ 图谱查询:马云 --创立--> 阿里巴巴 --总部位于--> 杭州
→ 直接得到答案:杭州

Graph RAG的独特优势:

  1. 关系理解:知道"马云"和"阿里巴巴"的关系
  2. 多跳推理:能推理出"马云创立的公司"是谁
  3. 可解释性:能展示推理路径
  4. 全局视角:理解整个知识网络的结构

适用场景:

  • 金融风控:理解公司间的股权关系
  • 医疗诊断:理解症状、疾病、药物的关系
  • 法律咨询:理解法条、案例、当事人关系
  • 企业知识库:理解组织架构、项目关系

8. RAG Fusion(钻石段位)- 多路召回融合

核心思路: 用LLM生成多个查询,从不同角度检索,然后融合结果。

# 🔀 RAG Fusion - 多路召回融合
class RAGFusion:
    def __init__(self, llm, retriever):
        self.llm = llm
        self.retriever = retriever

    def process(self, query):
        # 1. 生成多个相关查询
        generated_queries = self._generate_queries(query)
        all_queries = [query] + generated_queries
        
        # 2. 对每个查询进行检索
        all_results = {}
        for q in all_queries:
            results = self.retriever.get_relevant_documents(q)
            for rank, doc in enumerate(results):
                doc_id = doc.metadata.get('id', hash(doc.page_content))
                if doc_id not in all_results:
                    all_results[doc_id] = {"doc": doc, "ranks": []}
                all_results[doc_id]["ranks"].append(rank + 1)
        
        # 3. 使用RRF(Reciprocal Rank Fusion)融合排序
        fused_results = self._reciprocal_rank_fusion(all_results)
        
        return fused_results

    def _generate_queries(self, query, num_queries=3):
        """生成多个相关查询"""
        prompt = f"""
        基于以下查询,生成{num_queries}个不同角度的相关查询:
        
        原始查询:{query}
        
        要求:
        1. 每个查询覆盖原问题的不同方面
        2. 使用不同的表达方式
        3. 保持与原问题的相关性
        
        生成的查询(每行一个):
        """
        result = self.llm.invoke(prompt).content
        return [q.strip() for q in result.split('\n') if q.strip()][:num_queries]

    def _reciprocal_rank_fusion(self, all_results, k=60):
        """RRF融合算法"""
        fused_scores = {}
        
        for doc_id, data in all_results.items():
            # RRF公式:score = sum(1 / (k + rank))
            score = sum(1 / (k + rank) for rank in data["ranks"])
            fused_scores[doc_id] = {"doc": data["doc"], "score": score}
        
        # 按分数排序
        sorted_results = sorted(
            fused_scores.values(), 
            key=lambda x: x["score"], 
            reverse=True
        )
        
        return [item["doc"] for item in sorted_results]

RAG Fusion的工作流程:

用户问:"如何提高Python代码性能?"
        ↓
    生成多个查询:
    1. "Python性能优化技巧"
    2. "Python代码加速方法"
    3. "Python内存优化"
    4. "Python并发编程"
        ↓
    分别检索,每个查询返回Top 5
        ↓
    RRF融合:出现在多个结果中的文档得分更高
        ↓
    返回融合后的Top K结果

9. Agentic RAG(王者段位)- 会主动行动的RAG

这是2025年最前沿的方向! RAG系统变成了智能体,不只是被动回答,还会主动规划、调用工具、迭代优化。

# 🤖 Agentic RAG - 智能体驱动的RAG
class AgenticRAG:
    def __init__(self, llm):
        self.llm = llm
        self.tools = {
            "search_knowledge_base": KnowledgeBaseSearcher(),
            "web_search": WebSearcher(),
            "database_query": DatabaseQuerier(),
            "calculator": Calculator(),
            "code_executor": CodeExecutor()
        }
        self.planner = TaskPlanner()
        self.memory = ConversationMemory()

    def process(self, query):
        # 1. 任务规划 - 分解复杂问题
        plan = self.planner.create_plan(query, self.tools.keys())
        
        # 2. 执行计划 - 动态选择工具
        results = []
        for step in plan.steps:
            tool_name = step.tool
            tool_params = step.parameters
            
            # 执行工具
            result = self.tools[tool_name].execute(**tool_params)
            results.append({"step": step.description, "result": result})
            
            # 根据中间结果,可能需要调整计划
            if step.requires_adaptation:
                plan = self.planner.adapt_plan(plan, result)
        
        # 3. 综合所有结果生成最终答案
        final_answer = self._synthesize(query, results)
        
        # 4. 保存到记忆
        self.memory.save(query, final_answer)
        
        return final_answer

class TaskPlanner:
    def create_plan(self, query, available_tools):
        """创建执行计划"""
        prompt = f"""
        你是一个任务规划专家。根据用户查询,制定执行计划。
        
        用户查询:{query}
        可用工具:{available_tools}
        
        工具说明:
        - search_knowledge_base:搜索内部知识库
        - web_search:搜索互联网
        - database_query:查询数据库
        - calculator:进行数学计算
        - code_executor:执行代码
        
        请制定执行计划,格式如下:
        步骤1:[工具名] - [参数] - [目的]
        步骤2:[工具名] - [参数] - [目的]
        ...
        
        执行计划:
        """
        result = self.llm.invoke(prompt).content
        return self._parse_plan(result)

Agentic RAG的实际例子:

用户问:"我们公司Q3的销售额相比Q2增长了多少?"

传统RAG:
→ 检索"Q3销售额""Q2销售额"
→ 可能找不到直接的对比数据
→ 回答不准确

Agentic RAG:
→ 规划:
   步骤1:database_query - 查询Q2销售额
   步骤2:database_query - 查询Q3销售额
   步骤3:calculator - 计算增长率
→ 执行:
   Q2销售额:1000万
   Q3销售额:1200万
   增长率:(1200-1000)/1000 = 20%
→ 回答:"Q3销售额相比Q2增长了20%,从1000万增长到1200万"

Agentic RAG的核心特性:

特性说明
主动规划不只是被动回答,会主动分解问题
工具调用能调用各种外部工具和API
动态调整根据中间结果调整执行策略
多步推理能处理需要多个步骤的复杂问题
记忆能力记住对话历史,支持多轮交互

10. Multi-Modal RAG(王者段位)- 多模态RAG

不只处理文本,还能处理图片、表格、音视频!

# 🎨 Multi-Modal RAG - 多模态RAG
class MultiModalRAG:
    def __init__(self):
        self.text_encoder = TextEncoder()
        self.image_encoder = ImageEncoder()  # CLIP等
        self.table_encoder = TableEncoder()
        self.text_store = VectorStore("text")
        self.image_store = VectorStore("image")
        self.table_store = VectorStore("table")

    def index_document(self, document):
        """索引多模态文档"""
        # 索引文本
        if document.text:
            text_embedding = self.text_encoder.encode(document.text)
            self.text_store.add(document.id, text_embedding, document.text)
        
        # 索引图片
        if document.images:
            for img in document.images:
                img_embedding = self.image_encoder.encode(img)
                # 同时生成图片描述
                img_caption = self._generate_caption(img)
                self.image_store.add(img.id, img_embedding, img_caption)
        
        # 索引表格
        if document.tables:
            for table in document.tables:
                # 将表格转换为结构化描述
                table_desc = self._table_to_text(table)
                table_embedding = self.table_encoder.encode(table_desc)
                self.table_store.add(table.id, table_embedding, table)

    def retrieve(self, query, modalities=["text", "image", "table"]):
        """多模态检索"""
        results = {}
        
        # 文本检索
        if "text" in modalities:
            text_query_emb = self.text_encoder.encode(query)
            results["text"] = self.text_store.search(text_query_emb, k=5)
        
        # 图片检索(文本到图片)
        if "image" in modalities:
            # 使用CLIP等模型,支持文本查询图片
            img_query_emb = self.image_encoder.encode_text(query)
            results["image"] = self.image_store.search(img_query_emb, k=3)
        
        # 表格检索
        if "table" in modalities:
            table_query_emb = self.table_encoder.encode(query)
            results["table"] = self.table_store.search(table_query_emb, k=3)
        
        return self._merge_results(results)

    def _generate_caption(self, image):
        """生成图片描述"""
        # 使用视觉语言模型生成描述
        return vision_model.generate_caption(image)

    def _table_to_text(self, table):
        """将表格转换为文本描述"""
        prompt = f"""
        将以下表格转换为自然语言描述:
        {table.to_string()}
        
        描述应包含:
        1. 表格的主题
        2. 关键数据点
        3. 数据趋势(如有)
        """
        return self.llm.invoke(prompt).content

Multi-Modal RAG的应用场景:

  • 技术文档:代码 + 架构图 + 流程图
  • 产品手册:文字说明 + 产品图片 + 规格表格
  • 财务报告:分析文字 + 数据图表 + 财务表格
  • 医疗诊断:病历文字 + 医学影像 + 检验报告

实战踩坑指南:血泪换来的经验

坑1:文档切分不合理,上下文丢失

# ❌ 脑残式切分:固定长度,不管语义
def stupid_chunking(text, chunk_size=500):
    return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]
    # 问题:可能把一句话切成两半

# ✅ 智能切分:保持语义完整性
from langchain.text_splitter import RecursiveCharacterTextSplitter

def smart_chunking(text):
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=1000,
        chunk_overlap=200,  # 重叠部分保留上下文
        separators=["\n\n", "\n", "。", ",", " "],  # 按优先级切分
        length_function=len
    )
    return splitter.split_text(text)

坑2:Embedding模型选错,检索效果差

# ❌ 错误选择:用通用模型处理专业领域
embeddings = OpenAIEmbeddings()  # 通用模型

# ✅ 正确选择:根据场景选模型
# 中文场景
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")

# 英文场景
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-en-v1.5")

# 多语言场景
embeddings = HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large")

坑3:检索数量不合理

# ❌ 贪多嚼不烂:检索太多,LLM看花眼
docs = retriever.get_relevant_documents(query, k=50)

# ❌ 太少不够用:检索太少,信息不全
docs = retriever.get_relevant_documents(query, k=1)

# ✅ 合理数量:根据场景调整
# 简单问答:3-5个
# 复杂分析:5-10个
# 综合报告:10-15个(配合重排序)

坑4:忽视元数据过滤

# ❌ 只看相似度,不管时效性
docs = vectorstore.similarity_search(query, k=5)
# 问题:可能返回过时的文档

# ✅ 结合元数据过滤
docs = vectorstore.similarity_search(
    query, 
    k=5,
    filter={"date": {"$gte": "2024-01-01"}}  # 只要2024年以后的
)

2025年RAG技术趋势预测

趋势1:RAG + Agent深度融合

不再是简单的检索+生成,而是智能体主导的复杂任务处理。

趋势2:多模态RAG成为标配

文本、图片、表格、音视频统一处理。

趋势3:实时更新RAG

知识库实时更新,不需要重新索引整个库。

趋势4:个性化RAG

根据用户画像、历史行为动态调整检索策略。

趋势5:端侧RAG

在手机、边缘设备上运行轻量级RAG。


如何选择适合你的RAG方案?

你的情况推荐方案理由
刚入门,做DemoNaive RAG简单快速,先跑起来
生产环境,预算有限Advanced RAG性价比最高
中大型项目,需要扩展Modular RAG灵活可扩展
高准确性要求Corrective RAG自动纠错
复杂推理任务Self-RAG + Adaptive RAG智能判断
实体关系查询Graph RAG理解关系
企业级复杂应用Agentic RAG全能选手

写在最后

记住一句话:RAG不是银弹,选对方案比堆技术更重要。

不要为了用RAG而用RAG,要先想清楚:

  • 你的用户真正需要什么?
  • 你的数据有什么特点?
  • 你的团队能维护多复杂的系统?

选对适合的RAG方案,比追求最新潮的技术更重要。


你在项目中用的是什么RAG方案?遇到了什么坑?

评论区聊聊,看看有没有更骚的操作。

(如果等不及想动手试试,推荐从LangChain或LlamaIndex开始,它们把这些方案都封装好了,懒人福音~)