向量检索与图检索融合架构
原创
灵阙教研团队
S 精选 提升 |
约 7 分钟阅读
更新于 2026-02-27 AI 导读
向量检索与图检索融合架构 GraphRAG vs VectorRAG 与混合检索实战 | 2026-02 一、两种检索范式的本质差异 大模型时代的知识检索有两条路径:基于向量相似度的语义检索(VectorRAG)和基于图结构的关系检索(GraphRAG)。二者解决的是不同维度的问题: VectorRAG 擅长回答: "跟 X 语义最相似的内容是什么?" -> 基于 embedding...
向量检索与图检索融合架构
GraphRAG vs VectorRAG 与混合检索实战 | 2026-02
一、两种检索范式的本质差异
大模型时代的知识检索有两条路径:基于向量相似度的语义检索(VectorRAG)和基于图结构的关系检索(GraphRAG)。二者解决的是不同维度的问题:
VectorRAG 擅长回答:
"跟 X 语义最相似的内容是什么?"
-> 基于 embedding 余弦相似度,模糊匹配
GraphRAG 擅长回答:
"X 和 Y 之间有什么关系?经过了哪些中间节点?"
-> 基于图遍历,精确的结构化推理
对比分析:
| 维度 | VectorRAG | GraphRAG | 混合架构 |
|---|---|---|---|
| 检索方式 | 语义相似度 (ANN) | 图遍历 + 子图匹配 | 两者结合 |
| 擅长问题 | 模糊语义查询 | 多跳关系推理 | 全类型问题 |
| 数据结构 | 文档块 -> 向量 | 实体-关系三元组 | 文档+图谱 |
| 构建成本 | 低(切片+嵌入) | 高(NER+关系抽取+图构建) | 最高 |
| 维护成本 | 低 | 中-高 | 中-高 |
| 幻觉控制 | 中(可能检索到不相关块) | 强(结构化事实约束) | 最强 |
| 全局视角 | 弱(局部文档块) | 强(全图社区+摘要) | 最强 |
二、VectorRAG 架构解析
2.1 标准流程
文档 -> 分块(Chunking) -> 向量化(Embedding) -> 存入向量数据库
|
用户查询 -> 向量化 -> ANN 检索 -> Top-K 文档块 -> LLM 生成回答
2.2 关键组件选型
| 组件 | 选项 | 推荐 |
|---|---|---|
| 向量数据库 | Milvus / Qdrant / Weaviate / Pinecone / pgvector | Qdrant(轻量)/ Milvus(规模) |
| Embedding | text-embedding-3-large / bge-m3 / jina-v3 | bge-m3(多语言性价比最高) |
| 分块策略 | 固定长度 / 递归分割 / 语义分块 | 语义分块(LlamaIndex SemanticChunker) |
| 重排序 | bge-reranker-v2 / Cohere Rerank | bge-reranker-v2(本地部署) |
2.3 LangChain 实现
from langchain_community.vectorstores import Qdrant
from langchain_openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
# 1. 文档分块
splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=64)
chunks = splitter.split_documents(documents)
# 2. 向量化并存入 Qdrant
embeddings = OpenAIEmbeddings(model="text-embedding-3-large")
vectorstore = Qdrant.from_documents(
chunks,
embeddings,
location=":memory:",
collection_name="knowledge_base",
)
# 3. 检索增强生成
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
llm = ChatOpenAI(model="gpt-4o", temperature=0)
qa_chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)
answer = qa_chain.invoke("灵阙科技的主要产品是什么?")
2.4 VectorRAG 的局限
- 多跳问题失效:"张三的老板的客户是谁?"需要跨文档块关联,单纯向量召回困难
- 全局摘要缺失:"这个领域的整体趋势是什么?"向量检索只返回局部片段
- 结构化关系丢失:文档被切片后,实体间的精确关系信息被稀释
三、GraphRAG 架构解析
3.1 微软 GraphRAG 流程
文档 -> LLM 实体抽取 -> LLM 关系抽取 -> 构建知识图谱
|
社区检测 (Leiden)
|
社区摘要 (LLM)
|
┌───────────────────┴───────────────────┐
| |
Local Search Global Search
(实体 + 关系 + (社区摘要 +
局部上下文) Map-Reduce)
3.2 Local Search vs Global Search
| 模式 | 适用问题 | 检索策略 | 示例 |
|---|---|---|---|
| Local | 具体实体查询 | 实体匹配 -> 子图展开 -> 上下文组装 | "Neo4j 的创始人是谁" |
| Global | 全局概述/趋势 | 社区摘要 -> Map(各社区回答) -> Reduce(汇总) | "图数据库行业趋势" |
3.3 LlamaIndex PropertyGraph 实现
from llama_index.core import PropertyGraphIndex, SimpleDirectoryReader
from llama_index.llms.openai import OpenAI
from llama_index.graph_stores.neo4j import Neo4jPropertyGraphStore
# 1. 加载文档
documents = SimpleDirectoryReader("./data").load_data()
# 2. 配置图存储
graph_store = Neo4jPropertyGraphStore(
username="neo4j",
password="password",
url="bolt://localhost:7687",
)
# 3. 构建 PropertyGraph 索引(自动抽取实体和关系)
llm = OpenAI(model="gpt-4o", temperature=0)
index = PropertyGraphIndex.from_documents(
documents,
llm=llm,
graph_store=graph_store,
show_progress=True,
)
# 4. 图检索问答
query_engine = index.as_query_engine(
include_text=True, # 包含原始文本上下文
response_mode="tree_summarize",
)
response = query_engine.query("张三和灵阙科技之间的关系是什么?")
3.4 GraphRAG 的局限
- 构建成本高:LLM 抽取实体和关系的 API 调用费用显著
- 抽取质量不稳定:LLM 可能遗漏实体或抽取错误关系
- 语义模糊查询弱:图检索依赖精确的实体匹配,模糊语义查询不如向量检索
四、混合架构设计
4.1 架构总览
┌─────────────────┐
│ 用户查询 │
└────────┬────────┘
|
┌────────┴────────┐
│ 查询路由器 │
│ (意图分类) │
└───┬────┬────┬───┘
| | |
┌─────────┘ | └──────────┐
v v v
┌────────────┐ ┌──────────┐ ┌─────────────┐
│ 向量检索 │ │ 图检索 │ │ 混合检索 │
│ (语义匹配) │ │ (结构化) │ │ (两者结合) │
└─────┬──────┘ └────┬─────┘ └──────┬──────┘
| | |
└───────────────┼───────────────┘
|
┌──────┴──────┐
│ 结果融合 │
│ + 重排序 │
└──────┬──────┘
|
┌──────┴──────┐
│ LLM 生成 │
│ (带引用) │
└─────────────┘
4.2 查询路由策略
from enum import Enum
class QueryType(Enum):
SEMANTIC = "semantic" # "什么是知识图谱?"
STRUCTURAL = "structural" # "张三的同事有哪些?"
HYBRID = "hybrid" # "知识图谱在风控中有哪些应用案例?"
GLOBAL = "global" # "图数据库行业整体趋势"
def classify_query(query: str, llm) -> QueryType:
"""用 LLM 对查询意图分类"""
prompt = f"""
将以下查询分类为四种类型之一:
- semantic: 概念解释、定义、描述类问题
- structural: 涉及具体实体间关系、路径、多跳推理
- hybrid: 既需要语义理解又需要结构化关系
- global: 全局概述、趋势、总结类问题
查询: {query}
类型:
"""
result = llm.invoke(prompt).content.strip().lower()
return QueryType(result)
def route_query(query: str, query_type: QueryType):
"""根据类型路由到不同检索器"""
if query_type == QueryType.SEMANTIC:
return vector_retrieve(query, k=5)
elif query_type == QueryType.STRUCTURAL:
return graph_retrieve(query)
elif query_type == QueryType.GLOBAL:
return global_search(query)
else: # HYBRID
vec_results = vector_retrieve(query, k=3)
graph_results = graph_retrieve(query)
return merge_and_rerank(vec_results, graph_results)
4.3 结果融合策略
| 策略 | 方法 | 适用场景 |
|---|---|---|
| 分数归一化 | 将向量和图分数归一到 [0,1] 后加权求和 | 两路结果质量稳定 |
| RRF (Reciprocal Rank Fusion) | 1/(k+rank) 加权合并 | 通用场景 |
| LLM 重排序 | 用 LLM 对合并结果做相关性打分 | 质量优先 |
| 交叉验证 | 两路都命中的结果优先 | 高精度场景 |
def reciprocal_rank_fusion(results_lists: list[list], k: int = 60) -> list:
"""RRF 融合多路检索结果"""
scores = {}
for results in results_lists:
for rank, item in enumerate(results):
item_id = item["id"]
if item_id not in scores:
scores[item_id] = {"item": item, "score": 0}
scores[item_id]["score"] += 1.0 / (k + rank + 1)
fused = sorted(scores.values(), key=lambda x: x["score"], reverse=True)
return [entry["item"] for entry in fused]
五、何时用哪种方案
决策树:
你的数据是非结构化文档为主?
|
是 -> 实体关系对业务重要吗?
| |
| 是 -> 混合架构(Vector + Graph)
| 否 -> VectorRAG 足够
|
否 -> 数据已经是结构化的?
|
是 -> 已有知识图谱?
| |
| 是 -> GraphRAG
| 否 -> 先建图谱,再 GraphRAG
|
否 -> 半结构化 -> 混合架构
六、性能基准参考
以 10 万文档(约 50 万文档块、200 万三元组)规模测试:
| 指标 | VectorRAG | GraphRAG (Local) | GraphRAG (Global) | 混合架构 |
|---|---|---|---|---|
| 构建时间 | 2 小时 | 18 小时 | 同左 + 社区摘要 6h | 24 小时 |
| 构建成本 | $5 (embedding) | $150 (LLM 抽取) | $200 (含社区摘要) | $205 |
| 检索延迟 | 50-100ms | 100-300ms | 2-5s (Map-Reduce) | 200-500ms |
| 事实型问题准确率 | 72% | 85% | 68% | 88% |
| 多跳推理准确率 | 35% | 78% | 55% | 82% |
| 全局概述质量 | 4.2/10 | 6.5/10 | 8.8/10 | 8.5/10 |
| 存储空间 | 2 GB | 8 GB | 10 GB | 12 GB |
关键发现:
- 事实型单跳问题:VectorRAG 够用,GraphRAG 成本回报比不高
- 多跳推理问题:GraphRAG 大幅领先,VectorRAG 几乎不可用
- 全局概述问题:GraphRAG Global Search 独有优势
- 混合架构在多数场景取得最佳综合表现,但构建成本最高
七、生产级实现建议
7.1 增量更新策略
class HybridIndexUpdater:
"""混合索引增量更新"""
def update(self, new_documents: list):
# 1. 向量索引更新(低成本)
chunks = self.splitter.split_documents(new_documents)
self.vectorstore.add_documents(chunks)
# 2. 图谱增量更新(高成本,可异步)
for doc in new_documents:
entities, relations = self.extract_knowledge(doc)
self.graph_store.upsert_entities(entities)
self.graph_store.upsert_relations(relations)
# 3. 社区重计算(周期性,非每次更新)
if self.should_recompute_communities():
self.recompute_communities()
7.2 成本优化
- 图谱构建用小模型(GPT-4o-mini / Gemini Flash)抽取,质量损失约 5-10%
- 社区摘要按周更新而非实时更新
- 向量检索用开源 embedding(bge-m3),节省 API 费用
- 查询路由将 60-70% 的简单查询路由到纯向量检索,节省图查询开销
7.3 监控指标
| 指标 | 目标 | 告警阈值 |
|---|---|---|
| 检索延迟 P95 | <500ms | >1000ms |
| 回答准确率(人工抽检) | >85% | <75% |
| 图谱更新延迟 | <24h | >48h |
| 向量索引碎片率 | <20% | >40% |
| LLM Token 消耗 | 按预算 | 超预算 120% |
Maurice | maurice_wen@proton.me