Neo4j 与 LLM:图数据库赋能的知识问答

FreeGuideOnline 最新 2026-06-23

环境准备与基础概念

在开始将 Neo4j 与大型语言模型(LLM)结合之前,需要理解二者各自扮演的角色以及协作的基础设施。Neo4j 是一个属性图数据库,数据以节点(Node)、关系(Relationship)和属性(Property)的形式存储,擅长表达高度互联的数据和复杂语义网络。LLM 则负责理解自然语言、生成答案并推理上下文。

为什么图数据库能增强 LLM 的知识问答

LLM 虽然具备强大的泛化能力,却面临知识截止、幻觉、缺乏领域专有知识等挑战。图数据库从三个层面弥补这些缺陷:

  • 结构化知识存储:将企业文档、业务实体及其关系建模为图,构成可查询的知识图谱。
  • 精确的上下文检索:基于图的遍历与模式匹配,检索出与用户问题高度相关的子图,作为 LLM 的提示上下文。
  • 可解释的推理路径:关系本身就是推理单元,答案生成后可追溯至图中的具体路径,增强透明度和可信度。

技术栈选型

推荐组合:

  • 图数据库:Neo4j(社区版或 AuraDB 免费实例)
  • LLM 访问:OpenAI API、Azure OpenAI,或本地模型通过 LangChain、LlamaIndex 封装
  • 编排框架:LangChain(提供 GraphCypherQAChain)或 LlamaIndex(KnowledgeGraphIndex)
  • 编程语言:Python 3.10+

知识图谱构建:从非结构化文本到 Neo4j

知识问答系统的起点是构建一张包含领域知识的知识图谱。以下流程将原始文档转化为 Neo4j 中的节点和关系。

实体与关系抽取流水线

典型流水线有两种构建方式:基于 LLM 的一体化抽取,或使用传统 NLP 结合规则。

方式一:利用 LLM 直接抽取三元组

通过提示工程引导 LLM 从文本片段中抽取 (头实体, 关系, 尾实体) 三元组。提示模板示例:

从以下文本中提取所有实体和它们之间的关系,以JSON列表返回,每个元素包含 head, relation, tail 三个字段。
文本:{chunk_text}

处理长文档时,先按段落或固定 Token 长度切分文本块,对每个块调用 LLM,聚合结果并去重。Python 伪代码:

import openai
from neo4j import GraphDatabase

def extract_triplets(text_chunk):
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": f"提取三元组: {text_chunk}"}]
    )
    # 解析返回的JSON三元组列表并返回
    return parse_json(response.choices[0].message.content)

# 写入 Neo4j
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))
with driver.session() as session:
    for head, rel, tail in triplets:
        session.run("""
            MERGE (h:Entity {name: $head})
            MERGE (t:Entity {name: $tail})
            MERGE (h)-[r:RELATION {type: $rel}]->(t)
        """, head=head, rel=rel, tail=tail)

方式二:预定义模式 + 实体链接

如果领域边界清晰,可先设计本体(节点标签和关系类型),然后用命名实体识别(NER)模型(如 spaCy)抽取实体,再通过 LLM 对实体对分类关系。此方法更可控,适合精度要求高的场景。

图数据质量优化

  • 实体归一化:对相似名称(如“Apple”与“Apple Inc.”)进行实体对齐,可利用字符串相似度和 LLM 判断。
  • 关系细化:将通用关系(RELATION)替换为领域特有类型,如 :ACTED_IN:WORKS_FOR
  • 属性嵌入:为节点生成文本向量(OpenAI Embeddings),存储为节点属性,支持后续语义搜索。

知识问答实现模式

将 Neo4j 的查询能力与 LLM 结合,主要分为三种实现模式,复杂度递增。

模式一:文本到 Cypher(Text2Cypher)

最通用的方法,让 LLM 将用户自然语言问题翻译为 Cypher 查询,执行查询后,将结果提供给 LLM 合成最终答案。

核心架构:GraphCypherQAChain

LangChain 内置了此模式,封装了提示、查询生成、结果处理和答案合成。

from langchain.chains import GraphCypherQAChain
from langchain_community.graphs import Neo4jGraph
from langchain_openai import ChatOpenAI

graph = Neo4jGraph(
    url="bolt://localhost:7687",
    username="neo4j",
    password="password"
)

chain = GraphCypherQAChain.from_llm(
    llm=ChatOpenAI(model="gpt-4", temperature=0),
    graph=graph,
    verbose=True
)

chain.run("谁导演了电影《盗梦空间》?")

该链的底层工作原理:

  1. Schema 注入:自动获取 Neo4j 数据库中所有节点标签、关系类型和属性键,构造提示前缀。
  2. Cypher 生成:LLM 根据 Schema 和用户问题生成查询。
  3. 查询执行:在 Neo4j 中执行,捕获错误并可能让 LLM 自我修正。
  4. 答案合成:将查询结果与原始问题一同提交给 LLM,生成自然语言回答。

限制与优化

  • 复杂问题生成错误:可通过少样本提示(Few-shot)提供问题-Cypher 对示例,显著提升生成准确率。
  • 只读安全:在提示中严格声明只允许 MATCHRETURN 等只读操作,避免数据篡改。
  • 性能:限制生成查询返回的记录数,使用 LIMIT

模式二:图增强检索生成(Graph RAG)

Graph RAG 不依赖 LLM 生成数据库查询,而是先基于用户问题从图中检索相关的结构化知识,再把这些知识块注入 LLM 上下文。

检索器设计

检索分为两步:实体链接与子图抽取。

  • 实体链接:使用向量相似度搜索(利用节点上的文本嵌入属性)或全文搜索,找到问题中提及的实体节点。
    MATCH (e:Entity)
    WHERE e.embedding IS NOT NULL
    WITH e, gds.similarity.cosine(e.embedding, $question_embedding) AS score
    ORDER BY score DESC
    LIMIT 5
    RETURN e.name, score
    
  • 子图抽取:从已链接的实体出发,沿关系扩展1-2跳,构成局部子图。可基于规则或使用图算法(如PageRank)过滤重要关系。

上下文组装与生成

将子图序列化为人类可读的文本格式(如“实体A -[关系]-> 实体B”),与用户问题拼接后送入 LLM。

context = "知识图谱片段:\n"
for r in subgraph_relations:
    context += f"{r['source']} -- {r['type']} --> {r['target']}\n"

prompt = f"根据以下知识回答问题:\n{context}\n问题:{question}\n回答:"
answer = llm.predict(prompt)

Graph RAG 的优势在于避免了 Text2Cypher 可能的翻译错误,尤其适合图模式复杂、但问题偏向于局部信息查询的场景。缺点是当需要聚合统计(如“有多少导演与克里斯托弗·诺兰合作过?”)时可能检索不全,需回退到 Cypher 模式。

模式三:智能体循环(Agentic Loop)

对于需要多步推理、多工具协作的复杂问题,可将 Neo4j 封装为一个工具,由 LLM 智能体(Agent)决策何时调用图工具,并结合其他工具(如计算器、搜索引擎)完成回答。

使用 LangChain 的 create_openai_tools_agent

from langchain_core.tools import tool
from langchain_community.graphs import Neo4jGraph
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_openai_tools_agent

graph = Neo4jGraph(...)

@tool
def query_knowledge_graph(question: str) -> str:
    """用于查询电影和导演相关知识的图数据库。输入为自然语言问题,返回相关信息。"""
    # 内部可以调用 Text2Cypher 或 Graph RAG
    return graph.query(question_to_cypher(question))

llm = ChatOpenAI(model="gpt-4-turbo", temperature=0)
tools = [query_knowledge_graph]

agent = create_openai_tools_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

agent_executor.invoke({"input": "莱昂纳多·迪卡普里奥演过的电影中,哪一部评分超过9.0且导演也参演了?"})

智能体能够自主拆分问题、多次调用图工具,甚至结合外部数据,但延迟较高,成本也需注意。

实战案例:构建电影知识问答应用

为具体说明,我们用一个公开电影数据集构建一个问答系统。数据集来自MovieLens或IMDB,包含电影、演员、导演、评分等。

数据建模与导入

节点标签 属性
Movie title, released, imdbRating
Person name, born
Genre name

关系:

  • (:Person)-[:ACTED_IN {roles}]->(:Movie)
  • (:Person)-[:DIRECTED]->(:Movie)
  • (:Movie)-[:IN_GENRE]->(:Genre)

假设已有 CSV 文件,使用 Cypher 的 LOAD CSV 或 Neo4j ETL 工具导入。

实现并对比两种问答方式

我们实现 Text2Cypher 和 Graph RAG 两种模式,在相同测试集上对比效果。

  • Text2Cypher 实现:直接复用 GraphCypherQAChain,携带包含少样本的提示。
  • Graph RAG 实现
    1. 使用 OpenAI Embeddings 为每个 Person 和 Movie 节点生成描述嵌入(由 LLM 生成一句话描述)。
    2. 检索时,将问题嵌入,通过向量索引找到最相关的实体。
    3. 从这些实体出发,执行如下查询获取1跳子图:
      MATCH (n)-[r]->(m)
      WHERE id(n) IN $entity_ids
      RETURN n.name, type(r), m.title
      
    4. 将子图文本化后与问题一同提交给 LLM。

评测与观察

对于聚合统计类问题(如“诺兰电影的均分是多少”),Text2Cypher 正确率高但可能出现语法错误;Graph RAG 因缺乏全局聚合能力无法直接回答,需结合 Cypher。对于事实型问题(如“莱昂纳多演过恋爱类电影吗”),Graph RAG 更稳定,因为始终能提供相关背景。实际生产环境中,通常采用“先 Graph RAG 检索,若置信度不足则尝试 Text2Cypher”的混合路由策略。

生产化注意事项

  • 图索引优化:为常用查询属性创建索引(CREATE INDEX movie_title FOR (m:Movie) ON (m.title)),为向量搜索使用 Neo4j 向量索引(5.x以上支持)。
  • 读取副本:高并发问答场景使用只读副本分离负载。
  • 权限控制:LLM 生成的 Cypher 必须由只读用户执行,并通过参数化查询防止注入。
  • 缓存:对常见问题或相似图查询结果进行缓存,降低成本。
  • 监控与反馈:记录问答日志,收集用户反馈,建立 “问题-Cypher” 黄金数据集,用于微调小模型或提示优化。

总结与进阶方向

Neo4j 与 LLM 的结合为知识问答赋予了结构化思维和精确检索能力,避免了纯生成式模型的幻觉和冷知识盲区。本文介绍的三种模式从简单到复杂覆盖了大部分场景,起步可从 Text2Cypher 开始,逐步根据痛点引入 Graph RAG 和智能体。

进阶学习路径:

  • 探索 Neo4j 图数据科学库(GDS)进行社区发现和图嵌入,辅助问题理解。
  • 使用 LangGraph 构建更精细的图问答状态机,支持多轮对话澄清。
  • 在本地部署微调的代码生成模型(如 CodeLlama)专门完成 Cypher 翻译,降低 API 成本和延迟。

通过持续迭代知识图谱质量与问答架构,你将能够打造出深度理解领域知识的下一代智能应用。