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

news2025/1/8 22:35:26

一、建立基本的知识图谱并导入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资源要换什么大模型基座。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

量子计算遇上人工智能:突破算力瓶颈的关键?

引言:量子计算遇上人工智能——突破算力瓶颈的关键? 在数字化时代的浪潮中,人工智能(AI)正以前所未有的速度改变着我们的生活,从语音助手到自动驾驶,从医学诊断到金融分析,无不彰显其…

jenkins入门12-- 权限管理

Jenkins的权限管理 由于jenkins默认的权限管理体系不支持用户组或角色的配置,因此需要安装第三发插件来支持角色的配置,我们使用Role-based Authorization Strategy 插件 只有项目读权限 只有某个项目执行权限

IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)

时序预测 | MATLAB实现IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元) 目录 时序预测 | MATLAB实现IWOA-GRU和GRU时间序列预测(改进的鲸鱼算法优化门控循环单元)预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现IWOA-GRU和GRU时间序列预测…

分享3个国内使用正版GPT的网站【亲测有效!2025最新】

1. molica 传送入口:https://ai-to.cn/url/?umolica 2. 多帮AI 传送入口:https://aigc.openaicloud.cn?inVitecodeMYAAGGKXVK 3. 厉害猫 传送入口:https://ai-to.cn/url/?ulihaimao

Personal APP

1、Matlab 2023b https://www.bilibili.com/opus/887246540317392920 https://blog.csdn.net/qq_25719943/article/details/138096918 https://www.jokerdown.com/22886.html 2、 3、

Vue2:el-table中的文字根据内容改变颜色

想要实现的效果如图,【级别】和【P】列的颜色根据文字内容变化 1、正常创建表格 <template><el-table:data="tableData"style="width: 100%"><el-table-column prop="id" label="ID"/> <el-table-column …

ArmSoM RK3588/RK3576核心板,开发板网络设置

ArmSoM系列产品都搭配了以太网口或WIFI模块&#xff0c;PCIE转以太网模块、 USB转以太网模块等&#xff0c;这样我们的网络需求就不止是上网这么简单了&#xff0c;可以衍生出多种不同的玩法。 1. 网络连接​ 连接互联网或者组成局域网都需要满足一个前提–设备需要获取到ip&a…

动态规划六——两个数组的dp问题

目录 题目一——1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 题目二——1035. 不相交的线 - 力扣&#xff08;LeetCode&#xff09; 题目三——115. 不同的子序列 - 力扣&#xff08;LeetCode&#xff09; 题目四—— 44. 通配符匹配 - 力扣&#xff08;…

LQ quarter 5th

目录 B. 开赛主题曲 C. BlueAI E. 精准难度 B. 开赛主题曲 &#xff08;1&#xff09;两层循环枚举所有子串。第一层子串长度&#xff0c;第二层子串起点 &#xff08;2&#xff09;判子串是否合法还要一个 for&#xff0c;26 * 26 * 2e5 快要超时&#xff0c;因此计算每个字母…

Sam Altman发布博客,回顾OpenAI九年历程,直言目标已瞄准ASI超级人工智能

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Python爬虫与1688图片搜索API接口:深度解析与显著收益

在电子商务的浩瀚海洋中&#xff0c;数据是驱动业务决策的核心引擎。阿里巴巴旗下的1688平台&#xff0c;作为全球领先的B2B在线市场&#xff0c;不仅汇聚了海量的商品信息&#xff0c;还提供了丰富的API接口&#xff0c;为开发者提供了强大的数据获取工具。本文将深入探讨1688…

回归预测 | MATLAB实LSTM多输入单输出回归预测

回归预测 | MATLAB实LSTM多输入单输出回归预测 目录 回归预测 | MATLAB实LSTM多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 LSTM多输入单输出回归预测 程序设计 完整代码&#xff1a;MATLAB实LSTM多输入单输出回归预测 %% 清空环境变量 warni…

从 0 到 1,用 FastGPT 搭建专属私有化知识库与超智能 AI 助理

田园课堂私有化知识库搭建流程与总结 引言 在当今数字化时代&#xff0c;知识管理与智能交互对于教育领域的创新发展至关重要。FastGPT作为一款高效的AI流程构建可视化开源工具&#xff0c;为田园课堂实现私有化知识库的快速搭建提供了有力支持。本文将详细阐述使用FastGPT搭…

centos服务器 /1ib64/libm.so.6: version “GLIBc 2.27’ not found 异常

centos服务器 /1ib64/libm.so.6: version “GLIBc 2.27’ not found 异常 问题 在服务器使用open3d时&#xff0c;报错缺失GLIBC_2.27&#xff0c;因为后续操作出问题会导致服务器挂&#xff0c;所以最好先备份一下。 解决 查询glibc版本 输入指令查询系统glibc版本&#x…

UE播放声音

蓝图中有两个播放声音的函数 Play Sound 2D 和 Play Sound at Location Play Sound 2D没有声音距离衰减&#xff0c;一般用于界面ui Play Sound at Location 有声音距离衰减&#xff0c;一般用于枪声&#xff0c;场景声等&#xff0c;比较常用

【情感】程序人生之情感关系中的平等意识(如何经营一段长期稳定的关系 沸羊羊舔狗自查表)

【情感】程序人生之情感关系中的平等意识&#xff08;如何经营一段长期稳定的关系 & 沸羊羊舔狗自查表&#xff09; 文章目录 1、情感关系中的平等意识2、如何经营一段长期稳定的关系&#xff08;避免左倾 | 敬畏与担当&#xff09;3、沸羊羊/舔狗自查表&#xff08;避免右…

借助免费GIS工具箱轻松实现las点云格式到3dtiles格式的转换

在当今数字化浪潮下&#xff0c;地理信息系统&#xff08;GIS&#xff09;技术日新月异&#xff0c;广泛渗透到城市规划、地质勘探、文化遗产保护等诸多领域。而 GISBox 作为一款功能强大且易用的 GIS 工具箱&#xff0c;以轻量级、免费使用、操作便捷等诸多优势&#xff0c;为…

Chapter4.1 Coding an LLM architecture

文章目录 4 Implementing a GPT model from Scratch To Generate Text4.1 Coding an LLM architecture 4 Implementing a GPT model from Scratch To Generate Text 本章节包含 编写一个类似于GPT的大型语言模型&#xff08;LLM&#xff09;&#xff0c;这个模型可以被训练来生…

Git revert回滚

回退中间的某次提交&#xff08;此操作在预生产分支上比较常见&#xff09;&#xff0c;建议此方式使用命令进行操作&#xff08;做好注释&#xff0c;方便后续上线可以找到这个操作&#xff09; Git操作&#xff1a; 命令&#xff1a;revert -n 版本号 1&#xff1a;git re…

1. 使用springboot做一个音乐播放器软件项目【前期规划】

背景&#xff1a; 现在大部分音乐软件都是要冲会员才可以无限常听的。对于喜欢听音乐的小伙伴&#xff0c;资金又比较紧张&#xff0c;是那么的不友好。作为程序员的我&#xff0c;也是喜欢听着歌&#xff0c;敲着代码。 最近就想做一个音乐播放器的软件&#xff0c;在内网中使…