跳到主要内容

知识抽取数据模型 ​

概述 ​

大模型可以从“林默加入青云宗”中识别出人物、组织和关系,但模型返回的内容还不是图数据库数据。SDK 需要知道:候选是什么、证据在哪里、关系连接哪些实体、哪些候选通过了校验,以及最终如何生成稳定的节点和边。

本章介绍 agents-flex-graph-extractor 在各阶段之间传递的数据模型。它不是查询语言,也不是网络通信协议,而是模型输出、SDK 校验、审核系统和图变更之间共同遵守的数据约定。

这个数据模型解决什么问题 ​

如果没有统一的数据模型,应用会遇到:

  • 不同模型返回不同 JSON,Parser 无法稳定处理;
  • 抽取出的关系无法回到原文,审核者不知道为什么得到它;
  • 不同 Chunk 中的“林默”无法判断是否是同一个人;
  • 合法候选和错误候选混在一起,无法安全入图;
  • 文档更新时无法识别事实来源和过期关系;
  • 一次导入操作的 ID 被误当作节点或边 ID。

数据模型的目标,是让每个候选都能回答四个问题:

text
它是什么?       -> 类型、属性和关系
来自哪里?       -> documentId、chunkId 和 evidence
指向谁?         -> mentionId、nodeId 和实体归一结果
能否入图?       -> issue、审核结果和 GraphMutation

从模型输出到图变更 ​

text
GraphExtractionRequest
  -> 模型响应
  -> GraphCandidateBatch
  -> GraphCandidateValidator
  -> GraphExtractionResult
  -> GraphEntityResolver / Registry
  -> GraphMutation

这条链路中,每个对象都有明确职责:请求描述抽取范围,候选表示模型发现的知识,校验器筛选合法子集,Resolver 确定长期实体身份,Mutation 表示准备写入图数据库的变化。

抽取请求:告诉模型和 SDK 要处理什么 ​

GraphExtractionRequest 描述一个 Chunk 的抽取范围:

字段作用
text当前 Chunk 的正文,也是 evidence 允许引用的唯一文本范围
schema允许的节点、关系、属性和类型
documentId跨版本稳定的逻辑文档 ID
chunkId当前分段 ID,参与证据定位和候选作用域
context仅用于指代消解的前文,不能作为当前证据
metadata页码、章节和来源系统等只读来源信息
options置信度、数量上限、断言类型和响应大小策略

例如,前一个 Chunk 提到“林默”,当前 Chunk 只写“他加入了青云宗”。前文 context 可以帮助模型理解“他”是谁,但证据仍必须来自当前 Chunk,不能引用 context 中没有出现在当前正文的句子。

候选结果:模型认为文本中有什么 ​

GraphCandidateBatch ​

一个 Chunk 的解析结果,包括:

  • entities:实体候选;
  • relations:关系候选;
  • issues:解析阶段发现的问题;
  • rawResponse:模型原始响应,可能包含敏感原文。

GraphEntityCandidate ​

表示文本中的一次实体提及,通常包含:

  • mentionId;
  • 名称、类型、别名和属性;
  • evidence;
  • confidence。

同一个真实人物在不同 Chunk 中可以有不同的 mentionId。是否归一为同一个图节点,要等 Resolver 和 Registry 处理,不能直接按名称写入。

GraphRelationCandidate ​

表示两个候选实体之间可能存在的关系。它使用 sourceMentionId 和 targetMentionId 引用当前候选实体,并携带关系类型、属性、证据、置信度和 assertionType。

关系候选不能直接把名称当作长期端点,也不能引用只存在于 context、没有出现在当前候选集合中的实体。

证据:说明为什么得到这条知识 ​

GraphEvidence 让候选可以回到原文,至少包含:

  • documentId:来自哪个逻辑文档;
  • chunkId:来自哪个分段;
  • quote:连续原文引文;
  • startOffset、endOffset:当前 Chunk 内的字符范围;
  • metadata:页码、章节等扩展位置。

提供偏移时必须满足:

text
0 <= startOffset <= endOffset <= text.length()
text.substring(startOffset, endOffset).equals(quote)

如果无法可靠定位,应使用 -1/-1,不能把 PDF 字节位置或整篇文档位置冒充 Chunk 偏移。证据是审核、质量评估、文档更新和事实撤回的基础。

GraphExtractionResult:一次完整抽取的结果 ​

流水线合并所有 Chunk 后产生 GraphExtractionResult,其中最重要的是:

内容作用
allEntities/allRelations保留全部解析候选,便于审核和回放
entities/relations通过 Schema、证据和质量校验的合法子集
issues解析、校验和 Chunk 容错问题
resolution候选提及到规范实体的映射
mutation待审核的节点和边变更
rawResponses各 Chunk 的模型原始响应

结果对象不等于数据库写入结果。即使存在合法 Mutation,也仍然需要经过审核策略和显式写入。

身份字段不能混用 ​

同一个“林默”在不同阶段会有不同身份。它们解决的问题不同:

字段示例含义作用域
mentionIdm1当前 Chunk 中的一次文本提及单个 Chunk
candidateKeychunk-01:m1定位候选和问题一次抽取或 Chunk
nodeIdcharacter:lin-moGraph Space 中的长期实体Space
factIdfact:doc-01:001某个来源对事实的声明来源事实
operationIdimport-2026-001一次增量入图操作业务操作

必须牢记:

text
mentionId != candidateKey != nodeId != factId != operationId

GraphEdgeKey 还表示物化边的身份,通常由 sourceId、关系类型、targetId 和稳定 rank 组成。它也不等同于 factId:多份文档事实可以共同支持同一条物化边。

问题:说明为什么候选不能直接使用 ​

GraphExtractionIssue 是结构化质量问题,不是 Java 异常。它包含:

  • 稳定 code;
  • WARNING 或 ERROR 严重级别;
  • candidateKey 或 Chunk 定位;
  • 面向开发者的诊断信息。

例如,未知关系类型、证据不在当前 Chunk、端点类型不匹配和置信度过低,都可以作为 issue 返回。业务程序应依据 code 和 severity 分流,不要依赖英文 message。

模型调用失败、根响应无法解析或流水线无法继续时,才使用 GraphExtractionException。错误处理详见错误处理。

从数据模型到图变更 ​

text
候选实体和关系
  -> Schema 与证据校验
  -> 实体归一,得到 nodeId
  -> GraphMutationMapper
  -> 节点 Upsert、边 Upsert 和稳定 EdgeKey 去重

GraphMutationMapper 不负责审核、删除、写数据库或解决来源冲突。旧关系是否删除,由增量计划结合文档状态和事实来源决定。

开发者什么时候需要关注这些数据 ​

  • 接入 DeepSeek、OpenAI 或其他模型时,适配输出结构;
  • 开发候选、证据和关系审核后台时,展示可追溯信息;
  • 保存抽取结果、人工修改和审核记录时,保持身份稳定;
  • 实现增量导入、文档更新和撤回时,区分事实来源与物化边;
  • 做模型评估和问题回放时,关联原文、Chunk、Schema 和配置版本。

自定义模型适配要求 ​

自定义 Parser 或模型适配器至少应保证:

  1. 缺失 entities 或 relations 时返回明确问题;
  2. 单个坏候选尽量隔离,不丢弃同一响应中的合法候选;
  3. 保留请求中的 documentId、chunkId 和 metadata;
  4. 不把 context 中的文字当作 evidence;
  5. 把未知 Schema 类型和非法端点交给 Validator;
  6. 保存足够的响应和版本信息,使结果可以回放。

下一步阅读 ​