在数据科学领域,传统 RAG 帮助你找到直接答案,比如预测建模中的具体特征。而基于图的 RAG 更适合在复杂数据集中发现关系。例如,在临床试验中进行因果分析时,传统 RAG 可能会搜索相关研究或结果,而 GraphRAG 可以分析变量之间的关系——比如治疗方法、结果和混杂因素。
通过数学模型来了解每种方法背后的算法。
传统 RAG 使用向量嵌入技术,将查询和文档表示为高维空间中的向量。每个单词或文档被转化为一个向量 (v \in R^n),其中 (n) 是嵌入的维度。当用户发送查询时,系统将查询转化到相同的空间,并计算查询向量与文档向量之间的相似度。
最常见的相似度度量是余弦相似度,其计算公式为:
其中:
• (q) 是查询向量,
• (v) 是文档向量,
• (|q|) 和 (|v|) 是向量的模。
系统会检索出与查询向量 (q) 余弦相似度最高的文档向量 (v)。在计算余弦距离后,算法会按相似度得分对文档进行排序,并根据相似度阈值选择排名前 (k) 的文档。
与仅使用向量相似度不同,GraphRAG 将数据组织成一个图,其中的点(称为节点)表示人、治疗方法或事件等事物,而连接(称为边)表示“治疗”、“导致”或“依赖于”等关系。系统根据用户的查询在图中搜索相关子图。
1.将数据放入图中(Microsoft GraphRAG 和 Neo4j)
•Microsoft GraphRAG:LLM 解析输入文本以提取实体和关系,并将它们放入知识图中。节点表示关键实体,边表示它们之间的关系。这种结构化表示允许处理更复杂的查询,尤其是涉及多个实体之间关系的查询。
•Neo4j:在 Neo4j 中,数据通过工具如 TextLoader 或 llm_transformer 添加到图数据库中。它遵循标准的图方法,其中实体显示为节点,节点之间的连接为边。Neo4j 使用 Cypher 查询语言搜索图并基于这些关系找到相关部分。
2.利用 LLM 从图数据中进行 RAG
•Microsoft GraphRAG:构建图后,应用全局搜索和局部搜索算法检索相关子图以回答用户的查询。例如,在关于药物相互作用的查询中,GraphRAG 识别不同药物与疾病之间的关系,通过遍历图分析相关实体之间的连接,生成上下文丰富的回答。
•Neo4j 与 LangChain:Neo4j 通过图算法(如 PageRank 或社区检测)检索子图。这些算法识别相关实体的聚类,LangChain 则从 Neo4j 中检索子图并利用 LLM 生成回答。
GraphRAG 的关键功能之一是通过社区检测算法识别相关实体的聚类。Leiden 算法是 GraphRAG 中表现最优秀的算法之一。我们来详细讲解它。
想象你在一个派对上,需要根据谁最常交谈将人分组。有些人形成了紧密的小圈子,而另一些人则在圈子之间游走。Leiden 算法在图中执行类似的任务:通过观察节点(人)之间的连接(对话),将它们分组,并将联系最紧密的节点聚集在一起。以下是它的工作步骤:
初始分组:算法首先根据连接将节点分组。如果两个人(节点)经常互动,他们会被放入同一组。
优化分组:然后算法检查是否有节点适合属于不同的组,就像有人在派对上切换谈话对象一样。如果他们更适合其他组,算法会将其移动。
分裂与合并:最后,较大的组会被分裂为更小的组,并在内部连接紧密时重新合并,形成更紧密的聚类。
从数学上讲,Leiden 算法基于模块度优化。它试图最大化模块度(Q),即组内连接的密度与组间连接的密度的差异:
其中:
• (A_{ij}) 是图的邻接矩阵,
• (k_i) 和 (k_j) 是节点 (i) 和 (j) 的度,
• (m) 是图中的总边数,
• (\delta(c_i, c_j)) 当节点 (i) 和 (j) 属于同一社区时为 1,否则为 0。
与 Louvain 等旧算法相比,Leiden 算法通常在 GraphRAG 中表现更好,因为它识别出的组连接更紧密且更加稳定。
由微软研究院开发的 GraphRAG 应用了大语言模型(LLMs)来从非结构化文本中检索结构化数据。Microsoft GraphRAG 提供了多种方法以通过全局和局部搜索方法从大型数据集中检索信息。以下是每种搜索方法的概述。
该方法允许通过命令行查询文本数据集。它使用全局和局部搜索来发现故事中的主要主题。该过程从文件夹加载预先索引的数据集,并通过全局社区摘要运行查询。这种方法适合一次性查询大规模文档集或进行批量数据分析。
以下是我探索后的总结步骤:
1.安装与设置:
• 使用 Python 包管理器安装 GraphRAG:
pipinstallgraphrag
为项目设置虚拟环境。截至本文撰写时,GraphRAG 支持 Python 3.10 至 3.11 版本。
condacreate-ngraphrag-envpython=3.11condaactivategraphrag-en
2. 运行索引管道:
要初始化 GraphRAG 索引器,输入并执行以下命令以设置必要的目录和配置,以便后续的 GraphRAG 操作:
python-mgraphrag.index--init--rootC:\backupcgi\ragtest
接着,编辑文件 settings.yaml 以正确配置嵌入模型(例如 azure_openai_embedding 或 orazure_openai_embedding)。此步骤非常重要,任何配置错误都会导致任务失败。以下是我的配置:
encoding_model:cl100k_base
skip_workflows:[]
llm:
api_key:#####
type:azure_openai_chat
model:gpt-4
model_supports_json:true#recommendedifthisisavailableforyourmodel.
#max_tokens:4000
#request_timeout:180.0
api_base:https://#####
api_version:2023-12-01-preview
#organization:<organization_id>
deployment_name:gpt4
tokens_per_minute:150_000#setaleakybucketthrottle
requests_per_minute:10_000#setaleakybucketthrottle
max_retries:10
max_retry_wait:10.0
sleep_on_rate_limit_recommendation:true#whethertosleepwhenazuresuggestswait-times
concurrent_requests:25#thenumberofparallelinflightrequeststhatmaybemade
temperature:0.3#temperatureforsampling
top_p:1#top-psampling
n:1#Numberofcompletionstogenerate
parallelization:
stagger:0.3
#num_threads:50#thenumberofthreadstouseforparallelprocessing
async_mode:threaded#orasyncio
embeddings:
##parallelization
verride..._length:2000
max_input_length:8000
cluster_graph:
max_cluster_size:10
embed_graph:
enabled:false#iftrue,willgeneratenode2vecembeddingsfornodes
#num_walks:10
#walk_length:40
#window_size:2
#iterations:3
#random_seed:597832
umap:
enabled:false#iftrue,willgenerateUMAPembeddingsfornodes
snapshots:
graphml:false
raw_entities:false
top_level_nodes:false
local_search:
#text_unit_prop:0.5
#community_prop:0.1
#conversation_history_max_turns:5
#top_k_mapped_entities:10
#top_k_relationships:10
#llm_temperature:0#temperatureforsampling
#llm_top_p:1#top-psampling
#llm_n:1#Numberofcompletionstogenerate
#max_tokens:12000
global_search:
#llm_temperature:0#temperatureforsampling
#llm_top_p:1#top-psampling
#llm_n:1#Numberofcompletionstogenerate
#max_tokens:12000
#data_max_tokens:12000
#map_max_tokens:1000
#reduce_max_tokens:2000
#concurrency:32以下是 GraphRAG 文件结构:
3. 数据准备:
在启动 GraphRAG 之前,应将非结构化文本数据放入指定文件夹,例如 C:\graphrag\ragtest\input。此数据将被索引以创建知识图。请注意,截至本文撰写时,Microsoft GraphRAG 仅支持 TXT 文件格式。
例如,我使用了一篇关于“经典力学基本原理”的文章。该主题包含许多间接关系,非常适合 GraphRAG。
经典力学的基本原理 经典力学是物理学的一个分支,研究在力系统作用下物体的运动。经典力学的研究基于三条主要定律,即牛顿运动定律,它们描述了物体与作用力之间的关系。
牛顿第一定律,也称为惯性定律,指出静止的物体将保持静止,运动的物体将以恒定速度运动,除非受到外力作用。该定律引入了惯性这一概念,即物体抵抗其运动状态变化的趋势。惯性与物体的质量直接相关;质量越大,惯性越大。
………………
在能量守恒的单独部分中,文本引入了动能的概念。动能是物体由于其运动而具有的能量,其公式为 (KE = \frac{1}{2}mv^2),其中 (m) 是物体的质量,(v) 是其速度。物体的动能与其运动直接相关;速度增加时,动能呈指数增长。
4. 创建知识图:
• 运行索引管道以创建知识图:
python-mgraphrag.index--rootC:\backupcgi\ragtest
• 该过程涉及创建实体、节点、关系以及用于查询处理的最终文档:
5. 查询知识图:
• 索引完成后,可以通过graphrag.query命令查询知识图:
#尝试以下GRAPHRAG命令
python-mgraphrag.query--rootC:\backupcgi\ragtest--methodglobal"这篇文章的主要主题是什么?"
python-mgraphrag.query--rootC:\backupcgi\ragtest--methodlocal"这篇文章的主要主题是什么?"
python-mgraphrag.query--rootC:\backupcgi\ragtest--methodglobal"用不超过100字描述这篇文章的主要主题"
python-mgraphrag.query--rootC:\backupcgi\ragtest--methodlocal"用不超过100字描述这篇文章的主要主题"这些命令从知识图中检索信息,重点关注数据中的主题和关系。使用的两个选项全局搜索(Global Search)和局部搜索(Local Search)的工作方式不同:
全局搜索(Global Search)分析整个数据集,聚合多个文档的信息以识别关系和主题。它需要明确且直接的查询才能有效工作。
局部搜索(Local Search)针对数据集的特定部分,专注于从定义的实体或文档段落中检索详细信息,能够处理更灵活的查询措辞。
例如,当我运行查询“这篇文章的主要主题是什么?”时,全局和局部搜索分别返回了以下结果:
全局搜索返回了一份详细的响应,列出了多个主题,包括:
## 能量守恒数据集强调了……
## 动能及其相互关系另一个主要主题是动能,……
## 简谐运动(SHM)简谐运动(SHM)作为一个关键主题出现……
然而,当我用简短提示运行全局搜索时,出现了错误:“很抱歉,我无法根据提供的数据回答此问题。” 这可能是因为全局搜索在处理模糊或压缩查询时存在困难。相比之下,局部搜索能够返回简洁而清晰的答案:
局部搜索响应:这篇文章的主要主题围绕基础物理概念展开,例如动能、简谐运动(SHM)和牛顿运动定律。动能与质量和速度密切相关,在封闭系统中保持守恒。SHM 描述了摆和弹簧等振荡系统,其中能量在动能和势能之间转化。
Microsoft GraphRAG 的结构化局部搜索是一种基于 Python 的方法,专注于查询特定的局部数据集。这种方法适合需要精确和聚焦回答的场景,比如解答技术性问题或提供详细解释。
以下是实现此方法的代码分解:
1.初始化 LLM、Token 编码器和文本嵌入器:
llm=ChatOpenAI(api_key="###",model="gpt-4",...)
token_encoder=tiktoken.get_encoding("cl100k_base")
text_embedder=OpenAIEmbedding(api_key="##",...)2.加载和准备索引数据:
INPUT_DIR="../ragtest/output/..."
entity_df=pd.read_parquet(f"{INPUT_DIR}/{ENTITY_TABLE}.parquet")3.创建上下文构建器:
context_builder=LocalSearchMixedContext(community_reports=reports,...)
4.定义搜索参数:
local_context_params={"text_unit_prop":0.5,"community_prop":0.1,...}5.执行局部搜索:
search_engine=LocalSearch(llm=llm,context_builder=context_builder,...)
6.运行搜索查询:
result=awaitsearch_engine.asearch("这篇文章的主要主题是什么?")Microsoft GraphRAG 的结构化全局搜索通过分析多个文档之间的连接来查询大型数据集。与局部搜索不同,全局搜索提供了更广阔的视角,非常适合在不同来源中寻找模式和趋势。
1.定义社区级搜索:
COMMUNITY_LEVEL=2
reports=read_indexer_reports(...)2.全局上下文构建器:
context_builder=GlobalCommunityContext(community_reports=reports,...)
3.上下文构建器参数:
context_builder_params={"use_community_summary":False,"shuffle_data":True,...}4.搜索引擎初始化:
search_engine=GlobalSearch(llm=llm,context_builder=context_builder,...)
5.运行全局搜索:
result=awaitsearch_engine.asearch("牛顿运动定律如何影响其他研究?")在本节中,我们研究如何使用 Neo4j 和 LangChain 实现 GraphRAG。Neo4j 是一个流行的图数据库,用于以图结构表示数据,其中实体是节点,节点之间的关系是边。当与 LangChain 集成时,Neo4j 成为一个强大的工具,可以对结构化图数据执行 RAG。
以下是设置 Neo4j、导入数据和运行查询以检索相关信息的步骤。
1. 安装 Neo4j(本地设置):
首先,您需要在本地安装 Neo4j。可以使用 Neo4j Desktop,它提供了一个直观的界面来管理和查询图数据库。安装完成后,您需要在 Python 环境中配置 URI、用户名和密码,如下所示:
importos
fromlangchain_community.document_loadersimportTextLoader
fromlangchain.text_splitterimportRecursiveCharacterTextSplitter
fromlangchain_core.promptsimportPromptTemplate,ChatPromptTemplate
fromlangchain_core.pydantic_v1importBaseModel,Field,validator
fromlangchain_core.runnablesimportRunnablePassthrough
fromlangchain_core.output_parsersimportStrOutputParser
fromlangchain_experimental.graph_transformersimportLLMGraphTransformer
fromlangchain_openaiimportAzureChatOpenAI
fromlangchain_openaiimportAzureOpenAIEmbeddings
fromneo4jimportGraphDatabase
fromlangchain_community.vectorstores.neo4j_vectorimportNeo4jVector
fromlangchain_community.vectorstores.neo4j_vectorimportremove_lucene_chars
fromlangchain_community.graphsimportNeo4jGraph
os.environ["NEO4J_URI"]="bolt://localhost:7687"#Neo4jDesktop的默认URI
os.environ["NEO4J_USERNAME"]="neo4j"#替换为您的Neo4j用户名
os.environ["NEO4J_PASSWORD"]="12345678"#替换为您的Neo4j密码
#连接到Neo4j图数据库
graph=Neo4jGraph(refresh_schema=False)2. 数据导入:拆分与加载数据
在将数据导入 Neo4j 之前,需要将数据(如 .txt 或 .csv 文件)拆分为可管理的块。这可以通过TextLoader和RecursiveCharacterTextSplitter实现,如下所示:
loader=TextLoader("../mechanics.txt",encoding='UTF-8')
docs=loader.load()
text_splitter=RecursiveCharacterTextSplitter(
chunk_size=300,
chunk_overlap=30,
length_function=len,
)
documents=text_splitter.split_documents(docs)在此步骤中,文本数据被分解为更小、更易于分析的部分。
3. 使用 LangChain 将数据导入 Neo4j:
准备好数据后,可以使用 LangChain 的LLMGraphTransformer模块将其导入 Neo4j,将文档转换为图结构:
llm=AzureChatOpenAI(
openai_api_version="2023-12-01-preview",
azure_deployment="gpt4",
)
llm_transformer=LLMGraphTransformer(
llm=llm,
)
#将文档转换为图结构
graph_doc=llm_transformer.convert_to_graph_documents(documents)
#添加到Neo4j
graph.add_graph_documents(graph_doc,baseEntityLabel=True,include_source=True)在这里,文档被转换为图结构,其中实体被创建为节点,关系在节点之间建立。您也可以使用以下代码可视化图:
fromyfiles_jupyter_graphsimportGraphWidget
defshowGraph():
driver=GraphDatabase.driver(uri="bolt://localhost:7687",auth=("neo4j","12345678"))
session=driver.session()
widget=GraphWidget(graph=session.run("MATCH(s)-[r:!MENTIONS]->(t)RETURNs,r,t").graph())
widget.node_label_mapping='id'
returnwidget
showGraph()4. 定义图检索器:
接下来,使用 Neo4j 数据库定义检索器,以通过混合搜索查找相关信息。在此步骤中,我们使用嵌入技术来提高搜索效率:
embeddings=AzureOpenAIEmbeddings(
deployment="textembedding3large",
model="text-embedding-3-large",
azure_endpoint="https://##",
openai_api_type="azure",
)
vector_index=Neo4jVector.from_existing_graph(
embeddings,
search_type="hybrid",
node_label="Document",
text_node_properties=["text"],
embedding_node_property="embedding"
)
vector_retriever=vector_index.as_retriever()此代码集成了混合搜索,结合了向量和基于图的搜索策略,从 Neo4j 数据库中检索相关数据。
5. 使用 LangChain 查询图:
最后,我们可以使用 LangChain 通过graph_retriever()函数查询图,并使用提示模板根据图数据生成简洁的答案:
defgraph_retriever(question:str):
vector_data=[el.page_contentforelinvector_retriever.invoke(question)]
final_data=f"""vectordata:{"#Document".join(vector_data)}"""
returnfinal_data
question="牛顿第三定律如何与力学原理相关?"
template="""Answerthequestionbasedonlyonthefollowingcontext:{context}Question:{question}Usenaturallanguageandbeconcise.Answer:"""
prompt=ChatPromptTemplate.from_template(template)
chain=(
{
"context":graph_retriever,
"question":RunnablePassthrough(),
}
|prompt
|llm
|StrOutputParser()
)
chain.invoke(input=question)graph_retriever()函数在图中搜索相关信息,而 LangChain 流水线使用 LLM 根据查询生成简洁的答案。
我已经展示了使用 Neo4j 和 LangChain 实现的另一种 GraphRAG 解决方案。接下来,我将其与 Microsoft 的 GraphRAG 和传统的 RAG 进行比较。
为了评估,我选择了一个普通的生活故事,GraphRAG 可以突出事件与人物之间的关系,这是其可能优于传统 RAG 的地方。需要注意的是,虽然 GraphRAG 是一个新工具,但它并不保证在所有情况下都表现更好。我比较了三种 RAG 方法:
1. Microsoft GraphRAG
2. Neo4j + LangChain GraphRAG
3. 传统的嵌入式 RAG
以下是用于比较的故事:
上周日,米勒一家在家中共进晚餐。大女儿安娜与母亲艾米丽一起做了一顿美味的饭菜,而父亲约翰负责摆放餐具。最小的儿子蒂姆非常兴奋,因为他的表妹莎拉来拜访了。当他们坐下来吃饭时,谈话非常热烈。约翰谈到了他在工作中完成的一项大交易,而艾米丽分享了一些园艺技巧。安娜刚从大学回来,聊起了她的新课程,而莎拉提到了她即将开始的欧洲之旅。
热爱运动的蒂姆问大家是否愿意在晚饭后踢足球。家人都同意了,晚饭后,他们一起到后院踢了一场有趣的比赛。莎拉的旅行、安娜的学校生活以及约翰的工作成功让家人感到自豪和兴奋,使他们的关系更加紧密。
测试问题:
晚餐的事件是如何加强家庭成员之间的关系的?
Microsoft GraphRAG 的回答:
米勒一家的晚餐是一个关键时刻,通过共同活动和谈话增强了他们的联系。安娜与母亲艾米丽的合作体现了养育关系和家庭传统的传承。约翰谈论他的工作成就,为家庭带来了自豪感和集体支持。
蒂姆对运动的热情以及他提出的晚饭后踢足球的建议,增加了一个充满乐趣和凝聚力的活动,进一步巩固了家庭的亲密关系。莎拉的出现以及她即将开始的欧洲旅行激发了兴趣和谈话,突显了她在家庭中的重要角色,以及他们对她冒险的共同兴奋。
Neo4j + LangChain GraphRAG 的回答:
晚餐通过分享米勒一家的最新情况和成就,加强了他们的关系,培养了自豪感和亲密感。蒂姆提出的晚饭后踢足球的建议,为他们的联系增添了一层乐趣和身体互动。安娜参与与艾米丽一起做饭,以及约翰摆放餐具,展现了他们在准备聚会时的共同努力,加强了他们的团结。在晚餐谈话中,约翰讨论了他的工作成功,艾米丽提供了园艺技巧,安娜谈到了她的大学经历,而莎拉分享了她的旅行计划,让每个成员都有机会表达他们的兴趣和成就。这种故事的交流和对彼此努力的支持,促进了家庭成员之间更深层次的情感联系。
传统嵌入式 RAG 的回答:
晚餐事件通过共同活动和开放的交流,加强了米勒家庭成员之间的关系。蒂姆提出的晚饭后踢足球的建议,带来了一个集体且愉快的家庭活动,通过游戏增进了联系。晚餐谈话让每位家庭成员分享个人成就和经历,例如约翰的工作成功、安娜的学术进展以及莎拉的旅行计划,这培养了自豪感和相互兴趣。这些元素结合在一起,创造了支持和兴奋的氛围,加深了家庭联系。
•Microsoft GraphRAG:此方法提供了最详细且富有情感的回答。它解释了特定行为(如一起做饭或踢足球)如何增强家庭联系。例如,它描述了安娜与母亲一起做饭如何增进亲密关系,使回答更具个人性和关联性。
•Neo4j + LangChain GraphRAG:此方法突出了团队合作和共同活动,展示了家庭如何一起努力。它更多地关注实际细节,例如每个人摆放餐具或踢足球,强调了家庭的团结。然而,它在情感联系方面没有深入。例如,它解释了晚餐准备如何让家庭更紧密,但没有深入探讨情感层面的影响。
•传统嵌入式 RAG:此方法提供了一个简单的事件总结,但缺乏情感深度。它主要描述了活动(如踢足球),而没有展示这些行为如何建立更强的关系。例如,它提到家庭成员一起玩耍,但没有说明这如何影响他们彼此的感受。
在本文中,我讨论了 GraphRAG 的创建和使用,强调了它在开源项目中的重要性。我介绍了 Microsoft GraphRAG 和 Neo4j + LangChain GraphRAG 的设置、架构和 RAG 管理过程。此外,我提供了有关导入数据和利用图查询算法支持实时应用程序开发的分步指南。
我还评估了三种 RAG 方法的性能,重点是它们生成详细、上下文感知响应的能力。我希望这一比较能够为选择特定场景的最佳 RAG 方法提供有价值的指导。
| 欢迎光临 链载Ai (https://www.lianzai.com/) | Powered by Discuz! X3.5 |