LangChain+Neo4j实战:构建图RAG管道与评估指南,全程干货,小白也能轻松掌握!!
本文详细介绍了使用LangChain和Neo4j构建图RAG管道的完整流程,包括从PDF文件提取文本、构建知识图谱、优化检索设置以及使用QAEvalChain评估系统准确性。通过滑雪领域的真实案例,演示了图文档生成、Cypher查询优化和答案评估的全过程,为开发者提供了实用的图RAG应用构建指南。
前言
这次我就接着带大家使用LangChain和Neo4j实现一个真实的图RAG管道,然后我还会采用最简单的方式,也就是LangChain中一个简单的用来评估模型答案准确性的类QAEvalChain
对图RAG结果的准确性进行简单的评估,简单的模拟真实开发场景。
1.构建知识图谱
在之前的分享中,我随便在网上摘抄了一段非常简单的文本来呈现知识图谱的构建流程,这样做的目的主要是为了研究学习,让大家看清楚整个流程。在实际的工作中,引入的数据源可不会这么简单,为了更贴近真实场景,这次我会使用一份关于滑雪的PDF文件来构建知识图谱,整个构建过程依次包含PDF文本提取、文本分块、图文档生成与保存四个阶段。
1.1 引入包
import os
from dotenv import load_dotenv
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
from langchain_experimental.graph_transformers import LLMGraphTransformer
from langchain_neo4j import Neo4jGraph
from langchain_openai import ChatOpenAI
1.2 获取Neo4j实例连接凭证
load_dotenv()
URI = os.getenv("NEO4J_URI")
USER = os.getenv("NEO4J_USER")
PASS = os.getenv("NEO4J_PASS")
1.3 提取PDF文本
对于PDF文件,这里使用的是LangChain自带的用来导入PDF文件并从中提取文本的工具PyPDFLoader
。 通过调用PyPDFLoader
的load()
方法,会返回一个Document列表,列表中每个Document对应PDF中的一页,列表的大小对应PDF的页数。
“
Tip:LangChain中的Document是用来表示文档内容片段的类, 作用主要是传递文档的内容和元数据。
pdf_path = "data/skiing.pdf"
loader = PyPDFLoader(pdf_path)
# pages是一个Document列表
pages = loader.load()
1.4 文本分块
为了规避大语言模型上下文窗口的限制,需将原文本切分成更小的块,分块这里我们采用最为常用的递归切分。
“
Tip:递归切分演练场
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
chunks = text_splitter.split_documents(pages)
1.5 生成图文档
llm = ChatOpenAI(model="gpt-5-nano", temperature=0)
llm_transformer = LLMGraphTransformer(llm=llm)
# graph_documents是包含节点与关系的图文档
graph_documents = llm_transformer.convert_to_graph_documents(chunks)
print(f"Nodes:{graph_documents[0].nodes}")
print(f"Relationships:{graph_documents[0].relationships}")
1.6 保存图文档
graph = Neo4jGraph(url=URI, username=USER, password=PASS)
graph.add_graph_documents(
graph_documents,
# 图谱中要包含引用的源
include_source = True
)
1.7 完整代码
import os
from dotenv import load_dotenv
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
from langchain_experimental.graph_transformers import LLMGraphTransformer
from langchain_neo4j import Neo4jGraph
from langchain_openai import ChatOpenAI
load_dotenv()
URI = os.getenv("NEO4J_URI")
USER = os.getenv("NEO4J_USER")
PASS = os.getenv("NEO4J_PASS")
pdf_path = "data/skiing.pdf"
loader = PyPDFLoader(pdf_path)
pages = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
chunks = text_splitter.split_documents(pages)
llm = ChatOpenAI(model="gpt-5-nano", temperature=0)
llm_transformer = LLMGraphTransformer(llm=llm)
graph_documents = llm_transformer.convert_to_graph_documents(chunks)
print(f"Nodes:{graph_documents[0].nodes}")
print(f"Relationships:{graph_documents[0].relationships}")
graph = Neo4jGraph(url=URI, username=USER, password=PASS)
graph.add_graph_documents(
graph_documents,
include_source = True
)
执行结果如下图所示:
2.设置检索
之前我们简单分享了使用GraphCypherQAChain
基于Neo4j数据库进行问答的简单流程,这是图RAG应用最基础的功能。在真实的使用场景中,大家可能会发现大语言模型与图配合得并不理想——无法生成正确的Cypher查询语句。
什么原因?这是因为大语言模型理解语言,但未必理解数据库模式。在人工智能领域有句名言**“垃圾进,垃圾出”,这既可以指输入数据的质量**,也可以指提示的有效性,我们这里主要讨论后者——提示的有效性,目的是创建出最佳提示,让模型理解图的模式(Schema)。
模式指的是数据的组织方式。在SQL中,模式中包含了表、表中的列以及表与表之间的关系。对于图而言,模式描述的是节点之间的关联关系。要获取图的模式,有两种方式:
- 在Neo4j浏览器中执行
CALL db.schema.visualization
- 在使用LangChain进行图RAG编码时,让LangChain告知模式。
graph = Neo4jGraph(url=URI, username=USER, password=PASS)
# 查看图的模式
print(graph.schema)
# 启用模式增强,让框架从Neo4j中提取更详细的模式
enhanced_graph = Neo4jGraph(url=URI, username=USER, password=PASS, enhanced_schema=True)
# 查看图的模式
print(enhanced_graph.schema)
关于这个schema
,GraphCypherQAChain
内部会在查询时自动提取和传递,无需手动提取和传递,这是LangChain框架封装的便捷功能,目的是确保大语言模型始终能获取到最新的schema
,生成更准确的Cypher查询。
如果我们还想更进一步,我们可以把正确示例包含在提示中,也就是few-shot prompt
,这会让生成的Cypher更加准确。接下来我们就以这个为例,看看具体的代码。
2.1 引入包
import os
from dotenv import load_dotenv
from langchain_neo4j import Neo4jGraph,GraphCypherQAChain
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
2.2 获取Neo4j实例连接凭证
load_dotenv()
URI = os.getenv("NEO4J_URI")
USER = os.getenv("NEO4J_USER")
PASS = os.getenv("NEO4J_PASS")
2.3 创建数据库问答链
llm = ChatOpenAI(model="gpt-5-nano", temperature=0)
graph = Neo4jGraph(url=URI, username=USER, password=PASS, enhanced_schema=True)
CYPHER_GENERATION_TEMPLATE = """
You are an expert Neo4j Developer translating user questions into Cypher to
answer questions about skiing.
Convert the user's question based on the schema.
When you are presented with query properties such as id's like "alpine touring",
be sure to convert the first letter to capital case, such as "Alpine Touring"
before you run the Cypher query.
For example, if I were to ask "Tell me about telemark skiing," you should create
a Cypher query that finds all nodes with the id "Telemark Skiing" and then find
all nodes connected to those nodes and use those to forumulate your answer, like this:
MATCH (a {id: "Telemark Skiing"})-[r]-(b)
RETURN a, r, b
Schema:{schema}
Question: {question}
"""
cypher_generation_prompt = PromptTemplate(
template = CYPHER_GENERATION_TEMPLATE,
input_variables = ["schema", "question"]
)
cypher_chain = GraphCypherQAChain.from_llm(
llm = llm,
graph = enhanced_graph,
prompt = cypher_generation_prompt,
verbose = True,
allow_dangerous_requests = True
)
2.4 查询图数据库
cypher_chain.invoke({"query": "Tell me about freestyle?"})
2.5 完整代码
import os
from dotenv import load_dotenv
from langchain_neo4j import Neo4jGraph,GraphCypherQAChain
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
load_dotenv()
URI = os.getenv("NEO4J_URI")
USER = os.getenv("NEO4J_USER")
PASS = os.getenv("NEO4J_PASS")
llm = ChatOpenAI(model="gpt-5-nano", temperature=0)
graph = Neo4jGraph(url=URI, username=USER, password=PASS, enhanced_schema=True)
CYPHER_GENERATION_TEMPLATE = """
You are an expert Neo4j Developer translating user questions into Cypher to
answer questions about skiing.
Convert the user's question based on the schema.
When you are presented with query properties such as id's like "alpine touring",
be sure to convert the first letter to capital case, such as "Alpine Touring"
before you run the Cypher query.
For example, if I were to ask "Tell me about telemark skiing," you should create
a Cypher query that finds all nodes with the id "Telemark Skiing" and then find
all nodes connected to those nodes and use those to forumulate your answer, like this:
MATCH (a {id: "Telemark Skiing"})-[r]-(b)
RETURN a, r, b
Schema:{schema}
Question: {question}
"""
cypher_generation_prompt = PromptTemplate(
template = CYPHER_GENERATION_TEMPLATE,
input_variables = ["schema", "question"]
)
cypher_chain = GraphCypherQAChain.from_llm(
llm = llm,
graph = enhanced_graph,
prompt = cypher_generation_prompt,
verbose = True,
allow_dangerous_requests = True
)
cypher_chain.invoke({"query": "Tell me about freestyle?"})
3.评估图RAG管道
对于采用大语言模型构建的任何应用,都必须在构建完成后制定测试和评估计划,评估其是否满足上生产环境的条件,这一步至关重要。即使对其进行了细微的调整,最好的做法也是对其再次进行评估,否则如何确认修改的有效性。
截止目前,我们已经构建了知识图谱,设置了检索功能,接下来我们要做的就是判断这个系统是否真的有效。我们的目标很简单——确保答案既相关又准确。
准确性指的是模型是否正确回答了用户问题,准确性最简单的评估方式是通过给模型提供一系列已标注答案的问题让模型生成自己的答案,然后将模型的输出与预期答案进行对比评分。
理想情况下我们应当准备大量评估问题,不过这样做既有挑战性,也非常耗时,所以我们就让模型来代劳。补充一下,目前市面上有许多评估人工智能应用性能的工具包,其中包含LangChain中的LangSmith,但我们这里主要使用的是LangChain中一个简单的类QAEvalChain
,它可以用来评估模型生成的答案是否匹配参考答案,我们具体来看看怎么做。
3.1 引入包
import os
from dotenv import load_dotenv
from langchain.evaluation.qa.eval_chain import QAEvalChain
from langchain_neo4j import Neo4jGraph,GraphCypherQAChain
from langchain_openai import ChatOpenAI
3.2 获取Neo4j实例凭证
load_dotenv()
URI = os.getenv("NEO4J_URI")
USER = os.getenv("NEO4J_USER")
PASS = os.getenv("NEO4J_PASS")
3.3 构造测试集
需要注意这里为了演示我只构造了少量测试集,对于测试集来说最佳的做法是尽可能构造大规模、包含多样化查询问题的测试集。
examples = [
{"query": "What sports is the International Ski And Snowboard Federation responsible for?",
"answer": "Alpine Skiing, Freestyle Skiing, Snowboarding, Nordic Combined, Ski Jumping, Cross-Country Skiing"},
{"query": "What activity are ski poles not used in?", "answer": "Ski jumping"},
{"query": "Who do athletes get help from?", "answer": "Coaches, Peer Mentors, and Sports Psychologists"},
]
3.4 创建数据库问答链
graph = Neo4jGraph(url=URI, username=USER, password=PASS, enhanced_schema=True)
llm = ChatOpenAI(model="gpt-5-nano", temperature=0)
chain = GraphCypherQAChain.from_llm(
graph=graph,
llm=llm,
verbose=True,
allow_dangerous_requests=True,
)
3.5 执行并保存模型答案
predictions = []
for ex in examples:
response = chain.invoke({"query": ex["query"]})
predictions.append({"result": response["result"].strip()})
3.6 使用模型进行评估
eval_chain = QAEvalChain.from_llm(llm)
results = eval_chain.evaluate(examples, predictions)
3.7 构造打印评估结果
correct = 0
for i, res in enumerate(results):
print(f"Query: {examples[i]['query']}")
print(f"Prediction from graph: {predictions[i]['result']}")
print(f"Gold answer: {examples[i]['answer']}")
print(f"Grade: {res['results']}")
print("---")
if res["results"] == "CORRECT":
correct += 1
accuracy = correct / len(examples)
print(f"Graph QA Accuracy: {accuracy:.2f}")
3.8 完整代码
import os
from dotenv import load_dotenv
from langchain.evaluation.qa.eval_chain import QAEvalChain
from langchain_neo4j import Neo4jGraph,GraphCypherQAChain
from langchain_openai import ChatOpenAI
load_dotenv()
URI = os.getenv("NEO4J_URI")
USER = os.getenv("NEO4J_USER")
PASS = os.getenv("NEO4J_PASS")
examples = [
{"query": "What sports is the International Ski And Snowboard Federation responsible for?",
"answer": "Alpine Skiing, Freestyle Skiing, Snowboarding, Nordic Combined, Ski Jumping, Cross-Country Skiing"},
{"query": "What activity are ski poles not used in?", "answer": "Ski jumping"},
{"query": "Who do athletes get help from?", "answer": "Coaches, Peer Mentors, and Sports Psychologists"},
]
graph = Neo4jGraph(url=URI, username=USER, password=PASS, enhanced_schema=True)
llm = ChatOpenAI(model="gpt-5-nano", temperature=0)
chain = GraphCypherQAChain.from_llm(
graph=graph,
llm=llm,
verbose=True,
allow_dangerous_requests=True,
)
predictions = []
for ex in examples:
response = chain.invoke({"query": ex["query"]})
predictions.append({"result": response["result"].strip()})
eval_chain = QAEvalChain.from_llm(llm)
results = eval_chain.evaluate(examples, predictions)
correct = 0
for i, res in enumerate(results):
print(f"Query: {examples[i]['query']}")
print(f"Prediction from graph: {predictions[i]['result']}")
print(f"Gold answer: {examples[i]['answer']}")
print(f"Grade: {res['results']}")
print("---")
if res["results"] == "CORRECT":
correct += 1
accuracy = correct / len(examples)
print(f"Graph QA Accuracy: {accuracy:.2f}")
由于模型生成答案的随机性,可能每次结果都不一样,所以应当运行多次,这其实也是需要大量测试问题的原因,目的是为了更好的理解评分分布。我们采用的这种方法仅评估基础准确率是否符合预期,要知道还有很多其它指标用来对图RAG进行评估,比如实用性、相关性,甚至图的可追溯性。
4.总结
这次分享我们完整走了一遍图RAG管道的构建流程:从用PDF构建滑雪领域知识图谱,到优化提示词提升检索准确性,再到用QAEvalChain评估系统性能。希望通过这个案例,能让大家对图RAG真实构建过程有一定的了解,对大家有点帮助。
最后
为什么要学AI大模型
当下,⼈⼯智能市场迎来了爆发期,并逐渐进⼊以⼈⼯通⽤智能(AGI)为主导的新时代。企业纷纷官宣“ AI+ ”战略,为新兴技术⼈才创造丰富的就业机会,⼈才缺⼝将达 400 万!
DeepSeek问世以来,生成式AI和大模型技术爆发式增长,让很多岗位重新成了炙手可热的新星,岗位薪资远超很多后端岗位,在程序员中稳居前列。
与此同时AI与各行各业深度融合,飞速发展,成为炙手可热的新风口,企业非常需要了解AI、懂AI、会用AI的员工,纷纷开出高薪招聘AI大模型相关岗位。
最近很多程序员朋友都已经学习或者准备学习 AI 大模型,后台也经常会有小伙伴咨询学习路线和学习资料,我特别拜托北京清华大学学士和美国加州理工学院博士学位的鲁为民老师给大家这里给大家准备了一份涵盖了AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频 全系列的学习资料,这些学习资料不仅深入浅出,而且非常实用,让大家系统而高效地掌握AI大模型的各个知识点。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】

AI大模型系统学习路线
在面对AI大模型开发领域的复杂与深入,精准学习显得尤为重要。一份系统的技术路线图,不仅能够帮助开发者清晰地了解从入门到精通所需掌握的知识点,还能提供一条高效、有序的学习路径。
但知道是一回事,做又是另一回事,初学者最常遇到的问题主要是理论知识缺乏、资源和工具的限制、模型理解和调试的复杂性,在这基础上,找到高质量的学习资源,不浪费时间、不走弯路,又是重中之重。
AI大模型入门到实战的视频教程+项目包
看视频学习是一种高效、直观、灵活且富有吸引力的学习方式,可以更直观地展示过程,能有效提升学习兴趣和理解力,是现在获取知识的重要途径
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
海量AI大模型必读的经典书籍(PDF)
阅读AI大模型经典书籍可以帮助读者提高技术水平,开拓视野,掌握核心技术,提高解决问题的能力,同时也可以借鉴他人的经验。对于想要深入学习AI大模型开发的读者来说,阅读经典书籍是非常有必要的。
600+AI大模型报告(实时更新)
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
AI大模型面试真题+答案解析
我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】


为武汉地区的开发者提供学习、交流和合作的平台。社区聚集了众多技术爱好者和专业人士,涵盖了多个领域,包括人工智能、大数据、云计算、区块链等。社区定期举办技术分享、培训和活动,为开发者提供更多的学习和交流机会。
更多推荐
所有评论(0)