Memgraph
Memgraph 是开源图数据库,兼容
Neo4j
。 该数据库使用Cypher
图查询语言,Cypher 是一种声明式图查询语言,允许在属性图中进行富有表现力和高效的数据查询。
本笔记本展示了如何使用 LLMs 为 Memgraph 数据库提供自然语言接口。
设置
要完成本教程,您需要安装 Docker 和 Python 3.x。
确保您有一个正在运行的 Memgraph 实例。要快速首次运行 Memgraph 平台(Memgraph 数据库 + MAGE 库 + Memgraph Lab),请执行以下操作:
在 Linux/MacOS 上:
curl https://install.memgraph.com | sh
在 Windows 上:
iwr https://windows.memgraph.com | iex
这两个命令运行一个脚本,将 Docker Compose 文件下载到您的系统,并在两个独立的容器中构建和启动 memgraph-mage
和 memgraph-lab
Docker 服务。
有关安装过程的更多信息,请参阅 Memgraph 文档。
现在,您可以开始使用 Memgraph
了!
首先安装并导入所有必要的包。我们将使用名为 pip 的包管理器,并使用 --user
标志以确保正确的权限。如果您安装了 Python 3.4 或更高版本,pip 默认包含在内。您可以使用以下命令安装所有所需的包:
pip install langchain langchain-openai neo4j gqlalchemy --user
您可以在此笔记本中运行提供的代码块,或使用单独的 Python 文件来实验 Memgraph 和 LangChain。
import os
from gqlalchemy import Memgraph
from langchain.chains import GraphCypherQAChain
from langchain_community.graphs import MemgraphGraph
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
我们利用 Python 库 GQLAlchemy 在我们的 Memgraph 数据库和 Python 脚本之间建立连接。您还可以使用 Neo4j 驱动程序与运行中的 Memgraph 实例建立连接,因为它与 Memgraph 兼容。要使用 GQLAlchemy 执行查询,我们可以如下设置 Memgraph 实例:
memgraph = Memgraph(host="127.0.0.1", port=7687)
填充数据库
您可以使用 Cypher 查询语言轻松填充新的空数据库。如果您还不完全理解每一行,也不用担心,您可以从文档 这里 学习 Cypher。运行以下脚本将在数据库上执行种子查询,为我们提供有关视频游戏的数据,包括发布者、可用平台和类型等详细信息。这些数据将作为我们工作的基础。
# Creating and executing the seeding query
query = """
MERGE (g:Game {name: "Baldur's Gate 3"})
WITH g, ["PlayStation 5", "Mac OS", "Windows", "Xbox Series X/S"] AS platforms,
["Adventure", "Role-Playing Game", "Strategy"] AS genres
FOREACH (platform IN platforms |
MERGE (p:Platform {name: platform})
MERGE (g)-[:AVAILABLE_ON]->(p)
)
FOREACH (genre IN genres |
MERGE (gn:Genre {name: genre})
MERGE (g)-[:HAS_GENRE]->(gn)
)
MERGE (p:Publisher {name: "Larian Studios"})
MERGE (g)-[:PUBLISHED_BY]->(p);
"""
memgraph.execute(query)
刷新图谱架构
您已准备好使用以下脚本实例化 Memgraph-LangChain 图谱。此接口将允许我们使用 LangChain 查询我们的数据库,自动创建生成 Cypher 查询所需的图谱架构,通过 LLM。
graph = MemgraphGraph(url="bolt://localhost:7687", username="", password="")
如有必要,您可以手动刷新图谱架构,如下所示。
graph.refresh_schema()
为了熟悉数据并验证更新后的图谱架构,您可以使用以下语句打印它。
print(graph.schema)
Node properties are the following:
Node name: 'Game', Node properties: [{'property': 'name', 'type': 'str'}]
Node name: 'Platform', Node properties: [{'property': 'name', 'type': 'str'}]
Node name: 'Genre', Node properties: [{'property': 'name', 'type': 'str'}]
Node name: 'Publisher', Node properties: [{'property': 'name', 'type': 'str'}]
Relationship properties are the following:
The relationships are the following:
['(:Game)-[:AVAILABLE_ON]->(:Platform)']
['(:Game)-[:HAS_GENRE]->(:Genre)']
['(:Game)-[:PUBLISHED_BY]->(:Publisher)']
查询数据库
要与 OpenAI API 交互,您必须使用 Python os 包将您的 API 密钥配置为环境变量。这确保了您请求的正确授权。您可以在 这里 找到有关获取 API 密钥的更多信息。
os.environ["OPENAI_API_KEY"] = "your-key-here"
您应该使用以下脚本创建图形链,该脚本将在基于您的图形数据的问题回答过程中使用。虽然它默认使用 GPT-3.5-turbo,但您也可以考虑尝试其他模型,例如 GPT-4,以显著改善 Cypher 查询和结果。我们将利用 OpenAI 聊天,使用您之前配置的密钥。我们将温度设置为零,以确保答案的可预测性和一致性。此外,我们将使用我们的 Memgraph-LangChain 图形,并将 verbose 参数(默认为 False)设置为 True,以接收有关查询生成的更详细消息。
chain = GraphCypherQAChain.from_llm(
ChatOpenAI(temperature=0), graph=graph, verbose=True, model_name="gpt-3.5-turbo"
)
现在您可以开始提问!
response = chain.run("Which platforms is Baldur's Gate 3 available on?")
print(response)
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (g:Game {name: 'Baldur\'s Gate 3'})-[:AVAILABLE_ON]->(p:Platform)
RETURN p.name
Full Context:
[{'p.name': 'PlayStation 5'}, {'p.name': 'Mac OS'}, {'p.name': 'Windows'}, {'p.name': 'Xbox Series X/S'}]
> Finished chain.
Baldur's Gate 3 is available on PlayStation 5, Mac OS, Windows, and Xbox Series X/S.
response = chain.run("Is Baldur's Gate 3 available on Windows?")
print(response)
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (:Game {name: 'Baldur\'s Gate 3'})-[:AVAILABLE_ON]->(:Platform {name: 'Windows'})
RETURN true
Full Context:
[{'true': True}]
> Finished chain.
Yes, Baldur's Gate 3 is available on Windows.
链修饰符
要修改链的行为并获得更多上下文或额外信息,您可以修改链的参数。
返回直接查询结果
return_direct
修饰符指定是否返回执行的 Cypher 查询的直接结果或处理过的自然语言响应。
# Return the result of querying the graph directly
chain = GraphCypherQAChain.from_llm(
ChatOpenAI(temperature=0), graph=graph, verbose=True, return_direct=True
)
response = chain.run("Which studio published Baldur's Gate 3?")
print(response)
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (:Game {name: 'Baldur\'s Gate 3'})-[:PUBLISHED_BY]->(p:Publisher)
RETURN p.name
> Finished chain.
[{'p.name': 'Larian Studios'}]
返回查询中间步骤
return_intermediate_steps
链修饰符通过在初始查询结果之外包含查询的中间步骤来增强返回的响应。
# Return all the intermediate steps of query execution
chain = GraphCypherQAChain.from_llm(
ChatOpenAI(temperature=0), graph=graph, verbose=True, return_intermediate_steps=True
)
response = chain("Is Baldur's Gate 3 an Adventure game?")
print(f"Intermediate steps: {response['intermediate_steps']}")
print(f"Final response: {response['result']}")
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (g:Game {name: 'Baldur\'s Gate 3'})-[:HAS_GENRE]->(genre:Genre {name: 'Adventure'})
RETURN g, genre
Full Context:
[{'g': {'name': "Baldur's Gate 3"}, 'genre': {'name': 'Adventure'}}]
> Finished chain.
Intermediate steps: [{'query': "MATCH (g:Game {name: 'Baldur\\'s Gate 3'})-[:HAS_GENRE]->(genre:Genre {name: 'Adventure'})\nRETURN g, genre"}, {'context': [{'g': {'name': "Baldur's Gate 3"}, 'genre': {'name': 'Adventure'}}]}]
Final response: Yes, Baldur's Gate 3 is an Adventure game.
限制查询结果的数量
top_k
修饰符可用于限制返回的查询结果的最大数量。
# Limit the maximum number of results returned by query
chain = GraphCypherQAChain.from_llm(
ChatOpenAI(temperature=0), graph=graph, verbose=True, top_k=2
)
response = chain.run("What genres are associated with Baldur's Gate 3?")
print(response)
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (:Game {name: 'Baldur\'s Gate 3'})-[:HAS_GENRE]->(g:Genre)
RETURN g.name
Full Context:
[{'g.name': 'Adventure'}, {'g.name': 'Role-Playing Game'}]
> Finished chain.
Baldur's Gate 3 is associated with the genres Adventure and Role-Playing Game.
高级查询
随着解决方案复杂性的增加,您可能会遇到需要仔细处理的不同用例。确保应用程序的可扩展性对于保持用户流畅体验至关重要。
让我们再次实例化我们的链,并尝试询问一些用户可能会问的问题。
chain = GraphCypherQAChain.from_llm(
ChatOpenAI(temperature=0), graph=graph, verbose=True, model_name="gpt-3.5-turbo"
)
response = chain.run("Is Baldur's Gate 3 available on PS5?")
print(response)
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (g:Game {name: 'Baldur\'s Gate 3'})-[:AVAILABLE_ON]->(p:Platform {name: 'PS5'})
RETURN g.name, p.name
Full Context:
[]
> Finished chain.
I'm sorry, but I don't have the information to answer your question.
生成的Cypher查询看起来很好,但我们没有收到任何信息作为响应。这说明了与LLM工作时常见的挑战——用户提出查询的方式与数据存储方式之间的不一致。在这种情况下,用户的认知与实际数据存储之间的差异可能会导致不匹配。提示优化,即精细化模型提示以更好地理解这些差异的过程,是解决此问题的有效方案。通过提示优化,模型在生成准确和相关查询方面的能力得到了提高,从而成功检索所需的数据。
提示优化
为了解决这个问题,我们可以调整QA链的初始Cypher提示。这涉及到为LLM添加指导,以便用户可以引用特定的平台,例如在我们的案例中是PS5。我们通过使用LangChain PromptTemplate 来实现这一点,创建一个修改过的初始提示。然后将这个修改后的提示作为参数提供给我们优化后的Memgraph-LangChain实例。
CYPHER_GENERATION_TEMPLATE = """
Task:Generate Cypher statement to query a graph database.
Instructions:
Use only the provided relationship types and properties in the schema.
Do not use any other relationship types or properties that are not provided.
Schema:
{schema}
Note: Do not include any explanations or apologies in your responses.
Do not respond to any questions that might ask anything else than for you to construct a Cypher statement.
Do not include any text except the generated Cypher statement.
If the user asks about PS5, Play Station 5 or PS 5, that is the platform called PlayStation 5.
The question is:
{question}
"""
CYPHER_GENERATION_PROMPT = PromptTemplate(
input_variables=["schema", "question"], template=CYPHER_GENERATION_TEMPLATE
)
chain = GraphCypherQAChain.from_llm(
ChatOpenAI(temperature=0),
cypher_prompt=CYPHER_GENERATION_PROMPT,
graph=graph,
verbose=True,
model_name="gpt-3.5-turbo",
)
response = chain.run("Is Baldur's Gate 3 available on PS5?")
print(response)
> Entering new GraphCypherQAChain chain...
Generated Cypher:
MATCH (g:Game {name: 'Baldur\'s Gate 3'})-[:AVAILABLE_ON]->(p:Platform {name: 'PlayStation 5'})
RETURN g.name, p.name
Full Context:
[{'g.name': "Baldur's Gate 3", 'p.name': 'PlayStation 5'}]
> Finished chain.
Yes, Baldur's Gate 3 is available on PlayStation 5.
现在,通过修订后的初始Cypher提示,包括关于平台命名的指导,我们获得了更准确和相关的结果,更加符合用户查询。
这种方法可以进一步改善您的QA链。您可以轻松地将额外的提示优化数据集成到您的链中,从而增强应用程序的整体用户体验。