2. 知识图谱增强的大模型问答系统

任务说明

构建一个知识图谱增强的大模型问答系统:当用户提出问题时,系统先从知识图谱中检索相关事实,将检索结果与原始问题拼接为增强提示词,再交由大模型生成最终答案。本案例聚焦于“检索-增强-生成”链路的最小可复现实现,使用小型示例知识图谱与模拟大模型接口完成闭环。

系统架构

用户问题 "谁是图灵奖得主?" 实体识别 + 查询构建 识别"图灵奖" → SPARQL 知识图谱检索 返回事实三元组 提示词增强 问题 + 图谱事实 大模型生成 基于增强提示词 最终答案 返回给用户 知识图谱存储 实体-关系-实体 (图灵奖, 获奖者, 姚期智) 输入 处理 检索 增强 生成 输出

核心实现

以下代码实现了一个完整的知识图谱增强问答链路。知识图谱以Python字典存储三元组,实体识别通过关键词匹配完成,检索模块返回与问题实体相关的事实,增强模块将事实拼接到提示词中,最后调用模拟的大模型接口生成答案。

# kg_qa_system.py
"""知识图谱增强的大模型问答系统 - 最小可复现实现"""

class KnowledgeGraph:
    """基于字典的简易知识图谱存储"""
    def __init__(self):
        # 存储形式: (头实体, 关系, 尾实体)
        self.triples = [
            ("图灵奖", "获奖者", "姚期智"),
            ("图灵奖", "获奖者", "约翰·霍普克罗夫特"),
            ("图灵奖", "设立年份", "1966年"),
            ("姚期智", "国籍", "中国"),
            ("姚期智", "研究领域", "计算理论"),
            ("约翰·霍普克罗夫特", "国籍", "美国"),
            ("约翰·霍普克罗夫特", "研究领域", "算法设计"),
            ("清华大学", "教授", "姚期智"),
        ]
        # 构建索引: 头实体 -> [(关系, 尾实体)]
        self.head_index = {}
        for h, r, t in self.triples:
            self.head_index.setdefault(h, []).append((r, t))

    def query_by_head(self, head_entity):
        """根据头实体查询所有关联事实"""
        return self.head_index.get(head_entity, [])

class EntityRecognizer:
    """基于词典的实体识别器"""
    def __init__(self, kg):
        self.entities = set()
        for h, r, t in kg.triples:
            self.entities.add(h)
            self.entities.add(t)

    def recognize(self, question):
        """从问题中识别出知识图谱中存在的实体"""
        matched = []
        for entity in self.entities:
            if entity in question:
                matched.append(entity)
        return matched

class PromptAugmenter:
    """提示词增强器"""
    @staticmethod
    def augment(question, facts):
        """将检索到的事实拼接到问题后"""
        if not facts:
            return question
        fact_str = ";".join([f"{h}的{r}是{t}" for h, r, t in facts])
        return f"已知事实:{fact_str}。\n问题:{question}\n请基于以上事实回答问题。"

class MockLLM:
    """模拟大模型接口(真实场景替换为实际LLM API调用)"""
    def generate(self, prompt):
        # 模拟:从增强提示词中提取答案
        # 实际项目中替换为: .ChatCompletion.create(...) 等
        if "已知事实" in prompt:
            # 简单模拟:返回提示词中最后的事实
            lines = prompt.split("\n")
            for line in lines:
                if line.startswith("已知事实"):
                    facts = line.replace("已知事实:", "").replace("。", "").split(";")
                    if facts:
                        return f"根据知识图谱,{facts[0]}。"
        return "抱歉,我没有足够的信息回答这个问题。"

class KGEnhancedQA:
    """知识图谱增强问答主流程"""
    def __init__(self):
        self.kg = KnowledgeGraph()
        self.recognizer = EntityRecognizer(self.kg)
        self.augmenter = PromptAugmenter()
        self.llm = MockLLM()

    def answer(self, question):
        # 1. 实体识别
        entities = self.recognizer.recognize(question)
        if not entities:
            return "无法从问题中识别出知识图谱中的实体。"

        # 2. 知识图谱检索
        all_facts = []
        for entity in entities:
            facts = self.kg.query_by_head(entity)
            for r, t in facts:
                all_facts.append((entity, r, t))

        # 3. 提示词增强
        enhanced_prompt = self.augmenter.augment(question, all_facts)

        # 4. 大模型生成
        answer = self.llm.generate(enhanced_prompt)
        return answer

# ===== 使用示例 =====
if __name__ == "__main__":
    qa_system = KGEnhancedQA()

    # 测试问题1
    q1 = "谁是图灵奖得主?"
    print(f"问题: {q1}")
    print(f"答案: {qa_system.answer(q1)}\n")

    # 测试问题2
    q2 = "姚期智的研究领域是什么?"
    print(f"问题: {q2}")
    print(f"答案: {qa_system.answer(q2)}\n")

    # 测试问题3(无匹配实体)
    q3 = "今天天气怎么样?"
    print(f"问题: {q3}")
    print(f"答案: {qa_system.answer(q3)}")

运行与验证

运行方式:将上述代码保存为 kg_qa_system.py,在Python 3.6+环境中执行 python kg_qa_system.py。

预期输出:基于代码逻辑可直接推出的结果如下:

问题: 谁是图灵奖得主?
答案: 根据知识图谱,图灵奖的获奖者是姚期智。

问题: 姚期智的研究领域是什么?
答案: 根据知识图谱,姚期智的研究领域是计算理论。

问题: 今天天气怎么样?
答案: 无法从问题中识别出知识图谱中的实体。

验证判定标准:

  • 问题1和问题2能返回包含知识图谱事实的答案,证明“检索-增强-生成”链路已打通;
  • 问题3返回实体识别失败提示,证明系统对图谱外问题有兜底处理;
  • 将MockLLM.generate替换为真实大模型API调用(如、智谱等),保持输入输出接口不变,即可接入实际大模型。

扩展说明:本案例使用字典模拟知识图谱和关键词匹配实体识别,用于演示核心增强链路。生产环境中可将KnowledgeGraph替换为Neo4j等图数据库,将EntityRecognizer替换为基于NLP的命名实体识别模型,将MockLLM替换为实际大模型API,各模块接口保持不变即可平滑迁移。