引言
在工业领域,大量专业知识散落在设备手册、维修报告、故障日志等非结构化文本中。传统方法难以高效地从这些海量文档中提取有用信息并组织成可计算的知识。随着大语言模型(LLM)的发展,利用LLM进行信息抽取成为新的趋势。谷歌开源的 LangExtract库正是为此而设计的框架,它结合LLM强大的语言理解能力,从非结构化文本中提取结构化信息,被广泛用于工业故障诊断、设备维护等场景。
LangExtract 的核心优势在于其独特的架构,如下图所示,它将 Schema 驱动的抽取流程与多种 LLM 提供程序无缝集成,从而实现了高效、可靠的信息提取。

本文将介绍如何利用 LangExtract 结合本地部署的大模型(如 Ollama),从工业文本中抽取知识,并通过实体对齐、去重,将结果存储到 Neo4j 图数据库,最后使用 Pyvis 进行知识图谱的可视化。我们将结合 工业设备故障诊断与维修这一典型场景,提供从数据准备到最终可视化的完整代码示例和图示说明。
一、系统原型展现
为了增加读者的感性认识,先把本系统实现的界面展示一下,方便大家理解后面的拆解。
- 利用 LangExtract抽取知识图谱后,基于PyVis实现的可视化web界面:

- 利用 LangExtract抽取知识图谱后,基于Cytoscape.js实现的交互式知识图谱可视化Web应用:

- 利用 LangExtract抽取知识图谱:

二、技术选型与方案设计
-
LangExtract 信息抽取框架:LangExtract 是 Google 于2025年开源的指令式信息抽取框架,可同时兼容多种 LLM 模型,包括云端的 Google Gemini、OpenAI 模型,以及本地的 Ollama 模型。它通过“分块+并行+多遍扫描”的策略优化长文档处理,提高信息召回率,并确保每个抽取结果都有明确的原文出处(精确溯源)。LangExtract 采用 Schema 驱动的方式,只需提供少量示例和清晰的提示,即可让 LLM 按照指定格式输出结构化信息,避免了传统方法对大量标注数据的依赖。其“Few-Shot 示例引导”机制允许用户通过一两个高质量标注示例教会模型期望的输出格式。这些特性使 LangExtract 非常适合工业场景下复杂文本的信息抽取,在灵活性、准确性和可追溯性之间取得了平衡。
-
Ollama 本地大模型:为了在企业内部部署且避免对外部API的依赖,我们选择 Ollama 来提供本地的大语言模型服务。Ollama 是一个开源项目,可在本地轻松部署各种预训练大模型(如 LLaMA2 等)。LangExtract 内置了对 Ollama 的支持,通过OllamaLanguageModel接口与 Ollama 服务器通信。使用本地模型不仅降低了调用成本,也确保数据不出内网,满足企业数据安全要求。在本方案中,我们将使用 Ollama 加载一个适合中文工业场景的大模型(例如本地化的 LLaMA2 变种),供 LangExtract 调用完成信息抽取。
-
Neo4j 图数据库:知识图谱通常以图结构存储,Neo4j 是当前最流行的开源图数据库之一。选择 Neo4j 的原因在于其灵活的图数据模型和强大的图查询能力,适合表示工业设备、故障、原因、维修措施等实体及其复杂关系。Neo4j 使用 Cypher 查询语言,可以方便地进行路径查找、关联分析等操作,非常契合故障诊断中“查找可能原因”“追溯维修历史”等需求。此外,Neo4j 提供了完善的事务支持和企业级特性,适合作为工业知识图谱的存储和管理平台。在本方案中,我们将把 LangExtract 抽取得到的实体和关系导入 Neo4j,构建工业故障知识图谱。
-
Pyvis 可视化工具:为了将知识图谱直观地呈现出来,我们采用 Pyvis 库进行交互式可视化。Pyvis 是一个基于 Python 的网络可视化工具,它封装了强大的 Vis.js JavaScript 库,使我们能够通过少量代码生成动态的交互式网络图。Pyvis 生成的 HTML 图表支持节点拖拽、缩放、悬停提示等交互功能,方便用户探索复杂的知识关系。在本方案中,我们将利用 Pyvis 将 Neo4j 中的知识图谱渲染成交互式网页,实现对故障知识的可视化浏览和分析。
-
方案整体流程:综合以上技术,我们设计了从原始文本到知识图谱的完整流程,如下图所示。整个流程包括信息抽取、知识融合、知识存储和知识可视化四个主要阶段。

首先,使用 LangExtract 结合本地 Ollama 模型从工业文本中抽取结构化的实体和关系;然后,对抽取结果进行实体对齐和去重,解决同一实体不同表述的问题;接下来,将清洗后的知识存入 Neo4j 图数据库;最后,利用 Pyvis 将知识图谱进行可视化展示。下面我们将分步骤详细介绍各环节的实现。
三、工业故障诊断场景与数据准备
场景描述假设我们有一个工业企业,积累了大量设备故障维修方面的文档资料,包括设备操作手册、故障报告、维修日志等。这些资料以 PDF、Word 或纯文本形式存在,属于非结构化数据。工程师在遇到设备故障时,往往需要翻阅多份文档查找类似故障的原因和解决办法。我们的目标是从这些文档中自动提取知识,构建一个 工业故障诊断知识图谱,使得当新的故障发生时,可以通过图谱快速定位可能的原因和处理措施。
数据示例:我们选取几篇具有代表性的文本作为输入数据:
设备手册片段:例如某离心泵的维护手册中关于常见故障的描述。如:“离心泵常见故障包括无法启动、流量不足和异常振动等。无法启动可能由电机故障或电源问题导致;流量不足通常由于叶轮堵塞或入口阀门未全开引起。”
故障报告单:例如某次故障的记录。如:“2025年9月10日,P-101离心泵出现出口压力下降20%并伴随异常振动的现象。经检查,发现叶轮被异物堵塞。处理措施为停机并清理叶轮异物。”
维修日志:记录历史维修情况。如:“2025年8月15日,V-201反应釜机械密封泄漏,紧固法兰螺栓后泄漏停止。”
以上文本涵盖了故障现象、可能原因、处理措施以及时间、设备名称等信息。我们需要从中抽取 实体(如设备、故障现象、原因、措施等)以及实体之间的 关系(如“导致”、“采取措施”等)。
数据预处理:在将文本输入 LangExtract 之前,需要进行必要的预处理:
-
文本提取:对于 PDF、Word 等格式的文档,使用相应的库将其转换为纯文本。例如使用 PyPDF2 提取 PDF 文本,或使用 python-docx 读取 Word 文档内容。确保提取后的文本段落清晰、无乱码。
-
分段与清洗:将长文档按逻辑段落或章节拆分,方便后续分块处理。同时去除无关内容(如页眉页脚、广告等),过滤特殊字符和空白行。对提取的文本进行编码转换和规范化(如统一为 UTF-8 编码,全角转半角等)。
-
保存输入:将处理后的文本保存为若干 .txt 文件或一个大文本,作为 LangExtract 的输入。可以根据需要将不同来源的文本分开处理,以便后续区分知识来源。
完成数据准备后,我们进入信息抽取阶段,利用 LangExtract 和本地模型从这些文本中提取结构化知识。
四、信息抽取:使用LangExtract与Ollama提取知识
- LangExtract 安装与配置:首先安装 LangExtract 库。可以使用 pip 直接安装最新版本:
pip install langextract
安装完成后,需要配置 LangExtract 使用本地的 Ollama 模型。LangExtract 默认支持 Google Gemini 等云端模型,但我们可以通过添加自定义 Provider 来接入 Ollama。LangExtract 内置了OllamaLanguageModel类,通过 HTTP API 与 Ollama 服务器通信。确保 Ollama 已在本地启动并加载了所需模型(例如模型名为QWen3:8B)。Ollama 默认运行在http://localhost:11434,我们需要在代码中指定该地址。
- 定义抽取模式(Schema):在开始抽取前,我们需要明确希望从文本中提取哪些信息,即定义目标 Schema。LangExtract 允许我们通过定义 Python 数据类(如使用 Pydantic 模型)来精确描述要抽取的实体类型及其属性。针对工业故障场景,我们定义如下数据结构:
- FaultInfo(故障信息):描述一次设备故障的详细信息,包含属性:设备名称、故障现象、可能原因、解决措施。
- FaultReport(故障报告):包含一份报告中抽取的故障信息列表。
用 Python 代码定义这些类(使用 dataclass 或 Pydantic 均可):
from dataclasses import dataclass, fieldfrom typing import List, Optional@dataclassclass FaultInfo: """描述一次设备故障的详细信息。""" equipment_name: Optional[str] = field(default=None, metadata={"description": "发生故障的设备名称,例如 'P-101 离心泵'"}) phenomenon: Optional[str] = field(default=None, metadata={"description": "观察到的具体故障现象,例如 '出口压力下降20%'"}) cause: Optional[str] = field(default=None, metadata={"description": "分析得出的根本原因,例如 '密封环磨损'"}) solution: Optional[str] = field(default=None, metadata={"description": "采取的维修或解决方案,例如 '更换O型密封环'"})@dataclassclass FaultReport: """从一份报告中抽取的故障信息列表。""" faults: List[FaultInfo]
上述定义相当于制定了抽取任务的“Schema”,即我们希望抽取的实体类别和字段。LangExtract 将根据这个 Schema 来约束 LLM 的输出格式,确保结果符合预期结构。
- 编写提示词(Prompt):接下来编写自然语言的提示词,用于指导 LLM 执行抽取任务。提示词应清晰说明任务要求、抽取内容和格式规范。例如:
import textwrap prompt_desc = textwrap.dedent(""" 从工业设备故障报告中,按出现顺序抽取出故障信息。 请精确使用原文中的文本进行抽取,不要转述或概括。 为每个实体提供有意义的属性。""")
上述提示要求模型从输入文本中按顺序提取故障信息,并强调使用原文原句,不要自行改写,以保证信息准确可追溯。同时要求为每个实体(这里指每次故障)提供属性(即设备名称、现象、原因、措施等)。
- 提供示例(Few-Shot Examples):为了让模型更好地理解我们期望的输出格式,我们可以提供一两个高质量的示例。示例包含一段输入文本和对应的正确抽取结果。LangExtract 通过ExampleData类来定义示例:
from langextract import data as lx_dataexample_text = "记录编号:20250910-01。巡检发现,P-101离心泵出口压力下降20%,伴随异常振动。初步判断为叶轮堵塞。处理措施:停机并清理叶轮异物。"example_extractions = [ lx_data.Extraction( extraction_class="FaultInfo", extraction_text="P-101离心泵出口压力下降20%,伴随异常振动。初步判断为叶轮堵塞。处理措施:停机并清理叶轮异物。", attributes={ "equipment_name": "P-101离心泵", "phenomenon": "出口压力下降20%,伴随异常振动", "cause": "叶轮堵塞", "solution": "停机并清理叶轮异物" } )]example = lx_data.ExampleData(text=example_text, extractions=example_extractions)
上述示例中,我们选取了一段故障报告文本,并给出了从中抽取得到的FaultInfo实体及其属性值。需要注意extraction_text字段填写的是原文中对应的片段,attributes则列出了从该片段中提取的各属性值。通过这个示例,模型将学会如何从类似结构的句子中抽取所需信息。
- 调用 LangExtract 执行抽取:一切准备就绪后,调用 LangExtract 的extract函数对新的输入文本执行信息抽取:
import langextract as lx# 输入待处理的新文本input_text = "2025年9月11日,当班操作员报告,V-201反应釜的机械密封出现泄漏,现场有明显物料滴落。经检查,确认为法兰连接螺栓松动导致。已派维修工紧固所有螺栓,泄漏停止。"# 运行抽取(需配置本地Ollama模型)result = lx.extract( text_or_documents=input_text, prompt_description=prompt_desc, examples=[example], target_schemas=[FaultInfo], # 指定目标Schema model_id="ollama:llama2" # 指定使用Ollama的模型llama2)
这里我们将待处理的新故障报告文本传给text_or_documents参数,传入之前定义的提示词和示例,并通过target_schemas指明我们要抽取的是FaultInfo类型的实体。model_id=";ollama:llama2"告诉 LangExtract 使用本地 Ollama 提供的llama2模型进行推理(LangExtract 会自动通过 Ollama 的 HTTP API 调用该模型)。执行lx.extract后,将返回抽取结果result。
- 处理抽取结果:LangExtract 返回的result包含了从输入文本中抽取的实体列表。我们可以遍历结果查看提取到的内容:
for extraction in result.extractions: if extraction.extraction_class == 'FaultInfo': # 将抽取结果转为我们定义的FaultInfo对象 fault_info = FaultInfo(**extraction.attributes) print(f"设备: {fault_info.equipment_name}") print(f"现象: {fault_info.phenomenon}") print(f"原因: {fault_info.cause}") print(f"措施: {fault_info.solution}\n")
对于上述输入文本,LangExtract 借助示例和提示,应输出类似如下的结构化信息:
设备: V-201反应釜现象: 机械密封出现泄漏,现场有明显物料滴落原因: 法兰连接螺栓松动措施: 紧固所有螺栓
可以看到,模型成功从文本中提取出了设备名称、故障现象、原因和解决措施,并与原文片段精确对应。这验证了 LangExtract 在给定明确 Schema 和示例时,能够让 LLM 稳定地输出符合要求的结构化结果。
- 批量抽取与长文档处理:针对多个文档或长篇文档,可以利用 LangExtract 的批量处理和分块机制。例如,将多个文本文件路径传给text_or_documents参数,LangExtract 会并行处理这些文档。对于特别长的文档,LangExtract 会自动按一定长度分块,并可通过设置extraction_passes进行多轮扫描以提高召回率。每个分块的抽取结果最终会合并成完整结果。在代码中可以通过调整max_workers等参数来优化并行度,加快处理速度。处理完成后,可将结果保存为 JSONL 等格式以便后续处理:
lx.io.save_annotated_documents([result], output_name="extraction_results.jsonl", output_dir=".")
这一步将抽取结果写入 JSON Lines 文件,每行一个文档的抽取结果。通过 LangExtract 提供的visualize功能,还可以将 JSONL 结果生成交互式 HTML 可视化,用于检查抽取效果。
至此,我们已经成功利用 LangExtract 和本地 Ollama 模型从工业文本中提取出了结构化的故障知识。接下来需要对这些初步提取的知识进行清洗和融合,解决实体重复和不一致的问题。
五、知识融合:实体去重与对齐
从不同来源或不同文档抽取的知识,可能存在 实体对齐和 去重的问题。例如,同一台设备在不同报告中可能有简称和全称两种写法(如“P-101”和“P-101离心泵”指同一设备),或者不同报告提到了同一故障原因但表述略有差异。知识融合的目标是将这些指称相同真实世界对象的实体合并,避免知识图谱中出现重复节点,从而保证知识的一致性和完整性。
**1. 实体对齐策略:**实体对齐(Entity Alignment),也称实体匹配,是知识图谱构建中的关键步骤。其任务是识别不同抽取结果中的实体是否代表同一对象。常用的策略包括:
- **基于规则的匹配:**针对已知的命名模式进行匹配。例如定义设备命名规则:若两个设备名中编号相同(如“P-101”出现在两者中),则视为同一设备;或利用同义词表将不同表述映射到统一名称(如“电动机”和“电机”视为同一实体)。
- **字符串相似度:**计算实体名称的相似度得分,超过阈值则认为是同一实体。常用算法有 Levenshtein 编辑距离、Jaccard 相似度、余弦相似度(基于 TF-IDF 或嵌入向量)等。对于中文,还可以考虑拼音相似度、简繁体转换等。
- **上下文和属性匹配:**结合实体的其他属性或上下文信息判断。例如两个“故障原因”实体如果在各自上下文中导致的现象相同或设备相同,则更可能是同一原因。又如根据时间、地点等属性辅助判断两个实体是否指向同一事件。
- **机器学习/嵌入方法:**利用预训练的实体嵌入模型将实体名称或描述编码为向量,然后计算向量间距离进行匹配。这种方法能捕捉语义相似性,例如“叶轮堵塞”和“叶轮被异物堵塞”可能语义相近。近年来也有研究将大模型用于实体对齐,通过Prompt让LLM判断两个实体是否相同。
在本项目中,由于实体类型和数量相对有限,我们可以采用规则+相似度结合的方法:首先根据设备编号等关键字进行精确匹配,然后对剩余候选使用字符串相似度筛选,最后辅以人工审核确认。对于重要实体(如关键设备),也可以建立一个标准名称库,将所有别名映射到标准名称,从而在入库前统一。
**2. 实体去重实现:**假设我们已经将所有抽取得到的实体存入一个列表all_entities,其中可能包含重复项。我们可以编写一个简单的实体对齐函数:
from fuzzywuzzy import fuzzdef align_entities(entities): # 创建标准名称映射字典 name_mapping = {} # 按实体类型分组处理 for entity_type in ['equipment', 'phenomenon', 'cause', 'solution']: group = [e for e in entities if e['type'] == entity_type] # 简单示例:按字符串相似度匹配 for i in range(len(group)): if group[i]['name'] in name_mapping: continue# 已匹配过 for j in range(i+1, len(group)): # 计算名称相似度 ratio = fuzz.ratio(group[i]['name'], group[j]['name']) if ratio > 80: # 设定阈值 # 将j合并到i name_mapping[group[j]['name']] = group[i]['name'] # 应用映射去重 aligned = [] for e in entities: std_name = name_mapping.get(e['name'], e['name']) # 检查是否已存在标准名称的实体 existing = next((x for x in aligned if x['name'] == std_name and x['type'] == e['type']), None) if existing: # 合并属性或关系等(视需求处理) pass else: aligned.append({'name': std_name, 'type': e['type'], **e.get('attrs', {})}) return aligned
上述代码使用了fuzzywuzzy库计算字符串相似度,当两个实体名称相似度超过80%时认为是同一实体,将其中一个名称映射到另一个。然后根据映射关系去除重复实体。这只是一个简化示例,实际应用中可根据需要调整阈值和匹配逻辑。例如,对设备名可以严格些(要求编号完全匹配),对故障现象可以宽松些(允许部分描述不同)。
**3. 关系对齐:**除了实体本身,关系也需要在对齐后进行调整。例如,如果实体A和实体B原本有一条关系,但在对齐后A被合并到A’,那么关系也应更新为A’和B之间的关系。在代码实现中,可以在实体对齐完成后,遍历所有关系,将其中涉及旧实体名称的替换为标准名称,然后再去除重复的关系。
**4. 人工审核与反馈:**自动对齐难免有错误,因此建立人工审核机制很重要。可以将自动对齐结果可视化或列出可疑项(如相似度接近阈值的),由领域专家确认。将确认的结果加入规则或训练数据,不断完善对齐算法。这种人机结合的方式在企业知识图谱构建中较为常见。
通过实体对齐与去重,我们确保了知识图谱中每个节点代表唯一的概念或对象。例如,所有文档中提到的“P-101离心泵”都会被统一为一个节点,其别名或简称作为属性记录。这样处理后,就可以将清洗后的知识存入图数据库,进行持久化管理和查询分析。
六、知识存储:Neo4j图数据库构建与优化
**1. Neo4j 安装与配置:**在将数据存入 Neo4j 之前,需要先安装和配置 Neo4j 数据库。可以选择下载 Neo4j Desktop 或使用 Docker 部署 Neo4j。确保 Neo4j 服务运行正常,并记录其连接URL(如bolt://localhost:7687)以及用户名和密码。在本示例中,我们使用 Neo4j Python 驱动来连接数据库,因此需要安装neo4j驱动包:
pip install neo4j
**2. 数据导入 Neo4j:Neo4j 以节点(Node)和关系(Relationship)**的形式存储图数据。我们计划将抽取得到的实体作为节点,实体之间的关系作为边。具体来说:
- 创建 **设备(Equipment)**节点,标签为
:Equipment,属性包括名称(name)等。 - 创建 **故障现象(Phenomenon)**节点,标签为
:Phenomenon,属性包括现象描述。 - 创建 **原因(Cause)**节点,标签为
:Cause,属性包括原因描述。 - 创建 **措施(Solution)**节点,标签为
:Solution,属性包括措施描述。 - 关系方面,根据抽取结果建立如下关系:
:Equipment -[:HAS_PHENOMENON]-> :Phenomenon(设备出现某现象):Phenomenon -[: CAUSED_BY]-> :Cause(现象由某原因导致):Cause -[:SOLVED_BY]-> :Solution(原因可通过某措施解决)- 还可根据需要建立其他关系,如
:Equipment -[:HAS_CAUSE]-> :Cause(设备常出现的原因)等。
在代码中,我们使用 Neo4j Python 驱动执行 Cypher 语句来创建节点和关系。首先,连接到 Neo4j:
from neo4j import GraphDatabaseuri = "bolt://localhost:7687"user = "neo4j"password = "your_password"driver = GraphDatabase.driver(uri, auth=(user, password))
然后定义函数来执行数据库操作。例如,创建节点的函数:
def create_node(tx, label, name, **kwargs): # 确保名称唯一,避免重复创建 query = f"MERGE (n:{label} {{name: $name}}) SET n += $props RETURN n" tx.run(query, name=name, props=kwargs)
这里使用MERGE语句代替CREATE,以保证如果节点已存在则不会重复创建(MERGE会根据给定的属性匹配现有节点,不存在则创建)。SET n += $props用于将额外属性更新到节点上。
接着定义创建关系的函数:
def create_relationship(tx, start_label, start_name, rel_type, end_label, end_name): query = f""" MATCH (a:{start_label} {{name: $a_name}}), (b:{end_label} {{name: $b_name}}) MERGE (a)-[r:{rel_type}]->(b) """ tx.run(query, a_name=start_name, b_name=end_name)
这里通过 MATCH 找到起始和结束节点,然后 MERGE 关系,确保关系唯一。
现在,将之前对齐后的实体和关系导入数据库。假设我们有一个列表all_entities包含所有唯一实体,以及一个列表all_relations包含所有关系三元组(如 (设备名, ‘HAS_PHENOMENON’, 现象名) 等)。我们可以在一个事务中批量执行创建:
with driver.session() as session: # 开始事务 tx = session.begin_transaction() # 创建所有节点 for entity in all_entities: create_node(tx, entity['type'], entity['name'], **entity.get('attrs', {})) # 创建所有关系 for rel in all_relations: start_name, rel_type, end_name = rel # 假设关系两端的类型可以由rel_type推断或存储在某处 start_type = get_type_from_rel(start_name, rel_type) end_type = get_type_from_rel(end_name, rel_type) create_relationship(tx, start_type, start_name, rel_type, end_type, end_name) # 提交事务 tx.commit()
上述伪代码中,get_type_from_rel函数需要根据关系类型和实体名称确定其标签类型。例如,如果关系是 ‘HAS_PHENOMENON’,那么起始节点通常是 Equipment,结束节点是 Phenomenon。实际实现中可以建立一个关系类型到节点类型的映射,或者在关系数据中直接包含类型信息。
通过以上步骤,我们就将清洗后的故障知识成功存储到了 Neo4j 中。现在在 Neo4j Browser 中执行简单的查询,例如MATCH (e:Equipment)-[r]->(n) RETURN e, r, n LIMIT 25,应该能看到设备节点与其相关的现象、原因等节点连接而成的知识图谱。
**3. Neo4j 索引与优化:**随着知识图谱规模扩大,为了提高查询性能,需要合理使用索引和优化配置:
- **索引:**在经常用于查询的属性上建立索引。例如,为
:Equipment(name)、:Phenomenon(name)等创建唯一索引,这样在按名称查找节点时可以快速定位。在 Neo4j 中可以使用CREATE INDEX语句创建索引。 - **内存配置:**Neo4j 的性能很大程度上依赖于内存。应确保将足够的内存分配给 Neo4j 的页缓存(Page Cache),以缓存尽可能多的图数据在内存中。一般建议将可用内存的一半以上分配给页缓存,具体比例需根据数据量调整。同时配置合适的 JVM 堆内存用于事务处理等。合理的内存设置可以显著减少磁盘 I/O,提升查询速度。
- **存储与IO:**使用高速存储介质(SSD)存放数据库文件,并确保有足够的磁盘空间。Neo4j 写入性能也与文件系统和IO调度有关,可参考官方指南进行调优。
- **查询优化:**编写高效的 Cypher 查询,避免全图扫描。例如,利用索引从特定节点出发遍历关系,而不是匹配所有节点。分页获取结果,避免一次性返回过多数据。对于复杂查询,可以使用
EXPLAIN或PROFILE分析执行计划,找出瓶颈。 - **批量导入工具:**如果初始数据量非常大,直接使用 Cypher 逐行插入可能较慢。这时可以考虑使用 Neo4j 提供的批量导入工具(如
neo4j-admin import),将数据准备成CSV后高速导入。不过对于本方案这种逐步构建的场景,逐条插入已经足够。
通过以上优化措施,我们可以确保 Neo4j 数据库高效稳定地运行,为后续的知识查询和应用提供支持。
七、知识可视化:基于Pyvis的交互式图谱展示
将知识存储在数据库后,还需要一种直观的方式展示和探索知识图谱。Pyvis 提供了简单易用的接口来创建交互式网络图,非常适合知识图谱的可视化。
**1. 安装 Pyvis:**使用 pip 安装 Pyvis:
pip install pyvis
**2. 从 Neo4j 检索数据:**在可视化之前,我们需要从 Neo4j 中检索出要展示的子图或全部数据。例如,可以查询所有设备及其直接关联的现象、原因、措施,构建一个包含主要知识的子图。使用 Neo4j 驱动执行查询:
def get_kg_data(tx): query = """ MATCH (e:Equipment)-[hp:HAS_PHENOMENON]->(p:Phenomenon) MATCH (p)-[cb:CAUSED_BY]->(c:Cause) MATCH (c)-[sb:SOLVED_BY]->(s:Solution) RETURN e.name as equipment, p.name as phenomenon, c.name as cause, s.name as solution """ result = tx.run(query) # 将结果整理为节点和边列表 nodes = set() edges = [] for record in result: equipment = record["equipment"] phenomenon = record["phenomenon"] cause = record["cause"] solution = record["solution"] # 添加节点 nodes.add( (equipment, "Equipment") ) nodes.add( (phenomenon, "Phenomenon") ) nodes.add( (cause, "Cause") ) nodes.add( (solution, "Solution") ) # 添加边 edges.append( (equipment, phenomenon, "出现") ) edges.append( (phenomenon, cause, "由...导致") ) edges.append( (cause, solution, "解决措施") ) return list(nodes), edges
上述查询获取了设备-现象-原因-措施的一条典型路径上的所有节点和关系。实际应用中,可以根据需要调整查询,例如只获取某台设备的知识,或者获取所有知识等。返回的nodes是包含节点名称和类型的列表,edges是包含起始节点、结束节点和关系类型的列表。
**3. 使用 Pyvis 绘图:**利用 Pyvis 的Network类创建网络,并添加节点和边:
from pyvis.network import Network# 初始化一个无向网络,指定尺寸和布局net = Network(height="750px", width="100%", directed=True)# 添加节点for node_name, node_type in nodes: # 根据类型设置节点颜色和形状 if node_type == "Equipment": net.add_node(node_name, label=node_name, color="#3498db", shape="box") elif node_type == "Phenomenon": net.add_node(node_name, label=node_name, color="#f1c40f", shape="ellipse") elif node_type == "Cause": net.add_node(node_name, label=node_name, color="#e74c3c", shape="diamond") elif node_type == "Solution": net.add_node(node_name, label=node_name, color="#2ecc71", shape="triangle")# 添加边for src, dst, rel_type in edges: net.add_edge(src, dst, label=rel_type)# 开启物理仿真布局net.barnes_hut()# 生成HTML并展示net.show("knowledge_graph.html")
上述代码中,我们为不同类型的节点设置了不同的颜色和形状(例如设备用蓝色矩形,现象用黄色椭圆等),以便在图中区分。然后添加所有边,并使用barnes_hut()方法启用物理布局算法,使节点自动排列。最后调用net.show()将生成一个名为knowledge_graph.html的文件,并在默认浏览器中打开。
**4. 交互式浏览:**在浏览器中打开生成的 HTML 文件,即可看到绘制的知识图谱。可以用鼠标拖拽节点、滚动缩放视图。点击节点会弹出其标签,悬停在边上面会显示关系类型。Pyvis 生成的图表支持多种交互操作:
- **拖拽节点:**按住节点拖动可以重新布局,松开后物理引擎会重新计算位置。
- **缩放平移:**使用鼠标滚轮缩放,拖动空白处平移视图。
- **查看详情:**点击节点或边,会弹出包含其名称或标签的信息框(可通过配置显示更多属性)。
- **搜索节点:**Pyvis 提供搜索框(在
Network初始化时可以设置select_menu=True来启用),方便快速定位特定节点。 - **过滤与高亮:**可以通过设置
filter_menu=True启用过滤菜单,根据节点类型或属性筛选显示,并高亮相关节点和边。
通过这些交互功能,用户可以自由地探索知识图谱中的关系。例如,找到某设备节点后,查看它连接的故障现象;进一步点击现象节点,查看导致它的原因节点,以及解决该原因的措施节点。这直观地展示了从故障现象到原因再到解决方案的知识链条,符合故障诊断的思维过程。
**5. 可视化定制:**Pyvis 允许对图表外观和行为进行丰富的定制。例如,可以调整节点大小、字体、边的粗细和颜色,设置动画效果,或者禁用物理引擎改用预设布局等。还可以通过net.set_options()传入定制的 Vis.js 配置项来自定义更高级的行为。在本方案中,我们采用了默认的物理布局和简单配色,实际应用中可根据企业视觉风格进行调整,使图表更加美观专业。
通过 Pyvis 的可视化,我们将冷冰冰的数据库数据转化为了易于理解的图形界面,为非技术人员和工程师提供了一个友好的知识探索工具。
八、基于React + TypeScript + Cytoscape.js的交互式知识图谱可视化
知识图谱系统的可视化组件,专门用于展示和交互知识图谱数据:
- 动态数据加载: 从JSON文件异步加载知识图谱数据
- 智能搜索: 支持节点搜索和高亮显示
- 丰富交互: 缩放、拖拽、节点选择等交互功能
- 响应式设计: 支持桌面和移动设备
技术架构
知识图谱数据 → React应用 → Cytoscape.js → 交互式图谱展示 ↓ ↓ ↓ ↓ JSON文件 组件化界面 图谱引擎 用户交互
核心技术栈
- React 18- 用户界面框架
- TypeScript- 类型安全的JavaScript
- Vite- 快速构建工具和开发服务器
- Cytoscape.js- 专业图谱可视化库
- Tailwind CSS- 实用程序优先的CSS框架
- React Hooks- 状态管理和副作用处理
数据格式
系统从 public/knowledge_graph.json加载知识图谱数据,数据格式如下:
{ "entities": [ { "name": "P-101离心泵出口压力下降20%", "type": "Equipment", "attributes": { "description": "设备: P-101离心泵出口压力下降20%" }, "aliases": [] }, { "name": "压力下降", "type": "Phenomenon", "attributes": { "description": "故障现象: 压力下降" }, "aliases": [] } ],"relationships": [ { "start_entity": "P-101离心泵出口压力下降20%", "end_entity": "压力下降", "relation_type": "causes" } ]}
呈现的知识图谱交互界面:

九、示例:端到端流程与代码
为了帮助读者更直观地理解整个流程,下面给出一个端到端的代码示例,将上述各环节串联起来。由于篇幅限制,这里仅展示关键步骤的代码片段,完整代码可到知识星球下载(见文末链接)。
1. 信息抽取部分:(已在第四节详细展示,此处略)
2. 实体对齐部分:(已在第五节展示,此处略)
3. 知识入库部分:(已在第六节展示,此处略)
4. 可视化部分:(已在第七节、第八节展示,此处略)
**5. 综合调用:**最后,将各部分整合,实现从读取文本到输出可视化的一键运行:
def run_full_pipeline(self, texts: List[str] = None, data_dir: str = None): """运行完整流程""" print("=" * 60) print("工业故障知识图谱构建系统") print("=" * 60) # 1. 加载数据 if texts isNone: if data_dir: texts = self.load_text_files(data_dir) else: texts = self.load_sample_data() print("使用内置示例数据") ifnot texts: print("错误: 没有可处理的文本数据") return # 2. 信息抽取 faults = self.extract_knowledge(texts) ifnot faults: print("警告: 没有提取到任何故障信息") return # 3. 知识融合 kg = self.fuse_knowledge(faults) # 4. 存储到数据库 try: self.store_to_neo4j(kg) except Exception as e: print(f"数据库操作失败,跳过存储步骤: {e}") # 5. 可视化 try: self.visualize_knowledge(kg) except Exception as e: print(f"可视化失败: {e}") print("=" * 60) print("知识图谱构建完成!") print("=" * 60) return kg
上述代码只是示意,实际实现中需要根据具体函数和数据结构进行调整。但通过这样的流程,我们已经实现了从原始文本输入到生成知识图谱可视化的完整管道。运行该程序后,最终会在浏览器中打开知识图谱的可视化页面,展示我们构建的工业故障知识图谱。
下图展示了本系统基于Pyvis呈现的知识图谱示例,其中节点代表设备、现象、原因和措施,边代表它们之间的关系。

十、性能优化与企业级部署建议
在将本方案应用于企业实际时,还需要考虑性能和部署方面的优化,以确保系统稳定高效运行。
**1. LangExtract 性能优化:**对于大规模文档的信息抽取,可以采取以下措施提升性能:
- **并行处理:**充分利用 LangExtract 的并行处理能力,通过设置max_workers参数并发调用 LLM 接口。这要求本地模型服务(Ollama)能够处理并发请求,或者有多个模型实例分担负载。
- **分批处理:**将海量文档分成批次处理,避免一次性加载过多数据到内存。LangExtract 支持输入一个文件列表或一个生成器,可逐条处理大文件。
- **模型选择:**根据任务复杂度选择合适大小的模型。本地模型参数量越大准确率可能越高,但推理速度越慢。可以考虑使用蒸馏模型或量化模型在速度和精度间折中。Ollama 支持加载不同模型,可按需切换。
- **缓存机制:**对重复内容或多次处理的文档,可缓存其抽取结果,避免重复调用模型。例如将已处理文档的哈希与结果存储,下次遇到相同内容直接读取缓存。
- 提示词和示例优化:精心设计提示词和示例,减少模型误解和无效输出。使用 LangExtract 的精确溯源功能确保模型严格引用原文,从而减少校验开销。
**2. Neo4j 部署优化:**在企业环境中部署 Neo4j,应考虑以下几点:
- **硬件配置:**确保服务器有足够的内存和存储。Neo4j 对内存敏感,建议为其分配尽可能多的可用内存用于页缓存。使用 SSD 提高I/O性能。CPU方面,Cypher 查询在多线程上表现良好,可选用多核CPU提升并发查询能力。
- **企业版功能:**Neo4j 企业版提供了集群部署(HA或Causal Cluster)、备份恢复、监控等高级功能。对于关键业务,可考虑使用企业版搭建集群,实现高可用和数据冗余。
- **安全与权限:**配置数据库的安全策略,启用身份认证和加密传输。根据用户角色设置权限,例如只读用户用于查询,管理员用户用于更新等。定期备份数据库,防止数据丢失。
- **监控与日志:**利用 Neo4j 内置的监控工具或第三方监控(如 Prometheus+Grafana)跟踪数据库的性能指标(CPU、内存占用、查询延迟等)。设置慢查询日志,及时发现性能瓶颈查询并优化。
- **调优配置:**根据实际负载调整 Neo4j 配置参数。例如,并发事务较多时可适当增大 Bolt 线程池大小;写入频繁时调整事务日志和检查点策略等。参考 Neo4j 官方运维手册进行最佳实践配置。
3. 企业级集成建议:
- **流水线与自动化:**将知识抽取与入库过程封装为自动化流水线。可以使用 Airflow 或自研脚本定时触发,定期从新产生的文档中抽取知识并更新图谱。这样可保持知识图谱的实时性,不断纳入新的故障案例和维修经验。
- **与业务系统对接:**将知识图谱与企业现有系统集成,例如在设备管理系统或运维平台中嵌入知识图谱查询功能。当工程师提交故障报告时,自动触发知识抽取并更新图谱;当查询故障解决方案时,通过调用 Neo4j 查询接口从图谱中获取推荐。这种集成可以通过后端服务实现,例如开发一个 Spring Boot 或 Python FastAPI 服务作为中间层,封装 LangExtract 抽取和 Neo4j 查询的逻辑,向前端应用提供API。
- **权限与审核:**对于知识图谱的更新,引入审核机制。例如,新抽取的知识先标记为“待审核”,由专家确认后再正式加入图谱。可以在可视化界面或管理后台中提供审核功能,保证知识的准确性。
- **扩展与维护:**随着应用深入,可能需要扩展知识图谱的模型。例如增加“故障频率”属性、“备件”节点等。应设计灵活的模式,方便后续添加新的实体类型和关系。同时制定知识图谱的维护计划,定期清理无效节点、更新过时信息,确保图谱质量。
通过以上优化和部署策略,我们可以将本方案从一个示例原型提升为企业级的知识管理系统,真正发挥知识图谱在工业运维中的价值。
结语
本文详细介绍了如何利用 LangExtract 和 Ollama 从工业文本中抽取知识,并经过实体对齐、Neo4j 存储和 Pyvis 可视化,构建出工业故障诊断知识图谱的全过程。我们结合实际场景提供了代码示例和图示说明,展示了从原始数据到可交互知识图谱的端到端解决方案。
通过本方案,企业可以将分散在各处的设备故障知识进行集中管理和利用。当出现新的故障时,工程师不仅可以查询历史报告,还能通过知识图谱直观地看到该故障可能的原因和解决措施,以及相关联的设备和维修记录。这将大大提高故障诊断的效率和准确性,减少停机时间,为工业生产保驾护航。
知识图谱的构建是一个持续迭代的过程。随着更多数据的加入和业务需求的变化,我们需要不断完善抽取规则、优化模型和扩展知识表示。希望本文的实践经验能为读者在工业领域应用大模型和知识图谱提供有益借鉴。
如何高效转型Al大模型领域?
作为一名在一线互联网行业奋斗多年的老兵,我深知持续学习和进步的重要性,尤其是在复杂且深入的Al大模型开发领域。为什么精准学习如此关键?
- 系统的技术路线图:帮助你从入门到精通,明确所需掌握的知识点。
- 高效有序的学习路径:避免无效学习,节省时间,提升效率。
- 完整的知识体系:建立系统的知识框架,为职业发展打下坚实基础。
AI大模型从业者的核心竞争力
- 持续学习能力:Al技术日新月异,保持学习是关键。
- 跨领域思维:Al大模型需要结合业务场景,具备跨领域思考能力的从业者更受欢迎。
- 解决问题的能力:AI大模型的应用需要解决实际问题,你的编程经验将大放异彩。
以前总有人问我说:老师能不能帮我预测预测将来的风口在哪里?
现在没什么可说了,一定是Al;我们国家已经提出来:算力即国力!
未来已来,大模型在未来必然走向人类的生活中,无论你是前端,后端还是数据分析,都可以在这个领域上来,我还是那句话,在大语言AI模型时代,只要你有想法,你就有结果!只要你愿意去学习,你就能卷动的过别人!
现在,你需要的只是一份清晰的转型计划和一群志同道合的伙伴。作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。

第一阶段(10天):初阶应用
该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。
- 大模型 AI 能干什么?
- 大模型是怎样获得「智能」的?
- 用好 AI 的核心心法
- 大模型应用业务架构
- 大模型应用技术架构
- 代码示例:向 GPT-3.5 灌入新知识
- 提示工程的意义和核心思想
- Prompt 典型构成
- 指令调优方法论
- 思维链和思维树
- Prompt 攻击和防范
- …
第二阶段(30天):高阶应用
该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。
- 为什么要做 RAG
- 搭建一个简单的 ChatPDF
- 检索的基础概念
- 什么是向量表示(Embeddings)
- 向量数据库与向量检索
- 基于向量检索的 RAG
- 搭建 RAG 系统的扩展知识
- 混合检索与 RAG-Fusion 简介
- 向量模型本地部署
- …
第三阶段(30天):模型训练
恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。
到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?
- 为什么要做 RAG
- 什么是模型
- 什么是模型训练
- 求解器 & 损失函数简介
- 小实验2:手写一个简单的神经网络并训练它
- 什么是训练/预训练/微调/轻量化微调
- Transformer结构简介
- 轻量化微调
- 实验数据集的构建
- …
第四阶段(20天):商业闭环
对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。
- 硬件选型
- 带你了解全球大模型
- 使用国产大模型服务
- 搭建 OpenAI 代理
- 热身:基于阿里云 PAI 部署 Stable Diffusion
- 在本地计算机运行大模型
- 大模型的私有化部署
- 基于 vLLM 部署大模型
- 案例:如何优雅地在阿里云私有部署开源大模型
- 部署一套开源 LLM 项目
- 内容安全
- 互联网信息服务算法备案
- …
学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。
如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。
这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】


被折叠的 条评论
为什么被折叠?



