GraphRAG 工作流
Motivation
当前的 RAG 技术无法回答关于语料库的全局性问题,比如“这个数据集的主题是什么”。这一类问题不是可以通过检索增强技术解决的,因为答案一般不在某一段文本里面,正确答案需要理解整个语料库并给出抽象的总结,作者称这类问题为 query-focused summarization (QFS) 问题1。普通的 RAG 技术无法很好处理这个问题。
将整个语料库的文本放在上下文窗口里面又不大现实,就算能放得下,面对超长输入,LLM 经常会忘掉中间的信息
本文提出的 GraphRAG1 就是要解决这些问题
GraphRAG
要理解 GraphRAG 最好要有知识图谱的背景,比如对社区、社区检测算法要有一定的了解。另外要对图这种数据结构有比较清楚的了解
Document -> TextChunk
flowchart LR Document --> TextChunk1 & TextChunk2 & ...
将文档划分为多个 Text Chunk(彼此之间可以有重叠)
TextChunk -> Entity & Relationship & Claim
flowchart LR TextChunk --> Entity & Relationship & Claim
每一个 Text Chunk 会被 LLM 用来提取知识图谱里的
- 实体,包括
名字、类型、描述
- 关系,包括
起点、描述、终点
- 断言(Claim)
如果提取到重复的实体/关系(不考虑 描述
)会将其合并,但每一个实体/关系的描述会被记录下来,即一个实体/关系可能会有多个描述
提取的原理就是写 Prompt 给大模型,这里的 Prompt 会用 Few-shot learning 和 In-Context learning 的技术作增强,可以想象,这里的 Prompt 很关键
除了精心编写 Prompt 以外,作者1还提出可以多次执行提取的步骤,这是为了鼓励 LLM 发现上一轮遗漏的实体。怎么鼓励呢?可以尝试告诉 LLM 说上一轮遗漏掉了非常多的实体
注意,Text Chunk 设置得越大,LLM 调用的次数就越少,速度越快。但作者1发现提取的实体量、关系的数量会变少,因此这里需要做好权衡,可以参考论文里的 Figure 2
Graph Communities Detection
flowchart LR Document(Document in the form of entity, relationships, and claims) subgraph community_tree root(Community1) root2(Community2) root3(Community3) root --> root2 & root3 root --> dots(...) root2 --> dots1(...) root3 --> dots2(...) dots --> dots3(...) end Document --> community_tree
在上一个阶段后,其实我们已经为每个文档搭建了一个知识图谱,接下来就可以在这个知识图谱上用 Leiden 社区检测算法,该算法会返回知识图谱里面的社区(Graph Communities),注意这些社区是树状的(下称社区树),结构是有层次的
Graph Communities -> Community Summaries
flowchart LR Community --> CommuniySummary
这一步需要用 LLM 得到每个社区的总结,针对不同类型的社区有不同的策略
- 叶子社区
- 将所有的关系按照
起点
和终点
的度数和降序排列,🤔 也许是度数和越高越重要 - 按顺序处理,对于每条关系,依次添加如下的文本到上下文窗口里直到上下文窗口放不下
起点
对应的描述
终点
对应的描述
- 任何跟这条关系有关联的断言
- 这条关系的
描述
- 将所有的关系按照
- 非叶子社区,即下面都是子社区
- 假装子社区不存在:按照上面的方法处理,但前提是不超过 LLM 的上下文窗口长度
- 否则,对子社区进行排序,按照它包含的实体、关系的
描述
文本的总长度降序排列(🤔 文本越多信息越丰富越要保留)。然后依次将社区总结(短)替换为叶子社区那样拼接的描述(长),目的显然是要保留更细粒度的信息(社区 -> 社区包含的实体、关系)
所以,社区总结的处理方式是在社区树上用 Bottom-Up 的方式得到的
Community Summaries -> Community Answers -> Global Answer
flowchart LR a(Random shuffled community summaries) a --> Chunk1 & Chunk2 & annoy(...) Chunk1 --> p(Intermediate Answer1) Chunk2 --> q(Intermediate Answer2) annoy --> r(...) window(Context Window) p & q & r --> window window --> ans(Global Answer)
现在,每一个社区都有自己的社区总结,可以用这些社区总结来回答用户的问题,具体步骤如下
- 将所有的社区总结打乱,然后划分为一个个 Chunk。这种方式确保了相关的信息分布在不同的 Chunk
- Map 阶段:用每一个 Chunk 让 LLM 生成临时回复,并让 LLM 给出临时回复的得分(0~100),得分衡量了这个生成的临时回复对用户问题的帮助程度
- Reduce 阶段:将临时回复按照得分降序排列然后一一拼接起来,直到上下文窗口长度放不下,然后再让 LLM 生成最终回复
总结
上面就是 GraphRAG 的全部内容,整体流程还算是蛮清晰的,官方也提供了实现,但折腾了一会发现只支持 OpenAI 的 LLM。搜索的时候看到有人用 LangChain 实现的 langchain-graphrag,准备看看是否能用
-
Edge, Darren, et al. “From local to global: A graph rag approach to query-focused summarization.” arXiv preprint arXiv:2404.16130 (2024). ↩︎ ↩︎ ↩︎ ↩︎