【大模型+本地自建知识图谱/GraphRAG/neo4j/ollama+Qwen千问(或llama3)】 python实战(中)

一、建立基本的知识图谱并导入neo4j

这里我举例用的属性表、关系表,大概格式如下

id名字颜色
a1苹果红色
startrelend
a1属于b1

启动neo4j(关于neo4j的安装此处不再赘述)

import pandas as pd
from py2neo import Graph, Node, Relationship

graph = Graph("bolt://localhost:7687", auth=("neo4j", "xxxxxx"))  # Xxxxx是你自己的密码

# 导入属性表
def create_nodes(file_name, label, tx):
    df_1 = pd.read_csv("./graph_data/"+ file_name)
    df = df_1.dropna(subset=['id'])
    for index, row in df.iterrows():
        node = Node(label, id=row['id'], **row.drop('id').to_dict())
        tx.merge(node, label, "id")

attribute_tables = {
    "attributes_a.csv":"a",
    "attributes_b.csv":"b",
}


tx = graph.begin()


try:
    for file_name, label in attribute_tables.items():
        create_nodes(file_name, label, tx)

    # 导入关系表
    relationship_types = {
        "rel_a_b.csv": "属于",
    }


    for file_name, rel_type in relationship_types.items():
        df = pd.read_csv("./graph_data/"+ file_name)
        for index, row in df.iterrows():
            start_label, end_label = file_name.split("_")[1], file_name.split("_")[2].split(".")[0]    # 这里的start_label, end_label根据自己的实际需求来定
            start_node = graph.nodes.match(start_label, id=row['start']).first()
            end_node = graph.nodes.match(end_label, id=row['end']).first()
            if start_node and end_node:
                rel = Relationship(start_node, rel_type, end_node)
                tx.merge(rel)
            else:
                print(f"无法找到节点: {row['start']} 或 {row['end']}")

    tx.commit()
    print("成功导入!")

except Exception as e:
    tx.rollback()
    print(f"导入失败:{e}")

运行后在neo4j中的效果大概是这样:

二、尝试基于Ollama+QWEN大模型做一个基于KG的检索提问

1、关于ollama本地部署的教程

部署ollama后,可以根据需求随便run模型(记得用管理员模式启动)

本地部署 Ollama_ollama本地部署-CSDN博客

Ollama在Windows11部署与使用qwen(自学使用)_ollama qwen-CSDN博客

2、搭建整个RAG的框架

(1)插件安装

这里有一个前置步骤要解决,就是在输入问题后,根据问题中的实体在KG里面进行检索需要一个允许进行检索的插件,下载和安装教程如下:

https://blog.csdn.net/m0_38064529/article/details/125206908

https://blog.csdn.net/zz_dyx/article/details/135172438

https://blog.csdn.net/m0_53573725/article/details/136964980

安装成功!

尝试创建索引

CREATE FULLTEXT INDEX companyIndex IF NOT EXISTS

FOR (n:a)

ON EACH [n.名字, n.颜色]

验证索引是否创建成功

CALL db.indexes()

使用索引进行查询示例:

CALL db.index.fulltext.queryNodes("appleIndex", "搜索词")
YIELD node, score
RETURN node, score

如果你需要创建向量索引(用于语义搜索),语法是

CREATE VECTOR INDEX entity_embedding IF NOT EXISTS
FOR (n:Entity)
ON n.embedding
OPTIONS {
    indexType: 'vector',
    similarity: 'cosine',
    dimension: 384
}

有一个十分重要的注意点!!!在 Neo4j 5.x 版本中,全文索引的创建语法发生了变化,而网上很多教程给出的语句都是4版本的,一定要注意区分!不然容易报类似这样的错误:

There is no procedure with the name db.index.fulltext.createNodeIndex registered for this database instance.

(2)将知识图谱内容转换为大模型可以理解的上下文

根据提问中的实体,找到图谱中的实体和关系,以及头节点、尾节点各自的属性。图谱中通常是以字典型存的,需要转换为语义信息。

def format_context(results):
    """
    将查询结果格式化为上下文字符串,方便后续规范prompt
    """
    context_parts = []
    for record in results:
        node = record['node']
        rel_type = record['relationship_type']
        related = record['related']  # 尾节点

        # 获取节点的所有属性
        node_props = {k: v for k, v in node.items()}
        related_props = {k: v for k, v in related.items()}

        # 构建描述性文本
        node_desc = ", ".join([f"{k}: {v}" for k, v in node_props.items() if v is not None and str(v) != 'nan'])
        related_desc = ", ".join([f"{k}: {v}" for k, v in related_props.items() if v is not None])

        context_part = f"节点【{node_desc}】通过关系【{rel_type}】连接到【{related_desc}】"
        context_parts.append(context_part)
        #print(context_parts)

    return "\n".join(context_parts)

输出结果大概是:

节点【苹果】通过关系【拥有子类】连接到【红富士,颜色:红,气味:甜】

具体的形式都可以自己定,在后续prompt的过程中看大模型更能理解哪种形式。

(3)设计prompt

这个就见仁见智了,我设计的基本可以得到答案,仅供参考:
prompt = f"""
   你是一个拥有很多农业知识的专家。针对我提出的问题,第一步请直接搜集答案:
   问题:{question}

   第二步结合我给出的知识图谱信息作为补充放入答案:
   知识图谱背景信息:
   {context}

   请将两部分结合用中文提供详细且准确的回答。
   """

三、RAG构建部分全流程代码以及不足之处

#!/usr/bin/python
# encoding=utf-8


from neo4j import GraphDatabase
from transformers import AutoModelForCausalLM, AutoTokenizer
from langchain.chains import RetrievalQA
from langchain_community.vectorstores import Neo4jVector
import ollama
import math



# Neo4j 数据库连接配置,另一种方式
uri = "bolt://localhost:7687"
user = "neo4j"
password = "********"  #自己的密码

# 创建驱动对象
driver = GraphDatabase.driver(uri, auth=(user, password))

# 在neo4j里提问
def query_neo4j(query):
    with driver.session() as session:
        result = session.run(query)
        return [record for record in result]


def generate_response(question):
    # 使用Ollama生成回答
    response = ollama.generate(model="llama3:8b", prompt=question)
    return response['response']


def Index_Create():
    # 建立索引
    create_index_query = """
        CREATE FULLTEXT INDEX companyIndex IF NOT EXISTS
        FOR (n:fruit)  # 这里是你建的图谱中实际实体的类型
        ON EACH [n.颜色, n.气味]
        """
    query_neo4j(create_index_query)

def Get_Node():
    # 查询Neo4j获取相关信息。
    neo4j_query = f"""
    CALL db.index.fulltext.queryNodes("fruitIndex",  "{question}")   
    YIELD node, score
    MATCH (node)-[r]-(related)
    RETURN DISTINCT node, type(r) as relationship_type, related, score
    LIMIT 3
    """
    results = list(query_neo4j(neo4j_query)) 
    return results


def format_context(results):
    """
    将查询结果格式化为上下文字符串,方便后续规范prompt
    """
    context_parts = []
    for record in results:
        node = record['node']
        rel_type = record['relationship_type']
        related = record['related']  # 尾节点

        # 获取节点的所有属性
        node_props = {k: v for k, v in node.items()}
        related_props = {k: v for k, v in related.items()}

        # 构建描述性文本
        node_desc = ", ".join([f"{k}: {v}" for k, v in node_props.items() if v is not None and str(v) != 'nan'])
        related_desc = ", ".join([f"{k}: {v}" for k, v in related_props.items() if v is not None])

        context_part = f"节点【{node_desc}】通过关系【{rel_type}】连接到【{related_desc}】"
        context_parts.append(context_part)
        #print(context_parts)

    return "\n".join(context_parts)


def generate_prompt_answer(question, context):
    """
    生成回答
    """
    prompt = f"""
       你是一个拥有很多农业知识的专家。针对我提出的问题,第一步请直接搜集答案:
       问题:{question}

       第二步结合我给出的知识图谱信息作为补充放入答案:
       知识图谱背景信息:
       {context}

       请将两部分结合用中文提供详细且准确的回答。
       """

    #print("流程已进入llm回答阶段……")
    try:
        response = generate_response(prompt)
        return response
    except Exception as e:
        return f"生成回答时出错:{e}"

if __name__ == "__main__":
    while True:
        question = input("请输入你的问题:")    # 把question变为全局变量
        if question.lower() in ["exit", "quit"]:
            break

        results = Get_Node()

        if not results:
            print("没有找到相关的信息。")
            continue

        context = format_context(results)
        answer = generate_prompt_answer(question, context)
        print(f"问题:{question}")
        print(f"回答:{answer}")

不足:

1、对话提问的question通常是一个句子,在图谱中查询的输入应该是一个实体的名称。也就是我这里面其实差了一步提取实体名词的过程。目前通常有两种思路:①利用传统的深度学习的方法(现在应该有现成的工具)提取一句话中的重要实体;②直接再次调用大模型识别句子中的实体,优点就是更省事儿,缺点是费时,大模型一个问答来回llama3 在cpu上大约要2分钟。我目前的代码中其实这一块实际搜索的时候为了测试流程通畅性,直接将“苹果”代替了{question}。

    neo4j_query = f"""
    CALL db.index.fulltext.queryNodes("fruitIndex",  "苹果")   
    YIELD node, score
    MATCH (node)-[r]-(related)
    RETURN DISTINCT node, type(r) as relationship_type, related, score
    LIMIT 3
    """
    results = list(query_neo4j(neo4j_query)) 
    return results

2、 如果一个实体关联的信息很多,对于LIMIT 的限制需要重新考量。我这里为了测试方便先写了limit 3(上面代码中),即只显示3个相关的节点和关系。在neo4j中,这个limit指的是显示3条结果,而不是根据输入的实体信息给出排名前三的实体,以及相关的关系,这跟我们想要检索的实际需求是不太匹配的。

3、大模型是由token限制的,如果想要查询的实体关系和属性极多,可能会出现超出token的情况,要么是读不全上下文,要么是输出受限。可能在实际应用的过程中给用户展示的依然需要两个部分,一个是这个GraphRAG,另外就是传统数据库的检索答案,类似现在的百度搜索,先给AI的答案,下面再是其他链接。

一个简单的问答实例:

这里换了一个数据,是公司信息的,给出一个输出的样例(pycharm里面,还没有做前端)

下一篇可能会探索一下构建前端chat或者检索页面,以及连GPU跑的问题,还有针对不同GPU资源要换什么大模型基座。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/949886.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【pyqt】(四)Designer布局

布局 之前我们利用鼠标拖动的控件的时候,发现一些部件很难完成对齐这些工作,pyqt为我们提供的多种布局功能不仅可以让排版更加美观,还能够让界面自适应窗口大小的变化,使得布局美观合理。最常使用的三种布局就是垂直河子布局、水…

解决“KEIL5软件模拟仿真无法打印浮点数”之问题

在没有外部硬件支持时,我们会使用KEIL5软件模拟仿真,这是是仿真必须要掌握的技巧。 1、点击“Project”,然后点击“Options for target 项目名字”,点击“Device”,选择CPU型号。 2、点击“OK” 3、点击“Target”,勾选“Use Mi…

【项目实战1】五子棋游戏

目录 C语言编程实现五子棋&#xff1a;&#xff1a; game.h game.c 1.打印菜单 2.打印棋盘 3.玩家下棋 4.判断五子连珠 5.判断输赢 6.游戏运行 game.c完整源代码展示 test.c C语言编程实现五子棋&#xff1a;&#xff1a; game.h #pragma once #include<stdio.h> …

用ResNet50+Qwen2-VL-2B-Instruct+LoRA模仿Diffusion-VLA的论文思路,在3090显卡上训练和测试成功

想一步步的实现Diffusion VLA论文的思路&#xff0c;不过论文的图像的输入用DINOv2进行特征提取的&#xff0c;我先把这个部分换成ResNet50。 老铁们&#xff0c;直接上代码&#xff1a; from PIL import Image import torch import torchvision.models as models from torch…

Spring Boot 项目自定义加解密实现配置文件的加密

在Spring Boot项目中&#xff0c; 可以结合Jasypt 快速实现对配置文件中的部分属性进行加密。 完整的介绍参照&#xff1a; Spring Boot Jasypt 实现application.yml 属性加密的快速示例 但是作为一个技术强迫症&#xff0c;总是想着从底层开始实现属性的加解密&#xff0c;…

A/B实验之置信检验(一):如何避免误判 (I类) 和漏报 (II类)

假设检验的依据&#xff1a;如何避免误判和漏报 A/B实验系列相关文章&#xff08;置顶&#xff09; 1.A/B实验之置信检验&#xff08;一&#xff09;&#xff1a;如何避免误判和漏报 2.A/B实验之置信检验&#xff08;二&#xff09;&#xff1a;置信检验精要 引言 在数据驱动…

每日一题:链表中环的入口结点

文章目录 判断链表环的入口节点描述数据范围&#xff1a;复杂度要求&#xff1a;输入输出 示例代码实现思路解析注意事项&#xff1a; 判断链表环的入口节点 描述 给定一个链表&#xff0c;判断该链表是否存在环。如果存在环&#xff0c;返回环的入口节点&#xff1b;如果不存…

深度学习blog-Meanshift均值漂移算法-最大熵模型

均值漂移&#xff08;Mean Shift&#xff09;是一种无监督的聚类算法&#xff0c;广泛应用于数据挖掘和计算机视觉任务。它通过移动样本点到其近邻的均值位置来寻找数据的高密度区域&#xff0c;最终形成聚类。 均值漂移算法原理 均值漂移算法的核心思想是通过滑动窗口&#…

51c自动驾驶~合集45

我自己的原文哦~ https://blog.51cto.com/whaosoft/13020031 #运动控制和规划控制需要掌握的技术栈~ 各大垃圾家电造车厂又要开始了~~~​ 1、ROS的通信方式 李是Lyapunov的李&#xff1a;谈谈ROS的通信机制 话题通信和服务通信&#xff0c;其中话题通信是通过发布和订阅…

Python基于jieba和wordcloud绘制词云图

【Cesium】自定义材质&#xff0c;添加带有方向的滚动路线 &#x1f356; 前言&#x1f3b6;一、实现过程✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 Python基于jieba和wordcloud绘制词云图 &#x1f3b6;一、实现过程 读取文本…

计算机网络与服务器

目录 架构体系及相关知识 三层架构&#xff1a; 四层架构&#xff1a; 常见的应用的模式&#xff1a; OSI模型 分层 数据链路层 TCP/IP模型 TCP和UDP都是传输层的协议 TCP三次握手、四次次分手 URL&HTTP协议详解 网址URL 结构化 报文行 报文头 空行 报文体…

Cursor实现go项目配置并实现仓库Gin项目运行

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a;知识备份 ✨特色专栏&#xff1a;知识分享 &#x…

141.环形链表 142.环形链表II

141.环形链表 & 142.环形链表II 141.环形链表 思路&#xff1a;快慢指针 or 哈希表 快慢指针代码&#xff1a; class Solution { public:bool hasCycle(ListNode *head) {if(headnullptr||head->nextnullptr)return false;ListNode *fasthead->next; //不能设置成…

信用租赁系统助力企业实现免押金租赁新模式

内容概要 在现代商业环境中&#xff0c;信用租赁正在迅速崛起。通过结合大数据与区块链技术&#xff0c;信用租赁系统彻底改变了传统的租赁流程。什么是信用租赁呢&#xff1f;简单说&#xff0c;就是不需要押金&#xff0c;你也能够租到你想要的物品&#xff0c;这对企业和消…

el-select下拉框在弹框里面错位

问题出现 Element Plus 是一个基于 Vue 3 的组件库&#xff0c;el-select 是其中一个用于选择器的组件。在 el-select 组件中&#xff0c;teleported 属性用于控制下拉菜单的渲染位置。 解决方法 teleported 属性「element-plus」 popper-append-to-body属性「element」 ‌…

IO进程day1

一、思维导图

力扣-21-合并两个有序链表

思路&#xff1a; 因为是升序的两个链表&#xff0c;我们可以进行数据域比大小&#xff0c;然后把p3(自己创建的)的指针域指向小的那个 注&#xff1a;一定要先判断两个指针为0的情况

人工智能的发展领域之GPU加速计算的应用概述、架构介绍与教学过程

文章目录 一、架构介绍GPU算力平台概述优势与特点 二、注册与登录账号注册流程GPU服务器类型配置选择指南内存和存储容量网络带宽CPU配置 三、创建实例实例创建步骤镜像选择与设置 四、连接实例SSH连接方法远程桌面配置 一、架构介绍 GPU算力平台概述 一个专注于GPU加速计算的…

QT实现 端口扫描暂停和继续功能 3

上篇QT给端口扫描工程增加线程2-CSDN博客 为按钮pushButton_Stop添加clicked事件&#xff0c;功能为暂停扫描&#xff0c;并在暂停后显示继续按钮&#xff0c;点击继续按钮之后继续扫描 1.更新UI 添加继续按钮 点击转到槽则会自动声明 2. 更新 MainWindow.h 需要新增的部分…

汽车微处理器安全机制以及测试介绍

本文介绍了三类汽车微处理器安全机制&#xff1a;硬件类、软件类和混合类&#xff0c;旨在提高系统的可靠性和安全性。硬件类安全机制包括逻辑内建自测试&#xff08;Logic-BIST&#xff09;、三重模块冗余&#xff08;TMR&#xff09;、内存内建自测试&#xff08;Memory-BIST…