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


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

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

        本地私有数据存储和查询

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

    • 历史对话(Hostory chat)

          又称为长期记忆。通常就是将历史对话存储在内存或者数据库中,但是,这种方式不分青红皂白一股脑地存下来,造成了各种幻觉,例如 问: 我是谁?LLM 将这个问话也存储起来了,再次问我是谁? LLM 则回答:我是谁。显然错了。

    • 上传的文档(upload documents)

    又称为RAG。

            历史对话和RAG 不同,历史对话是零星输入的,相同的内容不会集中在一起,而RAG 是从上传的文本中提取信息,相同的内容是相对集中在一起的。我们曾经尝试将历史数据存储在一个TEXT 文本中,然后定期地通过embedding 存储到vector 数据库中,效果并不会,例如 X 的儿子是Y,Y 的儿子是Z ,有时候LLM 会回答X 的儿子是Z。对应关系复杂的内容,RAG 的效果并不好。如果询问 X  的孙子是谁?LLM 也经常回答错误。

    基于图数据库的RAG 方法的基本过程

    • 将内容分成块( chunks.)
    • 将块存储到图数据库中,并且连接到文档节点
    • 高度相似的块通过SIMILAR 关系连接成为邻近节点。
    • 通过Embeddings生成矢量索引(vector index)
    • 使用lm-graph-transformer 或者 diffbot-graph-transformer,提取块的主体和关系
    • 将主体存储到图中,并且连接到原始的块

       查询的结果是通过实体查询到 chunks节点。进一步通过SIMILAR 关系查询相似的chunks节点。

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

    历史对话存储的方法

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

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

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

    LLM 与图数据库结合

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

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

     数据存入图数据库

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

    1. {
    2. startNodeName:"姚家湾"
    3. relationship:"儿子“
    4. endNodeName:"姚大为"
    5. }

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

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

    数据查询

            通过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 的提示信息十分重要。编写提示类似于辅导中学生做应用题,不断地提示大模型如何正确的思考。

    判断实体的提示

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

    判断下一个实体的提示

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

    使用迭代函数实现

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

    代码(PathSeach)

    1. async function PathSerch(entities,Message) {
    2. console.log("PathSerch....")
    3. for (let i = 0; i < entities.length; i++) {
    4. const Result= await graphDB.ReadNode(entities[i].name)
    5. ContextMessage=ContextMessage+JSON.stringify(Result)
    6. }
    7. //
    8. const Prefix = "根据提供的信息(来自于neo4j 图数据库,包括关系和节点的属性),回答下列问题:\n"
    9. const Suffix =`提示:
    10. 如果你已经有了答案,请简单地以字符串给出答案。否则,请提示通过哪个节点能够进一步查询到相关信息(JSON 格式)。
    11. JSON 格式为:
    12. {entities:[{name:name of entity]}
    13. json格式中的名称使用英文表示
    14. `
    15. const Prompt = Prefix + Message + ContextMessage+Suffix
    16. console.log(Prompt)
    17. const completion = await openai.chat.completions.create({
    18. messages: [
    19. {
    20. "role": "user",
    21. "content": Prompt,
    22. }],
    23. model: "yi-large",
    24. });
    25. const Content = completion.choices[0].message.content
    26. console.log(Content)
    27. let p= Content.indexOf("```json\n")
    28. console.log("p="+p)
    29. if (p>0){
    30. let ContentB=Content.replace("```json\n", "")
    31. let e= ContentB.indexOf("```")
    32. const JSonContent =ContentB.substr(p,e-p)
    33. //console.log("JSonContent:"+JSonContent)
    34. const entities = JSON.parse(JSonContent).entities
    35. console.log("entities:"+entities)
    36. const Result=await PathSerch(entities,Message)
    37. return Result
    38. } else
    39. return Content
    40. }

    结论

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

            对于关系不复杂的数据,例如与时间相关的活动,事件,使用图模型并不合适,不如使用传统数据库。

        利用大模型构建一套高效的记忆系统的应用,并不简单。而增强人类的记忆能力是AI 的重要应用之一。

  • 相关阅读:
    8月算法训练------第三天(排序)解题报告
    ModuleNotFoundError: No module named ‘torchvision.models.utils‘
    git-使用命令笔记
    机械臂<四大家族>你知道多少
    app全屏广告变现,有哪些利弊?如何发挥全屏广告的变现潜力?
    数据结构和算法——用C语言实现所有树形结构及相关算法
    数据处理:Numpy & Pandas(1)
    Spark简介
    linux下最全抓包命令使用方式学习和拓展
    python 如何自动读取含“xx”关键字的excel文件,并返回一个DataFrame
  • 原文地址:https://blog.csdn.net/yaojiawan/article/details/140886769