知识图谱构建实战:从零到有的完整指南

这篇文章解决什么问题

知识图谱听起来高大上,到底怎么从一堆文档里构建出来?这篇文章手把手教你:从文本里抽实体、找关系、存到图数据库、最后怎么用。

前言:知识图谱是什么

先说个让我印象深刻的故事。

有一次我去图书馆找书,想了解”深度学习之父”是谁。如果用传统搜索,我得:

  1. 搜”深度学习之父”
  2. 看到答案”Geoffrey Hinton”
  3. 再搜Geoffrey Hinton
  4. 看到他的学生”Yoshua Bengio”
  5. 再搜Yoshua Bengio…

累不累?

但如果有个知识图谱,它早就知道:

  • Geoffrey Hinton是深度学习之父
  • 他在多伦多大学工作
  • 他的学生包括Yoshua Bengio、Alex Krizhevsky
  • 他们一起发明了AlexNet
  • AlexNet赢得了2012年ImageNet竞赛…

我只需要问”深度学习的发展历程”,图谱就能给我串起来。

这就是知识图谱的价值:把知识连成网,而不是散落的点。

一、知识图谱的核心概念

1.1 三个要素

实体(Entity):现实世界的事物

  • 人物:张三、李四
  • 组织:谷歌、清华大学
  • 概念:人工智能、机器学习
  • 产品:iPhone、GPT-4

关系(Relation):实体之间的联系

  • “张三 - 工作于 - 谷歌”
  • “机器学习 - 属于 - 人工智能”
  • “Yoshua Bengio - 师从 - Geoffrey Hinton”

属性(Property):实体的特征

  • 张三:年龄=30,职位=工程师
  • 谷歌:成立时间=1998,总部=加州

1.2 图的表示

实体 = 节点(Node)
关系 = 边(Edge)
属性 = 节点的标签或边的属性
# 简单的图表示
graph = {
    "nodes": [
        {"id": "张三", "type": "人物", "properties": {"职位": "工程师"}},
        {"id": "谷歌", "type": "组织", "properties": {"总部": "加州"}},
        {"id": "人工智能", "type": "概念", "properties": {}},
    ],
    "edges": [
        {"source": "张三", "target": "谷歌", "relation": "工作于"},
        {"source": "人工智能", "target": "机器学习", "relation": "包含"},
    ]
}

1.3 打个比方

想象你在经营一家侦探事务所:

传统文档像一堆散落的档案:

  • “张三在谷歌工作”
  • “谷歌是一家AI公司”
  • “AI是当下的热门技术”

知识图谱像一张关系网:

           AI
           /|\
          / | \
         /  |  \
    机器学习 |  深度学习
        /    \   |
       /      \  |
    深度学习  CNN
      |
      |
    [Geoffrey Hinton] --师从--> [他的学生]

看到区别了吧?图谱把知识串起来了。

二、知识图谱构建流程

2.1 整体流程

原始文档 → 文本预处理 → 实体抽取 → 关系抽取 → 实体链接 → 图谱构建 → 应用

2.2 每一步做什么

步骤输入输出关键技术
文本预处理原始文本分词、清洗后的文本NLP基础
实体抽取句子实体边界+类型NER
关系抽取句子+实体(主体, 关系, 客体)SPO抽取
实体链接实体 Mention标准化实体IDEntity Linking
图谱构建实体+关系图数据库图存储

三、实体抽取

3.1 什么是实体抽取

实体抽取(Named Entity Recognition, NER)就是从文本中找出:

  1. 实体在哪里(边界识别)
  2. 实体是什么(类型识别)

3.2 常用实体类型

类型例子
人物(PER)张三、乔布斯
组织(ORG)谷歌、清华大学
地点(LOC)北京、美国
时间(TIME)2023年、昨天
货币(MON)100美元、5000元
品牌(PRO)iPhone、GPT-4

3.3 使用LLM做实体抽取

async def extract_entities_with_llm(text, entity_types=None):
    """
    用LLM抽取实体
    """
    
    entity_types = entity_types or ["人物", "组织", "地点", "时间"]
    
    prompt = f"""
从以下文本中抽取实体,并以JSON格式返回:
 
文本:{text}
 
实体类型:{', '.join(entity_types)}
 
请以JSON格式返回:
{{
    "entities": [
        {{"text": "实体文本", "type": "实体类型", "start": 起始位置, "end": 结束位置}},
        ...
    ]
}}
"""
    
    result = await llm.generate(prompt)
    return json.loads(result)
 
# 使用示例
text = "2023年,张三和李四共同创立了深脑科技,总部位于北京。"
 
result = await extract_entities_with_llm(text)
# 输出:
# {
#     "entities": [
#         {"text": "2023年", "type": "时间", "start": 0, "end": 5},
#         {"text": "张三", "type": "人物", "start": 6, "end": 8},
#         {"text": "李四", "type": "人物", "start": 9, "end": 11},
#         {"text": "深脑科技", "type": "组织", "start": 16, "end": 20},
#         {"text": "北京", "type": "地点", "start": 26, "end": 28}
#     ]
# }

3.4 使用传统NER模型

from transformers import pipeline
 
# 加载中文NER模型
ner_pipeline = pipeline("ner", model="dslim/bert-base-NER", aggregation_strategy="simple")
 
def extract_entities_with_model(text):
    """用BERT模型抽取实体"""
    
    results = ner_pipeline(text)
    
    entities = []
    for result in results:
        # 映射到通用类型
        entity_type = map_entity_type(result["entity_group"])
        entities.append({
            "text": result["word"],
            "type": entity_type,
            "score": result["score"]
        })
    
    return entities
 
def map_entity_type(entity_group):
    """映射实体类型"""
    mapping = {
        "PER": "人物",
        "ORG": "组织",
        "LOC": "地点",
        "MISC": "其他"
    }
    return mapping.get(entity_group, "其他")

3.5 使用 spaCy(中文)

import spacy
 
# 加载中文模型
nlp = spacy.load("zh_core_web_sm")
 
def extract_entities_spacy(text):
    """用spaCy抽取实体"""
    
    doc = nlp(text)
    
    entities = []
    for ent in doc.ents:
        entities.append({
            "text": ent.text,
            "type": ent.label_,
            "start": ent.start_char,
            "end": ent.end_char
        })
    
    return entities
 
# 使用
text = "张三和李四创办了深脑科技,总部在北京。"
entities = extract_entities_spacy(text)
print(entities)
# [{'text': '张三', 'type': 'PERSON', 'start': 0, 'end': 2},
#  {'text': '李四', 'type': 'PERSON', 'start': 3, 'end': 5},
#  {'text': '深脑科技', 'type': 'ORG', 'start': 8, 'end': 12},
#  {'text': '北京', 'type': 'GPE', 'start': 16, 'end': 18}]

四、关系抽取

4.1 什么是关系抽取

关系抽取就是找出实体之间的关系,输出三元组(SPO):

  • Subject(主语)
  • Predicate(谓语/关系)
  • Object(宾语)

4.2 常用关系类型

关系类型说明例子
工作于人物-组织张三-工作于-谷歌
师从人物-人物李四-师从-王教授
创立人物-组织马云-创立-阿里巴巴
位于组织-地点谷歌-位于-加州
属于下位-上位机器学习-属于-AI
成立于组织-时间谷歌-成立于-1998

4.3 使用LLM做关系抽取

async def extract_relations_with_llm(text, entities, relation_types=None):
    """
    用LLM抽取关系
    """
    
    relation_types = relation_types or [
        "工作于", "创立", "位于", "师从", "属于", 
        "合作", "竞争", "使用", "开发"
    ]
    
    # 构建实体列表
    entity_list = "\n".join([
        f"- {e['text']}{e['type']})" 
        for e in entities
    ])
    
    prompt = f"""
从以下文本中抽取实体之间的关系:
 
文本:{text}
 
已识别的实体:
{entity_list}
 
关系类型:{', '.join(relation_types)}
 
请抽取所有存在的关系,返回JSON:
{{
    "relations": [
        {{"subject": "主体", "predicate": "关系", "object": "客体"}},
        ...
    ]
}}
 
如果没有发现关系,返回空列表。
"""
    
    result = await llm.generate(prompt)
    return json.loads(result)
 
# 使用示例
text = "2023年,张三和李四共同创立了深脑科技,致力于人工智能研究。"
entities = [
    {"text": "张三", "type": "人物"},
    {"text": "李四", "type": "人物"},
    {"text": "深脑科技", "type": "组织"}
]
 
result = await extract_relations_with_llm(text, entities)
# 输出:
# {
#     "relations": [
#         {"subject": "张三", "predicate": "创立", "object": "深脑科技"},
#         {"subject": "李四", "predicate": "创立", "object": "深脑科技"},
#         {"subject": "张三", "predicate": "合作", "object": "李四"}
#     ]
# }

4.4 开放域关系抽取

如果没有预定义关系类型,可以用开放域抽取:

async def open_relation_extraction(text):
    """
    开放域关系抽取
    不限定关系类型,自动发现
    """
    
    prompt = f"""
从以下文本中抽取所有实体之间的关系,不要限定关系类型:
 
文本:{text}
 
请以JSON格式返回所有发现的关系:
{{
    "relations": [
        {{"subject": "主体", "predicate": "关系", "object": "客体"}},
        ...
    ]
}}
"""
    
    result = await llm.generate(prompt)
    return json.loads(result)

4.5 关系抽取模板

对于结构化文本,可以用模板匹配:

import re
 
# 定义关系抽取模板
RELATION_PATTERNS = {
    "工作于": [
        r"(\w+)[是在](\w+)[工作|任职|担任]",
        r"(\w+)的CEO是(\w+)",
    ],
    "创立": [
        r"(\w+)创立了(\w+)",
        r"(\w+)创办了(\w+)",
    ],
    "位于": [
        r"(\w+)位于(\w+)",
        r"(\w+)总部在(\w+)",
    ]
}
 
def extract_relations_with_patterns(text):
    """用模板匹配抽取关系"""
    
    relations = []
    
    for relation_type, patterns in RELATION_PATTERNS.items():
        for pattern in patterns:
            matches = re.finditer(pattern, text)
            for match in matches:
                relations.append({
                    "subject": match.group(1),
                    "predicate": relation_type,
                    "object": match.group(2)
                })
    
    return relations
 
# 使用
text = "张三在谷歌工作,他是谷歌的联合创始人。"
relations = extract_relations_with_patterns(text)
# [{'subject': '张三', 'predicate': '工作于', 'object': '谷歌'}]

五、实体链接

5.1 什么是实体链接

实体链接就是把文本中的实体Mention(提到)链接到知识库中的标准实体:

"深度学习之父" → Geoffrey Hinton(标准化实体)

5.2 为什么要实体链接

避免同一个实体有多种表达:

Mention(文本)标准实体
Geoffrey HintonGeoffrey Hinton
HintonGeoffrey Hinton
深度学习之父Geoffrey Hinton
图灵奖得主HintonGeoffrey Hinton

5.3 实体链接实现

class EntityLinker:
    """实体链接器"""
    
    def __init__(self, knowledge_base):
        """
        knowledge_base: 已知实体库,格式:
        {
            "实体ID": {"name": "名称", "aliases": ["别名1", "别名2"], ...}
        }
        """
        self.kb = knowledge_base
    
    def link(self, mention, context=None, candidates=None):
        """
        将Mention链接到标准实体
        
        返回:{"entity_id": "xxx", "confidence": 0.9}
        """
        
        # 1. 候选实体生成
        if candidates is None:
            candidates = self._generate_candidates(mention)
        
        if not candidates:
            return {"entity_id": None, "confidence": 0.0}
        
        # 2. 候选排序
        scored_candidates = []
        for entity_id in candidates:
            score = self._calculate_score(mention, entity_id, context)
            scored_candidates.append((entity_id, score))
        
        # 3. 选择最佳匹配
        scored_candidates.sort(key=lambda x: x[1], reverse=True)
        
        best_entity, best_score = scored_candidates[0]
        
        return {
            "entity_id": best_entity,
            "confidence": best_score
        }
    
    def _generate_candidates(self, mention):
        """生成候选实体"""
        
        candidates = []
        
        for entity_id, entity_info in self.kb.items():
            # 检查名称匹配
            if mention in entity_info.get("name", ""):
                candidates.append(entity_id)
            # 检查别名匹配
            for alias in entity_info.get("aliases", []):
                if mention in alias:
                    candidates.append(entity_id)
                    break
        
        return candidates
    
    def _calculate_score(self, mention, entity_id, context):
        """计算链接分数"""
        
        entity_info = self.kb[entity_id]
        
        # 名称相似度
        name = entity_info.get("name", "")
        name_score = self._string_similarity(mention, name)
        
        # 别名匹配
        alias_score = 0.0
        for alias in entity_info.get("aliases", []):
            if mention == alias:
                alias_score = 1.0
                break
            elif self._string_similarity(mention, alias) > 0.8:
                alias_score = 0.8
                break
        
        # 上下文匹配(如果有)
        context_score = 0.0
        if context:
            entity_desc = entity_info.get("description", "")
            context_score = self._context_similarity(context, entity_desc)
        
        # 综合分数
        final_score = name_score * 0.5 + alias_score * 0.3 + context_score * 0.2
        
        return final_score
    
    def _string_similarity(self, s1, s2):
        """字符串相似度(简单实现)"""
        if s1 == s2:
            return 1.0
        if s1 in s2 or s2 in s1:
            return 0.8
        # 可以用更复杂的算法如编辑距离
        return 0.0
    
    def _context_similarity(self, context, description):
        """上下文相似度"""
        # 简化实现
        common_words = set(context) & set(description)
        if not common_words:
            return 0.0
        return len(common_words) / max(len(set(context)), len(set(description)))

六、图谱构建与存储

6.1 选择图数据库

数据库特点适用场景
Neo4j功能强大,生态好通用场景
Neo4j Aura云托管快速上手
Amazon NeptuneAWS集成云原生
TigerGraph高性能大规模图
腾讯图数据库国产,优化好国内业务

6.2 使用Neo4j存储图谱

from neo4j import GraphDatabase
 
class KnowledgeGraph:
    """知识图谱管理器"""
    
    def __init__(self, uri, user, password):
        self.driver = GraphDatabase.driver(uri, auth=(user, password))
    
    def close(self):
        self.driver.close()
    
    def create_entity(self, entity_id, entity_type, properties=None):
        """创建实体节点"""
        
        properties = properties or {}
        props_str = ", ".join([f"{k}: '${k}'" for k in properties.keys()])
        
        cypher = f"""
        CREATE (e:{entity_type} {{id: '{entity_id}', {props_str}}})
        """
        
        # 设置属性值
        with self.driver.session() as session:
            session.run(cypher, **properties)
    
    def create_relation(self, subject_id, predicate, object_id):
        """创建关系"""
        
        cypher = f"""
        MATCH (s {{id: '{subject_id}'}})
        MATCH (o {{id: '{object_id}'}})
        CREATE (s)-[r:{predicate}]->(o)
        """
        
        with self.driver.session() as session:
            session.run(cypher)
    
    def create_triple(self, subject_id, predicate, object_id, s_props=None, o_props=None):
        """创建三元组(实体+关系)"""
        
        s_props = s_props or {}
        o_props = o_props or {}
        
        # 创建节点
        if s_props:
            self.create_entity(subject_id, s_props.get("type", "Entity"), s_props)
        if o_props:
            self.create_entity(object_id, o_props.get("type", "Entity"), o_props)
        
        # 创建关系
        self.create_relation(subject_id, predicate, object_id)
    
    def query(self, cypher):
        """执行查询"""
        
        with self.driver.session() as session:
            result = session.run(cypher)
            return [dict(record) for record in result]
    
    def get_neighbors(self, entity_id, depth=1):
        """获取实体的邻居"""
        
        cypher = f"""
        MATCH (e {{id: '{entity_id}'}})-[r]-(neighbor)
        RETURN neighbor, r
        """
        
        return self.query(cypher)
    
    def find_path(self, start_id, end_id, max_depth=5):
        """查找两个实体之间的路径"""
        
        cypher = f"""
        MATCH path = shortestPath((s {{id: '{start_id}'}})-[*1..{max_depth}]-(e {{id: '{end_id}'}}))
        RETURN path
        """
        
        return self.query(cypher)

6.3 批量导入图谱

async def bulk_import_graph(triples, kg):
    """
    批量导入三元组
    
    triples格式:
    [
        {"subject": "张三", "predicate": "工作于", "object": "谷歌"},
        ...
    ]
    """
    
    for triple in triples:
        try:
            kg.create_triple(
                subject_id=triple["subject"],
                predicate=triple["predicate"],
                object_id=triple["object"],
                s_props=triple.get("subject_props"),
                o_props=triple.get("object_props")
            )
        except Exception as e:
            print(f"导入失败: {triple}, 错误: {e}")
    
    print(f"成功导入 {len(triples)} 条三元组")

6.4 实际应用示例

# 初始化
kg = KnowledgeGraph("bolt://localhost:7687", "neo4j", "password")
 
# 导入数据
triples = [
    {"subject": "Geoffrey Hinton", "predicate": "被称为", "object": "深度学习之父"},
    {"subject": "Geoffrey Hinton", "predicate": "工作于", "object": "多伦多大学"},
    {"subject": "Geoffrey Hinton", "predicate": "师从", "object": "Christopher Bishop"},
    {"subject": "Yoshua Bengio", "predicate": "工作于", "object": "蒙特利尔大学"},
    {"subject": "Yoshua Bengio", "predicate": "合作", "object": "Geoffrey Hinton"},
    {"subject": "Alex Krizhevsky", "predicate": "合作", "object": "Geoffrey Hinton"},
    {"subject": "AlexNet", "predicate": "发明者", "object": "Alex Krizhevsky"},
    {"subject": "AlexNet", "predicate": "发明者", "object": "Geoffrey Hinton"},
    {"subject": "AlexNet", "predicate": "发表于", "object": "2012"},
]
 
await bulk_import_graph(triples, kg)
 
# 查询:谁被称为深度学习之父?
result = kg.query("""
    MATCH (e)-[r:被称为]->(d {id: '深度学习之父'})
    RETURN e.id
""")
# 结果:[{'e.id': 'Geoffrey Hinton'}]
 
# 查询:Hinton的学生有哪些?
result = kg.query("""
    MATCH (s)-[r:合作|师从]->(e {id: 'Geoffrey Hinton'})
    RETURN s.id, type(r)
""")
 
# 查询:Geoffrey Hinton和Yoshua Bengio的关系
result = kg.find_path("Geoffrey Hinton", "Yoshua Bengio")
# 返回两点之间的关系路径
 
kg.close()

七、知识图谱应用

7.1 问答系统

async def kg_qa(question, kg, llm):
    """
    基于知识图谱的问答
    """
    
    # 1. 抽取问题中的实体
    entities = await extract_entities_with_llm(question)
    
    if not entities:
        return "抱歉,没有找到问题中的实体"
    
    # 2. 链接到图谱
    linker = EntityLinker({})  # 假设已有知识库
    main_entity = linker.link(entities[0]["text"])["entity_id"]
    
    if not main_entity:
        return "抱歉,知识库中没有相关信息"
    
    # 3. 探索邻居
    neighbors = kg.get_neighbors(main_entity)
    
    # 4. 生成回答
    context = "\n".join([f"{n['s.id']} --{n['r']}--> {n['o.id']}" 
                         for n in neighbors])
    
    answer = await llm.generate(f"""
基于以下知识图谱信息回答问题:
 
问题:{question}
 
相关知识:
{context}
 
请根据知识图谱信息回答问题。
""")
    
    return answer

7.2 关系推理

def infer_relations(kg, entity_id):
    """
    推断实体可能的未知关系
    """
    
    # 1. 获取直接关系
    direct_relations = kg.query(f"""
        MATCH (e {{id: '{entity_id}'}})-[r]-(neighbor)
        RETURN type(r) as relation, neighbor.id as entity
    """)
    
    # 2. 获取二跳关系
    two_hop_relations = kg.query(f"""
        MATCH (e {{id: '{entity_id}'}})-[r1]-(n1)-[r2]-(n2)
        WHERE n2 <> e
        RETURN n1.id as intermediate, type(r1) as r1_type, 
               type(r2) as r2_type, n2.id as end_entity
    """)
    
    # 3. 推断传递关系
    # 例如:A工作于X,B工作于X → A和B可能是同事
    
    return {
        "direct": direct_relations,
        "two_hop": two_hop_relations
    }

八、实战:构建企业知识图谱

8.1 场景

假设我们要构建一个”公司-人物-产品”知识图谱:

数据来源:
- 公司介绍文档
- 员工介绍文档
- 产品介绍文档

8.2 完整代码

import asyncio
import json
from typing import List, Dict
from neo4j import GraphDatabase
 
class EnterpriseKnowledgeGraphBuilder:
    """
    企业知识图谱构建器
    """
    
    def __init__(self, llm, kg: KnowledgeGraph):
        self.llm = llm
        self.kg = kg
    
    async def build_from_documents(self, documents: List[Dict]):
        """
        从文档构建知识图谱
        
        documents格式:
        [{"type": "company"|"person"|"product", "content": "..."}, ...]
        """
        
        all_triples = []
        
        for doc in documents:
            triples = await self._process_document(doc)
            all_triples.extend(triples)
        
        # 去重
        unique_triples = self._deduplicate_triples(all_triples)
        
        # 导入图谱
        await self._import_to_graph(unique_triples)
        
        return unique_triples
    
    async def _process_document(self, doc: Dict) -> List[Dict]:
        """处理单个文档"""
        
        content = doc["content"]
        doc_type = doc["type"]
        
        # 1. 抽取实体
        entities = await extract_entities_with_llm(content, 
            ["人物", "组织", "产品", "地点", "时间"])
        
        # 2. 抽取关系
        relations = await extract_relations_with_llm(content, entities)
        
        # 3. 构建三元组
        triples = []
        
        # 添加实体
        for entity in entities:
            triples.append({
                "type": "entity",
                "id": entity["text"],
                "entity_type": self._map_entity_type(entity["type"], doc_type)
            })
        
        # 添加关系
        for relation in relations:
            triples.append({
                "type": "relation",
                "subject": relation["subject"],
                "predicate": relation["predicate"],
                "object": relation["object"]
            })
        
        return triples
    
    def _map_entity_type(self, ner_type: str, doc_type: str) -> str:
        """映射实体类型"""
        
        mapping = {
            ("人物", "person"): "Person",
            ("人物", "company"): "Person",
            ("组织", "company"): "Company",
            ("组织", "product"): "Product",
            ("产品", _): "Product",
            ("地点", _): "Location",
            ("时间", _): "Time",
        }
        
        return mapping.get((ner_type, doc_type), "Entity")
    
    def _deduplicate_triples(self, triples: List[Dict]) -> List[Dict]:
        """三元组去重"""
        
        seen = set()
        unique = []
        
        for triple in triples:
            if triple["type"] == "entity":
                key = f"entity:{triple['id']}"
            else:
                key = f"relation:{triple['subject']}:{triple['predicate']}:{triple['object']}"
            
            if key not in seen:
                seen.add(key)
                unique.append(triple)
        
        return unique
    
    async def _import_to_graph(self, triples: List[Dict]):
        """导入到图数据库"""
        
        entities = [t for t in triples if t["type"] == "entity"]
        relations = [t for t in triples if t["type"] == "relation"]
        
        # 创建实体
        for entity in entities:
            try:
                self.kg.create_entity(
                    entity_id=entity["id"],
                    entity_type=entity.get("entity_type", "Entity"),
                    properties={"source": "document"}
                )
            except:
                pass  # 已存在则忽略
        
        # 创建关系
        for relation in relations:
            try:
                self.kg.create_relation(
                    subject_id=relation["subject"],
                    predicate=relation["predicate"],
                    object_id=relation["object"]
                )
            except Exception as e:
                print(f"关系创建失败: {relation}, {e}")
 
 
# 使用示例
async def main():
    # 初始化
    kg = KnowledgeGraph("bolt://localhost:7687", "neo4j", "password")
    builder = EnterpriseKnowledgeGraphBuilder(llm=your_llm, kg=kg)
    
    # 准备文档
    documents = [
        {
            "type": "company",
            "content": """
            深脑科技成立于2023年,由张三和李四共同创立。
            张三担任CEO,李四担任CTO。
            公司总部位于北京,主要产品包括AI助手和知识图谱系统。
            """
        },
        {
            "type": "person",
            "content": """
            张三,35岁,深脑科技创始人兼CEO。
            曾在谷歌工作10年,师从著名AI专家王教授。
            2023年与李四一起创立深脑科技。
            """
        },
        {
            "type": "product",
            "content": """
            AI助手是深脑科技的核心产品。
            使用深度学习技术,可以回答用户问题。
            知识图谱系统帮助AI理解实体之间的关系。
            """
        }
    ]
    
    # 构建图谱
    triples = await builder.build_from_documents(documents)
    
    print(f"构建完成!共导入 {len(triples)} 个元素")
    
    # 查询验证
    result = kg.query("""
        MATCH (p:Person)-[r]->(c:Company)
        RETURN p.id, type(r), c.id
    """)
    print("人物-公司关系:", result)
    
    kg.close()
 
# 运行
asyncio.run(main())

九、常见问题

9.1 实体抽取不准怎么办

问题:NER模型经常抽错或漏抽

解决方案

  • 使用更大的模型(如RoBERTa)
  • 针对领域微调
  • 人工审核+规则补充

9.2 关系抽取噪音多

问题:抽出一堆不相关的关系

解决方案

  • 限定关系类型
  • 设置置信度阈值
  • 后处理过滤

9.3 图数据库性能差

问题:节点太多查询慢

解决方案

  • 建立索引
  • 分层存储
  • 图分区

十、总结

知识图谱构建的核心步骤

  1. 实体抽取:找出文本中的实体
  2. 关系抽取:找出实体间的关系
  3. 实体链接:统一实体的不同表达
  4. 图谱存储:存到图数据库
  5. 应用查询:支持问答和推理

实战建议

  • 先用LLM快速验证可行性
  • 效果稳定后考虑模型优化
  • 图数据库选型要匹配规模

记住:知识图谱的价值在于”连”,把知识连成网才能发挥最大威力。

相关主题


更新记录

  • 2026-04-24:改写完成,语言风格优化
  • 增加完整的图谱构建实战代码