使用 LLM 为文档构建实时知识图谱

2025年4月29日 · 阅读时长 7 分钟 Linghua Jin Linghua Jin Building Knowledge Graph for Documents with LLM 借助持续的源更新,构建和维护知识图谱变得非常容易。在本博客中,我们将处理一系列文档(以 CocoIndex 文档为例)。我们将使用 LLM 提取每个文档中概念之间的关系。我们将生成两种关系:

  1. 主体和对象之间的关系。例如,“CocoIndex 支持 Incremental Processing”
  2. 文档中实体的提及。例如,“core/basics.mdx”提到了 CocoIndexIncremental Processing

源代码可在 CocoIndex Examples - docs_to_knowledge_graph 中找到。 Example knowledge graph showing relationships between concepts in CocoIndex documentation 我们正在不断改进,更多功能和示例即将推出。请继续关注并通过为我们的 GitHub repo 加星标来关注我们的进展。

前提条件

文档

您可以在 此处 阅读有关 Property Graph Targets 的官方 CocoIndex 文档。

构建知识图谱的数据流

Data Flow

添加文档作为源

我们将处理来自 docs/core 目录的 CocoIndex 文档 markdown 文件(.md.mdx)(markdown 文件,[已部署的文档](https://cocoindex.io/blogs/knowledge-graph-for-docs/https:/cocoindex.io/docs/core/basics))。

@cocoindex.flow_def(name="DocsToKG")defdocs_to_kg_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope):  data_scope["documents"]= flow_builder.add_source(    cocoindex.sources.LocalFile(path="../../docs/docs/core",                  included_patterns=["*.md","*.mdx"]))

这里,flow_builder.add_source 创建一个 KTablefilename 是 KTable 的键。 Adding a source to the flow

添加数据收集器

在根范围添加收集器:

document_node = data_scope.add_collector()entity_relationship = data_scope.add_collector()entity_mention = data_scope.add_collector()

处理每个文档并提取摘要

定义一个 DocumentSummary 数据类来提取文档的摘要。

@dataclasses.dataclassclassDocumentSummary:  title:str  summary:str

在流程中,使用 cocoindex.functions.ExtractByLlm 进行结构化输出。

with data_scope["documents"].row()as doc:  doc["summary"]= doc["content"].transform(      cocoindex.functions.ExtractByLlm(        llm_spec=cocoindex.LlmSpec(          api_type=cocoindex.LlmApiType.OPENAI, model="gpt-4o"),        output_type=DocumentSummary,        instruction="Please summarize the content of the document."))  document_node.collect(    filename=doc["filename"], title=doc["summary"]["title"],    summary=doc["summary"]["summary"])

doc["summary"] 向 KTable data_scope["documents"] 添加一个新列。 Adding summary to the each document

使用 LLM 从文档中提取关系

定义一个数据类来表示 LLM 提取的关系。

@dataclasses.dataclassclassRelationship:"""  Describe a relationship between two entities.  Subject and object should be Core CocoIndex concepts only, should be nouns. For example, `CocoIndex`, `Incremental Processing`, `ETL`, `Data` etc.  """  subject:str  predicate:strobject:str

该数据类定义了知识图谱关系。我们建议在类级别的文档字符串中放置详细的说明,以帮助 LLM 正确提取关系。

这种结构表示诸如“CocoIndex 支持 Incremental Processing”之类的事实。其图形表示形式为: Presentation of a relationship in a knowledge graph 接下来,我们将使用 cocoindex.functions.ExtractByLlm 从文档中提取关系。

doc["relationships"]= doc["content"].transform(  cocoindex.functions.ExtractByLlm(    llm_spec=cocoindex.LlmSpec(      api_type=cocoindex.LlmApiType.OPENAI,      model="gpt-4o"),    output_type=list[Relationship],    instruction=("Please extract relationships from CocoIndex documents. ""Focus on concepts and ignore examples and code. ")))

doc["relationships"] 向每个文档添加一个新字段 relationshipsoutput_type=list[Relationship] 指定转换的输出是一个 LTableAdding relationships to each document

收集关系

with doc["relationships"].row()as relationship:# relationship between two entities  entity_relationship.collect(id=cocoindex.GeneratedField.UUID,    subject=relationship["subject"],object=relationship["object"],    predicate=relationship["predicate"],)# mention of an entity in a document, for subject  entity_mention.collect(id=cocoindex.GeneratedField.UUID, entity=relationship["subject"],    filename=doc["filename"],)# mention of an entity in a document, for object  entity_mention.collect(id=cocoindex.GeneratedField.UUID, entity=relationship["object"],    filename=doc["filename"],)

构建知识图谱

基本概念

Neo4j 的所有节点都需要两件事:

  1. 标签:节点的类型。例如,DocumentEntity
  2. 主键字段:唯一标识节点的字段。例如,Document 节点的 filename

CocoIndex 使用主键字段来匹配节点并对其进行重复数据删除。如果您有多个具有相同主键的节点,CocoIndex 只保留其中一个。 Deduplication of nodes with the same primary key 有两种方法可以映射节点:

  1. 当您有一个仅用于节点的收集器时,您可以将其直接导出到 Neo4j。
  2. 当您有一个用于连接到节点的关系的收集器时,您可以从关系收集器中的选定字段映射节点。您必须声明节点标签和主键字段。

配置 Neo4j 连接:

conn_spec = cocoindex.add_auth_entry("Neo4jConnection",  cocoindex.storages.Neo4jConnection(    uri="bolt://localhost:7687",    user="neo4j",    password="cocoindex",))

Document 节点导出到 Neo4j

Exporting document nodes to Neo4j

document_node.export("document_node",  cocoindex.storages.Neo4j(    connection=conn_spec,    mapping=cocoindex.storages.Nodes(label="Document")),  primary_key_fields=["filename"],)

这将从 document_node 收集器导出带有标签 Document 的 Neo4j 节点。

RELATIONSHIPEntity 节点导出到 Neo4j

Exporting relationships and entities to Neo4j

我们没有 Entity 节点的显式收集器。它们是 entity_relationship 收集器的一部分,并且字段在关系提取期间收集。 要将它们导出为 Neo4j 节点,我们需要首先声明 Entity 节点。

flow_builder.declare(  cocoindex.storages.Neo4jDeclaration(    connection=conn_spec,    nodes_label="Entity",    primary_key_fields=["value"],))

接下来,将 entity_relationship 导出到 Neo4j。

entity_relationship.export("entity_relationship",  cocoindex.storages.Neo4j(    connection=conn_spec,    mapping=cocoindex.storages.Relationships(      rel_type="RELATIONSHIP",      source=cocoindex.storages.NodeFromFields(        label="Entity",        fields=[          cocoindex.storages.TargetFieldMapping(            source="subject", target="value"),]),      target=cocoindex.storages.NodeFromFields(        label="Entity",        fields=[          cocoindex.storages.TargetFieldMapping(            source="object", target="value"),]),),),  primary_key_fields=["id"],))

cocoindex.storages.Relationships 声明如何在 Neo4j 中映射关系。

在一个关系中,有:

  1. 一个源节点和一个目标节点。
  2. 连接源和目标的关系。请注意,不同的关系可能共享相同的源和目标节点。

NodeFromFieldsentity_relationship 收集器中获取字段并创建 Entity 节点。

entity_mention 导出到 Neo4j。

Exporting entity mention to Neo4j

entity_mention.export("entity_mention",  cocoindex.storages.Neo4j(    connection=conn_spec,    mapping=cocoindex.storages.Relationships(      rel_type="MENTION",      source=cocoindex.storages.NodesFromFields(        label="Document",        fields=[cocoindex.storages.TargetFieldMapping("filename")],),      target=cocoindex.storages.NodesFromFields(        label="Entity",        fields=[cocoindex.storages.TargetFieldMapping(          source="entity", target="value")],),),),  primary_key_fields=["id"],)

同样,我们在这里使用 cocoindex.storages.Relationshipsentity_mention 导出到 Neo4j 关系。它通过以下方式创建关系:

主函数

最后,流的主函数初始化 CocoIndex 流并运行它。

@cocoindex.main_fn()def_run():passif __name__ =="__main__":  load_dotenv(override=True)  _run()

查询和测试你的索引

🎉 现在一切都已设置完毕!

  1. 安装依赖项:
pip install -e .
  1. 运行以下命令来设置和更新索引。
python main.py cocoindex setuppython main.py cocoindex update

您将在终端中看到索引更新状态。例如,您将看到以下输出:

documents: 7 added, 0 removed, 0 updated
  1. (可选) 我使用 CocoInsight 来解决索引生成问题并了解管道的数据沿袭。它现在处于免费 Beta 版中,您可以尝试一下。运行以下命令来启动 CocoInsight:
python3 main.py cocoindex server -c https://cocoindex.io

然后打开 url https://cocoindex.io/cocoinsight。它只是连接到您的本地 CocoIndex 服务器,零管道数据保留。 CocoInsight

浏览知识图谱

构建知识图谱后,您可以在 Neo4j Browser 中浏览您构建的知识图谱。 对于开发环境,您可以使用以下凭据连接到 Neo4j browser:

您可以在 http://localhost:7474 打开它,并运行以下 Cypher 查询以获取所有关系:

MATCH p=()-->() RETURN p

Neo4j Browser for CocoIndex Docs

支持我们

我们正在不断改进,更多功能和示例即将推出。如果您喜欢这篇文章,请在 GitHub repo 上给我们一个星标 ⭐ 来帮助我们成长。 感谢阅读!

标签: