基于neo4j数据库和dify大模型框架的rag模型搭建

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 基于neo4j数据库和dify大模型框架的rag模型搭建

本文主要讲述关于如何从pdf文档中提取数据并用于生成知识图谱,搭建基于知识图谱的rag模型的过程。

(其实就是知识库?有一说一因为根本没上课其实我也不知道我做的是啥,但是大概是符合课设要求的)

前置准备

neo4j数据库

neo4j用于存储从pdf文档中提取的数据。

安装方式有docker或者直接安装两种方式。

可以参考https://neo4j.com/docs/operations-manual/current/installation/linux/debian/

由于我使用的是直接安装的,因此docker安装方式就不作过多介绍了。

直接安装的配置如下:

主机: Ubuntu 22.04(其实是虚拟机)
jdk: openjdk-21-jdk
neo4j: (version)2025.04.0
AI 代码解读

由于neo4j是依赖于java运行的,因此需要java环境,如果之前没安装过java的话那很幸运,只需要一个java即可;如果之前已经安装过java,则需要对java版本的优先级进行调整(具体去问ai)。有一说一,其实不推荐安装最新版,因为大多数ai对最新版都不怎么熟悉,很容易出错,不会由于当时我已经装完了,所以只能硬着头皮往下干。(沉没成本不参与重大决策?)

安装流程

# 检验java是否安装
java --version
apt list openjdk-*jdk
sudo apt install openjdk-21-jdk
java --version
# 安装neo4j并检验
wget -O - https://debian.neo4j.com/neotechnology.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/neotechnology.gpg
echo 'deb [signed-by=/etc/apt/keyrings/neotechnology.gpg] https://debian.neo4j.com stable latest' | sudo tee -a /etc/apt/sources.list.d/neo4j.list
sudo apt-get update
apt list -a neo4j
sudo apt-get install neo4j:2025.04.0
neo4j help
AI 代码解读

第一步是安装java,第二步是将neo4j所在的库添加到apt源中然后用apt安装。

(其实可以用deb文件包然后dpkg安装,但是官方文档给的会显示不是一个合法的deb文件,肥肠奇怪,无法理解)

安装完之后将neo4j启动

sudo neo4j start
AI 代码解读

启动成功之后会显示
image-20250525202405716.png

之后自动使用守护进程运行,转入后台。

在回显中可以看到plugins目录和conf目录。先进入/var/lib/neo4j/labs中,将其中的apoc开头的jar包拷贝到plugins目录中。如果有需要,还可以去apoc的github仓库中安装额外的补全插件(插件地址为:https://github.com/neo4j-contrib/neo4j-apoc-procedures/releases/download/2025.04.0/apoc-2025.04.0-extended.jar)。

然后进入/etc/neo4j目录中,其中存在neo4j.conf文件,先对其进行修改,修改之后如下。这个修改使得在neo4j的浏览器页面中可以调用apoc函数。

image-20250525203002386.png

再作修改,使得其他主机能够访问neo4j。如果在容器中还可能用到host.docker.internal(只适用于macos和windows),当然直接安装就没有这种问题了。

# neo4j.conf
server.default_listen_address=0.0.0.0
AI 代码解读

再在neo4j.conf的同级目录中新建一个apoc.conf,内容为

apoc.import.file.enabled=true
AI 代码解读

这样neo4j就算安装完成了。

neo4j的浏览器地址为http://ip:7474/browser/,bolt端口为7687(默认是这样)

使用docker安装的话可以使用-v将docker中的目录映射到主机中,尤其记得要将plugin目录和conf目录映射出来,不然就得使用docker exec进入docker容器中再安装插件,比较麻烦。

dify框架

dify框架的安装比较简单,直接使用docker就可以完成安装,而且和neo4j不存在端口冲突。

首先从github克隆下dify的仓库,按照readme文档中的内容去做即可。

git clone https://github.com/langgenius/dify.git
cd dify
cd docker
cp .env.example .env
sudo docker compose up -d
AI 代码解读

如果没有docker compose的可以试一下docker-compose,不然就是没安装。

# 关闭dify的命令,在docker-compose.yaml目录下
sudo docker compose stop
AI 代码解读

dify的浏览器访问地址为ip,默认端口为80

搭建思路

提取数据 -> 建立数据结构 -> 存入数据库 -> 搭建检索系统 -> 输入llm -> 得到最终输出
AI 代码解读

关于提取数据、建立数据结构、存入数据库这三个部分,可将其视为一个部分,也就是将文档中的数据存入数据库。

提取数据存入数据库

提取数据

数据存储在pdf文档中,在对数据进行读取时还需要对其进行词义分析,将其分类、分段,保留它原先的意思,但是又便于检索。

好在这一步不需要我们手动完成,只需要对数据进行提取,然后交给专门的语言模型处理即可😋。

由于数据是存储在pdf文档中,可以使用pdfplumer进行读取,再使用spacy对其进行分段。

补充关于token的小知识:
在大型语言模型(LLM)中,Token 是模型处理文本数据的基本单位。Token是LLM理解、处理和生成人类语言的基础单位。通过将文本分解为Token,LLM能够将复杂的语言转换为其可以进行数学运算的数字表示形式,从而实现各种强大的自然语言处理能力。
AI 代码解读

所以说将语句进行分段是必要的。

# 核心代码
with pdfplumber.open(pdf_path) as pdf:
        chunks = []
        # 使用spacy分句
        nlp = spacy.load("zh_core_web_sm")
        for idx,page in tqdm(enumerate(pdf.pages), total=len(pdf.pages), desc="Processing PDF"):
            text = page.extract_text()
            meta = {
                "page_number": page.page_number,
                "page_width": page.width,
                "page_height": page.height
            }
            doc = nlp(text)
            sentences = [sent.text.replace('\n', ' ').replace('\r', ' ').strip() for sent in doc.sents]
            # 合并为段落(每段3句)
            for i in range(0, len(sentences), 3):
                chunk_text = "".join(sentences[i:i+3])
                chunks.append({
                    "text": chunk_text,
                    "page_number": meta["page_number"],
                    "start_pos": i,
                    "end_pos": i+3
                })
AI 代码解读

在上述代码中使用spacy中的专门处理中文的模型zh_core_web_sm对从pdf中提取出的数据进行分句,并给其标注信息,如页号等。

当然也可以使用其他的类似模型或者更好的模型,使用更好的模型得到的效果也就更好
AI 代码解读

生成向量索引

token的向量索引,也称为Token Embeddings。在token的向量索引中包含了token的词义信息,也可以快速的检索到token,在之后的检索系统中会用到。

如果不使用向量索引的话,也可以根据输入的关键词对数据库进行检索,这种就很好理解了。
其实使用向量索引也是类似这种用法,只不过是对关键词的词义也进行相关性检索,而不是单纯的仅凭关键词本身。
AI 代码解读

生成向量索引的过程自然也是不需要我们多虑的,也有专门的模型用于创建向量索引。
生成的向量索引维度为384。

model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')
vectors = model.encode([chunk["text"] for chunk in chunks], batch_size=32)
for i, chunk in enumerate(chunks):
    vectors[i] = [x for x in vectors[i]]
    chunk["vector"] = vectors[i].tolist()
AI 代码解读
模型选择并不唯一,但是越好的模型生成的效果肯定是更好的
AI 代码解读

存储到数据库

接下来将其存储到数据库中,在本文中使用的是neo4j数据库,类型为nosql,主要是用于图的存储。

在存储到数据库中时需要创建不同的节点并且指出其相关关系,例如在如下代码中就创建了book节点和chunk节点两种节点,其中chunk节点属于book节点,构成了图。还添加了一些额外的meta data,便于管理和识别。

driver = GraphDatabase.driver("bolt://ip:port", auth=("neo4j", "password"))
with driver.session() as session:
    # 创建Book节点
    session.run("""
        CREATE (b:Book {
            book_id: $book_id,
            title: $title,
            author: $author
        })
    """, book_meta)

    # 创建Chunk节点及关系
    for chunk in chunks:
        session.run("""
            MATCH (b:Book {book_id: $book_id})
            CREATE (c:Chunk {
                chunk_id: $chunk_id,
                text: $text,
                page_number: $page_number,
                start_pos: $start_pos,
                end_pos: $end_pos,
                vector: $vector
            })
            CREATE (c)-[:BELONGS_TO]->(b)
        """, {
   
            "book_id": book_meta["book_id"],
            "chunk_id": f"{book_meta['book_id']}_chunk_{chunk['page_number']}_{chunk['start_pos']}",
            **chunk
        })
AI 代码解读

创建数据库索引

虽然听起来跟之前的向量索引有些相似,但是不是一个东西,之前的索引是作为节点的数据而存在,而现在要创建的数据库索引是为了提升数据库的查询效率而使用的,并且能够高效地执行语义相似度搜索,为检索系统的搭建作准备。

driver = GraphDatabase.driver("bolt://ip:port", auth=("neo4j", "password"))
with driver.session() as session:
    # 创建vector的索引
    session.run(
        """CREATE VECTOR INDEX chunk_vector_index 
        FOR (c:Chunk) ON (c.vector) OPTIONS
        { indexConfig: { `vector.dimensions`: 384,`vector.similarity_function`: 'cosine'}}"""
    )
AI 代码解读

(这里有一个坑,就是如果你使用低版本的neo4j的话,ai会使用apoc中跟vector相关的代码,就可以直接使用。但是由于版本太高了,vector函数被内置到neo4j里,apoc的函数就废弃了,这个函数还是从官方文档里搜出来的,肥肠难受😫)

搭建检索系统

所有对数据的前置准备已经完成,接下来要搭建的是检索系统,用于从数据库中检索出跟用户输入最相关的词条。

首先,要将用户输入的内容也转为向量索引,才好进行比较。

然后使用neo4j中内置的vector比较函数,将相关的数据从neo4j中取出,按照相关性进行排序。

为了提高相关性的准确度,这里可以使用reranker模型进行重排序,得到真正相关性更高的结果。

然后再根据得到相关内容,回到文档中原来的位置,提取其上下文,提高答案的正确率。

因此,检索系统分为四个部分。

输入转换 -> 向量检索 -> 重排序 -> 提取上下文
AI 代码解读

后两个步骤是可选的,在我写的代码中设置了选项,在使用时可选也可不选。只是不选的话得到的答案比较没人样,或者直接得不到答案而已。

听起来比较简单,其实做起来也不是很难(毕竟大部分代码都不是我写的)。

不过由于后续要使用dify框架,所以这里将检索系统封装为了一个http的api,便于后续的调用,使用的是fastapi。(主要是我感觉dify里面的代码执行应该是不允许搞这么复杂的,当然我也没仔细研究过)

输入llm

这个部分也比较简单,选择一个自己喜欢的模型,然后设置好prompt和参数就好了。

prompt可参考:

你是一个专业书籍问答助手,请严格基于用户提供的<上下文>回答问题。
若问题与上下文无关或超出知识范围,必须回答"未找到相关信息"。
回答必须满足以下要求:
1. 答案需完整覆盖问题核心,避免冗余
2. 必须使用中文口语化表达,禁用Markdown格式
3. 若上下文存在矛盾信息,需指出矛盾点

{
  {#context#}}

问题:
{
  {#sys.query#}}

请按以下格式回答:
【答案摘要】
简明总结核心答案(1-2句话)

【详细解释】
分点说明推导过程和依据

【相关延伸】
推荐2-3个关联知识点(可选)
AI 代码解读

实际上llm部分是在dify框架中完成的,所以要先启动dify,如何启动在前置准备章节中已经有详细描述,但是还有一个点没提到,那就是需要注册一个模型api平台的账号,这里我选择的是硅基流动,其实用deepseek或者豆包之类的平台也是一样的,只要它们有提供api的接口就可以。

硅基流动注册

注册只需要手机号验证就可以了(ps:我本来想用github登的,但是登完还是要手机号😓)

如果没有邀请码可以填我的:f1EqQpK5

双方都会获得免费的2000w tokens,我当时注册也是随便搜了一个邀请码就填上了。

注册成功之后在左侧的工具栏中有一个api密钥,新建一个,密钥描述随便写(当然填dify也可以)。

dify初始化

第一次进入dify会要求输入管理员账户,如果是自己用的话随便输一个也没事,有别人要用的话还是设置得复杂一点。

登录成功之后点击右上角的头像>设置>模型供应商,可以看到有很多家,选择硅基流动,输入之前新建的api密钥即可。

这就算初始化完成了。

dify_chatflow搭建

接下来根据之前的思路,也就是数据->检索->llm的流程搭建dify工作流,注意已经将检索系统封装为http的api并且在本地启动,并且数据也已经输入到数据库中。

image-20250525213001882.png

工作流的流程很简单,看看其内部构造

http请求

image-20250525213225134.png

封装了search接口,query是用户在对话框的输入,expand_window是上下文的窗口大小,默认开启了上下文检索但是没有开启重排序,参数类型为json。

代码执行

image-20250525213359658.png

使用http请求的返回值作为输入,解析json,并且提取其中的text的值,返回值为list。

llm

image-20250525213522940.png

prompt在上文中已给出,使用的是千问8B的模型(因为不要钱),真好,也可以自己在主机上跑一个开源的大模型,但是我指定不行,等下笔记本烧了😓。

最后一个选直接回复即可,以llm的输出作为输入。

对于小段文本的测试效果还不错,但是没有使用指标进行度量。其实是可以对性能进行评估的,但是我比较懒,课设的话没必要纠结太多(

而且如果要人工评估的话就要打标签,要用ai评估的话好像也比较麻烦,还得跑很多轮。

dify_workflow搭建

和chatflow差不多,只是开始时需要输入,结束时需要输出。
image-20250525221425847.png

改进方案

可以改进的方向有很多

1、在分句和创建向量时使用更好的模型

2、额外安装一个索引数据库,在neo4j中只存放索引的索引,可以有效提高查询的效率。

3、额外安装一个缓存数据库,如redis,也可以有效提高查询效率。

4、搭建检索系统时可以进行加权,对不同的权值进行调整

5、使用付费的高级llm和更加高级、专业的prompt

6、优化数据结构,例如在搭建的过程中我其实想给出每段文章的页码,但是这样的话要对数据结构进行修改,所以就没有做了

源代码

https://github.com/zx2023qj/rag_model

ZX0R
+关注
目录
打赏
0
37
35
4
10
分享
相关文章
再不玩通义 VACE 模型你就过时了!一个模型搞定所有视频任务
介绍通义的开源模型在 ecs 或 acs 场景如何一键部署和使用,如何解决不同视频生成场景的问题。
10+热门 AI Agent 框架深度解析:谁更适合你的项目?
选型Agent框架不等于追热门!要选真正能跑得稳、适配团队能力与业务需求的框架。架构选错,轻则性能差,重则项目难推进。本文详解10大热门框架对比、5大新兴框架推荐及四步选型法,助你高效落地AI应用。
1688图片搜索逆向工程与多模态搜索融合实践——基于CLIP模型的特征向
本文介绍了通过逆向工程分析实现图片搜索的技术方案,包括请求特征捕获、签名算法破解及多模态搜索的实现。利用CLIP模型提取图像特征,并结合Faiss优化相似度计算,提升搜索效率。最后提供完整调用示例,模拟实现非官方API的图片搜索功能。
|
17天前
|
配置Spring框架以连接SQL Server数据库
最后,需要集成Spring配置到应用中,这通常在 `main`方法或者Spring Boot的应用配置类中通过加载XML配置或使用注解来实现。
60 0
云上玩转Qwen3系列之四:构建AI Search RAG全栈应用
本文介绍如何利用人工智能平台 PAI-LangStudio、Qwen3 大模型与 AI 搜索开放平台结合 Elasticsearch,构建高效、精准的 AI Search RAG 智能检索应用。通过混合检索技术及 Agentic Workflow 编排,实现自然语言驱动的精准查询,并支持灵活扩展与二次开发,满足多样化场景需求。
通义首个音频生成模型 ThinkSound 开源,你的专业音效师
通义实验室推出首个音频生成模型ThinkSound,突破传统视频到音频生成技术局限,首次将思维链(CoT)应用于音频生成领域,实现高保真、强同步的空间音频生成。基于自研AudioCoT数据集,结合多模态大语言模型与统一音频生成模型,支持交互式编辑,显著提升音画匹配度与时序一致性。代码已开源,助力游戏、VR、AR等场景创新应用。
430 3
Jina Embeddings V4: 为搜索而生,多模态多语言向量模型
近日,Jina AI 正式发布 jina-embeddings-v4,一款全新的多模态向量模型,参数规模达到 38 亿,并首次实现了对文本与图像的同步处理。
134 2
通义灵码编程智能体深度评测(Qwen3模型+终端操作+MCP工具调用实战)
通义灵码作为阿里云推出的智能编程解决方案,凭借Qwen3模型与MCP平台的协同,在代码生成、终端操作与工具链调用方面展现强大能力。本文从真实开发场景出发,评测其在多语言代码理解、自动化工作流及复杂工程任务中的表现,结合性能与成本数据,揭示其在提升开发效率与系统集成方面的工程价值。
133 1
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
329 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问