高级 RAG:详解 LongRAG、Self-RAG 和 GraphRAG
LongRAG、Self-RAG、GraphRAG - 下一代技术
检索增强生成(RAG) 已经远远超越了简单的向量相似性搜索。 LongRAG、Self-RAG 和 GraphRAG 代表了这些能力的前沿。
现代 RAG 系统需要处理大量文档,理解复杂的实体关系等。
这张漂亮的图片由 AI 模型 Flux 1 dev 生成。
超越基础 RAG 的演变
传统 RAG 系统遵循一个简单的模式:对文档进行分块,将其嵌入向量,通过余弦相似性检索相似的块,并将其馈送到 LLM。虽然对许多用例有效,但这种方法在以下三个关键场景中存在困难:
- 长距离依赖:重要上下文可能跨越多个块的数千个标记
- 检索置信度:系统无法评估检索到的内容是否确实相关
- 关系复杂性:向量相似性无法捕捉实体之间的复杂连接
先进的 RAG 变体通过专门的架构来解决这些限制,这些架构针对特定挑战进行了优化。
LongRAG:征服扩展上下文
架构概述
LongRAG 通过利用具有扩展上下文窗口(32K、100K 或甚至 1M 个标记)的 LLM 彻底重新思考了分块策略。LongRAG 不是将文档分成小的 512 个标记块,而是使用一种分层方法:
文档级嵌入:整个文档(或非常大的部分)作为单个单元进行处理。文档级嵌入捕获整体语义含义,同时保留完整文本以供后续处理。
最小碎片化:当需要分块时,LongRAG 使用更大的块(4K-8K 个标记)并具有较大的重叠(20-30%)。这保留了叙述流畅性并减少了上下文碎片化。
上下文组装:在检索时,LongRAG 返回完整的文档或大型连贯部分,而不是零散的片段。LLM 接收到的上下文是连续的,保留了结构和语义关系。
实施策略
以下是使用 Python 和现代嵌入模型的概念性实现:
from typing import List, Dict
import numpy as np
class LongRAGRetriever:
def __init__(self, model, chunk_size=8000, overlap=1600):
self.model = model
self.chunk_size = chunk_size
self.overlap = overlap
self.doc_embeddings = []
self.documents = []
def create_long_chunks(self, text: str) -> List[str]:
"""创建重叠的大块"""
chunks = []
start = 0
while start < len(text):
end = start + self.chunk_size
chunk = text[start:end]
chunks.append(chunk)
start += (self.chunk_size - self.overlap)
return chunks
def index_document(self, doc: str, metadata: Dict):
"""使用分层嵌入索引文档"""
# 嵌入整个文档
doc_embedding = self.model.embed(doc)
# 创建带重叠的大块
chunks = self.create_long_chunks(doc)
chunk_embeddings = [self.model.embed(c) for c in chunks]
self.doc_embeddings.append({
'doc_id': len(self.documents),
'doc_embedding': doc_embedding,
'chunk_embeddings': chunk_embeddings,
'chunks': chunks,
'full_text': doc,
'metadata': metadata
})
self.documents.append(doc)
def retrieve(self, query: str, top_k: int = 3) -> List[Dict]:
"""检索相关长文本内容"""
query_embedding = self.model.embed(query)
# 首先在文档级别评分
doc_scores = [
np.dot(query_embedding, doc['doc_embedding'])
for doc in self.doc_embeddings
]
# 获取顶级文档
top_doc_indices = np.argsort(doc_scores)[-top_k:][::-1]
results = []
for idx in top_doc_indices:
doc_data = self.doc_embeddings[idx]
# 对每个文档,找到最佳块
chunk_scores = [
np.dot(query_embedding, emb)
for emb in doc_data['chunk_embeddings']
]
best_chunk_idx = np.argmax(chunk_scores)
# 返回最佳块周围的扩展上下文
context_chunks = self._get_extended_context(
doc_data['chunks'],
best_chunk_idx
)
results.append({
'text': ''.join(context_chunks),
'score': doc_scores[idx],
'metadata': doc_data['metadata']
})
return results
def _get_extended_context(self, chunks: List[str],
center_idx: int) -> List[str]:
"""获取相关块周围的扩展上下文"""
start = max(0, center_idx - 1)
end = min(len(chunks), center_idx + 2)
return chunks[start:end]
应用场景和性能
LongRAG 在上下文至关重要的场景中表现出色:
- 法律文件分析:合同和法律简报通常有跨越数十页的依赖关系
- 研究论文检索:理解方法论需要连贯的章节,而不是孤立的段落
- 代码仓库:函数和类必须在其模块上下文中理解
性能特征:
- 延迟:由于处理大块,比标准 RAG 慢 2-5 倍
- 准确性:在长文本问答基准测试中提高 15-25%
- 内存:需要 3-4 倍于标准 RAG 的内存
Self-RAG:反思检索
核心原则
Self-RAG 为 RAG 系统引入了一个元认知层。系统通过特殊的反思标记主动反思其自身过程,而不是盲目检索和生成:
检索标记:决定是否需要检索特定查询 相关性标记:评估检索到的文档是否确实相关 支持标记:检查生成的答案是否由检索到的内容支持 批评标记:评估生成响应的整体质量
架构组件
Self-RAG 架构由三个交错的阶段组成:
class SelfRAGSystem:
def __init__(self, retriever, generator, critic):
self.retriever = retriever
self.generator = generator
self.critic = critic
def generate_with_reflection(self, query: str,
max_iterations: int = 3):
"""生成答案并进行自我反思"""
# 阶段 1:决定是否需要检索
retrieve_decision = self.critic.should_retrieve(query)
if not retrieve_decision:
# 不进行检索直接生成
return self.generator.generate(query)
# 阶段 2:检索并评估相关性
retrieved_docs = self.retriever.retrieve(query)
relevant_docs = []
for doc in retrieved_docs:
relevance_score = self.critic.assess_relevance(
query, doc
)
if relevance_score > 0.7: # 阈值
relevant_docs.append(doc)
if not relevant_docs:
# 回退到不进行检索的生成
return self.generator.generate(query)
# 阶段 3:生成并验证支持
best_answer = None
best_score = -1
for _ in range(max_iterations):
# 生成候选答案
answer = self.generator.generate(
query, context=relevant_docs
)
# 评估支持和质量
support_score = self.critic.check_support(
answer, relevant_docs
)
quality_score = self.critic.assess_quality(answer)
total_score = 0.6 * support_score + 0.4 * quality_score
if total_score > best_score:
best_score = total_score
best_answer = answer
# 如果达到高质量则提前停止
if total_score > 0.9:
break
return {
'answer': best_answer,
'confidence': best_score,
'sources': relevant_docs,
'reflections': {
'retrieved': retrieve_decision,
'relevance': len(relevant_docs),
'support': support_score
}
}
训练反思机制
Self-RAG 需要训练批评组件以进行可靠的评估。这通常涉及:
- 监督微调:在带有相关性判断的标注数据集上进行
- 强化学习:使用准确预测的奖励
- 对比学习:区分支持和不支持的主张
反思标记可以实现为:
- 词汇表中的特殊标记(如
[RETRIEVE]、[RELEVANT]) - 模型上的单独分类器头
- 外部批评模型(集成方法)
生产考虑
在生产系统中部署 Self-RAG 时:
延迟权衡:每个反思步骤增加 20-40% 的推理开销。根据响应时间要求平衡彻底性和效率。
置信度阈值:根据使用场景调整反思阈值。法律或医疗应用需要比通用聊天机器人更高的置信度。
监控:跟踪反思决策以识别模式。如果检索很少需要,您可能会受益于更简单的架构。
GraphRAG:知识图谱增强检索
概念基础
GraphRAG 将检索问题从向量相似性转换为图遍历。GraphRAG 不是寻找语义相似的文本块,而是识别相关实体和关系的子图。
实体提取:识别命名实体、概念及其类型 关系映射:提取实体之间的关系(时间、因果、层次) 图构建:构建一个以实体为节点、关系为边的知识图谱 子图检索:根据查询找到相关的连接子图
图构建管道
从非结构化文本构建知识图谱涉及多个阶段:
class GraphRAGBuilder:
def __init__(self, entity_extractor, relation_extractor):
self.entity_extractor = entity_extractor
self.relation_extractor = relation_extractor
self.graph = NetworkGraph()
def build_graph(self, documents: List[str]):
"""从文档构建知识图谱"""
for doc in documents:
# 提取实体
entities = self.entity_extractor.extract(doc)
# 添加实体作为节点
for entity in entities:
self.graph.add_node(
entity['text'],
entity_type=entity['type'],
context=entity['surrounding_text']
)
# 提取关系
relations = self.relation_extractor.extract(
doc, entities
)
# 添加关系作为边
for rel in relations:
self.graph.add_edge(
rel['source'],
rel['target'],
relation_type=rel['type'],
confidence=rel['score'],
evidence=rel['text_span']
)
def enrich_graph(self):
"""添加派生关系和元数据"""
# 计算节点重要性(PageRank 等)
self.graph.compute_centrality()
# 识别社区/集群
self.graph.detect_communities()
# 如果有时间戳,添加时间顺序
self.graph.add_temporal_edges()
使用图进行查询处理
GraphRAG 查询涉及跨知识图谱的多跳推理:
class GraphRAGRetriever:
def __init__(self, graph, embedder):
self.graph = graph
self.embedder = embedder
def retrieve_subgraph(self, query: str,
max_hops: int = 2,
max_nodes: int = 50):
"""为查询检索相关子图"""
# 识别查询中的种子实体
query_entities = self.entity_extractor.extract(query)
# 在图中查找匹配节点
seed_nodes = []
for entity in query_entities:
matches = self.graph.find_similar_nodes(
entity['text'],
similarity_threshold=0.85
)
seed_nodes.extend(matches)
# 通过遍历扩展子图
subgraph = self.graph.create_subgraph()
visited = set()
for seed in seed_nodes:
self._expand_from_node(
seed,
subgraph,
visited,
current_hop=0,
max_hops=max_hops
)
# 按相关性排序节点
ranked_nodes = self._rank_subgraph_nodes(
subgraph, query
)
# 提取和格式化上下文
context = self._format_graph_context(
ranked_nodes[:max_nodes],
subgraph
)
return context
def _expand_from_node(self, node, subgraph, visited,
current_hop, max_hops):
"""递归扩展子图"""
if current_hop >= max_hops or node in visited:
return
visited.add(node)
subgraph.add_node(node)
# 获取邻居
neighbors = self.graph.get_neighbors(node)
for neighbor, edge_data in neighbors:
# 添加边到子图
subgraph.add_edge(node, neighbor, edge_data)
# 递归扩展
self._expand_from_node(
neighbor,
subgraph,
visited,
current_hop + 1,
max_hops
)
def _format_graph_context(self, nodes, subgraph):
"""将子图转换为文本上下文"""
context_parts = []
for node in nodes:
# 添加节点上下文
context_parts.append(f"实体: {node.text}")
context_parts.append(f"类型: {node.entity_type}")
# 添加关系信息
edges = subgraph.get_edges(node)
for edge in edges:
context_parts.append(
f"- {edge.relation_type} -> {edge.target.text}"
)
return "\n".join(context_parts)
微软的 GraphRAG 实现
微软的 GraphRAG 采用了一种独特的方法,通过生成社区摘要:
- 构建初始图:使用基于 LLM 的实体/关系提取从文档中构建图
- 检测社区:使用 Leiden 算法或其他方法
- 生成摘要:使用 LLM 为每个社区生成摘要
- 分层结构:构建多个级别的社区抽象
- 查询时间:检索相关社区并遍历到特定实体
这种方法特别有效于:
- 探索性查询(“这个语料库的主要主题是什么?”)
- 多跳推理(“A 如何通过 B 连接到 C?”)
- 时间分析(“这个实体的关系如何演变?”)
对比分析
何时使用每种变体
使用 LongRAG 时:
- 文档具有强烈的内部连贯性
- LLM 的上下文窗口支持大型输入(32K+)
- 查询答案需要理解长距离依赖
- 正在处理结构化文档(报告、论文、书籍)
使用 Self-RAG 时:
- 准确性和可信度至关重要
- 需要可解释的检索决策
- 无关检索的假阳性代价高昂
- 查询复杂性差异广泛(一些需要检索,一些不需要)
使用 GraphRAG 时:
- 领域有丰富的实体关系
- 查询涉及多跳推理
- 时间或层次关系重要
- 需要理解实体之间的连接
性能指标比较
| 指标 | 标准 RAG | LongRAG | Self-RAG | GraphRAG |
|---|---|---|---|---|
| 索引时间 | 1x | 0.8x | 1.1x | 3-5x |
| 查询延迟 | 1x | 2-3x | 1.4x | 1.5-2x |
| 内存使用 | 1x | 3-4x | 1.2x | 2-3x |
| 准确性(问答) | 基线 | +15-25% | +20-30% | +25-40%* |
| 可解释性 | 低 | 中等 | 高 | 高 |
*GraphRAG 改进高度依赖于领域
混合方法
最强大的生产系统通常结合多种技术:
LongRAG + GraphRAG:使用图结构识别相关文档集群,然后检索完整文档而不是片段
Self-RAG + GraphRAG:将反思机制应用于图遍历决策(应遵循哪些路径,何时停止扩展)
三阶段流水线:使用 GraphRAG 进行初始基于实体的检索 → 使用 Self-RAG 进行相关性过滤 → 使用 LongRAG 进行上下文组装
实施考虑
嵌入模型
不同的 RAG 变体有不同的嵌入需求:
LongRAG:需要在文档级和块级都表现良好的嵌入。考虑在长序列上使用对比学习训练的模型。
Self-RAG:从细粒度相关性评估中受益的嵌入。
GraphRAG:需要实体感知的嵌入。在实体链接任务上微调的模型表现更好。
嵌入模型的选择显著影响性能。在使用本地模型时,工具如 Ollama 提供了一种简单的方法,可以在部署到生产环境之前尝试不同的嵌入模型。
再次审视分块策略
传统的固定大小分块对于高级 RAG 不够:
语义分块:在自然边界(段落、章节、主题变化)处分块 递归分块:创建具有父子关系的层次化块 滑动窗口:使用重叠块以保留边界处的上下文 结构感知:尊重文档结构(Markdown 标题、XML 标签、代码块)
对于基于 Python 的实现,LangChain 和 LlamaIndex 等库提供了这些分块策略的内置支持。
重排序集成
重排序在所有 RAG 变体中显著提高了检索质量。初始检索后,一个专门的重排序模型根据查询-文档交互特征重新评分结果。这在巧妙集成时提供显著的准确性提升(10-20%),对延迟影响最小。
扩展到生产
索引管道:
- 使用分布式处理(Ray、Dask)处理大型文档语料库
- 实现增量索引以进行实时更新
- 在优化的向量数据库中存储嵌入(Pinecone、Weaviate、Qdrant)
查询优化:
- 缓存频繁查询及其结果
- 实现查询路由(不同 RAG 变体用于不同查询类型)
- 使用近似最近邻搜索实现次线性扩展
监控:
- 跟踪检索相关性评分
- 监控 Self-RAG 中的反思决策
- 测量图遍历路径和深度
- 记录置信度评分和用户反馈
实际应用
技术文档搜索
一家主要的云提供商在其文档中实现了 GraphRAG:
- 实体:API 端点、参数、错误代码、服务名称
- 关系:依赖项、版本兼容性、迁移路径
- 结果:支持票数减少 35%,解决时间加快 45%
法律发现
一家法律科技公司结合了 Self-RAG 和 LongRAG:
- Self-RAG 早期过滤无关文档
- LongRAG 保留文档中的上下文
- 律师审查的假阳性减少 60%
- 关键上下文保留从 71% 提高到 94%
研究文献回顾
使用混合方法的学术搜索引擎:
- GraphRAG 识别引用网络和研究社区
- LongRAG 检索完整部分以保持方法论上下文
- 相关论文发现提高 40%
- 将文献回顾时间从几周缩短到几天
高级主题
多模态 RAG
扩展这些变体以处理图像、表格和代码:
- 视觉定位:将文本实体链接到文档中的图像
- 表格理解:将结构化数据解析为图格式
- 代码分析:从代码库中构建依赖图
自适应 RAG
根据查询特征动态选择 RAG 策略:
- 查询复杂性分类器
- 文档类型检测器
- 策略选择的成本效益优化器
保护隐私的 RAG
在隐私约束下实现这些变体:
- 跨数据孤岛的联邦检索
- 嵌入中的差分隐私
- 加密相似性搜索
入门指南
使用 Python 快速入门
对于希望实施这些技术的人而言,打下坚实的 Python 基础是至关重要的。Python 丰富的机器学习生态系统使其成为 RAG 开发的自然选择。
以下是一个用于实验的简单起点:
# 安装依赖
# pip install sentence-transformers faiss-cpu langchain
from sentence_transformers import SentenceTransformer
import faiss
import numpy as np
# 用于实验的长文本基本设置
model = SentenceTransformer('all-MiniLM-L6-v2')
documents = [
# 这里放置你的长文本文档
]
# 创建嵌入向量
embeddings = model.encode(documents)
# 构建 FAISS 索引
dimension = embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(embeddings.astype('float32'))
# 查询
query = "你的问题在这里"
query_embedding = model.encode([query])
distances, indices = index.search(
query_embedding.astype('float32'), k=3
)
框架选择
LangChain:适合快速原型开发,集成丰富
LlamaIndex:针对文档索引和检索优化
Haystack:生产就绪,强大的流程抽象
自定义:当你需要完全控制和优化时
评估框架
在生产部署之前,实施严格的评估:
检索指标:
- Precision@K,Recall@K,MRR(均倒数排名)
- NDCG(归一化折扣累计增益)
生成指标:
- ROUGE,BLEU 用于文本相似性
- BERTScore 用于语义相似性
- 人工评估用于质量评估
端到端指标:
- 任务成功率
- 用户满意度评分
- 延迟百分位(p50,p95,p99)
结论
RAG 系统的格局已显著成熟,超越了基本的向量相似性搜索。LongRAG、Self-RAG 和 GraphRAG 各自解决了传统方法的特定限制:
LongRAG 通过采用扩展上下文窗口和最小化分块解决了上下文碎片化问题。当文档连贯性重要且你拥有处理大上下文的计算资源时,它是首选方案。
Self-RAG 为检索系统添加了关键的自我意识。通过反思自己的决策,它减少了误报并提高了可信度——这对于准确性比速度更重要的高风险应用至关重要。
GraphRAG 解锁了结构化知识表示的力量。当你的领域涉及实体之间的复杂关系时,基于图的检索可以揭示向量相似性完全忽略的联系。
RAG 的未来可能涉及 混合方法,结合这些变体的优势。一个生产系统可能使用 GraphRAG 来识别相关实体集群,使用 Self-RAG 来过滤和验证检索,使用 LongRAG 来为 LLM 组装连贯的上下文。
随着 LLM 不断改进和上下文窗口扩大,我们将看到更多复杂的 RAG 变体出现。关键是理解你特定的使用案例需求——文档结构、查询模式、准确性要求和计算约束,并选择适当的技巧或组合。
工具生态系统正在迅速成熟,像 LangChain、LlamaIndex 和 Haystack 这样的框架为这些高级模式提供了越来越复杂的支持。结合强大的本地 LLM 运行时和嵌入模型,现在比以往任何时候都更容易试验和部署生产级 RAG 系统。
从基础开始,严格衡量性能,并根据需求演变你的架构。本文中介绍的高级 RAG 变体为这种演变提供了路线图。
有用的链接
- Python 快速参考
- 使用嵌入模型进行重排序
- LLMs 与结构化输出:Ollama、Qwen3 与 Python 或 Go
- 云 LLM 提供商
- LLMs 比较:Qwen3:30b vs GPT-OSS:20b