用户指南:RAG

本指南为使用 Neo4j GraphRAG 包并根据特定要求进行配置提供了起点。

快速入门

要使用 neo4j-graphrag 包执行 GraphRAG 查询,需要一些组件:

  1. 一个 Neo4j 驱动程序:用于查询您的 Neo4j 数据库。

  2. 一个检索器:neo4j-graphrag 包提供了一些实现(请参阅专用部分),如果您提供的实现都不符合您的需求,您也可以编写自己的检索器(请参阅如何编写自定义检索器)。

  3. 一个 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)

警告

使用 OpenAILLM 需要 openai Python 客户端。您可以使用 pip install “neo4j_graphrag[openai]” 进行安装。

以下部分提供了有关如何自定义此代码的更多详细信息。

GraphRAG 配置

每个组件都可以单独配置:LLM 和提示词。

使用其他 LLM 模型

如果无法直接使用 OpenAI,有以下几种替代方案:

  • 使用 Azure OpenAI (GPT…)。

  • 使用 Google VertexAI (Gemini…)。

  • 使用 Anthropic LLM (Claude…)。

  • 使用 Mistral LLM

  • 使用 Cohere。

  • 使用本地 Ollama 模型。

  • 实现自定义接口。

  • 利用任何 LangChain 聊天模型。

所有选项均在下方说明。

使用 Azure OpenAI 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 “neo4j_graphrag[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 “neo4j_grpahrag[vertexai]”

另请参阅 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 “neo4j_graphrag[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 “neo4j_graphrag[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 “neo4j_graphrag[cohere]”

另请参阅 CohereLLM

通过 Ollama 使用本地模型

假设 Ollama 正在默认地址 127.0.0.1:11434 上运行,可以通过以下方式查询:

from neo4j_graphrag.llm import OllamaLLM
llm = OllamaLLM(
    model_name="orca-mini",
    # host="...",  # when using a remote server
)
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 管道中最后一个可配置组件是检索器。下面将介绍可用的各种选项。

检索器配置

我们为以下检索器提供了实现:

检索器列表

检索器

描述

VectorRetriever

根据 Neo4j 向量索引和查询文本或向量执行相似性搜索。返回匹配的 node 和相似性 score

VectorCypherRetriever

根据 Neo4j 向量索引和查询文本或向量执行相似性搜索。返回的结果可以通过一个在索引搜索后执行的检索查询参数进行配置。这可以用于获取匹配节点周围的更多上下文。

HybridRetriever

在 Neo4j 中同时使用向量索引和全文索引。

HybridCypherRetriever

与 HybridRetriever 相同,但具有类似于 VectorCypherRetriever 的检索查询。

Text2Cypher

将用户问题转换为 Cypher 查询,以便针对 Neo4j 数据库(或知识图谱)运行。查询结果随后传递给 LLM 以生成最终答案。

WeaviateNeo4jRetriever

当向量保存在 Weaviate 向量数据库中时使用此检索器

PineconeNeo4jRetriever

当向量保存在 Pinecone 向量数据库中时使用此检索器

QdrantNeo4jRetriever

当向量保存在 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

如果需要其他嵌入器,可以使用 Embedder 接口创建自定义嵌入器。

其他向量检索器配置

通常,并非所有节点属性都与 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 AND title = “The Matrix”

{“$and”: [{“year”: 2000}, {“title”: “The Matrix”}]}

year = 1999 AND title = “The Matrix”

{“$or”: [{“title”: “The Matrix Revolution”}, {“title”: “The Matrix”}]}

title = “The Matrix” OR title = “The Matrix Revolution”

{“title”: {“$like”: “The Matrix”}}

title CONTAINS “The Matrix”

{“title”: {“$ilike”: “the matrix”}}

toLower(title) CONTAINS “The Matrix”

另请参阅 VectorRetriever

向量 Cypher 检索器

VectorCypherRetriever 通过将基于向量的相似性搜索与图遍历技术相结合,充分利用了 Neo4j 的图能力。它处理查询嵌入以针对指定的向量索引执行相似性搜索,检索相关的节点变量,然后执行 Cypher 查询以基于这些节点遍历图。这种集成确保了检索既具有语义意义,又通过底层图结构得到了上下文丰富。

检索查询

在编写检索查询时,请务必注意查询范围中有两个可用变量:

  • node: 表示从向量索引搜索中检索到的节点。

  • score: 表示相似性得分。

例如,在一个包含演员的电影图谱中,如果向量索引与某些电影属性相关,检索查询可以按以下方式构建:

retrieval_query = """
RETURN  node.title as movieTitle,
        node.plot as moviePlot,
        collect { MATCH (actor:Actor)-[:ACTED_IN]->(node) RETURN actor.name } AS actors
"""
retriever = VectorCypherRetriever(
    driver,
    index_name=INDEX_NAME,
    retrieval_query=retrieval_query,
)

建议检索查询返回节点属性,而非节点本身。

格式化结果

警告

此 API 处于 Beta 模式,未来可能会有所更改。

result_formatter 函数用于自定义 Cypher 检索器的输出,以改进提示工程和可读性。它将每个 Neo4j 记录转换为一个具有两个字段的 RetrieverResultItem:contentmetadata

content 字段是一个格式化的字符串,包含供语言模型使用的关键信息,例如电影标题或描述。metadata 字段包含额外详细信息,例如分数或节点属性,这些信息对调试或提供额外上下文很有用。

def result_formatter(record: neo4j.Record) -> RetrieverResultItem:
    content=f"Movie title: {record.get('movieTitle')}, description: {record.get('movieDescription')}, actors: {record.get('actors')}",
    return RetrieverResultItem(
        metadata={
            "title": record.get('movieTitle'),
            "score": record.get("score"),
        }
    )

retriever = VectorCypherRetriever(
    driver,
    index_name=INDEX_NAME,
    retrieval_query="OPTIONAL 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 “neo4j_graphrag[weaviate]”

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_propertiesretrieval_query 参数的操作方式与其他检索器中的类似。

另请参阅 WeaviateNeo4jRetriever

Pinecone 检索器

注意

为了导入此检索器,必须安装 Pinecone Python 客户端:pip install “neo4j_graphrag[pinecone]”

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 “neo4j_graphrag[qdrant]”

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",
    using="my-vector",
    id_property_external="neo4j_id",    # The payload field that contains identifier to a corresponding Neo4j node id property
    id_property_neo4j="id",
    embedder=embedder,
)

另请参阅 QdrantNeo4jRetriever

其他检索器

混合检索器

在混合检索器中,结果会在向量索引和全文索引中进行搜索。因此,数据库中也必须存在一个全文索引,并且在实例化检索器时必须提供其名称

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 文档)。

混合 Cypher 检索器

在混合 Cypher 检索器中,结果会在向量索引和全文索引中进行搜索。一旦识别出相似节点,检索查询可以遍历图并返回更多上下文

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,
)

另请参阅 HybridCypherRetriever

Text2Cypher 检索器

此检索器首先要求 LLM 生成一个 Cypher 查询,以从数据库中获取回答问题所需的精确信息。然后执行此查询,并将结果记录添加到上下文中,供 LLM 编写对初始用户问题的答案。Cypher 生成和答案生成的 LLM 可以不同。

from neo4j import GraphDatabase
from neo4j_graphrag.retrievers import Text2CypherRetriever
from neo4j_graphrag.llm 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-4o")

# (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))

警告

使用 OpenAILLM 需要 openai Python 客户端。您可以使用 pip install “neo4j_graphrag[openai]” 进行安装。

注意

由于我们不执行任何相似性搜索(向量索引),Text2Cypher 检索器不需要任何嵌入器。

警告

LLM 生成的查询不保证语法正确。如果无法执行,将引发 Text2CypherRetrievalError

另请参阅 Text2CypherRetriever

自定义检索器

如果应用程序需要非常具体的检索策略,可以使用 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 random import random

from neo4j import GraphDatabase
from neo4j_graphrag.indexes import upsert_vectors
from neo4j_graphrag.types import EntityType

URI = "neo4j://localhost:7687"
AUTH = ("neo4j", "password")

# Connect to Neo4j database
driver = GraphDatabase.driver(URI, auth=AUTH)

# Upsert the vector
DIMENSION = 1536
vector = [random() for _ in range(DIMENSION)]
upsert_vectors(
    driver,
    ids=["1234"],
    embedding_property="vectorProperty",
    embeddings=[vector],
    entity_type=EntityType.NODE,
)

这将更新 id(node)=1234 的节点,以添加(或更新)node.vectorProperty 属性。此属性也将添加到向量索引中。

删除向量索引

警告

此操作不可逆,请谨慎使用。

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)
© . All rights reserved.