Skip to main content
Open In Colab在 GitHub 上打开

Kùzu 是一个可嵌入、可扩展、速度极快的图形数据库。 它采用 MIT 许可证进行许可,您可以在此处查看其源代码。

Kùzu 的主要特点:

  • 性能和可扩展性:为图形实施现代、最先进的连接算法。
  • 可用性: 非常易于设置和开始使用,因为没有服务器(嵌入式架构)。
  • 互作性:可以方便地扫描和复制来自外部列格式、CSV、JSON 和关系数据库的数据。
  • 结构化属性图模型:实现属性图模型,并添加了结构。
  • Cypher 支持:允许使用 Cypher(一种声明性查询语言)方便地查询图形。

通过访问他们的文档开始使用 Kùzu。

建立

Kùzu 是一个嵌入式数据库(它在进程内运行),因此无需管理服务器。安装 以下依赖项以开始使用:

pip install -U langchain-kuzu langchain-openai langchain-experimental

这将安装 Kùzu 及其 LangChain 集成,以及 OpenAI Python 包 这样我们就可以使用 OpenAI 的 LLM。如果您想使用其他 LLM 提供程序,您可以安装他们的 LangChain 附带的相应 Python 包。

以下是您首先在本地计算机上创建 Kùzu 数据库并连接到它的方法:

import kuzu

db = kuzu.Database("test_db")
conn = kuzu.Connection(db)

创造KuzuGraph

Kùzu 与 LangChain 的集成使得从非结构化文本创建和更新图形变得非常方便,还可以通过利用 LangChain 的 LLM 链的强大功能。首先,我们创建一个KuzuGraphObject 结合使用我们上面创建的 Database 对象和KuzuGraph构造 函数。

from langchain_kuzu.graphs.kuzu_graph import KuzuGraph

graph = KuzuGraph(db, allow_dangerous_requests=True)

假设我们想将以下文本转换为图形:

text = "Tim Cook is the CEO of Apple. Apple has its headquarters in California."

我们将利用LLMGraphTransformer以使用 LLM 从文本中提取节点和关系。 为了使图形更有用,我们将定义以下架构,以便 LLM 仅 提取与架构匹配的节点和关系。

# Define schema
allowed_nodes = ["Person", "Company", "Location"]
allowed_relationships = [
("Person", "IS_CEO_OF", "Company"),
("Company", "HAS_HEADQUARTERS_IN", "Location"),
]

LLMGraphTransformer类提供了一种将文本转换为图形文档列表的便捷方法。

from langchain_core.documents import Document
from langchain_experimental.graph_transformers import LLMGraphTransformer
from langchain_openai import ChatOpenAI

# Define the LLMGraphTransformer
llm_transformer = LLMGraphTransformer(
llm=ChatOpenAI(model="gpt-4o-mini", temperature=0, api_key=OPENAI_API_KEY), # noqa: F821
allowed_nodes=allowed_nodes,
allowed_relationships=allowed_relationships,
)

documents = [Document(page_content=text)]
graph_documents = llm_transformer.convert_to_graph_documents(documents)
graph_documents[:2]
[GraphDocument(nodes=[Node(id='Tim Cook', type='Person', properties={}), Node(id='Apple', type='Company', properties={}), Node(id='California', type='Location', properties={})], relationships=[Relationship(source=Node(id='Tim Cook', type='Person', properties={}), target=Node(id='Apple', type='Company', properties={}), type='IS_CEO_OF', properties={}), Relationship(source=Node(id='Apple', type='Company', properties={}), target=Node(id='California', type='Location', properties={}), type='HAS_HEADQUARTERS_IN', properties={})], source=Document(metadata={}, page_content='Tim Cook is the CEO of Apple. Apple has its headquarters in California.'))]

然后,我们可以调用上面定义的KuzuGraph对象的add_graph_documents方法将图形文档摄取到 Kùzu 数据库中。 这include_source参数设置为True这样,我们还在每个实体节点和它来自的源文档之间创建关系。

# Add the graph document to the graph
graph.add_graph_documents(
graph_documents,
include_source=True,
)

创建KuzuQAChain

要通过 Text2Cypher 管道查询图形,我们可以定义一个KuzuQAChain对象。然后,我们可以通过连接到存储在test_db目录。

from langchain_kuzu.chains.graph_qa.kuzu import KuzuQAChain

# Create the KuzuQAChain with verbosity enabled to see the generated Cypher queries
chain = KuzuQAChain.from_llm(
llm=ChatOpenAI(model="gpt-4o-mini", temperature=0.3, api_key=OPENAI_API_KEY), # noqa: F821
graph=graph,
verbose=True,
allow_dangerous_requests=True,
)

请注意,我们设置了一个略高于零的温度,以避免 LLM 的响应过于简洁。

让我们使用 QA 链提出一些问题。

chain.invoke("Who is the CEO of Apple?")


> Entering new KuzuQAChain chain...
Generated Cypher:
MATCH (p:Person)-[:IS_CEO_OF]->(c:Company {id: 'Apple'}) RETURN p
Full Context:
[{'p': {'_id': {'offset': 0, 'table': 1}, '_label': 'Person', 'id': 'Tim Cook', 'type': 'entity'}}]

> Finished chain.
{'query': 'Who is the CEO of Apple?',
'result': 'Tim Cook is the CEO of Apple.'}
chain.invoke("Where is Apple headquartered?")


> Entering new KuzuQAChain chain...
Generated Cypher:
MATCH (c:Company {id: 'Apple'})-[:HAS_HEADQUARTERS_IN]->(l:Location) RETURN l
Full Context:
[{'l': {'_id': {'offset': 0, 'table': 2}, '_label': 'Location', 'id': 'California', 'type': 'entity'}}]

> Finished chain.
{'query': 'Where is Apple headquartered?',
'result': 'Apple is headquartered in California.'}

刷新图形架构

如果您更改或更新图形,则可以检查 Text2Cypher 链用于生成 Cypher 语句的刷新架构信息。 您无需手动调用refresh_schema()每次调用它时都会自动调用它。

graph.refresh_schema()

print(graph.get_schema)
Node properties: [{'properties': [('id', 'STRING'), ('type', 'STRING')], 'label': 'Person'}, {'properties': [('id', 'STRING'), ('type', 'STRING')], 'label': 'Location'}, {'properties': [('id', 'STRING'), ('text', 'STRING'), ('type', 'STRING')], 'label': 'Chunk'}, {'properties': [('id', 'STRING'), ('type', 'STRING')], 'label': 'Company'}]
Relationships properties: [{'properties': [], 'label': 'HAS_HEADQUARTERS_IN'}, {'properties': [('label', 'STRING'), ('triplet_source_id', 'STRING')], 'label': 'MENTIONS_Chunk_Person'}, {'properties': [('label', 'STRING'), ('triplet_source_id', 'STRING')], 'label': 'MENTIONS_Chunk_Location'}, {'properties': [], 'label': 'IS_CEO_OF'}, {'properties': [('label', 'STRING'), ('triplet_source_id', 'STRING')], 'label': 'MENTIONS_Chunk_Company'}]
Relationships: ['(:Company)-[:HAS_HEADQUARTERS_IN]->(:Location)', '(:Chunk)-[:MENTIONS_Chunk_Person]->(:Person)', '(:Chunk)-[:MENTIONS_Chunk_Location]->(:Location)', '(:Person)-[:IS_CEO_OF]->(:Company)', '(:Chunk)-[:MENTIONS_Chunk_Company]->(:Company)']

使用单独的 LLM 生成密码和答案

您可以指定cypher_llmqa_llm分别使用不同的 LLM 来生成密码和生成答案。

chain = KuzuQAChain.from_llm(
cypher_llm=ChatOpenAI(temperature=0, model="gpt-4o-mini"),
qa_llm=ChatOpenAI(temperature=0, model="gpt-4"),
graph=graph,
verbose=True,
allow_dangerous_requests=True,
)
chain.invoke("Who is the CEO of Apple?")


> Entering new KuzuQAChain chain...
Generated Cypher:
MATCH (p:Person)-[:IS_CEO_OF]->(c:Company {id: 'Apple'}) RETURN p.id, p.type
Full Context:
[{'p.id': 'Tim Cook', 'p.type': 'entity'}]

> Finished chain.
{'query': 'Who is the CEO of Apple?',
'result': 'Tim Cook is the CEO of Apple.'}