用户指南:知识图谱构建器¶
本页面提供了关于如何从非结构化数据创建知识图谱的信息。
警告
此功能仍处于实验阶段。预计会有 API 变更和错误修复。
流水线结构¶
知识图谱 (KG) 构建流水线需要几个组件(以下部分组件可选):
数据加载器 (Data loader):从文件(PDF 等)中提取文本。
文本分割器 (Text splitter):将文本拆分为较小的文本片段(分块),以适应 LLM 上下文窗口(Token 限制)。
分块嵌入器 (Chunk embedder)(可选):计算分块嵌入。
模式构建器 (Schema builder):提供一个模式来限定 LLM 抽取的节点和关系类型,从而获得易于导航的知识图谱。模式可以手动提供,也可以使用 LLM 自动提取。
词法图构建器 (Lexical graph builder):构建词法图(文档、分块及其关系)(可选)。
实体与关系抽取器 (Entity and relation extractor):从文本中提取相关的实体和关系。
图剪枝器 (Graph pruner):根据提供的模式清理图数据。
知识图谱写入器 (Knowledge Graph writer):保存已识别的实体和关系。
实体解析器 (Entity resolver):将相似实体合并为单个节点。
本包包含上述每个组件的接口和实现,详见后续章节。
要查看知识图谱构建流水线的端到端示例,请访问项目 GitHub 仓库中的 example 文件夹。
简单知识图谱流水线¶
使用此包从非结构化数据开始构建知识图谱的最简单方法是利用 SimpleKGPipeline 接口。
from neo4j_graphrag.experimental.pipeline.kg_builder import SimpleKGPipeline
kg_builder = SimpleKGPipeline(
llm=llm, # an LLMInterface for Entity and Relation extraction
driver=neo4j_driver, # a neo4j driver to write results to graph
embedder=embedder, # an Embedder for chunks
from_pdf=True, # set to False if parsing an already extracted text
)
await kg_builder.run_async(file_path=str(file_path))
# await kg_builder.run_async(text="my text") # if using from_pdf=False
请参阅
使用其他 LLM 模型 以了解如何实例化 llm。
嵌入器 以了解如何实例化 embedder。
以下部分概述了此类别的配置参数。
自定义简单知识图谱流水线¶
图模式 (Graph Schema)¶
可以通过提供节点和关系类型的列表(可选包含预期的属性列表)以及如何连接它们的指令(模式)来引导 LLM。节点和关系类型可以表示为简单的字符串(代表标签)或字典。如果使用字典,则必须包含 label 键,并且可以根据需要包含 description 和 properties 键,如下所示:
NODE_TYPES = [
# node types can be defined with a simple label...
"Person",
# ... or with a dict if more details are needed,
# such as a description:
{"label": "House", "description": "Family the person belongs to"},
# or a list of properties the LLM will try to attach to the entity:
{"label": "Planet", "properties": [{"name": "name", "type": "STRING", "required": True}, {"name": "weather", "type": "STRING"}]},
]
# same thing for relationships:
RELATIONSHIP_TYPES = [
"PARENT_OF",
{
"label": "HEIR_OF",
"description": "Used for inheritor relationship between father and sons",
},
{"label": "RULES", "properties": [{"name": "fromYear", "type": "INTEGER"}]},
]
patterns 由格式为 (source_node_label, relationship_label, target_node_label) 的三元组列表定义。例如:
PATTERNS = [
("Person", "PARENT_OF", "Person"),
("Person", "HEIR_OF", "House"),
("House", "RULES", "Planet"),
]
这些模式信息可以按照以下方式提供给 SimpleKGBuilder:
# Using the schema parameter (recommended approach)
kg_builder = SimpleKGPipeline(
# ...
schema={
"node_types": NODE_TYPES,
"relationship_types": RELATIONSHIP_TYPES,
"patterns": PATTERNS,
"additional_node_types": False,
},
# ...
)
模式参数行为¶
schema 参数控制实体和关系的提取方式:
EXTRACTED:
schema="EXTRACTED"或 (schema=None,默认值)。模式会使用 LLM 从输入文本中自动提取一次。该引导模式随后用于规范所有分块的实体和关系提取。这保证了所有分块具有相同的引导模式。(参见 自动模式提取)FREE:
schema="FREE"或空模式 ({"node_types": ()})。不执行模式提取。实体和关系提取在没有预定义或派生模式的情况下进行,从而实现无引导的提取。使用此设置可绕过自动模式提取。
额外配置¶
这些参数属于 EntityAndRelationExtractor 组件的一部分。有关详细信息,请参阅 实体与关系抽取器 部分。它们也可以通过 SimpleKGPipeline 接口访问。
kg_builder = SimpleKGPipeline(
# ...
prompt_template="",
lexical_graph_config=my_config,
on_error="RAISE",
# ...
)
跳过实体解析¶
默认情况下,每次运行后,都会执行一次实体解析步骤,以合并具有相同标签和名称属性的节点。要禁用此行为,请调整以下参数:
kg_builder = SimpleKGPipeline(
# ...
perform_entity_resolution=False,
# ...
)
Neo4j 数据库¶
要写入非默认的 Neo4j 数据库,请使用此参数指定数据库名称:
kg_builder = SimpleKGPipeline(
# ...
neo4j_database="myDb",
# ...
)
结构化输出¶
当配置的 LLM 声明支持结构化输出时(即 supports_structured_output = True,例如 OpenAILLM 和 VertexAILLM),SimpleKGPipeline 会自动启用实体提取和(自动提取时)模式生成的结构化输出。这在 API 层面强制执行模式一致性,比基于 Prompt 的 JSON 解析更可靠。
注意
在实例化 LLM 时,结构化输出的优先级高于 model_params 中设置的任何 response_format。例如,对于支持的 LLM,{"type": "json_object"} 将被忽略,转而使用结构化输出。
有关组件级别结构化输出工作原理的更多详情,请参见实体与关系抽取器部分的 使用结构化输出。
使用自定义组件¶
对于高级定制或使用自定义实现时,您可以将特定组件的实例传递给 SimpleKGPipeline。目前可以定制的组件有:
text_splitter:必须是 TextSplitter 的实例。
pdf_loader:必须是 PdfLoader 的实例。
kg_writer:必须是 KGWriter 的实例。
例如,以下代码可用于自定义文本分割器组件中的分块大小和重叠量:
from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import (
FixedSizeSplitter,
)
text_splitter = FixedSizeSplitter(chunk_size=500, chunk_overlap=100)
kg_builder = SimpleKGPipeline(
# ...
text_splitter=text_splitter,
# ...
)
运行参数¶
SimpleKGPipeline 还接受额外的运行时参数:
document_metadata(dict):每个项目都将保存为附加到Document节点的属性。
使用配置文件¶
from neo4j_graphrag.experimental.pipeline.config.runner import PipelineRunner
file_path = "my_config.json"
pipeline = PipelineRunner.from_config_file(file_path)
await pipeline.run({"text": "my text"})
配置文件可以使用 JSON 或 YAML 格式编写。
这是一个 JSON 格式的基础配置文件示例:
{
"version_": 1,
"template_": "SimpleKGPipeline",
"neo4j_config": {},
"llm_config": {},
"embedder_config": {}
}
YAML 格式如下:
version_: 1
template_: SimpleKGPipeline
neo4j_config:
llm_config:
embedder_config:
定义 Neo4j 驱动程序¶
以下是在 JSON 配置文件中配置 Neo4j 驱动程序的示例:
{
"neo4j_config": {
"params_": {
"uri": "bolt://...",
"user": "neo4j",
"password": "password"
}
}
}
YAML 相同:
neo4j_config:
params_:
uri: bolt://
user: neo4j
password: password
在某些情况下,可能需要避免硬编码敏感值(如密码或 API 密钥)以确保安全。为此,配置解析器支持参数解析方法。
参数解析¶
要指示配置解析器从环境变量读取参数,请使用以下语法:
{
"neo4j_config": {
"params_": {
"uri": "bolt://...",
"user": "neo4j",
"password": {
"resolver_": "ENV",
"var_": "NEO4J_PASSWORD"
}
}
}
}
YAML 语法:
neo4j_config:
params_:
uri: bolt://
user: neo4j
password:
resolver_: ENV
var_: NEO4J_PASSWORD
resolver_=ENV 键是必须的,其值不能更改。
var_ 键指定要读取的环境变量名称。
此语法可应用于所有参数。
定义 LLM¶
以下是在 JSON 配置文件中配置 LLM 的示例:
{
"llm_config": {
"class_": "OpenAILLM",
"params_": {
"model_name": "gpt-5",
"api_key": {
"resolver_": "ENV",
"var_": "OPENAI_API_KEY",
},
"model_params": {
"temperature": 0,
"max_tokens": 2000
}
}
}
}
等效的 YAML:
llm_config:
class_: OpenAILLM
params_:
model_name: gpt-5
api_key:
resolver_: ENV
var_: OPENAI_API_KEY
model_params:
temperature: 0
max_tokens: 2000
class_ 键指定要实例化的类路径。
params_ 键包含要传递给类构造函数的参数。
使用本包提供的 LLM 实现时,class_ 键中的完整路径可以省略(解析器将自动从 neo4j_graphrag.llm 导入)。对于自定义实现,必须显式指定完整路径,例如:my_package.my_llm.MyLLM。
警告
检查 安装 部分,确保在使用 LLM 时已安装所需的依赖项。
定义嵌入器 (Embedder)¶
同样的原则适用于 embedder_config:
{
"embedder_config": {
"class_": "OpenAIEmbeddings",
"params_": {
"mode": "text-embedding-ada-002",
"api_key": {
"resolver_": "ENV",
"var_": "OPENAI_API_KEY",
}
}
}
}
或 YAML 版本:
embedder_config:
class_: OpenAIEmbeddings
params_:
api_key:
resolver_: ENV
var_: OPENAI_API_KEY
对于本包中的嵌入器实现,class_ 键中的完整路径可以省略(解析器将从 neo4j_graphrag.embeddings 导入)。
对于自定义实现,必须提供完整路径,例如:my_package.my_embedding.MyEmbedding。
其他配置¶
SimpleKGPipeline 中暴露的其他参数也可以在配置文件中进行配置:
{
"from_pdf": false,
"perform_entity_resolution": true,
"neo4j_database": "myDb",
"on_error": "IGNORE",
"prompt_template": "...",
"schema": {
"node_types": [
"Person",
{
"label": "House",
"description": "Family the person belongs to",
"properties": [
{"name": "name", "type": "STRING"}
]
},
{
"label": "Planet",
"properties": [
{"name": "name", "type": "STRING"},
{"name": "weather", "type": "STRING"}
]
}
],
"relationship_types": [
"PARENT_OF",
{
"label": "HEIR_OF",
"description": "Used for inheritor relationship between father and sons"
},
{
"label": "RULES",
"properties": [
{"name": "fromYear", "type": "INTEGER"}
]
}
],
"patterns": [
["Person", "PARENT_OF", "Person"],
["Person", "HEIR_OF", "House"],
["House", "RULES", "Planet"]
]
},
"lexical_graph_config": {
"chunk_node_label": "TextPart"
}
}
或在 YAML 中:
from_pdf: false
perform_entity_resolution: true
neo4j_database: myDb
on_error: IGNORE
prompt_template: ...
schema:
node_types:
- Person
- label: House
description: Family the person belongs to
properties:
- name: name
type: STRING
- label: Planet
properties:
- name: name
type: STRING
- name: weather
type: STRING
relationship_types:
- PARENT_OF
- label: HEIR_OF
description: Used for inheritor relationship between father and sons
- label: RULES
properties:
- name: fromYear
type: INTEGER
patterns:
- ["Person", "PARENT_OF", "Person"]
- ["Person", "HEIR_OF", "House"]
- ["House", "RULES", "Planet"]
lexical_graph_config:
chunk_node_label: TextPart
还可以使用与 llm_config 或 embedder_config 类似的语法进一步自定义组件:
{
"text_splitter": {
"class_": "text_splitters.FixedSizeSplitter",
"params_": {
"chunk_size": 500,
"chunk_overlap": 100
}
}
}
YAML 等效写法:
text_splitter:
class_: text_splitters.fixed_size_splitter.FixedSizeSplitter
params_:
chunk_size: 100
chunk_overlap: 10
如果需要,neo4j_graphrag.experimental.components 前缀将自动添加。
知识图谱构建器组件¶
以下是本包中可用组件的列表及使用方法。
每个组件都可以单独运行。
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(filepath=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, filepath: Path, metadata: Optional[Dict[str, str]] = None) -> PdfDocument:
# process file in `filepath`
return PdfDocument(
text="text",
document_info=DocumentInfo(
path=str(filepath),
metadata=metadata,
)
)
文本分割器¶
顾名思义,文档分割器将文档分割成可在 LLM token 限制内处理的较小分块。
from neo4j_graphrag.experimental.components.text_splitters.fixed_size_splitter import FixedSizeSplitter
splitter = FixedSizeSplitter(chunk_size=4000, chunk_overlap=200, approximate=False)
splitter.run(text="Hello World. Life is beautiful.")
注意
approximate 标志默认设置为 True,以确保尽可能获得整洁的分块开头和结尾(即避免在单词中间截断)。
此包中包含了对 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.")
另请参阅 LangChainTextSplitterAdapter 和 LlamaIndexTextSplitterAdapter。
要实现自定义文本分割器,可以使用 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(见下文),它们将作为 Chunk 节点属性保存到图中。
词法图构建器¶
一旦分块被提取并嵌入(如果需要),就可以创建图。
词法图 (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())
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(
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 应在文本中查找的类型,包括其属性(名称和类型)。
关系类型:这些节点类型之间感兴趣的关系,包括关系属性(名称和类型)。
模式 (Patterns)(三元组):定义每种关系起始(源)和终止(目标)实体类型的规则。
以下是一个说明这些概念的代码块:
from neo4j_graphrag.experimental.components.schema import (
SchemaBuilder,
NodeType,
PropertyType,
RelationshipType,
)
schema_builder = SchemaBuilder()
await schema_builder.run(
node_types=[
NodeType(
label="Person",
properties=[
PropertyType(name="name", type="STRING"),
PropertyType(name="place_of_birth", type="STRING"),
PropertyType(name="date_of_birth", type="DATE"),
],
),
NodeType(
label="Organization",
properties=[
PropertyType(name="name", type="STRING"),
PropertyType(name="country", type="STRING"),
],
),
],
relationship_types=[
RelationshipType(
label="WORKED_ON",
),
RelationshipType(
label="WORKED_FOR",
),
],
patterns=[
("Person", "WORKED_ON", "Field"),
("Person", "WORKED_FOR", "Organization"),
],
)
验证后,此模式将保存到 GraphSchema 对象中,其字典表示形式被传递给 LLM。
自动模式提取¶
除了手动定义模式,您还可以使用 SchemaFromTextExtractor 组件使用 LLM 从文本中自动提取模式:
from neo4j_graphrag.experimental.components.schema import SchemaFromTextExtractor
from neo4j_graphrag.llm import OpenAILLM
# Instantiate the automatic schema extractor component
schema_extractor = SchemaFromTextExtractor(
llm=OpenAILLM(
model_name="gpt-5",
model_params={
"max_tokens": 2000,
"response_format": {"type": "json_object"},
},
)
)
# Extract the schema from the text
extracted_schema = await schema_extractor.run(text="Some text")
SchemaFromTextExtractor 组件分析文本并识别节点类型、关系类型、其属性类型以及连接它们的模式。它创建一个完整的 GraphSchema 对象,其使用方式与手动定义的模式相同。
您还可以保存并重新加载提取的模式。
# Save the schema to JSON or YAML files
extracted_schema.save("my_schema.json")
extracted_schema.save("my_schema.yaml")
# Later, reload the schema from file
from neo4j_graphrag.experimental.components.schema import GraphSchema
restored_schema = GraphSchema.from_file("my_schema.json") # or my_schema.yaml
将结构化输出与模式提取结合使用¶
为了在使用 OpenAILLM 或 VertexAILLM 时提高可靠性,请启用结构化输出模式。当 use_structured_output=True 时,提取器将 GraphSchema Pydantic 模型作为 response_format 传递给 LLM,确保响应符合预期模式结构并自动进行验证。
from neo4j_graphrag.experimental.components.schema import SchemaFromTextExtractor
from neo4j_graphrag.llm import OpenAILLM
llm = OpenAILLM(model_name="gpt-5-mini", model_params={"temperature": 0})
schema_extractor = SchemaFromTextExtractor(
llm=llm,
use_structured_output=True
)
extracted_schema = await schema_extractor.run(text="Some text")
注意
在其他 LLM 提供商中使用 use_structured_output=True 将引发 ValueError。请勿在构造函数参数中传递 response_format;提取器在调用 invoke() 时会自动设置它。
模式验证与节点属性¶
重要:所有节点类型必须至少定义一个属性。当使用节点类型的字符串速记(例如 "Person")时,会自动添加一个默认的 "name" 属性,并将 additional_properties=True 设置为允许灵活的 LLM 提取。
# String shorthand - automatically gets default property
NodeType("Person") # Becomes: properties=[{"name": "name", "type": "STRING"}], additional_properties=True
# Explicit definition - must include at least one property
NodeType(
label="Person",
properties=[PropertyType(name="name", type="STRING")],
additional_properties=True # Allow LLM to extract additional properties
)
没有属性的关系类型会自动设置 additional_properties=True,以在图构建期间保留 LLM 提取的属性。
模式可视化¶
可以使用 schema_visualization 函数可视化经过验证的模式或模式字典。此函数返回一个 VisualizationGraph 对象(来自 neo4j-viz 包),可以按如下方式可视化:
from neo4j_graphrag.experimental.utils.schema import schema_visualization
VG = schema_visualization(schema)
html = VG.render()
# in Jupyter:
display(html)
# to save the generated HTML
with open("my_schema.html", "w") as f:
f.write(html.data)
实体与关系抽取器¶
此组件负责以模式为准则,从每个文本分块中提取相关的实体和关系。
此包包含一个基于 LLM 的实体和关系抽取器:LLMEntityRelationExtractor。它可以这样使用:
from neo4j_graphrag.experimental.components.entity_relation_extractor import (
LLMEntityRelationExtractor,
)
from neo4j_graphrag.experimental.components.types import (
TextChunks,
TextChunk
)
from neo4j_graphrag.llm import OpenAILLM
extractor = LLMEntityRelationExtractor(
llm=OpenAILLM(
model_name="gpt-5",
model_params={
"max_tokens": 1000,
"response_format": {"type": "json_object"},
},
)
)
await extractor.run(chunks=TextChunks(chunks=[TextChunk(text="some text", index=0)]))
警告
使用 OpenAILLM 需要 openai Python 客户端。您可以通过 pip install “neo4j_graphrag[openai]” 安装它。
注意
对于 OpenAILLM 和 VertexAILLM,结构化输出比 "response_format": {"type": "json_object"} 更推荐,以提高可靠性。请参阅下方的 使用结构化输出。
所使用的 LLM 可以自定义,唯一的限制是它必须遵循 LLMInterface。
为了在使用 OpenAILLM 或 VertexAILLM 时提高可靠性和类型安全性,请启用结构化输出模式。当 use_structured_output=True 时,提取器使用 LLMInterfaceV2,将 Neo4jGraph Pydantic 模型作为 response_format 传递给 invoke()。这确保 LLM 响应符合预期的图结构并进行自动类型验证,减少了对 JSON 修复和错误处理的需求。
注意 结构化输出仅适用于 使用结构化输出¶
from neo4j_graphrag.experimental.components.entity_relation_extractor import (
LLMEntityRelationExtractor,
)
from neo4j_graphrag.llm import OpenAILLM
llm = OpenAILLM(model_name="gpt-5-mini", model_params={"temperature": 0})
extractor = LLMEntityRelationExtractor(llm=llm, use_structured_output=True)
supports_structured_output=True 的 LLM(目前为 OpenAILLM 和 VertexAILLM)。在其他提供商中使用 use_structured_output=True 将引发 ValueError。请勿在构造函数参数(model_params 或 generation_config)中传递 response_format;提取器在调用 invoke() 时会自动设置它。
错误行为¶
默认情况下,如果一个分块提取失败,它将被忽略,且非失败的分块将被保存。此行为可以通过在 LLMEntityRelationExtractor 构造函数中使用 on_error 标志来更改:
from neo4j_graphrag.experimental.components.entity_relation_extractor import (
LLMEntityRelationExtractor,
OnError,
)
extractor = LLMEntityRelationExtractor(
# ...
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 且分块不存在,这将导致写入器在数据库中不创建任何关系。
自定义 Prompt¶
默认提示词使用 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.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})
],
)
模式引导与图过滤¶
提供的模式可作为图构建过程中语言模型的引导结构。但是,它不对模型的输出施加严格限制。因此,模型可能会生成模式中未明确定义的其他节点标签、关系类型或属性。
默认情况下,所有提取的元素(包括节点、关系和属性)都会保留在构建的图中。此行为可以使用以下模式选项进行配置:(参见 GraphSchema)
必需属性 (Required Properties) (默认: 附加属性 (Additional Properties):此节点或关系级别的选项决定是否保留模式中未列出的额外属性。
如果设置为 如果设置为 配置选项¶
False):可以在节点或关系类型级别指定必需属性。任何缺少一个或多个必需属性的已提取节点或关系都将从图中被修剪掉。
True,则保留所有提取的属性。False,则仅保留模式中定义的属性;所有其他属性都将被移除。
注意
默认行为:
默认情况下,如果至少定义了一个属性,则此标志设置为 False,否则为 True。
相同的规则适用于下述 additional_node_types、additional_relationship_types 和 additional_patterns。
警告
定义没有属性且 additional_properties_allowed=False 的节点或关系类型将引发 ValidationError。
注意
节点修剪:
如果在上述属性修剪规则之后,节点没有任何剩余属性,则该节点将从图中移除。
附加节点类型 (Additional Node Types):此模式级别的选项指定是否包含模式中未定义的节点类型。
如果设置为
True,则保留此类节点类型。如果设置为
False,则移除类型未定义的节点。
附加关系类型 (Additional Relationship Types):此模式级别的选项指定是否包含模式中未定义的关系类型。
如果设置为
True,则保留此类关系。如果设置为
False,则移除类型未定义的关系。
附加模式 (Additional Patterns) (默认: True):此模式级别的选项决定是否允许模式中未明确列出的关系模式。
如果设置为
True(默认值),则保留所有模式。如果设置为
False,则仅保留模式中定义的模式。注意:additional_relationship_types 也必须为 False。
执行规则¶
除了上述用户定义的配置选项外,GraphPruning 组件还执行以下清理操作:
标签或 ID 为空的节点被修剪。
缺少必需属性的节点被修剪。
没有剩余属性的节点被修剪。
类型为空的关系被修剪。
具有无效源节点或目标节点(即图中已不存在的节点)的关系被修剪。
方向错误的关系被纠正方向。
知识图谱写入器¶
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://:7687", auth=("neo4j", "password")
) as driver:
writer = Neo4jWriter(driver)
graph = Neo4jGraph(nodes=[], relationships=[])
await writer.run(graph)
调整 Neo4jWriter 的 batch_size 参数以优化插入性能。此参数控制每批次插入的节点或关系数量,默认值为 1000。
注意
索引
为了提高摄取性能,会自动向数据库添加一个名为 __entity__tmp_internal_id 的索引。
参见 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 参考中的 KGWriterModel 和 KGWriter。
实体解析器¶
KG 写入器组件为每个已识别的实体创建新节点,而不对实体相似性做任何假设。实体解析器负责通过合并代表同一现实对象的实体节点来优化已创建的知识图谱。
实际上,此包实现了三种解析器:
一个简单的解析器,合并具有相同标签和相同“name”属性的节点;
两个基于相似性的解析器,合并具有相同标签和相似文本属性集(默认使用“name”属性)的节点;
一个语义匹配解析器,基于 spaCy 嵌入和嵌入向量的余弦相似度。此解析器非常适合使用静态嵌入进行更高质量的 KG 解析。
一个模糊匹配解析器,基于 RapidFuzz 进行快速模糊字符串匹配(使用 Levenshtein 距离)。此解析器通过使用字符串相似度度量来提供更快的摄取速度,但可能以牺牲解析精度为代价。
警告
SinglePropertyExactMatchResolver、SpaCySemanticMatchResolver 和 FuzzyMatchResolver 将替换由 KG 写入器创建的节点。
检查 安装 部分,确保在使用 SpaCySemanticMatchResolver 和 FuzzyMatchResolver 时已安装所需的依赖项。
解析器的使用方法如下:
from neo4j_graphrag.experimental.components.resolver import (
SinglePropertyExactMatchResolver,
# SpaCySemanticMatchResolver,
# FuzzyMatchResolver,
)
resolver = SinglePropertyExactMatchResolver(driver) # exact match resolver
# resolver = SpaCySemanticMatchResolver(driver) # semantic match with spaCy
# resolver = FuzzyMatchResolver(driver) # fuzzy match with RapidFuzz
res = await resolver.run()
警告
默认情况下,所有带有 __Entity__ 标签的节点都将被解析。此行为可以使用下述 filter_query 参数进行控制。
过滤查询参数¶
要从解析中排除特定节点,可以在查询中添加 filter_query。例如,如果已对图中已解析的实体应用了 :Resolved 标签,则可以通过以下方法排除这些实体:
from neo4j_graphrag.experimental.components.resolver import (
SinglePropertyExactMatchResolver,
)
filter_query = "WHERE NOT entity:Resolved"
resolver = SinglePropertyExactMatchResolver(driver, filter_query=filter_query)
res = await resolver.run()
假设已为之前创建的文档节点分配了 OldDocument 标签,则可以使用类似方法排除在同一文档上运行的先前流水线所创建的实体:
filter_query = "WHERE NOT EXISTS((entity)-[:FROM_DOCUMENT]->(:OldDocument))"