免费POC, 零成本试错
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


我要投稿

如何使用 Knowledge Graph 和 LLM 构建构建问答系统

发布日期:2025-11-13 12:21:21 浏览次数: 1526
作者:AI大模型观察站

微信搜一搜,关注“AI大模型观察站”

推荐语

探索如何结合知识图谱与大语言模型打造高效问答系统,轻松实现智能客服与信息检索功能。

核心内容:
1. 基于FAQ文档构建知识图谱的完整流程
2. 利用Gemma3模型实现自然语言问题解析与答案生成
3. 系统架构设计思路与未来优化方向

杨芳贤
53AI创始人/腾讯云(TVP)最具价值专家

今天我带来一个基于 knowledge graph(用第一部分介绍的方法构建)和 LLM(这里用的是 Gemma3–4b-it-qat,与之前相同)的简易 Question Answer (QA) System。我选择使用 Gemma3–4b,是因为它体量足够小,可以在普通笔记本上运行,同时又非常擅长遵循指令。若你需要关于 KG、Gemma3 或如何在本地运行 LLM 的更多背景与信息,建议先快速浏览我上一篇文章。

在这篇博客中,我们会用一个关于假想智能手机的 FAQ 文本作为样例,利用上一篇文章中的代码(同一仓库)为其生成 knowledge graph,然后搭建一个系统来回答与该产品相关的问题,就像这样:

一些问答示例

在本文中,我们将学习:

  1. 什么是 QA System
  2. 了解我们的思路
  3. 查看代码
  4. 讨论局限与改进方向

什么是 QA System

引用 Google 的定义:

A question answering (QA) system is a software application that takes a user's question in natural language and provides a direct, relevant answer by processing the question's intent and retrieving information from a knowledge source or generating a new response.

在本文中,我们的 “knowledge source” 是我用 Gemma3 生成的一段模拟 FAQ 文本,你可以在这篇博客的 Github 仓库 中找到。我们可以运行仓库的 main.py 来构建 KG 并将其保存到输出目录:

python main.py --inputpath ./input/sample-faq.txt --outlabel faq

该命令会将 networkx graph 保存为文件 “nx_graph.pkl”,稍后在构建 QA system 时会加载它。

我们的思路

核心思路是:从用户问题中抽取 entities/keywords,找到与它们相关的所有 nodes 与 edges,然后将这些信息与问题一起提供给 LLM,让其基于 KG 中的信息进行回答。我们把方案正式化如下。

给定一个问题 q,以及基于任意语料构建的 knowledge graph (G):

  1. 使用 LLM 从 q 中抽取 named entities(entity_keywords)和 relations/predicates(relation_keywords)。
  2. 从 entity_keywords 中枚举所有可能的成对组合。这使我们之后可以用 source 和 target 参数查询图,因为我们无法预先假设某个 entity 是 source 还是 target。
  3. 对于第 2 步得到的每一对 (u, v),在 G 中查找 u 与 v 之间的所有路径。这样可以找出两个实体之间的所有 relations/paths/knowledge。引入这一步是个 game-changer。
  4. 对于找到的每条路径(source 与 target node),提取它们之间的 relation。例如 (box, include, charger)。
  5. 将形成的 “triple” 加入列表 relations
  6. 对 relation_keywords 做类似处理。对于每个 relation r,找到所有由 r 连接的 edges,形成 triples 并加入同一列表 relations
  7. 最后一步,将这些 triples 与问题 q 一起(封装在一个 prompt 中)传给 LLM,让其基于给定事实(triples)与查询生成答案。

代码实现

首先,用 main.py 构建 knowledge graph:

python main.py --inputpath ./input/sample-faq.txt --outlabel faq

然后从上一步生成的 pickle 文件中加载 graph:

import pickle

G = pickle.load(open(graph_file, "rb"))

我们需要定义一个函数,能够接收文本输入与 system level prompt,并从 LLM 获取响应。下面这个可复用函数实现了该功能:

def get_llm_response(text, system_prompt):
    response = Ollama.chat(model=model, messages=[
        {"role""system""content": system_prompt},
        {"role""user""content": text}
        ])
    resp_content = response['message']['content']
    return resp_content

接下来需要从给定 query 中抽取 entities 和 relations(对应上文的第 1 步)。我构造了一个基础的 system prompt,如下所示:

system_prompt_key_words = """You are a helpful assistant, expert of English language who can extracts keyword from the given question in root form (e.g. ran becomes run) and lowercase.
The returned keywords should be critical to answer the question.
Categorize the keywords into entity and relation keywords.
keywords must be in root form and lowercase.
The response should be in following format, no additional text:
{"entity": [list of entity keywords], "relation": [list of relation keywords]}"""


response = get_llm_response(query, system_prompt_key_words)
keyword_resp = json.loads(response)
entity_keywords = keyword_resp.get('entity', [])
relation_keywords = keyword_resp.get('relation', [])

假设 entity_keywords 为 [box, charger, phone],我们需要找出所有可能的 source-target 成对组合,以便对图做全面查询:

pairs = list(combinations(entities, 2))

对每个实体对,我们需要在图中查找所有 nodes 与 edges:

paths = list(nx.all_simple_paths(G, source=u, target=target_nodes))

上述步骤(第 1–6 步,含以上代码)都实现在下面这个函数中:

def search_kg2(G, query):
    response = get_llm_response(query, system_prompt_key_words)
    keyword_resp = json.loads(response)
    entity_keywords = keyword_resp.get('entity', [])
    relation_keywords = keyword_resp.get('relation', [])
    entities = [part.strip() for part in entity_keywords]
    pairs = list(combinations(entities, 2))
    relations = []
    for u, v in pairs:
        target_nodes = get_nodes(G, v)
        paths = list(nx.all_simple_paths(G, source=u, target=target_nodes))
        for path in paths:
            for i inrange(len(path)-1):
                for key in G[path[i]][path[i+1]]:
                    rel = G[path[i]][path[i+1]][key]['relation']
                    relations.append((path[i],rel, path[i+1]))

    for rel_keyword in relation_keywords:
        relations.extend([(u, rel, v) for u, v, rel in G.edges.data("relation"ifstr(rel) == rel_keyword])
    
    return relations

当我们从上述函数得到所有用 triples(entity->relation->entity)表示的 edges 后,就将这些 triples 嵌入到一个指令式 prompt 中传给 LLM:

context = f"""
    You are given facts from a knowledge graph:

    {triples}

    Answer the user query based ONLY on these facts.
    Answer in full sentence.
    Query: {query}
    """

response = ollama.chat(model="gemma3:4b-it-qat",
             messages=[{"role""user""content": context}])
print(f'query: {query}\nAnswer:{response["message"]["content"]}')

它会返回如下这类答案:

如你所见,对于缺乏相关数据/事实的问题,LLM 会合理地拒绝作答。

本文所有代码可在文件 

https://github.com/nayash/knowledge-graph-demo/blob/master/qa-from-kg.ipynb

中找到。

局限性

如上所示,我们几乎没费太多力气就创建了一个基础的 QA system,因为 LLM 负责了大量工作,比如文本预处理、抽取等。但它还不完美。在我的初步评估中,至少发现了几个问题。

系统无法回答 “what is the warranty period?”,因为在图里 warranty 是 relation 的 label,但它从问题中被抽取成了 named entity,导致系统找不到任何 edge。因此,我们用于构建 knowledge graph 的核心 system prompt 还需要优化。

还有一些问题需要稍微改写后系统才能回答。但我发现这类问题最终都可以归因于 KG 的构建方式或从 query 中抽取的 keyword。两者都可以通过改进 prompts 来修复。比如,我使用的图中有一条 edge 是:

phone → support_dual_sim → nano sim

这显然并不理想。但这些都可以通过更谨慎地设计用于构建 KG 的 prompt 来修正。正如我在上一篇文章中提到的,我最初是用 chatGPT 生成的 prompt,并在此基础上略作修改。在真实生产场景中,应当花更多时间打磨 prompt。对于企业级应用,还可以尝试更大的 model,因为资源限制不再是问题。

总之,这种方法很有前景,并且可以与 RAG 结合来提升回答质量。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询