RAG 接入知识图谱:全局数据关系表示与实战指南
在构建检索增强生成(RAG)系统时,传统方法往往面临上下文碎片化的问题。将知识图谱(Knowledge Graph, KG)引入 RAG 架构,能够利用图结构的全局数据关系表示能力,显著提升复杂查询的准确性。
1. 核心优势:全局数据关系表示
传统 RAG 通常基于向量相似度检索 Top-K 个文本块。当文本块过多超出大模型上下文限制,或关键信息分散在不相邻的文本块中时,回答质量会大幅下降。
知识图谱的优势在于其结构化特性:
- 全局视野:LLM 可以看到整个图谱的背景关系,而非孤立的片段。
- 精确关联:通过图遍历和 Cypher 查询,能精准定位实体间的关系。
- 减少幻觉:基于事实图谱的数据比纯文本检索更具可信度。
示例场景
用户提问:'有多少位于 Germany 的供应商?'
- 传统 RAG:可能检索到包含 "Germany" 和 "Supplier" 的文档片段,但难以统计总数。
- RAG + KG:LLM 理解图谱背景,执行 Cypher 查询,直接返回准确计数结果。
2. 基础概念:向量与相似度检索
要理解 RAG 与 KG 的结合,首先需要明确向量的基本概念。
2.1 什么是向量?
在机器学习中,现实世界的对象和概念通常被表示为一组连续数字,称为向量嵌入(Vector Embeddings)。这种方法将物体之间的相似性转换为向量空间中的距离。
- 语义相似性:由向量在空间中的接近程度表示。
- 常用模型:Word2Vec、GloVe、USE 用于文本;VGG 等 CNN 模型用于图像。
2.2 向量距离与相似度
通过计算对象向量之间的距离来判断相似性。常用的距离度量包括:
- 欧几里得距离 (Euclidean)
- 曼哈顿距离 (Manhattan)
- 余弦相似度 (Cosine)
- 切比雪夫距离 (Chebyshev)
选择合适的距离指标取决于具体任务需求。在 LangChain 与 Neo4j 集成中,通常使用余弦相似度来衡量文本嵌入的接近程度。
3. 环境准备与索引创建
本部分演示如何将 Neo4j 图数据库中的数据索引到 RAG 应用中,并实现指定范围的节点检索。
3.1 为什么指定索引节点?
图数据库可能包含大量数据,全量索引不仅消耗资源,还可能涉及数据安全问题。例如,财务部的数据不应被销售部随意查询。因此,支持按节点标签(Node Label)筛选索引至关重要。
3.2 实操步骤
激活环境
确保已安装必要的依赖库(如 langchain, neo4j, openai 等),并激活 Conda 环境:
conda activate medkg
启动 Jupyter Notebook
jupyter notebook
配置环境变量
打开 .env 文件,确保填写了正确的 API Key 和数据库连接信息:
NEO4J_URI: 数据库地址
NEO4J_USERNAME: 用户名
NEO4J_PASSWORD: 密码
OPENAI_API_KEY: 大模型密钥
创建向量索引
使用 Neo4jVector.from_existing_graph 方法基于已有图数据库创建向量索引。以下代码展示了如何配置索引参数:
from langchain.vectorstores import Neo4jVector
import os
neo4j_graph_vector_index = Neo4jVector.from_existing_graph(
embedding=OpenAIEmbeddings(),
url=os.getenv("NEO4J_URI"),
username=os.getenv("NEO4J_USERNAME"),
password=os.getenv("NEO4J_PASSWORD"),
index_name="employee",
node_label="Employee",
text_node_properties=[
"address", "note", "city",
"postcode", "job_title",
"first_name", "last_name",
"region"
],
embedding_node_property="embedding"
)
此配置将仅对标记为 Employee 的节点进行向量索引,并将生成的向量存储在 embedding 属性中。
4. 查询策略:从相似性搜索到精锁查询
索引完成后,即可发起检索。根据任务目标,可调整查询颗粒度。
4.1 单次相似性查询
最简单的查询方式是直接搜索最相似的节点。
result = neo4j_graph_vector_index.similarity_search("Andrew", k=1)
k=1:返回最相似的 1 个节点。
result[0]:获取第一个匹配结果。
潜在问题:如果公司中存在同名员工(如一个在美国,一个在英国),单纯依靠相似度可能导致歧义。
4.2 精锁查询(Filtering)
为解决多重合数据问题,可以添加过滤条件,锁定更精确的数据范围。
result = neo4j_graph_vector_index.similarity_search(
"Employee details",
filter={ "country": "UK" }
)
filter:只返回 country 属性值为 UK 的节点。
- 这确保了即使存在同名员工,也能根据地理位置精准定位。
5. 构建 Chat 应用:RAG + KG 实战
掌握索引与查询后,我们可以构建一个完整的问答聊天应用。
5.1 定义提示词模板
为了防止大模型产生幻觉,需明确指示其仅基于提供的上下文回答。
employee_details_chat_template_str = """
你的任务是使用提供的员工数据来回答关于他们的角色、表现和在公司内的经验的问题。
使用以下上下文来回答问题。
请尽可能详细地回答,但不要添加任何上下文之外的信息。
如果你不知道答案,就说你不知道。
{context}
"""
5.2 创建查询引擎
结合检索器和语言模型(LLM)构建链式处理流程。
from langchain.chains import RetrievalQA
qa_chain = RetrievalQA.from_chain_type(
llm=llm_model,
retriever=neo4j_graph_vector_index.as_retriever(),
chain_type="stuff"
)
链类型说明:
stuff:将所有文档文本合并后一次性输入模型。
map_reduce:分别处理每个文档后汇总。
refine:先生成初始答案,再逐步细化。
5.3 发起查询
用户提问:'介绍一下 Andrew?'
系统会自动检索相关节点,提取上下文,并由 LLM 生成自然语言回答。
6. 进阶:自然语言转 Cypher 实时对话
索引数据虽然高效,但无法实时更新。若部门有新数据加入 Neo4j,如何通过对话实时访问?
6.1 风险与权限控制
使用 LLM 自动生成 Cypher 语句存在风险(如误删数据)。必须严格分配权限,确保 LLM 只能执行读取操作,禁止写入或删除权限。
6.2 Few-Shot Prompting 策略
通过提供少量示例(Few-Shot),指导 LLM 正确生成 Cypher 查询。
qa_generation_template_str = """
您是一名助手,负责将 Neo4j Cypher 查询的结果转化为易于人类阅读的响应。
查询结果部分包含了基于用户自然语言问题生成的 Cypher 查询结果。
所提供的信息是权威的;您绝不能质疑它,或者使用您的内部知识去更改它。
确保您的回答听起来像是针对问题的回应。
Query Results:
{context}
Question:
{question}
如果提供的信息为空,请通过声明您不知道答案来回应。
空信息由以下方式表示:[]
如果信息不为空,您必须使用结果来提供答案。
当查询结果中提供名称时,例如医院名称,要小心任何包含逗号或其他标点符号的名称。
绝不要在查询结果中有数据的情况下表示你缺乏足够的信息。
Helpful Answer:
"""
6.3 创建链式实例
使用 GraphCypherQAChain 实现 NL2Cypher 功能。
from langchain.graphs import Neo4jGraph
from langchain.chains import GraphCypherQAChain
graph = Neo4jGraph()
cypher_qa_chain = GraphCypherQAChain.from_llm(
graph=graph,
verbose=True,
validate_cypher=True,
qa_prompt=qa_generation_prompt,
cypher_prompt=cypher_generation_prompt,
qa_llm=ChatOpenAI(model="gpt-3.5-turbo", temperature=0),
cypher_llm=ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
)
validate_cypher=True:防止语法错误的查询被执行。
temperature=0:降低随机性,确保查询逻辑稳定。
7. 总结与最佳实践
将知识图谱融入 RAG 系统,能够有效解决传统检索的碎片化问题,实现全局数据关系的精准表达。
关键要点:
- 混合检索:结合向量检索(语义)与图查询(关系),互补不足。
- 安全优先:NL2Cypher 模式务必限制数据库权限,防止数据泄露或破坏。
- 性能优化:合理设置索引节点范围,避免全量索引带来的资源浪费。
- 持续迭代:根据业务反馈调整提示词模板和过滤条件。
通过上述步骤,开发者可以构建出既具备语义理解能力,又拥有精确事实推理能力的智能问答系统。