小陈的知识图谱
RAGL5 实战重要

高级 RAG 模式

Agentic RAG、Graph RAG、多模态 RAG、Streaming

Agentic RAG

Agentic RAG 将 RAG 系统与 AI Agent 结合,让系统能够主动思考、调用工具、多步推理,而不仅仅是被动地检索和生成。

ReAct 模式

ReAct(Reasoning + Acting)让 Agent 交替进行推理和行动:

用户: "比较一下 Redis 和 Memcached 的区别"
                      │
                      ▼
┌────────────────────────────────────────┐
│  Thought: 用户想知道两者的区别,        │
│  我需要先检索 Redis 相关的文档,         │
│  再检索 Memcached 相关的文档。         │
│                                        │
│  Action: retrieve(query="Redis")       │
│  Observation: [Redis 相关文档]          │
│                                        │
│  Action: retrieve(query="Memcached")   │
│  Observation: [Memcached 相关文档]      │
│                                        │
│  Thought: 现在我有两种技术的文档了,     │
│  可以生成对比分析。                     │
│                                        │
│  Action: generate(comparison)          │
│  Observation: 对比结果                  │
│                                        │
│  Final: 输出对比答案                    │
└────────────────────────────────────────┘

LangGraph 实现

from langgraph.graph import StateGraph, MessagesState
from langgraph.prebuilt import ToolNode
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapper
from langchain_core.messages import SystemMessage
from typing import Literal

定义检索工具

@tool def retrieve_docs(query: str) -> str: """从知识库中检索相关文档""" docs = vector_store.similarity_search(query, k=3) return "\n\n".join([d.page_content for d in docs])

构建 Agent 图

tools = [retrieve_docs] tool_node = ToolNode(tools) def should_continue(state: MessagesState) -> Literal["tools", "end"]: messages = state["messages"] last = messages[-1] return "tools" if last.tool_calls else "end" def call_model(state: MessagesState): messages = state["messages"] response = llm_with_tools.invoke(messages) return {"messages": [response]}

编译图

graph = StateGraph(MessagesState) graph.add_node("agent", call_model) graph.add_node("tools", tool_node) graph.add_edge("agent", "tools", conditional=should_continue) graph.add_edge("tools", "agent") graph.set_entry_point("agent") app = graph.compile()

执行

result = app.invoke({ "messages": [ SystemMessage(content="你是一个 RAG 助手,可以检索知识库回答问题。"), HumanMessage(content="Redis 和 Memcached 有什么区别?"), ] })

Agentic RAG 的优势

特性传统 RAGAgentic RAG
多步推理单次检索 + 生成多轮检索 + 推理
工具调用仅检索检索 + 计算 + API + 数据库
问题分解不支持自动分解复杂问题
循环修正不支持可循环检索直到满意
状态管理无状态有状态(上下文记忆)

Graph RAG

Graph RAG 使用知识图谱(而非向量库)来组织和检索信息,特别适合处理多跳关系和全局性问题。

与向量 RAG 的区别

向量 RAG:
  文档 → 分块 → 向量 → ANN 检索
  优点:语义相似度匹配
  缺点:难以处理多跳关系

Graph RAG:
  实体 → 关系 → 图结构 → 图遍历检索
  优点:关系推理、全局理解
  缺点:需要实体抽取,构建成本高

构建流程

原始文档
    │
    ▼
┌──────────────────┐
│  Entity Extraction│  ──→ LLM 抽取实体和关系
│  (LLM)           │      例:(Redis, 是, 内存数据库)
└────────┬─────────┘       (Redis, 支持, 持久化)
         │
         ▼
┌──────────────────┐
│  Knowledge Graph  │  ──→ Neo4j / NetworkX
│  (图存储)         │      实体 = 节点,关系 = 边
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│  Community        │  ──→ Leiden 算法聚类
│  Detection        │      "缓存技术社区"
└────────┬─────────┘      "NoSQL 社区"
         │
         ▼
┌──────────────────┐
│  Graph Retrieval  │  ──→ 根据问题类型选择
│  (图检索)         │      检索策略
└──────────────────┘

图检索策略

# 使用 NetworkX 构建简单图
import networkx as nx

G = nx.Graph()

添加实体和关系

entities = [ ("Redis", {"type": "database", "desc": "内存数据库"}), ("Memcached", {"type": "database", "desc": "分布式缓存"}), ("持久化", {"type": "concept", "desc": "数据持久存储"}), ] G.add_nodes_from(entities) relations = [ ("Redis", "Memcached", {"relation": "competitor"}), ("Redis", "持久化", {"relation": "supports"}), ] G.add_edges_from(relations)

检索:实体扩展 + 邻居实体

def graph_retrieve(query: str, hops: int = 2): # 1. 识别问题中的实体 entities = extract_entities(query) # 2. 图遍历扩展 results = set() for entity in entities: if entity in G: # 获取邻居及其邻居 neighbors = nx.single_source_shortest_path_length( G, entity, cutoff=hops ) results.update(neighbors.keys()) return list(results)

全局搜索 vs 局部搜索

局部搜索(具体问题):
  问题: "Redis 支持哪些持久化方式?"
  策略: 从 Redis 节点出发,遍历关联的持久化节点
  结果: RDB、AOF、混合持久化

全局搜索(综合问题):
  问题: "缓存技术有哪些选型?"
  策略: 检索"缓存"社区的所有实体和关系
  结果: Redis、Memcached、Local Cache、CDN ...

多模态 RAG

将 RAG 从纯文本扩展到图片、表格、音视频等多模态内容。

架构方案

多模态文档(PDF/图片/视频)
    │
    ├── 文本提取 ──→ 文本 Embedding ──→ 文本向量库
    │
    ├── 图片提取 ──→ 多模态 Embedding ──→ 图片向量库
    │                    │
    │              ┌─────┴─────┐
    │              │ CLIP /    │
    │              │ SigLIP    │
    │              └───────────┘
    │
    └── 表格提取 ──→ 结构化存储 ──→ SQL/CSV 查询

图片检索方案

# 方案一:使用图片描述(成本低)
from langchain.chains import LLMChain

def image_to_text(image_path: str) -> str:
    """用多模态 LLM 生成图片描述"""
    response = multi_modal_llm.invoke([
        {"type": "text", "text": "请详细描述这张图片的内容"},
        {"type": "image", "image": image_path},
    ])
    return response.content

图片描述 → 文本检索

image_desc = image_to_text("architecture_diagram.png") image_doc = Document(page_content=image_desc, metadata={"source": "architecture_diagram.png"}) vector_store.add_documents([image_doc])

方案二:多模态 Embedding(精度高)

from sentence_transformers import SentenceTransformer

使用 CLIP 多模态模型

clip_model = SentenceTransformer("clip-ViT-B-32") text_emb = clip_model.encode("系统架构图") image_emb = clip_model.encode("architecture_diagram.png")

在同一个向量空间直接检索

表格检索

表格数据的检索是一个特殊挑战,常见方案:

方案方法优点缺点
文本序列化表格 → Markdown 文本简单丢失结构信息
结构化描述表格 → 自然语言描述检索效果好生成成本高
混合索引文本 + 元数据过滤准确实现稍复杂
Table-aware专门表格检索模型精度最高生态不成熟

# 表格 → 文本描述
def table_to_description(table_data: dict) -> str:
    prompt = f"""
    将以下表格转换为便于检索的自然语言描述:
    
    表名:{table_data['name']}
    列:{', '.join(table_data['columns'])}
    前 3 行数据:
    {table_data['sample_rows'][:3]}
    
    请用一段话总结这个表格的内容和用途。
    """
    return llm.invoke(prompt).content

Streaming RAG

实时流式输出对于用户体验至关重要。

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import asyncio

app = FastAPI()

@app.post("/rag/stream")
async def rag_stream(question: str):
    async def generate():
        # 1. 检索阶段(快速)
        yield f"data: {{\"type\": \"status\", \"message\": \"正在检索...\"}}\n\n"
        docs = await asyncio.to_thread(vector_store.similarity_search, question)
        yield f"data: {{\"type\": \"status\", \"message\": \"已检索到 {len(docs)} 篇文档\"}}\n\n"
        
        # 2. 生成阶段(流式)
        context = "\n\n".join([d.page_content for d in docs])
        stream = llm.stream(prompt.format(context=context, question=question))
        
        async for chunk in stream:
            yield f"data: {{\"type\": \"token\", \"content\": \"{chunk.content}\"}}\n\n"
        
        # 3. 标注引用(最后)
        yield f"data: {{\"type\": \"done\", \"sources\": {source_list}}}\n\n"
    
    return StreamingResponse(generate(), media_type="text/event-stream")

Corrective RAG 与 Self-RAG

Corrective RAG(CRAG)

自动检测检索结果质量,决定是否修正。

检索结果
    │
    ▼
┌────────────┐
│  质量评估   │ ← LLM 判断检索结果是否足够
│  (Judge)   │
└─────┬──────┘
      │
  ┌───┼───┐
  │   │   │
  ▼   ▼   ▼
可信 模糊 不可信
  │   │   │
  │   ▼   │
  │ 保留  │
  │   │   │
  │   ▼   │
  │ 补充  └──→ Web 搜索
  │ 检索       / 重写 Query
  │   │
  ▼   ▼
LLM 生成

Self-RAG

Self-RAG 让模型在生成过程中自我反思,动态决定是否检索。

生成过程:
  Token 1: "Redis 是" → 反思:需要引用吗?
    决定:需要 → 检索 → 继续生成
  Token 2: "内存数据库" → 反思:可信吗?  
    决定:可信 → 继续
  Token 3: "支持 5 种" → 反思:需要引用吗?
    决定:不需要 → 直接生成
  ...

优点:
  ✓ 只在需要时检索,节省成本
  ✓ 生成过程中自我纠错
  × 需要专门的训练或精心设计的 Prompt

实现对比

模式检索时机纠错机制实现复杂度
Naive RAG固定
CRAG固定 + 后验评估自动修正检索
Self-RAG动态按需生成时自我纠正
Agentic RAG多轮灵活多步推理验证

核心要点

  • Agentic RAG 与 ReAct 模式
  • Graph RAG 原理与实现
  • 多模态 RAG(图文检索生成)
  • Streaming RAG 实时流式输出
  • Corrective RAG 与 Self-RAG

关联知识点