RAG(检索增强生成)

返回工程实践

Retrieval-Augmented Generation:在 LLM 生成前先从外部知识库检索相关内容作为上下文,解决模型知识截止、幻觉和私域数据问题。


基础 RAG 流程

文档 → 分块(Chunk) → Embedding → 向量数据库
                                        ↓
用户提问 → Embedding → 向量检索 → Top-K 文档
                                        ↓
                              LLM(问题 + 上下文) → 回答
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Milvus
from langchain.chains import RetrievalQA
 
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
vectorstore = Milvus.from_documents(docs, embeddings, collection_name="kb")
 
qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o"),
    retriever=vectorstore.as_retriever(search_kwargs={"k": 5})
)
answer = qa.invoke("Redis 和 MongoDB 有什么区别?")

Vector RAG vs Graph RAG

维度Vector RAGGraph RAG
知识表示文本块向量实体 + 关系图
检索方式近似最近邻(ANN)图遍历 + 向量混合
多跳推理弱(单次检索)强(沿关系边推理)
全局理解局部文本片段跨文档关系网络
构建成本低(分块+向量化)高(实体抽取+图构建)
适用问题”X 是什么""X 和 Y 的关系”、“找出满足条件的链路”
典型工具LangChain、LlamaIndexMicrosoft GraphRAG、Neo4j + LangChain

Vector RAG 的局限

问题:A 公司的供应商中,有哪些同时也是 B 公司的竞争对手?

Vector RAG:检索到 A 的供应商文档、B 的竞争对手文档,
            但无法自动关联两个集合 → 依赖模型推理,容易出错

Graph RAG:图中直接查询两跳路径 → 精确、可解释

Graph RAG 核心思路(Microsoft GraphRAG)

1. 实体抽取  LLM 从文档中提取实体和关系 → 构建知识图谱
2. 社区检测  对图做 Leiden 算法聚类,生成社区摘要
3. 检索
   ├── Local Search:实体级检索,适合具体问题
   └── Global Search:社区摘要聚合,适合全局问题
4. 生成      将检索结果作为上下文输入 LLM

Hybrid RAG

结合稠密检索(向量语义)和稀疏检索(关键词匹配)双路召回,互补各自的盲区。

为什么需要混合

检索类型优势盲区
Dense(向量)语义相似,理解同义词精确术语(型号、代码、缩写)容易丢失
Sparse(BM25)精确关键词匹配无法理解语义,同义词漏召
Hybrid两者兼顾需要融合排序,实现略复杂
问题:"GPT-4o 的 context window 是多少?"

Dense 检索:理解"上下文长度"语义,但"128K"这种数字可能漏
BM25 检索:精确匹配"GPT-4o"和"context window"关键词
Hybrid:两路都召,RRF 融合后覆盖更全面

RRF 融合排序

Reciprocal Rank Fusion:把多路检索结果按排名倒数加权合并,无需调权重:

def rrf(results_list: list[list], k: int = 60) -> list:
    scores = {}
    for results in results_list:
        for rank, doc in enumerate(results):
            doc_id = doc.metadata["id"]
            scores[doc_id] = scores.get(doc_id, 0) + 1 / (rank + k)
    return sorted(scores, key=scores.get, reverse=True)

LangChain EnsembleRetriever

from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain_community.vectorstores import Milvus
 
# 稀疏检索(BM25)
bm25 = BM25Retriever.from_documents(docs, k=5)
 
# 稠密检索(向量)
vectorstore = Milvus.from_documents(docs, embeddings)
dense = vectorstore.as_retriever(search_kwargs={"k": 5})
 
# 混合:各占 50% 权重,内部使用 RRF 融合
hybrid = EnsembleRetriever(
    retrievers=[bm25, dense],
    weights=[0.5, 0.5]
)
 
results = hybrid.invoke("Redis 持久化方案有哪些?")

权重调整建议

场景BM25 权重Dense 权重
技术文档、代码检索0.60.4
通用问答、语义查询0.30.7
混合型知识库0.50.5

三种 RAG 横向对比

全维度对比表

维度Vector RAGHybrid RAGGraph RAG
知识表示文本块向量文本块向量实体 + 关系图
稀疏检索✓ BM25
稠密检索可选
关系推理
多跳查询
全局摘要✓(社区摘要)
精确术语
语义理解
构建成本(实体抽取)
查询延迟低~中
可解释性(路径可视)
适合问题”X 是什么""X 的型号/代号""X 和 Y 的关系”
典型工具LangChain、LlamaIndexEnsembleRetrieverMS GraphRAG、Neo4j

检索能力雷达

              精确术语
                 ▲
                 │
    Graph ───────┤──────── Hybrid
    RAG    ╲     │     ╱
            ╲    │    ╱
 关系推理 ────╲───┼───╱──── 语义理解
            ╱    │    ╲
           ╱     │     ╲
          ╱      │      ╲
         Vector RAG       
                 │
              构建简单
能力Vector RAGHybrid RAGGraph RAG
语义理解★★★★★★★★★★★★★
精确术语★★★★★★★★★★
关系推理★★★★★
全局理解★★★★★★★★★
构建简单★★★★★★★★★★★
查询速度★★★★★★★★★★★

典型问题对照

问题类型                      推荐方案
─────────────────────────────────────────
"Redis 是什么?"              Vector RAG
"GPT-4o 的上下文窗口多大?"   Hybrid RAG  ← 含精确数字/型号
"Redis 和 Kafka 哪些场景重叠?" Graph RAG  ← 关系对比
"A 公司供应商中谁是 B 的竞争对手?" Graph RAG ← 多跳推理
"整个知识库的核心主题是什么?"  Graph RAG  ← 全局摘要

组合使用

三种方式并非互斥,生产中常组合:

┌─────────────────────────────────────────────────┐
│                  问题路由层                      │
└──────┬──────────────────┬───────────────┬────────┘
       ↓                  ↓               ↓
  Vector RAG          Hybrid RAG      Graph RAG
  (语义问题)        (精确检索)    (关系推理)
       └──────────────────┴───────────────┘
                          ↓
                     RRF 融合排序
                          ↓
                     Re-ranking
                          ↓
                         LLM
# 简单路由示例:根据问题类型选择检索器
def route_retriever(question: str):
    # 含专有名词/数字/代号 → Hybrid
    if re.search(r'[A-Z0-9]{3,}|版本|型号|\d+[KM]', question):
        return hybrid_retriever
    # 含关系词 → Graph
    if any(w in question for w in ["关系", "区别", "对比", "影响", "依赖"]):
        return graph_retriever
    # 默认 → Vector
    return vector_retriever

Graph-enhanced Embedding

结合图结构改进向量表示,介于 Vector RAG 和 Graph RAG 之间的方案。

方案一:图上下文增强文本

# 为每个文档节点附加其图邻居信息,再做 Embedding
def enrich_with_graph(doc_text, entity, graph):
    neighbors = graph.neighbors(entity)
    context = ", ".join([f"{rel}: {node}" for rel, node in neighbors])
    return f"{doc_text}\n相关实体:{context}"
 
enriched = enrich_with_graph(doc.text, "Redis", knowledge_graph)
vec = embed(enriched)  # 携带了图结构信息的向量

方案二:Neo4j 原生向量 + 图混合检索

# Neo4j 5.x 向量索引 + 图关系联合查询
query = """
CALL db.index.vector.queryNodes('doc_embeddings', 5, $queryVec)
YIELD node, score
MATCH (node)-[:RELATED_TO]->(related)
RETURN node.text, related.name, score
ORDER BY score DESC
"""
results = session.run(query, queryVec=query_vector)

方案三:多路召回融合

稠密检索(向量相似)
    +
稀疏检索(BM25 关键词)  →  RRF 融合排序  →  重排序  →  LLM
    +
图检索(实体关系路径)

高级 RAG 模式

HyDE(假设文档扩展)

# 先让 LLM 生成假设答案,用假设答案去检索,效果优于原始问题
hypothesis = llm.invoke(f"请简要回答:{question}")
results = vectorstore.similarity_search(hypothesis, k=5)

Re-ranking(重排序)

from sentence_transformers import CrossEncoder
 
reranker = CrossEncoder("BAAI/bge-reranker-v2-m3")
pairs = [(question, doc.page_content) for doc in candidates]
scores = reranker.predict(pairs)
reranked = sorted(zip(scores, candidates), reverse=True)
top_docs = [doc for _, doc in reranked[:3]]

选型建议

场景推荐方案
快速落地、私域文档问答Vector RAG + Re-ranking
精确术语 + 语义并重Hybrid RAG(BM25 + Dense + RRF)
需要关系推理、多跳问题Graph RAG 或混合检索
全局摘要、宏观分析Graph RAG(社区摘要)
Agent 长期记忆RAG + Memory 层(mem0 / MemGPT)

相关文档