Node 抽取与消解(中文译文)
原始 DeepWiki 页面:https://deepwiki.com/getzep/graphiti/5.2-node-extraction-and-resolution
翻译时间:2026-05-27T08:44:56.624Z
翻译模型:deepseek-chat
原文字符数:12974
项目:Graphiti (graphiti)
---
节点提取与解析
相关源文件
以下文件为本 Wiki 页面的生成上下文:
examples/quickstart/dense_vs_normal_ingestion.pygraphiti_core/prompts/dedupe_edges.pygraphiti_core/prompts/dedupe_nodes.pygraphiti_core/prompts/extract_edges.pygraphiti_core/prompts/extract_nodes.pygraphiti_core/prompts/summarize_nodes.pygraphiti_core/utils/content_chunking.pygraphiti_core/utils/maintenance/edge_operations.pygraphiti_core/utils/maintenance/node_operations.pytests/utils/maintenance/test_edge_operations.pytests/utils/maintenance/test_node_operations.pytests/utils/test_content_chunking.py
本文档描述了从片段内容中提取实体节点,并针对现有图谱数据进行解析的过程。节点提取将非结构化内容转换为结构化的 EntityNode 对象,而解析则通过将实体与图谱中的现有节点进行匹配来去重。
关于边(关系)的提取与解析,请参阅边提取与解析。关于调用这些操作的更广泛片段处理工作流,请参阅片段处理。
概述
节点提取与解析是一个多阶段过程,它将原始片段内容转换为去重后的实体节点:
标题:节点提取与解析数据流
sequenceDiagram
participant EP as "片段内容"
participant Chunk as "graphiti_core.utils.content_chunking"
participant LLM as "大语言模型客户端"
participant Extract as "node_operations.extract_nodes"
participant Search as "搜索系统"
participant Resolve as "node_operations.resolve_extracted_nodes"
participant Enrich as "node_operations.extract_attributes_from_nodes"
participant Graph as "图驱动"
EP->>Extract: "片段, 先前片段"
Extract->>Chunk: "should_chunk()"
alt 高密度内容
Chunk->>Chunk: "chunk_json/message/text_content()"
Chunk->>LLM: "按片段并行提取"
LLM-->>Extract: "ExtractedEntities"
Extract->>Extract: "_merge_extracted_entities()"
else 正常密度
Extract->>LLM: "_extract_nodes_single()"
LLM-->>Extract: "ExtractedEntities"
end
Extract->>Extract: "_create_entity_nodes()"
Extract-->>Resolve: "list[EntityNode]"
Resolve->>Search: "_semantic_candidate_search()"
Search-->>Resolve: "候选节点"
Resolve->>Resolve: "_resolve_with_similarity()"
Resolve->>LLM: "_resolve_with_llm()"
LLM-->>Resolve: "NodeResolutions"
Resolve-->>Enrich: "已解析节点, uuid_map"
Enrich->>LLM: "extract_attributes_from_nodes()"
LLM-->>Enrich: "SummarizedEntities"
Enrich->>Enrich: "create_entity_node_embeddings()"
Enrich-->>Graph: "最终 EntityNode 对象"
来源: graphiti_core/utils/maintenance/node_operations.py:69-148, graphiti_core/utils/maintenance/node_operations.py:493-548, graphiti_core/utils/maintenance/node_operations.py:551-581
自适应片段切分的实体提取
extract_nodes 函数从片段内容中提取实体,当内容具有高实体密度时,会使用自适应片段切分。
片段切分决策逻辑
标题:自适应片段切分决策树
graph TB
Episode["EpisodicNode.content"]
Check{"should_chunk()"}
Single["_extract_nodes_single()"]
Chunked["_extract_nodes_chunked()"]
Merge["_merge_extracted_entities()"]
Create["_create_entity_nodes()"]
Output["list[EntityNode]"]
Episode-->Check
Check-->|"低密度"|Single
Check-->|"高密度"|Chunked
Single-->Create
Chunked-->Merge
Merge-->Create
Create-->Output
graphiti_core/utils/content_chunking.py 中的 should_chunk 函数根据内容大小和实体密度阈值来判断是否需要切分。高密度内容(每个 Token 包含多个实体)存在大语言模型上下文溢出或提取遗漏的风险,因此会将其拆分为重叠的片段,并使用 semaphore_gather 进行并行处理。
来源: graphiti_core/utils/maintenance/node_operations.py:124-127, graphiti_core/utils/content_chunking.py:59-83, graphiti_core/helpers.py:25-30
提取过程
单次提取路径
对于正常密度的内容,提取通过 _extract_nodes_single 使用单次大语言模型调用。
标题:单次节点提取逻辑
graph LR
Context["构建上下文:<br/>- 片段内容<br/>- 实体类型<br/>- 先前片段"]
Prompt["_call_extraction_llm()"]
Response["ExtractedEntities"]
Context-->Prompt
Prompt-->Response
_call_extraction_llm 函数根据 EpisodeType(message、text 或 json)从 prompt_library.extract_nodes 中选择合适的提示词。
来源: graphiti_core/utils/maintenance/node_operations.py:149-158, graphiti_core/utils/maintenance/node_operations.py:160-185
切分提取路径
对于高密度内容,提取过程会对内容进行切分,并并行处理各个片段:
标题:并行切分提取
graph TB
Content["EpisodicNode.content"]
ChunkType{"EpisodeType?"}
JSONChunk["chunk_json_content()"]
MessageChunk["chunk_message_content()"]
TextChunk["chunk_text_content()"]
Parallel["并行提取:<br/>_extract_from_chunk()"]
Merge["_merge_extracted_entities()"]
Content-->ChunkType
ChunkType-->|"json"|JSONChunk
ChunkType-->|"message"|MessageChunk
ChunkType-->|"text"|TextChunk
JSONChunk-->Parallel
MessageChunk-->Parallel
TextChunk-->Parallel
Parallel-->Merge
每个片段由 _extract_from_chunk 独立处理。_merge_extracted_entities 函数在转换为 EntityNode 对象之前,使用标准化名称匹配来跨片段去重实体。
来源: graphiti_core/utils/maintenance/node_operations.py:183-210, graphiti_core/utils/maintenance/node_operations.py:213-222, graphiti_core/utils/maintenance/node_operations.py:253-270
实体类型分类
提取的实体使用带有数字 ID 的实体类型系统进行分类。_build_entity_types_context 函数创建 ID 与类型名称之间的映射,该映射会在提取时提供给大语言模型。
| 实体类型 ID | 名称 | 描述 |
|---|---|---|
| 0 | 实体 | 未类型化实体的默认分类 |
| 1+ | 自定义类型 | 来自 entity_types 字典映射到 Pydantic 模型的用户定义实体类型 |
来源: graphiti_core/utils/maintenance/node_operations.py:151-180, graphiti_core/prompts/extract_nodes.py:28-33
EntityNode 创建
_create_entity_nodes 函数将 ExtractedEntity 对象(大语言模型响应模式)转换为 EntityNode 对象。每个节点会获得:
- 一个 UUID(自动生成)
- 标签,包括
Entity和具体的类型名称 - 用于多租户的片段的
group_id - 来自
utc_now()的created_at时间戳
来源: graphiti_core/utils/maintenance/node_operations.py:188-210
实体解析与去重
resolve_extracted_nodes 函数执行多阶段去重,将提取的实体映射到现有的图谱节点。
解析架构
标题:多层解析逻辑
graph TB
Extracted["提取的 EntityNodes"]
Collect["_collect_candidate_nodes()"]
Search["search() 每个节点"]
Build["_build_candidate_indexes()"]
Similarity["_resolve_with_similarity()"]
LLM["_resolve_with_llm()"]
Unresolved{"未解析<br/>索引?"}
Final["构建 uuid_map<br/>和 duplicate_pairs"]
Extracted-->Collect
Collect-->Search
Search-->Build
Build-->Similarity
Similarity-->Unresolved
Unresolved-->|"是"|LLM
Unresolved-->|"否"|Final
LLM-->Final
来源: graphiti_core/utils/maintenance/node_operations.py:493-548
候选收集
_collect_candidate_nodes 函数通过为每个提取的节点名称发起搜索查询来识别潜在匹配项。它使用混合搜索方法来检索具有相似名称或语义上下文的现有节点。
来源: graphiti_core/utils/maintenance/node_operations.py:309-341
多阶段解析策略
解析采用三层方法,以平衡速度和准确性:
- 精确匹配:标准化字符串比较(
_normalize_string_exact),用于名称完全相同的情况。 - 模糊相似度:使用 3-gram 分片(
_shingles)上的 Jaccard 相似度和 MinHash 签名(_minhash_signature)来识别潜在重复项,无需大语言模型开销。此步骤通过名称熵检查(_has_high_entropy)进行过滤,以避免对短/通用名称产生误报。 - 大语言模型推理:未解析的节点被发送到
dedupe_nodes.nodes提示词。大语言模型返回一个NodeResolutions对象,其中包含NodeDuplicate条目,将提取的 ID 映射到现有的candidate_id值。
来源: graphiti_core/utils/maintenance/dedup_helpers.py:39-141, graphiti_core/utils/maintenance/dedup_helpers.py:215-263, graphiti_core/prompts/dedupe_nodes.py:25-38
属性与摘要丰富
解析后,extract_attributes_from_nodes 使用摘要和结构化属性来丰富节点。
丰富工作流
标题:节点丰富管线
graph TB
ResolvedNodes["已解析的 EntityNode 列表"]
Parallel["semaphore_gather():<br/>_extract_entity_attributes_and_summary()"]
ExtractAttr["_extract_entity_attributes()"]
ExtractSum["_extract_entity_summary()"]
Embed["create_entity_node_embeddings()"]
Output["带有嵌入向量的丰富节点"]
ResolvedNodes-->Parallel
Parallel-->ExtractAttr
Parallel-->ExtractSum
ExtractAttr-->Embed
ExtractSum-->Embed
Embed-->Output
来源: graphiti_core/utils/maintenance/node_operations.py:551-581
属性提取
如果节点的实体类型定义了自定义 Pydantic 模型,_extract_entity_attributes 会提取结构化数据。它使用 extract_nodes.extract_attributes 提示词,从片段上下文中填充字段。
来源: graphiti_core/utils/maintenance/node_operations.py:607-639, graphiti_core/prompts/extract_nodes.py:61
摘要生成
_extract_entity_summary 生成自然语言摘要。如果存在现有摘要,大语言模型会使用 summarize_pair 或 summarize_context 提示词,将其与新信息进行综合。结果会使用 truncate_at_sentence 截断至 MAX_SUMMARY_CHARS(1000 个字符)。
来源: graphiti_core/utils/maintenance/node_operations.py:642-671, graphiti_core/utils/text_utils.py:29-59, graphiti_core/prompts/summarize_nodes.py:54-116
嵌入向量生成
create_entity_node_embeddings 使用配置的 EmbedderClient 为每个节点的名称生成向量嵌入,以支持后续的语义搜索。
来源: graphiti_core/nodes.py:33, graphiti_core/utils/maintenance/node_operations.py:579
函数参考
| 函数 | 位置 | 用途 |
|---|---|---|
extract_nodes | graphiti_core/utils/maintenance/node_operations.py:69 | 从片段中提取实体的主要入口点。 |
resolve_extracted_nodes | graphiti_core/utils/maintenance/node_operations.py:493 | 针对现有图谱对提取的实体进行去重。 |
extract_attributes_from_nodes | graphiti_core/utils/maintenance/node_operations.py:551 | 使用摘要、属性和嵌入向量丰富节点。 |
should_chunk | graphiti_core/utils/content_chunking.py:59 | 基于启发式的逻辑,用于判断内容是否过于密集,不适合单次提取。 |
_resolve_with_llm | graphiti_core/utils/maintenance/node_operations.py:344 | 使用大语言模型推理来解析模糊的实体重复项。 |
_resolve_with_similarity | graphiti_core/utils/maintenance/dedup_helpers.py:215 | 使用字符串标准化和 LSH 进行快速、确定性的解析。 |
来源: graphiti_core/utils/maintenance/node_operations.py:69-671, graphiti_core/utils/content_chunking.py:59-83, graphiti_core/utils/maintenance/dedup_helpers.py:39-263