在 AI 应用开发中,RAG(检索增强生成)可以把模型回答与外部数据关联起来,但不会自动消除幻觉或保证知识新鲜度。仅切块并向量检索的基线在部分事实查询中已经足够;它的边界取决于语料结构、问题分布、访问策略和评测设计。
本文将图结构检索作为一种设计选项,而不是普遍的“下一代替代方案”。这里的 “GraphRAG” 泛指基于图的 RAG;Microsoft GraphRAG 是具有特定索引和查询模式的具体实现。
1. 为什么 Naive RAG 会“迷失在文档海”?
在 Naive RAG 架构中,核心逻辑是 Chunking -> Embedding -> Vector Search -> Generation。这种模式在处理“事实提取类”问题(如:“公司去年的营收是多少?”)时表现优异。
但当面临以下挑战时,Naive RAG 往往束手无策:
- 跨文档综合:例如“总结 A 部门和 B 部门在 Q3 季度的战略协同点”可能需要多份文档、实体关联和证据覆盖。Top-K 向量查询可能漏掉来源,但查询拆分或混合检索也可能解决问题。
- 术语歧义与语义冲突:同一个词(如“Apple”)在不同的文档块中可能指代水果,也可能指代公司。单纯的 Embedding 难以在没有全局上下文的情况下进行消歧。
- 长上下文选择:增加文档块可能降低有效证据密度,并出现“Lost in the Middle”现象;实际影响取决于模型、提示、排序和任务。
这些现象说明可以评估结构化表示,并不意味着每个负载都需要知识图谱。
2. GraphRAG:为向量插上“逻辑的翅膀”
图结构 RAG 通常在文本块之外保留实体、关系、来源和可选的社区级摘要。LLM 抽取不是必选项,且应被视为带噪声、可版本化的数据管道,而不是事实真相。
2.1 核心原理解析
在图结构 RAG 中,检索可以组合结构化和非结构化证据:
- 实体与关系抽取:把文本转成候选结构化事实,同时保留来源片段、文档修订、抽取器版本和置信信息。
- 实体消歧与社区:用明确规则及人工或基准评测处理别名;Leiden 等社区检测只是可选分析步骤,不是授权边界。
- 混合检索:在同一租户、对象、用途和留存策略下检索文本与图证据,再引用原始来源,而不是把生成摘要当作证明。
3. 实战:构建轻量级 GraphRAG 管道
下面是一个示意管道。抽取结果是不可信输入:需要校验 schema、保留来源,不能让模型创建的关系授予访问权限或触发副作用。
3.1 定义实体抽取的 Prompt
可使用结构化输出接口,但仍必须在应用代码中校验。编码应由传输层和序列化器处理,而不是依赖额外的转换步骤。
from dataclasses import dataclass
@dataclass(frozen=True)
class CandidateRelation:
head: str
head_type: str
relation: str
tail: str
tail_type: str
source_id: str
source_revision: str
start: int
end: int
# 示意 Prompt。schema、长度、关系白名单、来源片段、租户和文档修订
# 必须在模型之外校验。
EXTRACTION_PROMPT = """从 TEXT 中抽取候选实体和关系。
返回符合应用 schema 的 JSON。不要推断文本中没有的事实,并包含
source_id、source_revision 和字符区间。
TEXT:
{{TEXT}}"""
3.2 向量查询与图谱查询的融合
在查询阶段,我们需要将向量数据库召回的文本片段与图数据库召回的邻居节点进行融合拼接。
async def hybrid_search(query, auth_context, policy):
# 候选检索受租户、对象和用途策略约束。
vector_results = await vector_db.search(
query,
tenant_id=auth_context.tenant_id,
allowed_objects=policy.allowed_objects,
limit=policy.vector_limit,
)
entities = await llm.extract_entities(query)
entities = policy.validate_query_entities(entities)
graph_results = await graph_db.neighbors(
entities=entities,
tenant_id=auth_context.tenant_id,
allowed_objects=policy.allowed_objects,
max_hops=policy.max_hops,
max_edges=policy.edge_limit,
)
evidence = policy.validate_and_merge(vector_results, graph_results)
return policy.build_cited_context(evidence)
4. 用基线做决策,而不是看架构图
GraphRAG 应是一项带明确假设的实验,而不是默认架构。先构建满足访问控制要求的最简词法加向量基线,再在相同语料快照、策略、模型、提示和答案验证器下,与图增强版本对比。
| 问题切片 | 基线通常足够 | 图证据可能增加价值 | 应度量什么 |
|---|---|---|---|
| 精确事实或标识符查询 | 是 | 很少 | Recall@K、延迟、访问过滤正确性 |
| 多跳关系问题 | 有时 | 值得测试 | 证据路径覆盖、答案忠实度 |
| 语料级综合 | 有时 | 社区或图摘要可能有帮助 | 引用覆盖、完整性、摘要漂移 |
| 实体歧义 | 有时 | 带类型实体和来源消歧可能有帮助 | 消歧精度、有害合并率 |
| 最近更新或删除内容 | 需要索引新鲜 | 需要派生血缘 | 新鲜度、删除传播、过期回答率 |
不要只比较最终答案的流畅度。图设计可能让回答看起来更连贯,却选择了没有证据支撑的关系。应记录召回的来源 ID、图路径、版本、过滤条件和答案引用,让评测能够区分更好的推理路径与更有说服力但缺乏证据的答案。
5. 将图谱作为派生数据运行
把图谱产物看作权威文档的派生视图。每个节点、边、实体合并和社区摘要都应保留来源 ID、修订版本、抽取器版本、创建时间、置信度和删除血缘。源文档更新时,应增量重算受影响产物或标记为过期;删除或访问策略变化时,应在响应生成前从所有检索路径中移除对应内容。
一条实用的发布门禁覆盖四层:
- 抽取与消歧: 关系类型精度、来源片段有效性、别名合并与拆分错误。
- 检索: Recall@K、nDCG、路径相关性、元数据过滤正确性和引用覆盖。
- 答案: 忠实度、完整性、证据不足时拒答,以及面对冲突来源时的表现。
- 运营: 入库与查询成本、尾延迟、刷新滞后、删除传播和回滚行为。
6. 常见问题 (FAQ)
Q: 构建 GraphRAG 的成本是不是很高? A: 可能更高,因为抽取、消歧、图存储和摘要刷新都会增加工作量;但倍数取决于模型、语料、批处理、缓存和刷新策略。应针对向量基线测量入库成本、查询延迟、证据覆盖和回答质量。
Q: 如何处理图谱中提取出的重复实体? A: 使用可版本化的消歧策略:规范化标识符,比较别名和类型化属性,要求来源证据,并把不确定合并交给复核。密码学哈希只能为完全相同的规范化字符串生成稳定键,不能证明两个实体相同。
Q: 什么时候不建议使用 GraphRAG? A: 当更简单的基线已经满足召回、事实依据、延迟、成本和维护要求时不必引入图。图可能帮助多跳或语料级问题,但也会增加抽取错误、刷新工作、schema 治理和权限复杂度。
总结
图结构检索是设计选项,不是必然的技术跃迁或“幻觉疗法”。只有在评测切片中证明图证据带来收益时才应采用,并在生产设计中保留来源、租户/对象授权、删除血缘、引用覆盖、拒答和回滚能力。