谈基于大语言模型的图数据库路径检索

devtools/2024/12/22 2:51:56/

        随着微软已经开源了GraphRAG项目的代码,基于图数据库的RAG 热度迅速升温。关注基于大语言模型与图模型数据库相结合的技术的人多了起来。

本文提出了一种类似人工搜索的“顺藤摸瓜”方法,实现图数据库的智能搜索方法。

    本地私有数据存储和查询

本地私有数据的存储和查询主要包括:

  • 历史对话(Hostory chat)

又称为长期记忆。

  • 上传的文档(upload documents)

又称为RAG。

   本文重点讨论如何使用图数据库实现长期记忆。

历史对话存储的方法

     历史对话使用memory 模块来实现,最简单的是将所有的对话都存储在内存(短期记忆),或者存储在数据库中(长期记忆)。

        图数据库适合存储复杂关系的信息,例如对话者的家庭关系。个人简历。

        普通数据库适合存储对话者的活动,备忘录等信息。

LLM 与图数据库结合

LLM 与图数据库结合关键在两点

  •  利用大模型将非结构化数据转换成为图数据库的结构化数据
  • 利用大模型智能搜索图模型中的相关数据

 数据存入图数据库

首先通过LLM判断陈述语句中的实体和关系。并且输出json 格式

{
startNodeName:"姚家湾"
relationship:"儿子“
endNodeName:"姚大为"
}

通过图数据库的语句将实体和关系存储到图数据库中。

下图是根据对话存储的个人信息。

数据查询

        通过LLM 实现图数据库看起来是十分简单的事情,许多的大模型能够直接产生图模型的查询语句。事实上并没有想象的简单,首先是LLM 提取实体和关系的名称是不确定的。有时候存储和查询对话产生的实体和关系的类型不能够对应。对于复杂的提问,LLM 也无法生成完整的查询语句。这就需要LLM具有智能(或者说是模糊的)查询的图数据库的能力。

     网络上有一些关于图模型查询的介绍,

      比如找出与实体连接的的一部分节点,搜索N跳以内的局部子图 比如4层。

     另一种方法是利用vector 数据库构建图数据库中所有节点,关系的vector 通过vector数据库查询相关的节点内容,这似乎失去了图模型的意义。

     这些方法基本上是简单粗暴法

       我们尝试模仿人类查询的方式,根据实体的属性和所有的关系顺藤摸瓜地检索图数据库的信息。姑且称之为“顺藤摸瓜法”

顺藤摸瓜法

       所谓顺藤摸瓜法就是模仿人工搜索图的方法,通过LLM 来逐步确定图数据库的搜索路径。

  1.   提取询问中的实体(Entity),实体对应于图数据库中的节点名称。
  2.   在图数据的查询实体节点的所有属性,与该节点连接的相邻节点,以及所有的关系集(relationships)。
  3.    将读出的信息添加到对话的上下文信息(Context Information) 中。
  4.     LLM 尝试回答问题,如果已经得到了答案,就直接输出答案,如果没有获得答案,就推荐下一步查询的子节点重复 (2),如果无法进一步推荐合适的子节点就退出。

      这个过程类似迷宫 站在一个节点上,看哪个方向的节点更接近目标,然后选择一个或者几个方向尝试。每前进一步,都需要思考。

下图是一个例子。

询问:

姚远的岳父是谁?

        大模型首先提取出询问中的实体-“姚远”,然后通过neo2J 数据库查询出“姚远”节点,已经临近节点,这是并不能回答“姚远的岳父是谁”,但是他会回答“通过查询”刘素霞节点进一步查询。

   通过第二次查询“刘素霞节点以及它相邻的节点,能够读取 ”刘亚敏“节点。

终于,LLM 回答:

    姚远的岳父是刘雅敏。 

一些例子:

实验

  • 基于NodeJS 平台
  • 基于neo4J 图数据库
  • 基于零一万物大模型yi-large

 实现该技术的难点

  设计LLM 的提示信息十分重要。

判断实体的提示

const Prefix = "请列出下列语句中的实体,实体的属性以及实体之间的关系 。"const Suffix = `请使用下列json 格式输出:{entities:[{name:name of entity,attributes:{name of attribute:Value of attribute}}],relashichips:[{source:source_node_name,target:target_node_name,type:relationship_type}]}json格式中的名称使用英文表示。关系使用中文表达。`const Prompt = Prefix + Message + Suffix

判断下一个实体的提示

const Prefix = "根据提供的信息(来自于neo4j 图数据库,包括关系和节点的属性),回答下列问题:\n"const Suffix =`提示:如果你已经有了答案,请简单地以字符串给出答案。否则,请提示通过哪个节点能够进一步查询到相关信息(JSON 格式)。JSON 格式为:{entities:[{name:name of entity]}json格式中的名称使用英文表示`const Prompt = Prefix + Message + ContextMessage+Suffix

使用迭代函数实现

路径搜索程序使用迭代函数实现会使程序十分简洁。

代码(PathSeach)

async function PathSerch(entities,Message) {console.log("PathSerch....")for (let i = 0; i < entities.length; i++) {const Result= await graphDB.ReadNode(entities[i].name)ContextMessage=ContextMessage+JSON.stringify(Result)}//const Prefix = "根据提供的信息(来自于neo4j 图数据库,包括关系和节点的属性),回答下列问题:\n"const Suffix =`提示:如果你已经有了答案,请简单地以字符串给出答案。否则,请提示通过哪个节点能够进一步查询到相关信息(JSON 格式)。JSON 格式为:{entities:[{name:name of entity]}json格式中的名称使用英文表示`const Prompt = Prefix + Message + ContextMessage+Suffixconsole.log(Prompt)const completion = await openai.chat.completions.create({messages: [{"role": "user","content": Prompt,}],model: "yi-large",});const Content = completion.choices[0].message.contentconsole.log(Content)let p= Content.indexOf("```json\n")console.log("p="+p)if (p>0){let ContentB=Content.replace("```json\n", "")let e= ContentB.indexOf("```")const JSonContent =ContentB.substr(p,e-p)//console.log("JSonContent:"+JSonContent)const entities = JSON.parse(JSonContent).entitiesconsole.log("entities:"+entities)const Result=await PathSerch(entities,Message)return Result} else return Content
}

结论

使用LLM 实现图数据库的路径搜索,图数据库存储是可能的,它对于复杂关系的数据存储和检索是十分有效的。


http://www.ppmy.cn/devtools/90461.html

相关文章

C语言——扫雷游戏

扫雷游戏通常是一个由方格组成的区域内进行的&#xff0c;其中随机分布着一定数量的地雷 。玩家的目标是通过点击方格来标记出所有地雷的位置&#xff0c;同时避免自己点到地雷而导致游戏失败。游戏开始时&#xff0c;玩家通常只能看到一部分方格&#xff0c;而其余的方格则需要…

MPU6050的STM32数据读取

目录 1. 概述2. STM32G030对MPU6050的读取3. STM32F1xx对MPU6050的读取 1. 概述 项目中&#xff0c;往往需要根据不同的环境使用不同的芯片处理某些数据&#xff0c;当使用不同的芯片对六轴陀螺仪芯片MPU6050进行数据处理中&#xff0c;硬件的连接、I/O口的设置往往需要根据相…

Radamsa:一款高性能通用模糊测试工具

关于Radamsa Radamsa是一款高性能的通用模糊测试工具&#xff0c;广大研究人员可以将其当作一个应用程序稳定性测试的测试用例生成工具。 工具运行机制 该工具使用简单&#xff0c;支持自定义脚本开发&#xff0c;可以用于测试程序对格式错误和潜在恶意输入的承受能力。它的工…

websocket封装与使用

新建WebSocketService.js export default class WebSocketService {constructor(url, getSocketMsg, sendSucc) {this.url url;this.getSocketMsg getSocketMsg;this.sendSucc sendSucc; // 发送命令成功后的回调&#xff0c;可有可无this.socketTask null;this.isOpenSoc…

Day19 标准IO的学习

标准IO 1.I input 输入 键盘 O output 输出 显示器 2.一般我们调用相关IO操作时必须调用stdio头文件库&#xff0c;其位置在/usr/include/stdio.h&#xff0c;linux系统中最高管理者是root。 stdio.h ~ stdio.c ~ libc.so ~ /usr/lib so动态库 3.…

21 mysql绿色安装版

2024/8/5 MySQL绿色安装版 #清空/etc目录下的my.confls -l /etc/my.cnf rm -rf /etc/my.cnfyum -y remove mariadb find / -name "*mysql*" -exec rm -rf {} \; 将MySQL压缩包拉拽到机器里tar -xvf mysql-8.0.33-linux-glibc2.12-x86_64.tartar -xf mysql-8.0.33-…

数据结构之双向链表

一&#xff0c;链表的分类 链表的结构非常多样化&#xff0c;以下情况组合起来就有八种&#xff08;2*2*2&#xff09;链表结构&#xff1a; 在前面实现链表中&#xff0c;口头上提到的头节点实际指的是第一个有效的节点&#xff0c;这不是正确的称呼 但是为了更好的理解才这…

c语言小知识点小计

c语言小知识点小计 1、运算符的优先级 运算符的优先级是和指针解引用*的优先级相同的&#xff0c;但在代码运行中执行顺序是从后往前的。因此下面代码 int a[10] {1,2,3,4}; int* arr a; printf("%d",*arr);//访问的值是2 //注意&#xff1a;printf("%d&qu…