传统 RAG 在跨文档、多步骤推理上存在局限,GraphRAG 通过构建知识图谱关联实体关系,实现更准确的多跳查询与答案生成。
我们很高兴你在这里。你可以期待 TNS 最好的内容从周一到周五每天送达,让你紧跟新闻动态、保持最佳状态。
查看你的收件箱,收到确认邮件后可以调整偏好设置,甚至加入其他社群。
在你最喜欢的社交媒体平台上关注 TNS。
在 LinkedIn 上成为 TNS 关注者。
在等待第一封 TNS 时事通讯时,看看最新的精选和热门文章。
当前 AI 工程中设计 LLM 的方法过于简化。根据回音室的看法,解决 LLM 幻觉很简单:只需设计一个标准的检索增强生成(RAG)系统,将 PDF 拆分为 1,000 个 token 的块,进行嵌入,插入向量数据库,然后执行余弦相似度搜索。
在真正部署之前……它运行得非常好。
部署之后,企业很快发现,仅使用分块文本进行检索在复杂问题面前效果并不好。标准 RAG 假设语义相似性意味着相关性,但事实并非如此。当用户提出需要通过概念 C 在概念 A 和概念 B 之间建立联系的多跳(multi-hop)问题时,标准 RAG 无法发挥作用,因为这些概念通常不会出现在同一个文本块中。RAG 在全局摘要("我们所有合规报告中讨论的主要风险因素是什么?")上也失效了。
"标准 RAG 假设语义相似性意味着相关性,但事实并非如此。"
如果你在为企业的 AI 系统做设计,你需要结构化推理。文本分块是可以的,但不应该随机进行。你需要的是 GraphRAG。
GraphRAG 将知识图谱的结构化知识与向量搜索的语义能力强大结合。本教程将解释你当前的流水线为何失败,并帮助你使用 Python 实现 GraphRAG 工作流。
我们现在来拆解一个关于向量嵌入的简单误解!
假设你有一个存储在向量数据库中的企业合同数据集。
Chunk 1: "Acme Corp 于 2022 年收购了 BetaTech。"
Chunk 2: "Sarah Connor 于 2023 年被任命为 BetaTech 的 CEO。"
查询: "谁领导 Acme Corp 收购的那家公司?"
朴素的向量搜索会嵌入查询并找到最相似的块。不可避免地,会找到与"Acme Corp"和"领导力"高度相似的块,但"Chunk 2"会被忽略,因为"Sarah Connor"和"BetaTech 的 CEO"在语义上与"Acme Corp"毫无关系。
常规 RAG 方法缺乏与不同实体的结构化关系。要回答多跳查询,你需要理解存在这样的关系:("Acme Corp") - [收购] -> (BetaTech),以及 ("Sarah Connor") - [领导] -> (BetaTech)。
这正是 GraphRAG 的用武之地。
GraphRAG 要求 LLM 在摄取步骤处理文档,提取节点(实体)和边(关系),从你的文本块创建知识图谱。
与传统方法(查询由孤立的文本字符串组成)不同,在 GraphRAG 中,我们首先通过向量搜索识别起始节点,然后遍历图的关系以获取与 LLM 推理高度相关的子图。
最近,Neo4j 的 neo4j-graphrag 等框架使这种架构对每个人都触手可及。我们将使用这个框架构建一个强大的流水线,执行摄取、模式强制和图遍历。
我们将构建一个能够摄取非结构化文本数据、构建知识图谱并通过动态 Cypher 查询图谱的流水线。
你需要一个活跃的 Neo4j 数据库(本地或云端)以及以下包:
Bash
pip install neo4j neo4j-graphrag openai python-dotenv
生产级流水线需要适当的凭证管理和弹性。
GraphRAG 摄取在 LLM API 请求方面极其昂贵。如果不配置速率限制处理器,你的流水线将在处理第一个真实文档时就因 RateLimitError 而失败。
Python
import os
from neo4j import GraphDatabase
from neo4j_graphrag.llm import OpenAILLM
from neo4j_graphrag.embeddings import OpenAIEmbeddings
from neo4j_graphrag.utils.rate_limit import RetryRateLimitHandler
# Initialize Neo4j Driver
neo4j_uri = os.environ.get("NEO4J_URI")
neo4j_user = os.environ.get("NEO4J_USERNAME")
neo4j_password = os.environ.get("NEO4J_PASSWORD")
if not all([neo4j_uri, neo4j_user, neo4j_password]):
raise ValueError("Missing required Neo4j environment variables (NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD).")
driver = GraphDatabase.driver(neo4j_uri, auth=(neo4j_user, neo4j_password))
driver.verify_connectivity()
# Initialize LLM with strict rate limiting for heavy extraction tasks
llm = OpenAILLM(
model_name="gpt-4o",
model_params={"temperature": 0},
rate_limit_handler=RetryRateLimitHandler(max_attempts=5, min_wait=2.0)
)
embedder = OpenAIEmbeddings(model="text-embedding-3-small")
非结构化图谱不过是一个无组织的数据库。一旦你不提供适当的模式,你的 LLM 就会产生实体标签幻觉,重复创建"Acme Corp"、"Acme Corporation"和"Ame"等节点。我们将预先构建架构并将其输入流水线。
"非结构化图谱不过是一个无组织的数据库。"
Python
from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline
# Define explicit schema to prevent LLM hallucinations during extraction
schema = {
"node_types": ["Organization", "Person", "Technology"],
"relationship_types": ["ACQUIRED", "LEADS", "DEVELOPS"],
"patterns": [
("Organization", "ACQUIRED", "Organization"),
("Person", "LEADS", "Organization")
]
}
# Define the pipeline enforcing the schema
kg_builder = SimpleKGPipeline(
llm=llm,
driver=driver,
embedder=embedder,
schema=schema
)
sample_text = """
Acme Corp acquired BetaTech in 2022.
In 2023, Sarah Connor was appointed CEO of BetaTech to drive AI initiatives.
"""
import asyncio
# Execute extraction and graph population
asyncio.run(kg_builder.run_async(text=sample_text))
工程笔记:在底层,这个流水线仍然使用 FixedSizeSplitter 分割文本。不同的是,它在保存之前使用 LLM 从这些块中提取语义架构。
这就是多跳推理发生的地方。普通的向量检索器只会给我们提供节点。要在图上遍历,我们使用 VectorCypherRetriever。我们将嵌入查询,识别语义入口点,最后对所有 1-hop 连接的邻居执行 Cypher 查询。
Python
from neo4j_graphrag.retrievers import VectorCypherRetriever
# Define the traversal logic: Find the vector match, then expand 1-hop to get relationships
traversal_query = """
MATCH (node)[r](neighbor)
RETURN "Entity: " + coalesce(node.id, '') + " (Info: " + coalesce(node.text, '') + ") | " +
"Relationship: " + type(r) + " | " +
"Neighbor: " + coalesce(neighbor.id, '') + " (Info: " + coalesce(neighbor.text, '') + ")" AS text,
score
"""
# Initialize a VectorCypherRetriever to enable actual GraphRAG
retriever = VectorCypherRetriever(
driver=driver,
index_name="entity_vector_index",
embedder=embedder,
retrieval_query=traversal_query
)
query = "Who leads the company that Acme Corp acquired?"
# Retrieve connected context based on the query
retrieved_context = retriever.search(query_text=query, top_k=3)
print(retrieved_context)
检索到的上下文包括 BetaTech、它被 Acme Corp 收购的事实,以及 Sarah Connor 领导它的事实,因为我们提供了特定的模式来检索关系。LLM 现在拥有提供准确回答所需的所有事实。
如果你想升级 RAG 系统,请考虑以下权衡:
摄取成本高昂,而 RAG 成本很低,因为嵌入模型价格低廉。要在 GraphRAG 中摄取每个文档块,你需要 GPT-4o 这样的 LLM 从文档中提取实体。请仔细过滤你的企业数据。
模式设计不是可选项:如步骤 3 所示,你不应该忽视数据建模。模式是高效检索引擎和一团乱节点之间的区别。
可观测性更优:要调试朴素的 RAG,你需要检查大型浮点数组。要调试 GraphRAG,你只需查看 Neo4j 仪表板来查看节点。很容易看出 LLM 是否产生了幻觉。
"标准向量搜索是一个非常强大的解决方案,但将其视为企业 AI 的万能解决方案是一种简单的出路。"
GraphRAG 需要在设计上更加审慎、遵循更严格的指导原则,以及更大的前期计算努力。然而回报是巨大的:GraphRAG给了你做真正有价值的事情的能力——对数据进行多跳推理,而这正是企业所需要的。