用户指南:RAG¶
本指南提供了使用 Neo4j GraphRAG 包并根据特定需求对其进行配置的起点。
快速入门¶
要使用 neo4j-graphrag 包执行 GraphRAG 查询,需要以下几个组件。
Neo4j 驱动程序:用于查询您的 Neo4j 数据库。
检索器:neo4j-graphrag 包提供了一些实现(请参阅专用部分),如果您提供的实现不满足您的需求,您可以编写自己的检索器(请参阅如何编写自定义检索器)。
LLM:要生成答案,我们需要调用一个 LLM 模型。neo4j-graphrag 包的 LLM 接口与 LangChain 兼容。开发人员也可以根据需要编写自己的接口。
实际上,只需几行代码就可以完成。
from neo4j import GraphDatabase
from neo4j_graphrag.retrievers import VectorRetriever
from neo4j_graphrag.llm import OpenAILLM
from neo4j_graphrag.generation import GraphRAG
from neo4j_graphrag.embeddings import OpenAIEmbeddings
# 1. Neo4j driver
URI = "neo4j://localhost:7687"
AUTH = ("neo4j", "password")
INDEX_NAME = "index-name"
# Connect to Neo4j database
driver = GraphDatabase.driver(URI, auth=AUTH)
# 2. Retriever
# Create Embedder object, needed to convert the user question (text) to a vector
embedder = OpenAIEmbeddings(model="text-embedding-3-large")
# Initialize the retriever
retriever = VectorRetriever(driver, INDEX_NAME, embedder)
# 3. LLM
# Note: the OPENAI_API_KEY must be in the env vars
llm = OpenAILLM(model_name="gpt-4o", model_params={"temperature": 0})
# Initialize the RAG pipeline
rag = GraphRAG(retriever=retriever, llm=llm)
# Query the graph
query_text = "How do I do similarity search in Neo4j?"
response = rag.search(query_text=query_text, retriever_config={"top_k": 5})
print(response.answer)
注意
要运行此代码,需要安装 openai Python 包:pip install openai
以下部分将详细介绍如何自定义此代码。
GraphRAG 配置¶
每个组件都可以单独配置:LLM 和提示。
使用其他 LLM 模型¶
如果无法直接使用 OpenAI,则有一些可用的替代方案。
使用 Azure OpenAI(GPT…)。
使用 Google VertexAI(Gemini…)。
使用 Anthropic LLM(Claude…)。
使用 Mistral LLM
使用 Cohere。
使用本地 Ollama 模型。
实现自定义接口。
利用任何 LangChain 聊天模型。
所有选项将在下面说明。
使用 Azure Open AI LLM¶
可以切换到 AzureOpenAILLM 类来使用 Azure OpenAI。
from neo4j_graphrag.llm import AzureOpenAILLM
llm = AzureOpenAILLM(
model_name="gpt-4o",
azure_endpoint="https://example-endpoint.openai.azure.com/", # update with your endpoint
api_version="2024-06-01", # update appropriate version
api_key="...", # api_key is optional and can also be set with OPENAI_API_KEY env var
)
llm.invoke("say something")
请查看 OpenAI Python 客户端文档以了解有关配置的更多信息。
注意
要运行此代码,需要安装 openai Python 包:pip install openai
请参阅AzureOpenAILLM。
使用 VertexAI LLM¶
要使用 VertexAI,请实例化 VertexAILLM 类。
from neo4j_graphrag.llm import VertexAILLM
from vertexai.generative_models import GenerationConfig
generation_config = GenerationConfig(temperature=0.0)
llm = VertexAILLM(
model_name="gemini-1.5-flash-001", generation_config=generation_config
)
llm.invoke("say something")
注意
要运行此代码,需要安装 google-cloud-aiplatform Python 包:pip install google-cloud-aiplatform
请参阅VertexAILLM。
使用 Anthropic LLM¶
要使用 Anthropic,请实例化 AnthropicLLM 类。
from neo4j_graphrag.llm import AnthropicLLM
llm = AnthropicLLM(
model_name="claude-3-opus-20240229",
model_params={"max_tokens": 1000}, # max_tokens must be specified
api_key=api_key, # can also set `ANTHROPIC_API_KEY` in env vars
)
llm.invoke("say something")
注意
要运行此代码,需要安装 anthropic Python 包:pip install anthropic
请参阅AnthropicLLM。
使用 MistralAI LLM¶
要使用 MistralAI,请实例化 MistralAILLM 类。
from neo4j_graphrag.llm import MistralAILLM
llm = MistralAILLM(
model_name="mistral-small-latest",
api_key=api_key, # can also set `MISTRAL_API_KEY` in env vars
)
llm.invoke("say something")
注意
要运行此代码,需要安装 mistralai Python 包:pip install mistralai
请参阅MistralAILLM。
使用 Cohere LLM¶
要使用 Cohere,请实例化 CohereLLM 类。
from neo4j_graphrag.llm import CohereLLM
llm = CohereLLM(
model_name="command-r",
api_key=api_key, # can also set `CO_API_KEY` in env vars
)
llm.invoke("say something")
注意
要运行此代码,需要安装 cohere Python 包:pip install cohere
请参阅CohereLLM。
通过 Ollama 使用本地模型¶
与官方 OpenAI Python 客户端类似,OpenAILLM 可与 Ollama 一起使用。假设 Ollama 运行在默认地址 127.0.0.1:11434 上,可以使用以下方法对其进行查询。
from neo4j_graphrag.llm import OpenAILLM
llm = OpenAILLM(api_key="ollama", base_url="http://127.0.0.1:11434/v1", model_name="orca-mini")
llm.invoke("say something")
使用 LangChain 中的模型¶
LangChain Python 包包含各种 LLM 和提供程序的实现。它的接口与我们的 GraphRAG 接口兼容,便于集成。
from neo4j_graphrag.generation import GraphRAG
from langchain_community.chat_models import ChatOllama
# retriever = ...
llm = ChatOllama(model="llama3:8b")
rag = GraphRAG(retriever=retriever, llm=llm)
query_text = "How do I do similarity search in Neo4j?"
response = rag.search(query_text=query_text, retriever_config={"top_k": 5})
print(response.answer)
但是,使用 LangChain 并非强制性。
使用自定义模型¶
如果提供的实现不满足他们的需求,开发人员可以通过子类化 LLMInterface 来创建自定义 LLM 类。以下是以 Python Ollama 客户端为例。
import ollama
from neo4j_graphrag.llm import LLMInterface, LLMResponse
class OllamaLLM(LLMInterface):
def invoke(self, input: str) -> LLMResponse:
response = ollama.chat(model=self.model_name, messages=[
{
'role': 'user',
'content': input,
},
])
return LLMResponse(
content=response["message"]["content"]
)
async def ainvoke(self, input: str) -> LLMResponse:
return self.invoke(input) # TODO: implement async with ollama.AsyncClient
# retriever = ...
llm = OllamaLLM("llama3:8b")
rag = GraphRAG(retriever=retriever, llm=llm)
query_text = "How do I do similarity search in Neo4j?"
response = rag.search(query_text=query_text, retriever_config={"top_k": 5})
print(response.answer)
请参阅LLMInterface。
配置提示¶
提示通过 PromptTemplate 类进行管理。具体来说,GraphRAG 管道使用 RagTemplate,它具有默认提示,可以通过 rag.prompt_template.template 访问。要使用其他提示,请子类化 RagTemplate 类,并在初始化期间将其传递给 GraphRAG 管道对象。
from neo4j_graphrag.generation import RagTemplate, GraphRAG
# retriever = ...
# llm = ...
prompt_template = RagTemplate(
prompt="Answer the question {question} using context {context} and examples {examples}",
expected_inputs=["context", "question", "examples"]
)
rag = GraphRAG(retriever=retriever, llm=llm, prompt_template=prompt_template)
# ...
请参阅PromptTemplate。
GraphRAG 管道中的最后一个可配置组件是检索器。以下是各种可用选项的说明。
检索器配置¶
我们提供了以下检索器的实现。
检索器 |
描述 |
---|---|
根据 Neo4j 向量索引和查询文本或向量执行相似性搜索。返回匹配的 node 和相似性 score。 |
|
根据 Neo4j 向量索引和查询文本或向量执行相似性搜索。返回的结果可以通过检索查询参数进行配置,该参数将在索引搜索后执行。它可用于获取匹配节点周围的更多上下文。 |
|
同时使用 Neo4j 中的向量索引和全文索引。 |
|
与 HybridRetriever 相同,具有与 VectorCypherRetriever 相似的检索查询。 |
|
将用户问题转换为 Cypher 查询,以针对 Neo4j 数据库(或知识图谱)运行。然后将查询结果传递给 LLM 以生成最终答案。 |
|
当向量保存在 Weaviate 向量数据库中时,请使用此检索器。 |
|
当向量保存在 Pinecone 向量数据库中时,请使用此检索器。 |
|
当向量保存在 Qdrant 向量数据库中时,请使用此检索器。 |
所有检索器都公开了一个 search 方法,我们将在下一节中讨论。
向量检索器¶
实例化向量检索器的最简单方法是
from neo4j_graphrag.retrievers import VectorRetriever
retriever = VectorRetriever(
driver,
index_name=POSTER_INDEX_NAME,
)
index_name 是用于相似性搜索的 Neo4j 向量索引的名称。
警告
向量索引使用近似最近邻算法。请参阅Neo4j 文档以了解其局限性。
搜索相似向量¶
要识别最相似的 3 个节点,请通过向量进行搜索。
vector = [] # a list of floats, same size as the vectors in the Neo4j vector index
retriever_result = retriever.search(query_vector=vector, top_k=3)
但是,在大多数情况下,将提供文本(来自用户)而不是向量。在这种情况下,需要 Embedder。
搜索相似文本¶
在搜索文本时,需要指定检索器如何将文本转换为向量(嵌入)。因此,检索器需要了解嵌入器。
embedder = OpenAIEmbeddings(model="text-embedding-3-large")
# Initialize the retriever
retriever = VectorRetriever(
driver,
index_name=POSTER_INDEX_NAME,
embedder=embedder,
)
query_text = "How do I do similarity search in Neo4j?"
retriever_result = retriever.search(query_text=query_text, top_k=3)
嵌入器¶
目前,此包支持以下嵌入器。
之前已经说明了 OpenAIEmbeddings。以下是如何使用 SentenceTransformerEmbeddings。
from neo4j_graphrag.embeddings import SentenceTransformerEmbeddings
embedder = SentenceTransformerEmbeddings(model="all-MiniLM-L6-v2") # Note: this is the default model
如果需要其他嵌入器,则可以创建自定义嵌入器。例如,考虑以下包装来自 LlamaIndex 的 OllamaEmbedding 模型的嵌入器实现。
from llama_index.embeddings.ollama import OllamaEmbedding
from neo4j_graphrag.embeddings.base import Embedder
class OllamaEmbedder(Embedder):
def __init__(self, ollama_embedding):
self.embedder = ollama_embedding
def embed_query(self, text: str) -> list[float]:
embedding = self.embedder.get_text_embedding_batch(
[text], show_progress=True
)
return embedding[0]
ollama_embedding = OllamaEmbedding(
model_name="llama3",
base_url="http://localhost:11434",
ollama_additional_kwargs={"mirostat": 0},
)
embedder = OllamaEmbedder(ollama_embedding)
vector = embedder.embed_query("some text")
其他向量检索器配置¶
通常,并非所有节点属性都与 RAG 上下文相关;只有少数属性与包含在 LLM 提示上下文中相关。您可以使用 return_properties 参数指定要返回的属性。
from neo4j_graphrag.retrievers import VectorRetriever
retriever = VectorRetriever(
driver,
index_name=POSTER_INDEX_NAME,
embedder=embedder,
return_properties=["title"],
)
预过滤器¶
执行相似性搜索时,可能需要应用约束。例如,筛选掉 2000 年之前上映的电影。这可以通过 filters 来实现。
注意
除了混合检索器之外,所有检索器都实现了过滤器。以下文档不适用于外部检索器,它们使用自己的过滤器语法(请参阅向量数据库)。
from neo4j_graphrag.retrievers import VectorRetriever
retriever = VectorRetriever(
driver,
index_name=POSTER_INDEX_NAME,
)
filters = {
"year": {
"$gte": 2000,
}
}
query_text = "How do I do similarity search in Neo4j?"
retriever_result = retriever.search(query_text=query_text, filters=filters)
警告
使用过滤器时,相似性搜索会绕过向量索引,而是使用精确匹配算法。确保预过滤足够严格,以防止查询过载。
当前支持的操作符是
$eq: 等于。
$ne: 不等于。
$lt: 小于。
$lte: 小于或等于。
$gt: 大于。
$gte: 大于或等于。
$between: 之间。
$in: 值在给定列表中。
$nin: 不在。
$like: LIKE 运算符区分大小写。
$ilike: LIKE 运算符不区分大小写。
以下是一些有效的过滤器语法及其含义的示例
过滤器 |
含义 |
---|---|
{“year”: 1999} |
year = 1999 |
{“year”: {“$eq”: 1999}} |
year = 1999 |
{“year”: 2000, “title”: “The Matrix”} |
year = 1999 并且 title = “The Matrix” |
{“$and”: [{“year”: 2000}, {“title”: “The Matrix”}]} |
year = 1999 并且 title = “The Matrix” |
{“$or”: [{“title”: “The Matrix Revolution”}, {“title”: “The Matrix”}]} |
title = “The Matrix” 或 title = “The Matrix Revolution” |
{“title”: {“$like”: “The Matrix”}} |
title 包含 “The Matrix” |
{“title”: {“$ilike”: “the matrix”}} |
toLower(title) 包含 “The Matrix” |
另请参见 VectorRetriever.
向量密码检索器¶
VectorCypherRetriever 通过结合基于向量的相似性搜索和图遍历技术,充分利用了 Neo4j 的图能力。它处理查询嵌入以对指定的向量索引执行相似性搜索,检索相关的节点变量,然后执行 Cypher 查询以根据这些节点遍历图。这种集成确保了检索在语义上有意义,并且通过底层图结构在上下文中得到丰富。
检索查询¶
在编写检索查询时,请注意查询范围内有两个可用的变量
node: 代表从向量索引搜索中检索到的节点。
score: 表示相似度得分。
例如,在一个具有演员的电影图中,其中向量索引与某些电影属性相关联,检索查询可以按如下方式构建
retrieval_query = """
MATCH
(actor:Actor)-[:ACTED_IN]->(node)
RETURN
node.title AS movie_title,
node.plot AS movie_plot,
collect(actor.name) AS actors;
"""
retriever = VectorCypherRetriever(
driver,
index_name=INDEX_NAME,
retrieval_query=retrieval_query,
)
建议检索查询返回节点属性,而不是节点。
格式化结果¶
警告
此 API 处于测试模式,将来可能会发生变化。
result_formatter 函数自定义了 Cypher 检索器的输出,以提高提示工程和可读性。它将每个 Neo4j 记录转换为包含两个字段的 RetrieverResultItem:content 和 metadata.
content 字段是一个格式化的字符串,包含旨在用于语言模型的关键信息,例如电影标题或描述。 metadata 字段包含其他详细信息,这些信息对于调试或提供额外的上下文很有用,例如分数或节点属性。
def result_formatter(record: neo4j.Record) -> RetrieverResultItem:
return RetrieverResultItem(
content=f"Movie title: {record.get('movieTitle')}, description: {record.get('movieDescription')}, actors: {record.get('actors')}",
metadata={
"title": record.get('movieTitle'),
"score": record.get("score"),
}
)
retriever = VectorCypherRetriever(
driver,
index_name=INDEX_NAME,
retrieval_query="MATCH (node)<-[:ACTED_IN]-(p:Person) RETURN node.title as movieTitle, node.plot as movieDescription, collect(p.name) as actors, score",
result_formatter=result_formatter,
)
另请参见 VectorCypherRetriever.
向量数据库¶
注意
对于外部检索器,过滤器语法取决于提供程序。有关详细信息,请参阅每个提供程序的 Python 客户端的文档。
Weaviate 检索器¶
注意
要导入此检索器,必须安装 Weaviate Python 客户端:pip install weaviate-client
from weaviate.connect.helpers import connect_to_local
from neo4j_graphrag.retrievers import WeaviateNeo4jRetriever
client = connect_to_local()
retriever = WeaviateNeo4jRetriever(
driver=driver,
client=client,
embedder=embedder,
collection="Movies",
id_property_external="neo4j_id",
id_property_neo4j="id",
)
在内部,此检索器在 Weaviate 中执行向量搜索,通过将 Weaviate 元数据 id_property_external 与 Neo4j node.id_property_neo4j 匹配来查找相应的节点,并返回匹配的节点。
return_properties 和 retrieval_query 参数的作用类似于其他检索器中的参数。
Pinecone 检索器¶
注意
要导入此检索器,必须安装 Pinecone Python 客户端:pip install pinecone-client
from pinecone import Pinecone
from neo4j_graphrag.retrievers import PineconeNeo4jRetriever
client = Pinecone() # ... create your Pinecone client
retriever = PineconeNeo4jRetriever(
driver=driver,
client=client,
index_name="Movies",
id_property_neo4j="id",
embedder=embedder,
)
另请参见 PineconeNeo4jRetriever.
Qdrant 检索器¶
注意
要导入此检索器,必须安装 Qdrant Python 客户端:pip install qdrant-client
from qdrant_client import QdrantClient
from neo4j_graphrag.retrievers import QdrantNeo4jRetriever
client = QdrantClient(...) # construct the Qdrant client instance
retriever = QdrantNeo4jRetriever(
driver=driver,
client=client,
collection_name="my-collection",
id_property_external="neo4j_id", # The payload field that contains identifier to a corresponding Neo4j node id property
id_property_neo4j="id",
embedder=embedder,
)
其他检索器¶
混合检索器¶
在混合检索器中,将在向量索引和全文索引中搜索结果。为此,数据库中也必须存在全文索引,并且在实例化检索器时必须提供其名称
from neo4j_graphrag.retrievers import HybridRetriever
INDEX_NAME = "embedding-name"
FULLTEXT_INDEX_NAME = "fulltext-index-name"
retriever = HybridRetriever(
driver,
INDEX_NAME,
FULLTEXT_INDEX_NAME,
embedder,
)
参见 HybridRetriever.
另请注意,有一个帮助函数可以创建全文索引(参见 API 文档)。
混合密码检索器¶
在混合密码检索器中,将在向量索引和全文索引中搜索结果。一旦识别出类似节点,检索查询就可以遍历图并返回更多上下文
from neo4j_graphrag.retrievers import HybridCypherRetriever
INDEX_NAME = "embedding-name"
FULLTEXT_INDEX_NAME = "fulltext-index-name"
retriever = HybridCypherRetriever(
driver,
INDEX_NAME,
FULLTEXT_INDEX_NAME,
retrieval_query="MATCH (node)-[:AUTHORED_BY]->(author:Author)" "RETURN author.name"
embedder=embedder,
)
Text2Cypher 检索器¶
此检索器首先要求 LLM 生成一个 Cypher 查询,以从数据库中获取回答问题所需的准确信息。然后执行此查询,并将生成的结果记录添加到上下文中,供 LLM 编写对初始用户问题的答案。Cypher 生成和答案生成 LLM 可以不同。
from neo4j import GraphDatabase
from neo4j_graphrag.retrievers import Text2CypherRetriever
from neo4j_graphrag.llm.openai import OpenAILLM
URI = "neo4j://localhost:7687"
AUTH = ("neo4j", "password")
# Connect to Neo4j database
driver = GraphDatabase.driver(URI, auth=AUTH)
# Create LLM object
llm = OpenAILLM(model_name="gpt-3.5-turbo")
# (Optional) Specify your own Neo4j schema
neo4j_schema = """
Node properties:
Person {name: STRING, born: INTEGER}
Movie {tagline: STRING, title: STRING, released: INTEGER}
Relationship properties:
ACTED_IN {roles: LIST}
REVIEWED {summary: STRING, rating: INTEGER}
The relationships:
(:Person)-[:ACTED_IN]->(:Movie)
(:Person)-[:DIRECTED]->(:Movie)
(:Person)-[:PRODUCED]->(:Movie)
(:Person)-[:WROTE]->(:Movie)
(:Person)-[:FOLLOWS]->(:Person)
(:Person)-[:REVIEWED]->(:Movie)
"""
# (Optional) Provide user input/query pairs for the LLM to use as examples
examples = [
"USER INPUT: 'Which actors starred in the Matrix?' QUERY: MATCH (p:Person)-[:ACTED_IN]->(m:Movie) WHERE m.title = 'The Matrix' RETURN p.name"
]
# Initialize the retriever
retriever = Text2CypherRetriever(
driver=driver,
llm=llm, # type: ignore
neo4j_schema=neo4j_schema,
examples=examples,
)
# Generate a Cypher query using the LLM, send it to the Neo4j database, and return the results
query_text = "Which movies did Hugo Weaving star in?"
print(retriever.search(query_text=query_text))
注意
由于我们没有执行任何相似性搜索(向量索引),因此 Text2Cypher 检索器不需要任何嵌入器。
警告
LLM 生成的查询不能保证语法正确。如果无法执行,则会引发 Text2CypherRetrievalError。
自定义检索器¶
如果应用程序需要非常具体的检索策略,则可以使用 Retriever 接口实现自定义检索器
from neo4j_graphrag.retrievers.base import Retriever
class MyCustomRetriever(Retriever):
def __init__(
self,
driver: neo4j.Driver,
# any other required parameters
) -> None:
super().__init__(driver)
def get_search_results(
self,
query_vector: Optional[list[float]] = None,
query_text: Optional[str] = None,
top_k: int = 5,
filters: Optional[dict[str, Any]] = None,
) -> RawSearchResult:
pass
参见 RawSearchResult 以了解返回类型的描述。
数据库操作¶
参见 数据库交互.
创建向量索引¶
from neo4j import GraphDatabase
from neo4j_graphrag.indexes import create_vector_index
URI = "neo4j://localhost:7687"
AUTH = ("neo4j", "password")
INDEX_NAME = "chunk-index"
DIMENSION=1536
# Connect to Neo4j database
driver = GraphDatabase.driver(URI, auth=AUTH)
# Creating the index
create_vector_index(
driver,
INDEX_NAME,
label="Document",
embedding_property="vectorProperty",
dimensions=DIMENSION,
similarity_fn="euclidean",
)
填充向量索引¶
from neo4j import GraphDatabase
from random import random
URI = "neo4j://localhost:7687"
AUTH = ("neo4j", "password")
# Connect to Neo4j database
driver = GraphDatabase.driver(URI, auth=AUTH)
# Upsert the vector
vector = [random() for _ in range(DIMENSION)]
upsert_vector(driver, node_id="1234", embedding_property="embedding", vector=vector)
这将更新节点 id(node)=1234 以添加(或更新)node.embedding 属性。此属性也将添加到向量索引中。
删除向量索引¶
警告
此操作不可逆,应谨慎使用。
from neo4j import GraphDatabase
URI = "neo4j://localhost:7687"
AUTH = ("neo4j", "password")
# Connect to Neo4j database
driver = GraphDatabase.driver(URI, auth=AUTH)
drop_index_if_exists(driver, INDEX_NAME)