用户指南:知识图谱构建器

此页面提供有关如何从非结构化数据创建知识图谱的信息。

警告

此功能仍处于实验阶段。预计会有 API 更改和错误修复。

管道结构

知识图谱 (KG) 构建管道需要一些组件(以下一些组件是可选的)

  • 文档解析器:从文件(PDF 等)中提取文本。

  • 文档分段器:将文本分割成更小的文本片段,以便于 LLM 上下文窗口处理(令牌限制)。

  • 分段嵌入器(可选):计算分段嵌入。

  • 模式构建器:提供一个模式来为 LLM 提取的实体和关系提供依据,并获得易于导航的 KG。

  • LexicalGraphBuilder:构建词汇图(文档、分段及其关系)(可选)。

  • 实体和关系提取器:从文本中提取相关的实体和关系。

  • 知识图谱写入器:保存已识别的实体和关系。

  • 实体解析器:将类似的实体合并到单个节点中。

KG Builder pipeline

此包包含每个组件的接口和实现,这些组件将在以下部分详细介绍。

要查看知识图谱构建管道的端到端示例,请参阅项目 GitHub 存储库中的示例文件夹

知识图谱构建器组件

以下是此包中提供的不同组件以及如何使用它们的列表。

这些组件中的每一个都可以单独运行

import asyncio
from neo4j_graphrag.experimental.components.pdf_loader import PdfLoader
my_component = PdfLoader()
asyncio.run(my_component.run("my_file.pdf"))

它们也可以在管道中使用

from neo4j_graphrag.experimental.pipeline import Pipeline
from neo4j_graphrag.experimental.components.pdf_loader import PdfLoader
pipeline = Pipeline()
my_component = PdfLoader()
pipeline.add_component(my_component, "component_name")

文档解析器

文档解析器从文件路径开始,并返回从该文件中提取的文本。

此包目前支持从 PDF 中提取文本

from pathlib import Path
from neo4j_graphrag.experimental.components.pdf_loader import PdfLoader

loader = PdfLoader()
await loader.run(path=Path("my_file.pdf"))

要实现您自己的加载器,请使用DataLoader接口

from pathlib import Path
from neo4j_graphrag.experimental.components.pdf_loader import DataLoader, PdfDocument

class MyDataLoader(DataLoader):
    async def run(self, path: Path) -> PdfDocument:
        # process file in `path`
        return PdfDocument(text="text")

文档分割器

文档分割器,顾名思义,将文档分割成更小的块,这些块可以在 LLM 令牌限制内处理

from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import FixedSizeSplitter

splitter = FixedSizeSplitter(chunk_size=4000, chunk_overlap=200)
splitter.run(text="Hello World. Life is beautiful.")

此包中包含 LangChain 和 LlamaIndex 文本分割器的包装器

from langchain_text_splitters import CharacterTextSplitter
from neo4j_graphrag.experimental.components.text_splitters.langchain import LangChainTextSplitterAdapter
splitter = LangChainTextSplitterAdapter(
    CharacterTextSplitter(chunk_size=4000, chunk_overlap=200, separator=".")
)
await splitter.run(text="Hello World. Life is beautiful.")

另请参见LangChainTextSplitterAdapterLlamaIndexTextSplitterAdapter

要实现自定义文本分割器,可以使用TextSplitter接口

from neo4j_graphrag.experimental.components.text_splitters.base import TextSplitter
from neo4j_graphrag.experimental.components.types import TextChunks, TextChunk


class MyTextSplitter(TextSplitter):

    def __init__(self, separator: str = ".") -> None:
        self.separator = separator

    async def run(self, text: str) -> TextChunks:
         return TextChunks(
             chunks=[
                 TextChunk(text=text_chunk)
                 for text_chunk in text.split(self.separator)
             ]
         )

分段嵌入器

为了嵌入分段文本(用于向量搜索 RAG),可以使用TextChunkEmbedder组件,该组件依赖于Embedder接口。

示例用法

from neo4j_graphrag.experimental.components.embedder import TextChunkEmbedder
from neo4j_graphrag.embeddings.openai import OpenAIEmbeddings
text_chunk_embedder = TextChunkEmbedder(embedder=OpenAIEmbeddings())
await text_chunk_embedder.run(text_chunks=TextChunks(chunks=[TextChunk(text="my_text")]))

注意

要使用 OpenAI(嵌入或 LLM),OPENAI_API_KEY 必须位于环境变量中,例如使用

import os
os.environ["OPENAI_API_KEY"] = "sk-..."

如果 OpenAI 不是一种选择,请参阅嵌入器以了解如何使用其他受支持的嵌入器。

嵌入被添加到每个分段元数据中,如果EntityRelationExtractor中启用了create_lexical_graph(继续阅读),则将作为图中的分段节点属性保存。

词汇图构建器

提取并嵌入分段(如果需要)后,可以创建一个图。

词汇图包含

  • Document节点:表示已处理的文档,并具有path属性。

  • Chunk节点:表示文本分段。它们具有text属性,如果已计算,则具有embedding属性。

  • NEXT_CHUNK关系:文档中一个分段节点与下一个分段节点之间的关系。它可用于增强 RAG 应用程序中的上下文。

  • FROM_DOCUMENT关系:每个分段与其所属文档之间的关系。

示例用法

from neo4j_graphrag.experimental.pipeline.components.lexical_graph_builder import LexicalGraphBuilder
from neo4j_graphrag.experimental.pipeline.components.types import LexicalGraphConfig

lexical_graph_builder = LexicalGraphBuilder(config=LexicalGraphConfig(id_prefix="example"))
graph = await lexical_graph_builder.run(
    text_chunks=TextChunks(chunks=[
        TextChunk(text="some text", index=0),
        TextChunk(text="some text", index=1),
    ]),
    document_info=DocumentInfo(path="my_document.pdf"),
)

请参阅知识图谱写入器以了解如何将生成的节点和关系写入 Neo4j。

Neo4j 分段读取器

Neo4j 分段读取器组件用于从 Neo4j 读取文本分段。文本分段可以通过词汇图构建器或其他进程创建。

import neo4j
from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader
from neo4j_graphrag.experimental.components.types import LexicalGraphConfig

reader = Neo4jChunkReader(driver)
result = await reader.run()

配置节点标签和关系类型

可选地,可以使用LexicalGraphConfig对象配置文档和分段节点标签

from neo4j_graphrag.experimental.components.neo4j_reader import Neo4jChunkReader
from neo4j_graphrag.experimental.components.types import LexicalGraphConfig, TextChunks

# optionally, define a LexicalGraphConfig object
# shown below with the default values
config = LexicalGraphConfig(
    id_prefix="",  # used to prefix the chunk and document IDs
    chunk_node_label="Chunk",
    document_node_label="Document",
    chunk_to_document_relationship_type="PART_OF_DOCUMENT",
    next_chunk_relationship_type="NEXT_CHUNK",
    node_to_chunk_relationship_type="PART_OF_CHUNK",
    chunk_embedding_property="embeddings",
)
reader = Neo4jChunkReader(driver)
result = await reader.run(lexical_graph_config=config)

模式构建器

模式用于尝试将 LLM 关联到感兴趣的可能实体和关系列表。到目前为止,必须通过指定以下内容手动创建模式:

  • 实体LLM 应该在文本中查找的实体,包括它们的属性(名称和类型)。

  • 这些实体之间感兴趣的关系,包括关系属性(名称和类型)。

  • 三元组定义每个关系的起始(源)和结束(目标)实体类型。

这是一个说明这些概念的代码块

from neo4j_graphrag.experimental.components.schema import (
    SchemaBuilder,
    SchemaEntity,
    SchemaProperty,
    SchemaRelation,
)

schema_builder = SchemaBuilder()

await schema_builder.run(
    entities=[
        SchemaEntity(
            label="Person",
            properties=[
                SchemaProperty(name="name", type="STRING"),
                SchemaProperty(name="place_of_birth", type="STRING"),
                SchemaProperty(name="date_of_birth", type="DATE"),
            ],
        ),
        SchemaEntity(
            label="Organization",
            properties=[
                SchemaProperty(name="name", type="STRING"),
                SchemaProperty(name="country", type="STRING"),
            ],
        ),
    ],
    relations=[
        SchemaRelation(
            label="WORKED_ON",
        ),
        SchemaRelation(
            label="WORKED_FOR",
        ),
    ],
    possible_schema=[
        ("Person", "WORKED_ON", "Field"),
        ("Person", "WORKED_FOR", "Organization"),
    ],
)

验证后,此模式将保存在SchemaConfig对象中,其字典表示形式将传递给 LLM。

实体和关系提取器

此组件负责使用模式作为指南,从每个文本分段中提取相关的实体和关系。

此包包含一个基于 LLM 的实体和关系提取器:LLMEntityRelationExtractor。它可以这样使用

from neo4j_graphrag.experimental.components.entity_relation_extractor import (
    LLMEntityRelationExtractor,
)
from neo4j_graphrag.llm.openai import OpenAILLM

extractor = LLMEntityRelationExtractor(
    llm=OpenAILLM(
        model_name="gpt-4o",
        model_params={
            "max_tokens": 1000,
            "response_format": {"type": "json_object"},
        },
    )
)
await extractor.run(chunks=TextChunks(chunks=[TextChunk(text="some text")]))

警告

如果模型参数中包含“response_format”: {“type”: “json_object”},则LLMEntityRelationExtractor的效果更好。

可以使用自定义 LLM,唯一的约束是它必须遵守LLMInterface

错误行为

默认情况下,如果一个分段的提取失败,它将被忽略,并且不会失败的分段将被保存。可以通过在LLMEntityRelationExtractor构造函数中使用on_error标志来更改此行为

from neo4j_graphrag.experimental.components.entity_relation_extractor import (
    LLMEntityRelationExtractor,
    OnError,
)

extractor = LLMEntityRelationExtractor(
    llm=OpenAILLM(
        model_name="gpt-4o",
        model_params={
            "max_tokens": 1000,
            "response_format": {"type": "json_object"},
        },
    ),
    on_error=OnError.RAISE,
)

在这种情况下,任何失败的分段都将导致整个管道失败(对于所有分段),并且不会将任何数据保存到 Neo4j。

词汇图

默认情况下,LLMEntityRelationExtractor还会创建词汇图

如果不希望使用此“词汇图”,请在提取器构造函数中将created_lexical_graph设置为False

extractor = LLMEntityRelationExtractor(
    llm=....,
    create_lexical_graph=False,
)

注意

  • 如果self.create_lexical_graph设置为True,则将创建完整的词汇图,包括文档和分段节点,以及实体与其提取来源分段之间的关系。

  • 如果self.create_lexical_graph设置为False但提供了lexical_graph_config,则不会创建文档和分段节点。但是,分段与从中提取的实体之间的关系仍将添加到图中。

警告

如果省略self.create_lexical_graph且分段不存在,这将导致写入器不会在数据库中创建任何关系。

自定义提示

默认提示使用ERExtractionTemplate。可以将自定义提示作为字符串提供

extractor = LLMEntityRelationExtractor(
    llm=....,
    prompt="Extract entities from {text}",
)

以下变量可以在提示中使用

  • text(str):要分析的文本(必填)。

  • schema(str):要使用的图模式。

  • examples(str):少样本学习的示例。

对 EntityRelationExtractor 进行子类化

如果需要更多自定义,可以对EntityRelationExtractor接口进行子类化

from pydantic import validate_call
from neo4j_graphrag.experimental.components.entity_relation_extractor import EntityRelationExtractor
from neo4j_graphrag.experimental.components.schema import SchemaConfig
from neo4j_graphrag.experimental.components.types import (
    Neo4jGraph,
    Neo4jNode,
    Neo4jRelationship,
    TextChunks,
)

class MyExtractor(EntityRelationExtractor):

    @validate_call
    async def run(self, chunks: TextChunks, **kwargs: Any) -> Neo4jGraph:
        return Neo4jGraph(
            nodes=[
                Neo4jNode(id="0", label="Person", properties={"name": "A. Einstein"}),
                Neo4jNode(id="1", label="Concept", properties={"name": "Theory of relativity"}),
            ],
            relationships=[
                Neo4jRelationship(type="PROPOSED_BY", start_node_id="1", end_node_id="0", properties={"year": 1915})
            ],
        )

请参阅EntityRelationExtractor

知识图谱写入器

KG 写入器用于保存EntityRelationExtractor的结果。主要的实现是Neo4jWriter,它将节点和关系写入 Neo4j 数据库

import neo4j
from neo4j_graphrag.experimental.components.kg_writer import Neo4jWriter
from neo4j_graphrag.experimental.components.types import Neo4jGraph

with neo4j.GraphDatabase.driver(
    "bolt://127.0.0.1:7687", auth=("neo4j", "password")
) as driver:
    writer = Neo4jWriter(driver)
    graph = Neo4jGraph(nodes=[], relationships=[])
    await writer.run(graph)

调整Neo4jWriterbatch_size参数以优化插入性能。此参数控制每个批次插入的节点或关系的数量,默认值为 1000。

请参阅Neo4jGraph

可以使用KGWriter接口创建自定义写入器

import json
from pydantic import validate_call
from neo4j_graphrag.experimental.components.kg_writer import KGWriter

class JsonWriter(KGWriter):

    def __init__(self, file_name: str) -> None:
        self.file_name = file_name

    @validate_call
    async def run(self, graph: Neo4jGraph) -> KGWriterModel:
        try:
            with open(self.file_name, "w") as f:
                json.dump(graph.model_dump(), f, indent=2)
            return KGWriterModel(status="SUCCESS")
        except Exception:
            return KGWriterModel(status="FAILURE")

注意

当输入参数包含Pydantic模型时,需要validate_call装饰器。

请参阅 API 参考中的KGWriterModelKGWriter

实体解析器

KG 写入器组件为每个识别的实体创建新节点,而不会对实体相似性做出任何假设。实体解析器负责通过合并表示同一现实世界对象的实体节点来细化已创建的知识图谱。

实际上,此包实现了一个单一的解析器,该解析器合并具有相同标签和相同“名称”属性的节点。

警告

SinglePropertyExactMatchResolver替换KG 写入器创建的节点。

它可以这样使用

from neo4j_graphrag.experimental.components.resolver import (
    SinglePropertyExactMatchResolver,
)
resolver = SinglePropertyExactMatchResolver(driver)
res = await resolver.run()

警告

默认情况下,所有具有__Entity__标签的节点都将被解析。要排除特定节点,可以将过滤器查询添加到查询中。例如,如果已在图中对已解析的实体应用了:Resolved标签,则可以使用以下方法排除这些实体

from neo4j_graphrag.experimental.components.resolver import (
    SinglePropertyExactMatchResolver,
)
resolver = SinglePropertyExactMatchResolver(driver, filter_query="WHERE not entity:Resolved")
res = await resolver.run()