
在大模型深度融入产业应用的当下,自然语言交互的流畅性已实现突破,但事实性幻觉、复杂关系推理薄弱、答案不可追溯三大核心问题,始终制约着大模型在知识服务、智能问答、专业咨询等高可信场景的落地。单纯依赖大模型的语义生成能力,难以处理多跳关联、实体关系推导、结构化知识校验等复杂任务,而传统知识图谱又存在交互门槛高、自然语言适配差的短板。
将图算法与大模型深度融合,正是破解这一困境的最优路径之一:图算法专注于实体关系抽取、路径推理、重要度排序与社区挖掘,构建结构化、可解释的知识图谱;大模型则承担自然语言理解、意图解析与答案生成,实现人机无障碍交互。今天我们依旧采用混元大模型API作为语言引擎,依托其强大的语义理解与指令遵循能力,将用户自然语言问题精准转化为图查询指令,再通过 PageRank、最短路径、社区发现等经典图算法完成知识推理与验证,最终由混元模型生成可信、流畅、可溯源的回答。这套“图算法管关系、大模型管语言”的双引擎架构,既消除了大模型幻觉,又强化了逻辑推理能力,为医疗、文旅、学术、企业知识服务等场景提供了可落地、高可靠的智能问答解决方案,也为大模型的可信化应用提供了清晰的实践思路。

图算法不是画图的工具,而是专门用来分析“关系网络”的数学方法。
图算法的核心优势在于:精准、可解释、擅长结构化推理。
知识图谱是一种用“图”来组织事实的方式,用“节点(实体)+ 边(关系)”的图形结构存储知识:
它不像普通数据库那样只存表格,而是把知识变成一张巨大的语义网络。因此,知识图谱本质上是一个结构化、可计算的关系知识库,为机器提供常识骨架。

大模型擅长理解和生成人类语言,在自然语言处理上表现出色:
但它的致命弱点也很明显,容易胡说八道,缺乏对复杂关系的推理能力:
换句话说,大模型像一个博学但记性不牢的演讲者,说得漂亮,但不一定靠谱。
单独使用任何一方都难以支撑高可靠性的智能问答:
而将三者结合,就能形成一个闭环协作系统:
用图算法处理“关系推理”,用大模型处理“语言理解和生成”,结合后既能听懂人话,又能精准推理,还能追溯答案来源。
纯大模型问答 | 图算法 + 大模型问答 |
|---|---|
答案可能幻觉,无法追溯 | 答案基于结构化关系,可追溯、无幻觉 |
缺乏复杂关系推理能力 | 擅长多步关系推理,如 “李白和杜甫的共同好友是谁” |
依赖海量语料,解释性差 | 基于明确的实体关系,解释性强 |
2.1 PageRank:给“谁更重要”打分
PageRank的核心思想是:被越多重要节点指向的节点,自己也越重要。

2.2 社区发现:自动找出“小圈子”
现实世界的关系网里,人总是扎堆的,同学群、家庭群、兴趣小组……社区发现算法就是干这个的:从复杂网络中自动划分出内部连接紧密、外部连接稀疏的子群体。

2.3 最短路径:找“最少中间人”的连接
如果我们想知道“我和某位名人之间隔了几层关系”?最短路径算法就能回答这个问题。

2.4 实体链接:识别“知识库里的真实对象”
用户问:“诗仙写过哪些诗?”,机器得先知道“诗仙”指的是知识图谱里的‘李白’这个节点,而不是字面意思或其他诗人。

流程说明:
- 1. 数据准备
- 2. 图算法抽取关系
- 3. 构建知识图谱
- 4. 大模型处理用户问题
你是一个知识图谱查询转换助手,需要把用户的自然语言问题转换成针对NetworkX图的查询指令。 知识图谱包含的节点类型:Person(人物:李白、杜甫、贺知章)、Place(地点:碎叶城、长安)。 关系类型:friend(朋友)、birthPlace(出生地)、livedIn(居住过)。 请返回简洁的Python查询指令,仅返回代码片段,不要多余解释。 示例: 用户问题:李白的出生地在哪里? 输出:list(kg[李白][x] for x in kg.neighbors('李白') if kg[李白][x]['relation'] == 'birthPlace') 用户问题:{question}
- 5. 图算法执行推理查询
- 6. 大模型生成回答 + 追溯来源
import networkx as nx
import matplotlib.pyplot as plt
from matplotlib import font_manager
# 设置中文字体(解决中文显示乱码问题)
font_family = ["Microsoft YaHei", "SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Arial Unicode MS"]
plt.rcParams["font.family"] = font_family
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 查找并设置可用字体
available_fonts = [f.name for f in font_manager.fontManager.ttflist]
node_font = None
for font in font_family:
if font in available_fonts:
node_font = font
break
if node_font is None:
node_font = "DejaVu Sans" # 默认字体
print("警告: 未找到中文字体,可能显示乱码")
# 1. 创建空的无向图
kg = nx.Graph()
# 2. 添加节点(实体):人物节点,带属性
kg.add_node("李白", type="Person", birth_year=701)
kg.add_node("杜甫", type="Person", birth_year=712)
kg.add_node("贺知章", type="Person", birth_year=659)
kg.add_node("碎叶城", type="Place", location="吉尔吉斯斯坦")
kg.add_node("长安", type="Place", location="中国西安")
# 3. 添加边(关系):带关系类型属性
kg.add_edge("李白", "贺知章", relation="friend")
kg.add_edge("李白", "杜甫", relation="friend")
kg.add_edge("李白", "碎叶城", relation="birthPlace")
kg.add_edge("李白", "长安", relation="livedIn")
kg.add_edge("杜甫", "长安", relation="livedIn")
# 4. 可视化知识图谱(生成图片)
plt.figure(figsize=(10, 6))
# 设置节点位置
pos = nx.spring_layout(kg, seed=42) # seed固定布局
# 绘制节点
nx.draw_networkx_nodes(kg, pos, node_size=3000, node_color="lightblue")
# 绘制边
nx.draw_networkx_edges(kg, pos, width=2, edge_color="gray")
# 绘制节点标签
nx.draw_networkx_labels(kg, pos, font_size=12, font_weight="bold", font_family=node_font)
# 绘制边的关系标签
edge_labels = nx.get_edge_attributes(kg, "relation")
nx.draw_networkx_edge_labels(kg, pos, edge_labels=edge_labels, font_size=10, font_family=node_font)
# 隐藏坐标轴
plt.axis("off")
# 保存图片
plt.savefig("83.用NetworkX构建简单知识图谱 knowledge_graph.png", dpi=300, bbox_inches="tight")
plt.show()
# 输出图谱基本信息
print("知识图谱节点数:", kg.number_of_nodes())
print("知识图谱边数:", kg.number_of_edges())
print("李白的所有关系:", list(kg.edges("李白")))输出结果:
知识图谱节点数: 5 知识图谱边数: 5 李白的所有关系: [('李白', '贺知章'), ('李白', '杜甫'), ('李白', '碎叶城'), ('李白', '长安')]
结果图示:

import networkx as nx
import matplotlib.pyplot as plt
from matplotlib import font_manager
# 设置中文字体(解决中文显示乱码问题)
font_family = ["Microsoft YaHei", "SimHei", "WenQuanYi Micro Hei", "Heiti TC", "Arial Unicode MS"]
plt.rcParams["font.family"] = font_family
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 查找并设置可用字体
available_fonts = [f.name for f in font_manager.fontManager.ttflist]
node_font = None
for font in font_family:
if font in available_fonts:
node_font = font
break
if node_font is None:
node_font = "DejaVu Sans" # 默认字体
print("警告: 未找到中文字体,可能显示乱码")
# 1. 创建空的无向图
kg = nx.Graph()
# 2. 添加节点(实体):人物节点,带属性
kg.add_node("李白", type="Person", birth_year=701)
kg.add_node("杜甫", type="Person", birth_year=712)
kg.add_node("贺知章", type="Person", birth_year=659)
kg.add_node("碎叶城", type="Place", location="吉尔吉斯斯坦")
kg.add_node("长安", type="Place", location="中国西安")
# 3. 添加边(关系):带关系类型属性
kg.add_edge("李白", "贺知章", relation="friend")
kg.add_edge("李白", "杜甫", relation="friend")
kg.add_edge("李白", "碎叶城", relation="birthPlace")
kg.add_edge("李白", "长安", relation="livedIn")
kg.add_edge("杜甫", "长安", relation="livedIn")
# 4. 可视化知识图谱(生成图片)
plt.figure(figsize=(10, 6))
# 设置节点位置
pos = nx.spring_layout(kg, seed=42) # seed固定布局
# 绘制节点
nx.draw_networkx_nodes(kg, pos, node_size=3000, node_color="lightblue")
# 绘制边
nx.draw_networkx_edges(kg, pos, width=2, edge_color="gray")
# 绘制节点标签
nx.draw_networkx_labels(kg, pos, font_size=12, font_weight="bold", font_family=node_font)
# 绘制边的关系标签
edge_labels = nx.get_edge_attributes(kg, "relation")
nx.draw_networkx_edge_labels(kg, pos, edge_labels=edge_labels, font_size=10, font_family=node_font)
# 隐藏坐标轴
plt.axis("off")
# 保存图片
plt.savefig("83.用NetworkX构建简单知识图谱 knowledge_graph.png", dpi=300, bbox_inches="tight")
# 1. 最短路径算法:找李白到贺知章的最短路径
shortest_path = nx.shortest_path(kg, source="李白", target="贺知章")
print("李白到贺知章的最短路径:", shortest_path)
# 2. PageRank算法:计算节点重要度
pagerank = nx.pagerank(kg)
# 按重要度排序
sorted_pagerank = sorted(pagerank.items(), key=lambda x: x[1], reverse=True)
print("\n节点重要度排名(PageRank):")
for node, score in sorted_pagerank:
print(f"{node}: {score:.4f}")
# 3. 社区发现算法:识别关系紧密的社区
from networkx.algorithms import community
# 贪心社区发现
communities = community.greedy_modularity_communities(kg)
print("\n识别到的社区:")
for i, comm in enumerate(communities):
print(f"社区{i+1}:{list(comm)}")输出结果:
李白到贺知章的最短路径: ['李白', '贺知章'] 节点重要度排名(PageRank): 李白: 0.3861 杜甫: 0.1949 长安: 0.1949 贺知章: 0.1121 碎叶城: 0.1121 识别到的社区: 社区1:['贺知章', '碎叶城', '李白'] 社区2:['长安', '杜甫']
import os
import json
import networkx as nx
from openai import OpenAI
# from dotenv import load_dotenv
# 使用腾讯混元大模型
client = OpenAI(
api_key='sk-bWlJPKjBrSFGoQ0Ys0ma********************Z5NP8Ze',
base_url="https://api.hunyuan.cloud.tencent.com/v1",
)
# 1. 创建空的无向图
kg = nx.Graph()
# 2. 添加节点(实体):人物节点,带属性
kg.add_node("李白", type="Person", birth_year=701)
kg.add_node("杜甫", type="Person", birth_year=712)
kg.add_node("贺知章", type="Person", birth_year=659)
kg.add_node("碎叶城", type="Place", location="吉尔吉斯斯坦")
kg.add_node("长安", type="Place", location="中国西安")
# 3. 添加边(关系):带关系类型属性
kg.add_edge("李白", "贺知章", relation="friend")
kg.add_edge("李白", "杜甫", relation="friend")
kg.add_edge("李白", "碎叶城", relation="birthPlace")
kg.add_edge("李白", "长安", relation="livedIn")
kg.add_edge("杜甫", "长安", relation="livedIn")
# 定义函数:大模型把自然语言问题转成图查询指令
def nl2graph_query(question):
prompt = f"""
你是一个知识图谱查询转换助手,需要把用户的自然语言问题转换成针对NetworkX图的查询指令。
知识图谱包含的节点类型:Person(人物:李白、杜甫、贺知章)、Place(地点:碎叶城、长安)。
关系类型:friend(朋友)、birthPlace(出生地)、livedIn(居住过)。
请返回简洁的Python查询指令,仅返回代码片段,不要多余解释。
示例:
用户问题:李白的出生地在哪里?
输出:list(kg[李白][x] for x in kg.neighbors('李白') if kg[李白][x]['relation'] == 'birthPlace')
用户问题:{question}
"""
response = client.chat.completions.create(
model="hunyuan-lite",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content.strip()
# 定义函数:大模型把图算法结果转成自然语言回答
def graph_result2nl(question, result):
prompt = f"""
你是一个智能问答助手,需要把知识图谱的查询结果转换成自然、流畅的人类语言回答。
用户问题:{question}
图算法查询结果:{result}
请返回简洁、易懂的回答,不要多余解释。
"""
response = client.chat.completions.create(
model="hunyuan-lite",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content.strip()
# 实战:用户自然语言问答
user_question = "李白的出生地在哪里?"
print(f"\n用户问题:{user_question}")
# 步骤1:大模型转换查询指令
graph_query = nl2graph_query(user_question)
print(f"原始返回:{repr(graph_query)}")
# 清理混元返回的代码标记
if graph_query.startswith("```"):
graph_query = graph_query.split("```")[1]
if graph_query.startswith("python"):
graph_query = graph_query[6:].strip()
graph_query = graph_query.strip()
print(f"清理后的图查询指令:{repr(graph_query)}")
# 步骤2:执行图查询(安全执行)
try:
# 构造执行环境,包含节点名称
exec_env = {"kg": kg, "list": list, "李白": "李白", "杜甫": "杜甫", "贺知章": "贺知章", "碎叶城": "碎叶城", "长安": "长安"}
# 执行查询
exec(f"result = {graph_query}", exec_env)
graph_result = exec_env["result"]
print(f"图算法查询结果:{graph_result}")
except Exception as e:
graph_result = f"查询出错:{str(e)}"
print(f"图算法查询结果:{graph_result}")
# 步骤3:大模型生成自然语言回答
nl_answer = graph_result2nl(user_question, graph_result)
print(f"最终回答:{nl_answer}")
# 另一个示例:多步推理
user_question2 = "李白的朋友有谁?他们都住过哪里?"
print(f"\n用户问题:{user_question2}")
# 步骤1:转换查询指令
graph_query2 = nl2graph_query(user_question2)
# 清理代码标记
if graph_query2.startswith("```"):
graph_query2 = graph_query2.split("```")[1]
if graph_query2.startswith("python"):
graph_query2 = graph_query2[6:].strip()
graph_query2 = graph_query2.strip()
print(f"转换后的图查询指令:{graph_query2}")
# 步骤2:执行查询(查询李白的朋友)
try:
exec_env2 = {"kg": kg, "list": list, "李白": "李白", "杜甫": "杜甫", "贺知章": "贺知章", "碎叶城": "碎叶城", "长安": "长安"}
exec(f"result2 = {graph_query2}", exec_env2)
friends_result = exec_env2["result2"]
print(f"查询返回结果:{friends_result}")
# 提取朋友节点名称(获取邻居节点)
friends_names = list(kg.neighbors('李白'))
# 筛选出关系是friend的朋友
friends = [n for n in friends_names if kg['李白'][n]['relation'] == 'friend']
print(f"李白的朋友:{friends}")
# 步骤3:查询朋友们居住的地方
if friends:
for friend in friends:
friend_places = []
for neighbor in kg.neighbors(friend):
if kg[friend][neighbor]['relation'] == 'livedIn':
friend_places.append(neighbor)
print(f" {friend} 住过:{friend_places}")
except Exception as e:
print(f"查询出错:{str(e)}")
# 步骤4:大模型生成自然语言回答
if 'friends_result' in locals():
nl_answer2 = graph_result2nl(user_question2, f"李白的朋友:{friends_result}")
print(f"最终回答:{nl_answer2}")示例细节:
输出结果:
用户问题:李白的出生地在哪里? 原始返回:"```python\nlist(kg[李白][x] for x in kg.neighbors('李白') if kg[李白][x]['relation'] == 'birthPlace')\n```" 清理后的图查询指令:"list(kg[李白][x] for x in kg.neighbors('李白') if kg[李白][x]['relation'] == 'birthPlace')" 图算法查询结果:[{'relation': 'birthPlace'}] 最终回答:李白的出生地是西域碎叶城,即今天的吉尔吉斯斯坦境内。 用户问题:李白的朋友有谁?他们都住过哪里? 转换后的图查询指令:list(kg[李白][x] for x in kg.neighbors('李白') if kg[李白][x]['relation'] in ['friend', 'livedIn']) 查询返回结果:[{'relation': 'friend'}, {'relation': 'friend'}, {'relation': 'livedIn'}] 李白的朋友:['贺知章', '杜甫'] 贺知章 住过:[] 杜甫 住过:['长安'] 最终回答:李白的朋友有杜甫、贺知章等人,他们曾共同居住在长安城。
以前我也总觉得,大模型够强就能搞定一切问答,但接触的越深越明白,纯大模型天生有短板,容易幻觉、推理不严谨、答案没法追溯。而基于图算法管关系、混元管语言的双引擎模式,刚好把两者的优势捏合在了一起:用 PageRank、最短路径、社区发现这些图算法做关系挖掘和推理,靠大模型做自然语言理解和生成,搭出来的知识图谱问答系统,既听得懂人话,又能给出靠谱、可溯源的答案。
总的来说,做落地项目,从来不是堆技术,而是让专业的工具干专业的事。知识图谱负责存事实,图算法负责推逻辑,大模型负责做交互,分工明确才够稳定。我们初次接触可以先别着急对接大模型,先用NetworkX搭小图谱、跑通图算法,把实体和关系的逻辑理清楚;再接入大模型的API或本地大模型做语言转换,循序渐进才不容易乱。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。