使用 LangChain 和 Neo4j 构建 GraphRAG 工作流

随着 Neo4j 宣布与 LangChain 的集成,我们见证了大量基于知识图谱和大语言模型(LLM)的检索增强生成(RAG)应用场景的涌现。这一发展在最近几个月显著推动了知识图谱在 RAG 中的应用。相比传统的 RAG 系统,基于知识图谱的 RAG 系统在管理幻觉(hallucinations)方面表现更佳。此外,基于代理的系统的使用也在快速增长,以进一步增强 RAG 应用。为了更进一步,LangChain 生态系统中新增了 LangGraph 框架,为 LLM 应用添加了循环和持久化功能。

本文将详细介绍如何使用 LangChain 和 Neo4j 构建一个 GraphRAG 工作流,并通过实际代码示例进行分步讲解,最后提供完整的代码实现。

目录

  1. 项目简介
  2. 环境配置
    • 安装必要的库
    • 配置环境变量
  3. 代码结构与功能概述
  4. 分步讲解代码
    • 导入库与加载环境变量
    • 配置 OpenAI LLM
    • 读取和分割文本
    • 转换为图文档
    • 连接 Neo4j 数据库
    • 写入图数据库
    • 查询与验证
  5. 完整代码
  6. 总结与展望

项目简介

在本项目中,我们将使用 LangChain 构建一个工作流,该工作流能够读取文本数据,使用大语言模型进行处理,并将结果存储在 Neo4j 图数据库中。这种方式不仅能够有效管理和查询知识,还能通过图数据库的强大关系分析能力,增强 RAG 应用的表现。

环境配置

安装必要的库

首先,确保您的开发环境中安装了以下必要的 Python 库:

pip install langchain_openai dotenv langchain_community python-dotenv

配置环境变量

为了确保敏感信息(如 API 密钥、数据库链接和密码)的安全,我们将使用环境变量来存储这些信息。您可以通过创建一个 .env 文件来管理这些变量。

  1. 创建 .env 文件

在项目的根目录下创建一个名为 .env 的文件,并添加以下内容:

OPENAI_API_KEY=your_openai_api_key
OPENAI_API_URL=http://your_api_url:port/v1
NEO4J_URI=bolt://your_neo4j_host:port
NEO4J_USERNAME=your_neo4j_username
NEO4J_PASSWORD=your_neo4j_password

注意: 请将 your_openai_api_keyyour_api_urlyour_neo4j_hostyour_neo4j_usernameyour_neo4j_password 替换为您的实际凭证信息。

  1. 加载环境变量

在代码中使用 python-dotenv 库加载 .env 文件中的环境变量:

from dotenv import load_dotenv

# 加载 .env 文件中的环境变量
load_dotenv()

代码结构与功能概述

整个工作流分为以下几个主要步骤:

  1. 导入库与加载环境变量:引入必要的 Python 库并加载环境变量。
  2. 配置 OpenAI LLM:设置大语言模型的相关参数。
  3. 读取和分割文本:从文件中读取文本内容,并使用 RecursiveCharacterTextSplitter 进行分块处理。
  4. 转换为图文档:将分割后的文档转换为适合存储在图数据库中的格式。
  5. 连接 Neo4j 数据库:配置并连接到 Neo4j 图数据库。
  6. 写入图数据库:将转换后的图文档写入 Neo4j 数据库中。
  7. 查询与验证:执行数据库查询以验证数据的正确写入。

分步讲解代码

下面我们将逐步解析每一部分代码,理解其功能与实现。

导入库与加载环境变量

from langchain_openai import OpenAI
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage
from langchain_core.documents import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_experimental.graph_transformers import LLMGraphTransformer
# 对接国产模型需要修改use_function_call 
# from llm_cn import LLMGraphTransformer 

import os
from dotenv import load_dotenv
from langchain_community.graphs import Neo4jGraph

# 加载 .env 文件中的环境变量
load_dotenv()

说明:

  • 导入了 LangChain 相关的库,用于与 OpenAI 的 API 交互以及处理文档。
  • 使用 dotenv 库加载环境变量,确保敏感信息不直接暴露在代码中。
  • 导入 Neo4jGraph 用于与 Neo4j 图数据库进行交互。

配置 OpenAI LLM

api_key = os.getenv("OPENAI_API_KEY")
api_url = os.getenv("OPENAI_API_URL")
model = "glm-4-plus"

llm = ChatOpenAI(
    model_name=model,
    openai_api_key=api_key,
    openai_api_base=api_url,
    temperature=0.9
)

说明:

  • 从环境变量中获取 OpenAI API 密钥和 API URL。
  • 配置大语言模型(LLM)的相关参数,包括模型名称和温度(控制生成文本的随机性)。

读取和分割文本

# 从文件读取文本
file_path = 'data/****.txt'  # 请替换为您实际的文件路径
with open(file_path, 'r', encoding='utf-8') as file:
    text = file.read()

# 使用 RecursiveCharacterTextSplitter 对文本进行分片
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=2000,  # 每个分片的最大字符数
    chunk_overlap=20  # 分片之间的重叠字符数
)

# 分片文档
chunks = text_splitter.split_text(text)
documents = [Document(page_content=chunk) for chunk in chunks]

说明:

  • 从指定路径读取文本文件内容。
  • 使用 RecursiveCharacterTextSplitter 将文本按指定的字符数进行分块,并设置块之间的重叠部分,以确保上下文的连贯性。
  • 将分块后的文本封装成 Document 对象列表,便于后续处理。

转换为图文档

llm_transformer = LLMGraphTransformer(llm=llm)
# 调用国产模型,需要增加关闭use_function_call的参数
# llm_transformer = LLMGraphTransformer(llm=llm, use_function_call=False)

graph_documents = llm_transformer.convert_to_graph_documents(documents)
print(len(graph_documents))
print(f"Nodes: {graph_documents[0].nodes}")
print(f"Relationships: {graph_documents[0].relationships}")

说明:

  • 创建一个 LLMGraphTransformer 对象,传入配置好的 LLM。
  • 使用 LLM 将文档转换为适合存储在图数据库中的图文档(包含节点和关系)。
  • 打印转换后的图文档的节点和关系数量,以验证转换效果。

连接 Neo4j 数据库

# 配置 Neo4j 连接信息
neo4j_uri = os.getenv("NEO4J_URI")
neo4j_username = os.getenv("NEO4J_USERNAME")
neo4j_password = os.getenv("NEO4J_PASSWORD")

os.environ["NEO4J_URI"] = neo4j_uri
os.environ["NEO4J_USERNAME"] = neo4j_username
os.environ["NEO4J_PASSWORD"] = neo4j_password

graph = Neo4jGraph()

说明:

  • 从环境变量中获取 Neo4j 的连接 URI、用户名和密码。
  • 设置环境变量,确保 Neo4jGraph 能够正确读取这些信息进行连接。
  • 创建一个 Neo4jGraph 对象,作为后续数据库操作的接口。

写入图数据库

# 写入到图数据库中,不包括原始文档
graph.add_graph_documents(
    graph_documents,
    baseEntityLabel=True,
    include_source=False
)

说明:

  • 使用 add_graph_documents 方法将转换后的图文档写入 Neo4j 数据库。
  • 参数说明:
    • baseEntityLabel=True:为每个实体添加基本标签。
    • include_source=False:不包括原始文档内容,仅存储转换后的节点和关系。

显示节点名称

# 看不到节点名称,可以用下面的查询复制一下 name
# 基于查询语句复制 name 属性
QUERY = """
MATCH (n)
WHERE n.id IS NOT NULL
SET n.name = n.id
RETURN n
"""
graph.query(QUERY)
print("success")

说明:

  • 执行一段 Cypher 查询语句,将每个节点的 name 属性设置为其 id 属性的值,便于在图数据库中查看和识别节点。
  • 打印 "success" 以确认操作成功完成。

完整代码

以下是完整的代码实现,整合了上述所有步骤:

from langchain_openai import OpenAI
from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage
from langchain_core.documents import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_experimental.graph_transformers import LLMGraphTransformer
# 对接国产模型需要修改use_function_call 
# from llm_cn import LLMGraphTransformer 

import os
from dotenv import load_dotenv
from langchain_community.graphs import Neo4jGraph

# 加载 .env 文件中的环境变量
load_dotenv()

api_key = os.getenv("OPENAI_API_KEY")
api_url = os.getenv("OPENAI_API_URL")
model = "glm-4-plus"

llm = ChatOpenAI(
    model_name=model,
    openai_api_key=api_key,
    openai_api_base=api_url,
    temperature=0.9
)

# 从文件读取文本
file_path = 'data/******.txt'  # 请替换为您实际的文件路径
with open(file_path, 'r', encoding='utf-8') as file:
    text = file.read()

# 使用 RecursiveCharacterTextSplitter 对文本进行分片
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=2000,  # 每个分片的最大字符数
    chunk_overlap=20  # 分片之间的重叠字符数
)

# 分片文档
chunks = text_splitter.split_text(text)
documents = [Document(page_content=chunk) for chunk in chunks]   

llm_transformer = LLMGraphTransformer(llm=llm)
# 调用国产模型,需要增加关闭use_function_call的参数
# llm_transformer = LLMGraphTransformer(llm=llm, use_function_call=False)

graph_documents = llm_transformer.convert_to_graph_documents(documents)
print(len(graph_documents))
print(f"Nodes: {graph_documents[0].nodes}")
print(f"Relationships: {graph_documents[0].relationships}")

# 配置 Neo4j 连接信息
neo4j_uri = os.getenv("NEO4J_URI")
neo4j_username = os.getenv("NEO4J_USERNAME")
neo4j_password = os.getenv("NEO4J_PASSWORD")

os.environ["NEO4J_URI"] = neo4j_uri
os.environ["NEO4J_USERNAME"] = neo4j_username
os.environ["NEO4J_PASSWORD"] = neo4j_password

graph = Neo4jGraph()

# 写入到图数据库中,不包括原始文档
graph.add_graph_documents(
    graph_documents,
    baseEntityLabel=True,
    include_source=False
)

# 看不到节点名称,可以用下面的查询复制一下 name
# 基于查询语句复制 name 属性
QUERY = """
MATCH (n)
WHERE n.id IS NOT NULL
SET n.name = n.id
RETURN n
"""
graph.query(QUERY)
print("success")

总结与展望

通过本文的介绍,我们展示了如何结合使用 LangChain 和 Neo4j 构建一个强大的 GraphRAG 工作流。这种工作流不仅能够高效地处理和存储大量文本数据,还能利用知识图谱的优势,提升检索与生成的能力。随着 LangChain 生态系统的不断发展,诸如 LangGraph 等新框架的加入,将进一步增强 LLM 应用的循环与持久化功能,为开发者提供更多可能性。

未来,基于知识图谱的 RAG 系统有望在各类应用场景中发挥更大的作用,如智能问答、推荐系统、知识管理等。同时,随着技术的进步和社区的贡献,相关工具和框架将变得更加成熟和易用,开发者可以更轻松地构建出符合自身需求的智能应用。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风翔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值