用LLM Graph Builder构建知识图谱实战篇

关系型数据库

前言

    在当今信息爆炸的时代,如何有效地将海量的非结构化文本转化为结构化的数据成为一大挑战。


    本文深入探讨了LangChain框架中基于大型语言模型(LLM)的LLM图转换器,展示了如何从文本中提取实体和关系,进而构建知识图谱。文章首先介绍了使用Neo4j作为图数据库的环境设置,强调了其内置的图形可视化功能,方便用户直观地理解数据结构。


    LLM图转换器提供了两种主要模式:基于工具的模式和基于提示的模式。前者利用LLM的结构化输出和函数调用能力,简化了提示工程和自定义解析的需求;后者则在LLM不支持工具时作为回退方案,通过少量示例引导模型进行信息提取。文章进一步阐述了如何定义图谱模式,包括允许的节点类型、关系类型及其属性,从而提高提取的一致性和准确性。


    此外,本文还详细介绍了如何将提取的图谱文档导入Neo4j数据库,提供了默认导入、基础实体标签以及包含源文档等多种导入选项。通过实际示例,展示了不同配置下的提取效果和可视化结果。


    最后,文章总结了LLM图转换器在构建知识图谱中的优势和应用前景,强调了结构化数据在增强检索生成(RAG)应用和处理复杂多跳查询中的重要性。

相关文章

llm-graph-builder——从非结构化数据创建知识图谱

如何将任何文本转换为图谱

GraphRAG会成为AI原生应用中RAG的终局吗?

深入探讨LangChain使用LLM实现图构建的实现

创建文本图谱令人兴奋,但确实具有挑战性。本质上,这是将非结构化文本转换为结构化数据。虽然这种方法已经存在一段时间,但随着大型语言模型(LLM)的出现,它获得了显著的关注,使其更为主流。

picture.image

从文本中提取实体和关系以构建知识图谱。图片由作者提供。

在上图中,您可以看到信息提取如何将原始文本转化为知识图谱。左侧显示了多个文档中关于个人及其与公司的关系的非结构化句子。右侧,这些相同的信息被表示为实体及其连接的图谱,显示谁在不同的组织工作或创立了哪些组织。

但为什么要从文本中提取结构化信息并以图的形式表示呢?一个关键原因是为了支持基于检索增强生成(RAG)的应用。虽然在非结构化文本上使用文本嵌入模型是一种有用的方法,但在回答需要理解多个实体之间的连接或需要进行诸如过滤、排序和聚合等结构化操作的复杂、多跳问题[1]时,这种方法可能会有所不足。通过从文本中提取结构化信息并构建知识图谱,您不仅可以更有效地组织数据,还可以创建一个强大的框架来理解实体之间的复杂关系。这种结构化的方法使得检索和利用特定信息变得更加容易,扩展了您可以回答的问题类型,同时提供了更高的准确性。

大约一年前,我开始使用LLM构建图谱的实验[2],由于兴趣日益增长,我们决定将这一功能集成到LangChain中,作为LLM图转换器[3]。在过去的一年中,我们获得了宝贵的见解并引入了新功能,本文将展示这些内容。

代码可在GitHub[4]上获取。

设置Neo4j环境

我们将使用Neo4j作为底层图存储,它自带开箱即用的图形可视化。最简单的入门方式是使用Neo4j Aura[5]的免费实例,它提供Neo4j数据库的云实例。或者,您也可以通过下载Neo4j Desktop[6]应用程序并创建本地数据库实例来设置Neo4j数据库的本地实例。


          
from langchain_community.graphs import Neo4jGraph
          

          
graph = Neo4jGraph(  
          
 url="bolt://54.87.130.140:7687",  
          
 username="neo4j",  
          
 password="cables-anchors-directories",  
          
 refresh_schema=False  
          
)
      
LLM图转换器

LLM图转换器旨在为使用任何LLM构建图谱提供灵活的框架。由于有许多不同的提供商和模型可用,这项任务远非简单。幸运的是,LangChain介入处理了大部分标准化过程。至于LLM图转换器本身,它就像两个猫堆叠在一件风衣里——能够在两个完全独立的模式下操作。

picture.image

LLM图转换器由两种从文本中提取图谱的独立模式组成。图片由用户提供。

LLM图转换器以两种不同的模式运行,每种模式都设计用于在不同场景下使用LLM从文档中生成图谱。

1.基于工具的模式(默认): 当LLM支持结构化输出或函数调用时,此模式利用LLM的内置[7][with_structured_output](https://python.langchain.com/docs/how_to/structured_output/)使用工具[8]。工具规范定义了输出格式,确保以结构化、预定义的方式提取实体和关系。这在图像的左侧展示,显示了节点和关系类的代码。 2.基于提示的模式(回退): 在LLM不支持工具或函数调用的情况下,LLM图转换器回退到纯基于提示的方法。这种模式使用少量示例提示来定义输出格式,引导LLM以基于文本的方式提取实体和关系。然后通过自定义函数解析结果,将LLM的输出转换为JSON格式。这个JSON用于填充节点和关系,就像基于工具的模式一样,但这里LLM完全由提示引导,而不是结构化工具。图像的右侧展示了一个示例提示和生成的JSON输出。

这两种模式确保LLM图转换器适应不同的LLM,允许它使用工具直接构建图谱或通过解析基于文本的提示输出构建图谱。

请注意,即使使用支持工具/函数的模型,您也可以通过设置属性ignore_tools_usage=True来使用基于提示的提取。

基于工具的提取

我们最初选择基于工具的方法进行提取,因为它最小化了对广泛的提示工程和自定义解析函数的需求。在LangChain中,with_structured_output方法允许您使用工具或函数提取信息,输出通过JSON结构或Pydantic对象定义。就个人而言,我觉得Pydantic对象更清晰,因此我们选择了它。

我们首先定义一个Node类。


          
class Node(BaseNode):  
          
 id: str = Field(..., description="Name or human-readable unique identifier")  
          
 label: str = Field(..., description=f"Available options are {enum_values}")  
          
 properties: Optional[List[Property]]
      

每个节点都有一个id、一个label和可选的properties。为了简洁,我在这里没有包含完整的描述。将id描述为可读的唯一标识符很重要,因为一些LLM倾向于以更传统的方式理解ID属性,如随机字符串或递增整数。相反,我们希望使用实体的名称作为id属性。我们还通过简单地在label描述中列出它们来限制可用标签类型。此外,像OpenAI这样的LLM支持enum参数,我们也使用了它。

接下来,我们看一下Relationship类。


          
class Relationship(BaseRelationship):  
          
 source_node_id: str  
          
 source_node_label: str = Field(..., description=f"Available options are {enum_values}")  
          
 target_node_id: str  
          
 target_node_label: str = Field(..., description=f"Available options are {enum_values}")  
          
 type: str = Field(..., description=f"Available options are {enum_values}")  
          
 properties: Optional[List[Property]]
      

这是Relationship类的第二个迭代。最初,我们为源和目标节点使用嵌套的Node对象,但我们很快发现嵌套对象会降低提取过程的准确性和质量。因此,我们决定将源和目标节点展平到单独的字段中,例如source_node_idsource_node_label,以及target_node_idtarget_node_label。此外,我们在节点标签和关系类型的描述中定义了允许的值,以确保LLM遵守指定的图谱模式。

基于工具的提取方法使我们能够为节点和关系定义属性。以下是我们用来定义它们的类。


          
class Property(BaseModel):  
          
 """A single property consisting of key and value"""  
          
 key: str = Field(..., description=f"Available options are {enum_values}")  
          
 value: str
      

每个Property被定义为一个键值对。虽然这种方法具有灵活性,但也有其局限性。例如,我们无法为每个属性提供唯一的描述,也无法将某些属性定义为必需而其他属性为可选,因此所有属性都被定义为可选。此外,属性不是为每种节点或关系类型单独定义的,而是在所有节点和关系类型之间共享。

我们还实现了一个详细的系统提示[9]来帮助指导提取过程。但在我的经验中,函数和参数描述的影响通常大于系统消息。

不幸的是,目前没有简单的方法来自定义LLM图转换器中函数或参数的描述。

基于提示的提取

由于只有少数商业LLM和LLaMA 3支持原生工具,我们为不支持工具的模型实现了回退。您还可以通过设置ignore_tool_usage=True来切换到基于提示的方法,即使在使用支持工具的模型时也是如此。

大部分基于提示的方法的提示工程和示例由Geraldus Wilsen[10]贡献。

使用基于提示的方法,我们必须在提示中直接定义输出结构。您可以在此处[11]找到完整的提示。在本文中,我们将仅进行高层次的概述。我们首先定义系统提示。


          
You are a top-tier algorithm designed for extracting information in structured formats to build a knowledge graph. Your task is to identify the entities and relations specified in the user prompt from a given text and produce the output in JSON format. This output should be a list of JSON objects, with each object containing the following keys:
          

          
- **"head"**: The text of the extracted entity, which must match one of the types specified in the user prompt.
          
- **"head_type"**: The type of the extracted head entity, selected from the specified list of types.
          
- **"relation"**: The type of relation between the "head" and the "tail," chosen from the list of allowed relations.
          
- **"tail"**: The text of the entity representing the tail of the relation.
          
- **"tail_type"**: The type of the tail entity, also selected from the provided list of types.
          

          
Extract as many entities and relationships as possible.
          

          
**Entity Consistency**: Ensure consistency in entity representation. If an entity, like "John Doe," appears multiple times in the text under different names or pronouns (e.g., "Joe," "he"), use the most complete identifier consistently. This consistency is essential for creating a coherent and easily understandable knowledge graph.
          

          
**Important Notes**:
          

          
- Do not add any extra explanations or text.
      

在基于提示的方法中,一个关键的区别是我们要求LLM仅提取关系,而不是单独的节点。这意味着我们不会有任何孤立的节点,与基于工具的方法不同。此外,因为缺乏原生工具支持的模型通常表现较差,我们不允许提取任何属性——无论是节点还是关系,以保持提取输出更简单。

接下来,我们为模型添加了几个少量示例。


          
examples = [  
          
 {  
          
 "text": (  
          
 "Adam is a software engineer in Microsoft since 2009, "  
          
 "and last year he got an award as the Best Talent"  
          
 ),  
          
 "head": "Adam",  
          
 "head_type": "Person",  
          
 "relation": "WORKS_FOR",  
          
 "tail": "Microsoft",  
          
 "tail_type": "Company",  
          
 },  
          
 {  
          
 "text": (  
          
 "Adam is a software engineer in Microsoft since 2009, "  
          
 "and last year he got an award as the Best Talent"  
          
 ),  
          
 "head": "Adam",  
          
 "head_type": "Person",  
          
 "relation": "HAS_AWARD",  
          
 "tail": "Best Talent",  
          
 "tail_type": "Award",  
          
 },  
          
 ...  
          
]
      

在这种方法中,目前不支持添加自定义的少量示例或额外的指令。唯一的定制方式是通过prompt属性修改整个提示。扩展定制选项是我们正在积极考虑的事项。

接下来,我们将看一下如何定义图谱模式。

定义图谱模式

使用LLM图转换器进行信息提取时,定义图谱模式对于引导模型构建有意义和结构化的知识表示至关重要。一个良好定义的图谱模式指定了要提取的节点和关系类型,以及每个节点和关系的任何属性。这个模式作为蓝图,确保LLM始终如一地提取相关信息,以符合所需的知识图谱结构。

在本文中,我们将使用玛丽·居里的维基百科页面[12]的开头段落进行测试,并在最后添加了一句关于罗宾·威廉姆斯的句子。


          
from langchain_core.documents import Document
          

          
text = """  
          
Marie Curie, 7 November 1867 – 4 July 1934, was a Polish and naturalised-French physicist and chemist who conducted pioneering research on radioactivity.  
          
She was the first woman to win a Nobel Prize, the first person to win a Nobel Prize twice, and the only person to win a Nobel Prize in two scientific fields.  
          
Her husband, Pierre Curie, was a co-winner of her first Nobel Prize, making them the first-ever married couple to win the Nobel Prize and launching the Curie family legacy of five Nobel Prizes.  
          
She was, in 1906, the first woman to become a professor at the University of Paris.  
          
Also, Robin Williams.  
          
"""  
          
documents = [Document(page_content=text)]
      

我们还将在所有示例中使用GPT-4o。


          
from langchain_openai import ChatOpenAI  
          
import getpass  
          
import os
          

          
os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI api key")
          

          
llm = ChatOpenAI(model='gpt-4o')
      

首先,让我们检查在不定义任何图谱模式的情况下,提取过程是如何工作的。


          
from langchain_experimental.graph_transformers import LLMGraphTransformer
          

          
no_schema = LLMGraphTransformer(llm=llm)
      

现在我们可以使用aconvert_to_graph_documents函数处理文档,该函数是异步的。建议使用异步方式进行LLM提取,因为它允许并行处理多个文档。这种方法可以显著减少等待时间并提高吞吐量,特别是在处理多个文档时。


        
            

          data = await no\_schema.aconvert\_to\_graph\_documents(documents)
        
      

LLM图转换器的响应将是一个图谱文档,其结构如下:


          
[  
          
 GraphDocument(  
          
 nodes=[  
          
 Node(id="Marie Curie", type="Person", properties={}),  
          
 Node(id="Pierre Curie", type="Person", properties={}),  
          
 Node(id="Nobel Prize", type="Award", properties={}),  
          
 Node(id="University Of Paris", type="Organization", properties={}),  
          
 Node(id="Robin Williams", type="Person", properties={}),  
          
 ],  
          
 relationships=[  
          
 Relationship(  
          
 source=Node(id="Marie Curie", type="Person", properties={}),  
          
 target=Node(id="Nobel Prize", type="Award", properties={}),  
          
 type="WON",  
          
 properties={},  
          
 ),  
          
 Relationship(  
          
 source=Node(id="Marie Curie", type="Person", properties={}),  
          
 target=Node(id="Nobel Prize", type="Award", properties={}),  
          
 type="WON",  
          
 properties={},  
          
 ),  
          
 Relationship(  
          
 source=Node(id="Marie Curie", type="Person", properties={}),  
          
 target=Node(  
          
 id="University Of Paris", type="Organization", properties={}  
          
 ),  
          
 type="PROFESSOR",  
          
 properties={},  
          
 ),  
          
 Relationship(  
          
 source=Node(id="Pierre Curie", type="Person", properties={}),  
          
 target=Node(id="Nobel Prize", type="Award", properties={}),  
          
 type="WON",  
          
 properties={},  
          
 ),  
          
 ],  
          
 source=Document(  
          
 metadata={"id": "de3c93515e135ac0e47ca82a4f9b82d8"},  
          
 page_content="\nMarie Curie, 7 November 1867 – 4 July 1934, was a Polish and naturalised-French physicist and chemist who conducted pioneering research on radioactivity.\nShe was the first woman to win a Nobel Prize, the first person to win a Nobel Prize twice, and the only person to win a Nobel Prize in two scientific fields.\nHer husband, Pierre Curie, was a co-winner of her first Nobel Prize, making them the first-ever married couple to win the Nobel Prize and launching the Curie family legacy of five Nobel Prizes.\nShe was, in 1906, the first woman to become a professor at the University of Paris.\nAlso, Robin Williams!\n",  
          
 ),  
          
 )  
          
]
      

图谱文档描述了提取的nodesrelationships。此外,提取的源文档被添加在source键下。

我们可以使用Neo4j Browser来可视化输出,更清晰、更直观地理解数据。

picture.image

在没有定义图谱模式的情况下,对同一数据集进行了两次提取。图片由作者提供。

上图展示了对同一段关于玛丽·居里的段落进行了两次提取。在这种情况下,我们使用了基于工具的提取,这也允许有孤立的节点,如图所示。由于没有定义图谱模式,LLM在运行时确定要提取的信息,这可能导致即使是同一段落的输出也存在差异。因此,有些提取比其他提取更详细,结构可能有所不同。例如,左侧玛丽被表示为诺贝尔奖的WINNER,而右侧她WON诺贝尔奖。

现在,让我们尝试使用基于提示的方法进行相同的提取。对于支持工具的模型,您可以通过设置ignore_tool_usage参数来启用基于提示的提取。


          
no_schema_prompt = LLMGraphTransformer(llm=llm, ignore_tool_usage=True)  
          
data = await no_schema.aconvert_to_graph_documents(documents)
      

同样,我们可以在Neo4j Browser中可视化两次独立的执行。

picture.image

使用基于提示的方法,在没有定义图谱模式的情况下,对同一数据集进行了两次提取。图片由作者提供。

使用基于提示的方法,我们不会看到任何孤立的节点。然而,与之前的提取一样,模式在运行之间可能会有所变化,导致相同输入的输出不同。

接下来,让我们详细了解如何定义图谱模式有助于产生更一致的输出。

定义允许的节点

限制提取的图谱结构可以带来很大好处,因为它引导模型专注于特定的相关实体和关系。通过定义清晰的模式,您可以提高提取的一致性,使输出更加可预测并与您实际需要的信息保持一致。这减少了运行之间的变异性,并确保提取的数据遵循标准化结构,捕捉到预期的信息。通过良好定义的模式,模型不太可能忽略关键细节或引入意外的元素,从而生成更干净、更可用的图谱。

我们将通过定义allowed_nodes参数来定义要提取的期望节点类型。


          
allowed_nodes = ["Person", "Organization", "Location", "Award", "ResearchField"]  
          
nodes_defined = LLMGraphTransformer(llm=llm, allowed_nodes=allowed_nodes)  
          
data = await allowed_nodes.aconvert_to_graph_documents(documents)
      

在这里,我们定义LLM应该提取五种类型的节点,如

Person

Organization , Location , Award 和 ResearchField 。我们在Neo4j Browser中可视化了两次独立的执行以进行比较。

picture.image

具有预定义节点类型的两次提取可视化。图片由作者提供。

通过指定期望的节点类型,我们实现了更一致的节点提取。然而,仍可能存在一些变化。例如,在第一次运行中,“radioactivity”被提取为研究领域,而在第二次运行中没有。

由于我们尚未定义关系,其类型也可能在运行之间有所不同。此外,有些提取可能捕获的信息比其他提取多。例如,玛丽和皮埃尔之间的MARRIED_TO关系并不是在所有提取中都存在。

现在,让我们探讨如何定义关系类型以进一步提高一致性。

定义允许的关系

如我们所观察到的,仅定义节点类型仍然允许关系提取的变化。为了解决这个问题,让我们探索如何定义关系。第一种方法是使用可用类型列表来指定允许的关系。


          
allowed_nodes = ["Person", "Organization", "Location", "Award", "ResearchField"]  
          
allowed_relationships = ["SPOUSE", "AWARD", "FIELD_OF_RESEARCH", "WORKS_AT", "IN_LOCATION"]  
          
rels_defined = LLMGraphTransformer(  
          
 llm=llm,  
          
 allowed_nodes=allowed_nodes,  
          
 allowed_relationships=allowed_relationships  
          
)  
          
data = await rels_defined.aconvert_to_graph_documents(documents)
      

让我们再次检查两次独立的提取。

picture.image

具有预定义节点和关系类型的两次提取可视化。图片由作者提供。

通过同时定义节点和关系,我们的输出变得显著更一致。例如,玛丽总是被显示为赢得奖项,是皮埃尔的配偶,并在巴黎大学工作。然而,由于关系被定义为一个通用列表,而没有限制它们可以连接哪些节点,因此仍然存在一些变化。例如,FIELD_OF_RESEARCH关系可能出现在PersonResearchField之间,但有时它将AwardResearchField连接。此外,由于未定义关系方向,方向一致性可能存在差异。

为了解决无法指定关系可以连接哪些节点以及强制关系方向的问题,我们最近引入了定义关系的新选项,如下所示。


          
allowed_nodes = ["Person", "Organization", "Location", "Award", "ResearchField"]  
          
allowed_relationships = [  
          
 ("Person", "SPOUSE", "Person"),  
          
 ("Person", "AWARD", "Award"),  
          
 ("Person", "WORKS_AT", "Organization"),  
          
 ("Organization", "IN_LOCATION", "Location"),  
          
 ("Person", "FIELD_OF_RESEARCH", "ResearchField")  
          
]  
          
rels_defined = LLMGraphTransformer(  
          
 llm=llm,  
          
 allowed_nodes=allowed_nodes,  
          
 allowed_relationships=allowed_relationships  
          
)  
          
data = await rels_defined.aconvert_to_graph_documents(documents)
      

而不是将关系定义为简单的字符串列表,我们现在使用三元组格式,每个元素分别代表源节点、关系类型和目标节点。

让我们再次可视化结果。

picture.image

具有预定义节点和高级关系类型的两次提取可视化。图片由作者提供。

使用三元组方法,跨多次执行提取图谱的模式更加一致。然而,鉴于LLM的性质,提取的细节级别可能仍存在一些变化。例如,在右侧,皮埃尔被显示为赢得诺贝尔奖,而在左侧则缺少此信息。

定义属性

我们可以对图谱模式进行的最后一个增强是定义节点和关系的属性。在这里,我们有两个选项。第一个是将node_propertiesrelationship_properties设置为true,允许LLM自主决定提取哪些属性。


          
allowed_nodes = ["Person", "Organization", "Location", "Award", "ResearchField"]  
          
allowed_relationships = [  
          
 ("Person", "SPOUSE", "Person"),  
          
 ("Person", "AWARD", "Award"),  
          
 ("Person", "WORKS_AT", "Organization"),  
          
 ("Organization", "IN_LOCATION", "Location"),  
          
 ("Person", "FIELD_OF_RESEARCH", "ResearchField")  
          
]  
          
node_properties=True  
          
relationship_properties=True  
          
props_defined = LLMGraphTransformer(  
          
 llm=llm,  
          
 allowed_nodes=allowed_nodes,  
          
 allowed_relationships=allowed_relationships,  
          
 node_properties=node_properties,  
          
 relationship_properties=relationship_properties  
          
)  
          
data = await props_defined.aconvert_to_graph_documents(documents)  
          
graph.add_graph_documents(data)
      

让我们检查结果。

picture.image

提取的节点和关系属性。图片由作者提供。

我们已启用LLM添加其认为相关的任何节点或关系属性。例如,它选择包括玛丽·居里的出生和死亡日期、她在巴黎大学担任教授的角色,以及她两次获得诺贝尔奖的事实。这些额外的属性显著丰富了提取的信息。

我们有的第二个选项是定义我们想要提取的节点和关系属性。


          
allowed_nodes = ["Person", "Organization", "Location", "Award", "ResearchField"]  
          
allowed_relationships = [  
          
 ("Person", "SPOUSE", "Person"),  
          
 ("Person", "AWARD", "Award"),  
          
 ("Person", "WORKS_AT", "Organization"),  
          
 ("Organization", "IN_LOCATION", "Location"),  
          
 ("Person", "FIELD_OF_RESEARCH", "ResearchField")  
          
]  
          
node_properties=["birth_date", "death_date"]  
          
relationship_properties=["start_date"]  
          
props_defined = LLMGraphTransformer(  
          
 llm=llm,  
          
 allowed_nodes=allowed_nodes,  
          
 allowed_relationships=allowed_relationships,  
          
 node_properties=node_properties,  
          
 relationship_properties=relationship_properties  
          
)  
          
data = await props_defined.aconvert_to_graph_documents(documents)  
          
graph.add_graph_documents(data)
      

属性仅仅被定义为两个列表。让我们看看LLM提取了什么。

picture.image

提取的预定义节点和关系属性。图片由作者提供。

出生和死亡日期与之前的提取保持一致。然而,这一次,LLM还提取了玛丽在巴黎大学担任教授的起始日期。

属性确实为提取的信息增添了有价值的深度,尽管在当前实现中存在一些限制:

•属性只能使用基于工具的方法提取。 •所有属性都被提取为字符串。 •属性只能全局定义,不能按节点标签或关系类型定义。 •没有选项来自定义属性描述,以引导LLM进行更精确的提取。

严格模式

如果您认为我们已经完善了一种让LLM完美遵循定义模式的方法,我必须澄清一下。尽管我们在提示工程上投入了大量努力,但让LLM,尤其是性能较低的LLM,完全准确地遵守指令是具有挑战性的。为了解决这个问题,我们引入了一个后处理步骤,称为strict_mode,它会移除任何不符合定义的图谱模式的信息,确保结果更干净、更一致。

默认情况下,strict_mode设置为True,但您可以通过以下代码将其禁用:


          
LLMGraphTransformer(  
          
 llm=llm,  
          
 allowed_nodes=allowed_nodes,  
          
 allowed_relationships=allowed_relationships,  
          
 strict_mode=False  
          
)
      

关闭严格模式后,您可能会得到不在定义的图谱模式中的节点或关系类型,因为LLM有时会对输出结构进行创造性的处理。

将图谱文档导入图数据库

从LLM图转换器提取的图谱文档可以使用add_graph_documents方法导入到Neo4j等图数据库中,以进行进一步的分析和应用。我们将探索不同的导入选项,以适应不同的用例。

默认导入

您可以使用以下代码将节点和关系导入Neo4j。


        
            

          graph.add\_graph\_documents(graph\_documents)
        
      

这种方法直接从提供的图谱文档中导入所有节点和关系。我们在整个博客文章中都使用了这种方法来查看不同LLM和模式配置的结果。

picture.image

默认导入设置。图片由作者提供。

基础实体标签

大多数图数据库支持索引以优化数据导入和检索。在Neo4j中,索引只能为特定的节点标签设置。由于我们可能事先不知道所有的节点标签,我们可以通过使用baseEntityLabel参数为每个节点添加一个辅助基础标签来处理。这种方式,我们仍然可以利用索引进行高效的导入和检索,而不需要为图谱中的每个可能的节点标签设置索引。


        
            

          graph.add\_graph\_documents(graph\_documents, baseEntityLabel=True)
        
      

如前所述,使用baseEntityLabel参数将导致每个节点具有额外的__Entity__标签。

picture.image

每个节点使用baseEntityLabel参数获得一个辅助标签。图片由作者提供。

包含源文档

最后一个选项是同时导入提取节点和关系的源文档。这种方法使我们能够跟踪每个实体出现在哪些文档中。您可以使用include_source参数导入源文档。


        
            

          graph.add\_graph\_documents(graph\_documents, include\_source=True)
        
      

在检查导入的图谱时,我们应该看到类似以下的结果。

picture.image

导入的源文档。图片由作者提供。

在此可视化中,源文档以蓝色突出显示,所有从中提取的实体通过MENTIONS关系连接。这种模式允许您构建利用结构化和非结构化搜索方法的检索器[13]。

总结

在本文中,我们探讨了LangChain的LLM图转换器及其用于从文本构建知识图谱的双模式。基于工具的模式,我们的主要方法,利用结构化输出和函数调用,减少了提示工程并允许属性提取。同时,基于提示的模式在无法使用工具时有用,依赖少量示例来引导LLM。然而,基于提示的提取不支持属性提取,也不会产生孤立的节点。

我们观察到,定义清晰的图谱模式,包括允许的节点和关系类型,可以提高提取的一致性和性能。受限的模式有助于确保输出遵循我们期望的结构,使其更可预测、可靠和适用。无论是使用工具还是提示,LLM图转换器都能实现更有组织、结构化的非结构化数据表示,从而实现更好的RAG应用和多跳查询处理。

代码可在GitHub[14]上获取。您还可以使用Neo4j托管的LLM Graph Builder 应用程序在无代码环境中试用LLM图转换器。

声明

本文由山行翻译整理自:https://towardsdatascience.com/building-knowledge-graphs-with-llm-graph-transformer-a91045c49b59,如果对您有帮助,请帮忙点赞、关注、收藏,谢谢~

References

[1] 复杂、多跳问题: https://medium.com/neo4j/knowledge-graphs-llms-multi-hop-question-answering-322113f53f51
[2] 使用LLM构建图谱的实验: https://medium.com/@bratanic-tomaz/constructing-knowledge-graphs-from-text-using-openai-functions-096a6d010c17
[3] LLM图转换器: https://python.langchain.com/docs/how\_to/graph\_constructing/
[4] GitHub: https://github.com/tomasonjo/blogs/blob/master/llm/llm\_graph\_transformer\_in\_depth.ipynb
[5] Neo4j Aura: https://neo4j.com/cloud/platform/aura-graph-database/
[6] Neo4j Desktop: https://neo4j.com/download/
[7] LLM的内置: https://python.langchain.com/docs/how\_to/structured\_output/
[8] 使用工具: https://python.langchain.com/docs/how\_to/structured\_output/
[9] 详细的系统提示: https://github.com/langchain-ai/langchain-experimental/blob/main/libs/experimental/langchain\_experimental/graph\_transformers/llm.py#L72
[10] Geraldus Wilsen: https://www.linkedin.com/in/geraldus-wilsen/
[11] 此处: https://github.com/langchain-ai/langchain-experimental/blob/main/libs/experimental/langchain\_experimental/graph\_transformers/llm.py#L206
[12] 玛丽·居里的维基百科页面: https://en.wikipedia.org/wiki/Marie\_Curie
[13] 利用结构化和非结构化搜索方法的检索器: https://medium.com/neo4j/enhancing-the-accuracy-of-rag-applications-with-knowledge-graphs-ad5e2ffab663
[14] GitHub: https://github.com/tomasonjo/blogs/blob/master/llm/llm\_graph\_transformer\_in\_depth.ipynb

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论