用LightRAG和Ollama搭建带知识图谱的可控RAG系统,从入门到实战

  • 时间:2025-11-17 23:41 作者: 来源: 阅读:2
  • 扫一扫,手机访问
摘要:在大语言模型(LLM)主导的AI应用浪潮中,检索增强生成(RAG)技术因其能解决LLM"幻觉"问题、提升输出可靠性而被广泛采用。但传统RAG多依赖单一向量检索,在复杂知识关联场景下常显不足。今天要介绍的LightRAG框架,通过融合知识图谱与向量检索,为构建可控、可解释的RAG系统提供了新思路。更重大的是,结合Ollama运行本地大模型,我们能在保护数据隐私的前提下,搭建一套全本地化的智能检索系统

在大语言模型(LLM)主导的AI应用浪潮中,检索增强生成(RAG)技术因其能解决LLM"幻觉"问题、提升输出可靠性而被广泛采用。但传统RAG多依赖单一向量检索,在复杂知识关联场景下常显不足。今天要介绍的LightRAG框架,通过融合知识图谱与向量检索,为构建可控、可解释的RAG系统提供了新思路。更重大的是,结合Ollama运行本地大模型,我们能在保护数据隐私的前提下,搭建一套全本地化的智能检索系统。

什么是LightRAG?为何选择它?

LightRAG是一款开源的模块化RAG框架,核心优势在于将"知识图谱"深度融入检索流程。与传统RAG仅依赖向量类似度不同,它会先从文本中提取实体(如人物、组织、概念)和关系(如"包含"“影响”),构建结构化的知识网络,再结合向量检索实现"语义+结构"的混合检索。这种设计让LLM在生成回答时,既能理解文本语义,又能依托实体间的关联关系,输出更精准、可追溯的结果。


用LightRAG和Ollama搭建带知识图谱的可控RAG系统,从入门到实战


从实用性来看,LightRAG的亮点很突出:

  • 模块化设计:LLM、嵌入模型、存储系统(向量库、图谱库)均可灵活替换,支持OpenAI、Gemini、Ollama等多种接口;
  • 知识图谱自动构建:无需手动标注,框架能自动从非结构化文本中提取实体和关系,生成可可视化的知识网络;
  • 多检索模式:支持朴素检索、本地检索、全局检索和混合检索,可根据场景灵活切换;
  • 本地部署友善:通过Ollama可对接本地大模型,无需依赖外部API,适合数据敏感场景。

基础环境搭建:从安装到配置

搭建系统的第一步是准备环境。LightRAG的安装过程很简洁,通过pip即可完成核心依赖安装,再配合Ollama运行本地模型,整个流程无需复杂配置。

1. 安装核心依赖

打开终端,执行以下命令:

# 创建虚拟环境(可选但推荐)
python3 -m venv venv
source venv/bin/activate  # Windows系统用:venvScriptsactivate

# 安装LightRAG及API支持
pip install --upgrade pip
pip install "lightrag-hku[api]"

# 安装Ollama客户端(用于调用本地模型)
pip install ollama

2. 配置Ollama与模型

Ollama是运行本地大模型的工具,需先安装Ollama客户端(官网:https://ollama.com/),再拉取所需模型。本文以IBM的Granite系列为例(轻量且性能均衡):

# 拉取LLM模型(用于生成回答)
ollama pull granite4:latest

# 拉取嵌入模型(用于文本向量化)
ollama pull granite-embedding:latest

启动Ollama服务后,模型会在本地11434端口运行,后续LightRAG将通过该端口调用模型。

3. 配置环境变量

LightRAG通过.env文件管理参数,官方提供了env.example模板,复制后可根据需求修改:

cp env.example .env  # 复制模板

.env文件参数丰富,核心配置如下(其余保持默认即可):

# LLM配置(使用Ollama)
LLM_BINDING=ollama
LLM_MODEL=granite4:latest
LLM_BINDING_HOST=http://localhost:11434

# 嵌入模型配置
EMBEDDING_BINDING=ollama
EMBEDDING_MODEL=granite-embedding:latest
EMBEDDING_DIM=1024  # 根据模型实际维度填写
EMBEDDING_BINDING_HOST=http://localhost:11434

# 存储配置(默认本地文件,生产环境可换Redis/Neo4j)
LIGHTRAG_KV_STORAGE=JsonKVStorage
LIGHTRAG_GRAPH_STORAGE=NetworkXStorage  # 用于存储知识图谱
LIGHTRAG_VECTOR_STORAGE=NanoVectorDBStorage

这些配置指定了LightRAG使用Ollama提供的本地模型,以及数据存储方式。如果需要使用知识图谱功能,确保LIGHTRAG_GRAPH_STORAGE设置正确(默认NetworkX适合小规模场景,生产可用Neo4j)。

核心代码实现:从初始化到查询

接下来通过实战代码,一步步构建RAG系统。我们将实现三个核心功能:初始化RAG实例、插入文档构建知识库、发起查询获取增强回答。

1. 初始化RAG实例

第一需要定义LLM和嵌入模型的调用逻辑,再初始化LightRAG。由于使用Ollama,需自定义调用函数适配其API:

import os
import asyncio
from functools import partial
from lightrag import LightRAG
from lightrag.utils import EmbeddingFunc, setup_logger
from lightrag.kg.shared_storage import initialize_pipeline_status
from ollama import AsyncClient  # 导入Ollama异步客户端

# 配置参数
OLLAMA_BASE_URL = "http://localhost:11434"
LLM_MODEL = "granite4:latest"
EMBEDDING_MODEL = "granite-embedding:latest"
WORKING_DIR = "./rag_storage_ollama"  # 数据存储目录
EMBEDDING_DIMENSION = 1024  # 与嵌入模型维度一致

# 初始化日志
setup_logger("lightrag", level="INFO")

# 创建存储目录
if not os.path.exists(WORKING_DIR):
    os.mkdir(WORKING_DIR)

# 自定义Ollama-LLM调用函数
async def custom_ollama_llm_complete(prompt: str, system_prompt: str = None, **kwargs):
    # 从参数中提取模型和地址(通过partial注入)
    model = kwargs.pop('model')
    base_url = kwargs.pop('base_url')
    
    # 构建对话消息
    client = AsyncClient(host=base_url)
    messages = []
    if system_prompt:
        messages.append({"role": "system", "content": system_prompt})
    messages.append({"role": "user", "content": prompt})
    
    # 过滤不必要的参数,避免Ollama接口报错
    keys_to_filter = {'host', 'hashing_kv', 'history_messages'}
    cleaned_kwargs = {k: v for k, v in kwargs.items() if k not in keys_to_filter}
    
    # 调用Ollama生成回答
    response = await client.chat(model=model, messages=messages,** cleaned_kwargs)
    return response['message']['content']

# 初始化RAG实例
async def initialize_rag():
    # 配置LLM函数(固定模型和地址)
    configured_llm = partial(
        custom_ollama_llm_complete,
        model=LLM_MODEL,
        base_url=OLLAMA_BASE_URL
    )
    
    # 配置嵌入函数(使用LightRAG提供的ollama_embed)
    from lightrag.llm.ollama import ollama_embed
    configured_embed = partial(
        ollama_embed,
        embed_model=EMBEDDING_MODEL,
        base_url=OLLAMA_BASE_URL
    )
    
    # 包装嵌入函数(指定维度)
    embedding_func = EmbeddingFunc(
        embedding_dim=EMBEDDING_DIMENSION,
        func=configured_embed
    )
    
    # 创建LightRAG实例
    rag = LightRAG(
        working_dir=WORKING_DIR,
        llm_model_func=configured_llm,
        embedding_func=embedding_func
    )
    
    # 初始化存储和管道状态(必须步骤)
    await rag.initialize_storages()
    await initialize_pipeline_status()
    return rag

这段代码的核心是通过partial固定Ollama的模型和地址,再将自定义的LLM和嵌入函数注入LightRAG。initialize_storages和
initialize_pipeline_status是初始化存储和处理管道的必须步骤,确保数据能正确读写。

2. 插入文档:构建知识库与知识图谱

有了RAG实例后,需要向系统中插入文档。LightRAG会自动处理文档:分割文本、生成向量、提取实体和关系、构建知识图谱。我们以读取本地Markdown和TXT文件为例:

import glob

# 文档目录(存放要导入的知识)
DOCUMENTS_DIR = "./documents"

# 创建文档目录(如果不存在)
if not os.path.exists(DOCUMENTS_DIR):
    os.mkdir(DOCUMENTS_DIR)
    print(f"请在{DOCUMENTS_DIR}目录下放入文档(.md或.txt)")

# 加载并插入文档
async def load_and_insert_documents(rag: LightRAG):
    # 获取目录下的所有md和txt文件
    file_paths = glob.glob(os.path.join(DOCUMENTS_DIR, "*.md")) + 
                 glob.glob(os.path.join(DOCUMENTS_DIR, "*.txt"))
    
    if not file_paths:
        print(f"未在{DOCUMENTS_DIR}找到文档,请添加文件后重试")
        return False
    
    print(f"发现{len(file_paths)}个文档,开始插入...")
    for file_path in file_paths:
        filename = os.path.basename(file_path)
        try:
            # 读取文件内容
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            
            # 插入文档(可添加元数据,如文件名)
            await rag.ainsert(content, doc_meta={"filename": filename})
            print(f"成功插入:{filename}{len(content)}字符)")
        except Exception as e:
            print(f"插入{filename}失败:{e}")
    
    return True

插入文档时,ainsert方法会自动完成一系列处理:

  • 文本分割:将长文档按CHUNK_SIZE(默认1200字符)拆分为片段;
  • 向量化:用嵌入模型生成每个片段的向量,存入向量库;
  • 实体关系提取:调用LLM从文本中识别实体(如"量子安全加密")和关系(如"基于"),存入知识图谱;
  • 元数据关联:将文档名等元数据与片段绑定,方便后续追溯来源。

3. 发起查询:混合检索与结果解析

文档插入后,就可以通过aquery方法发起查询。LightRAG支持多种检索模式,其中"hybrid"(混合检索)会同时调用向量库和知识图谱,返回最相关的信息:

from lightrag import QueryParam
from datetime import datetime

# 输出目录(保存查询结果)
OUTPUT_DIR = "./output"
if not os.path.exists(OUTPUT_DIR):
    os.mkdir(OUTPUT_DIR)

async def main():
    rag = None
    try:
        # 1. 初始化RAG
        print("初始化RAG系统...")
        rag = await initialize_rag()
        
        # 2. 插入文档
        documents_inserted = await load_and_insert_documents(rag)
        if not documents_inserted:
            return
        
        # 3. 发起查询(以"量子安全加密"为例)
        query = "什么是量子安全加密?它与传统加密有何区别?"
        print(f"
查询:{query}")
        
        # 混合检索(结合向量和知识图谱)
        result = await rag.aquery(
            query,
            param=QueryParam(mode="hybrid", top_k=5)  # top_k控制返回结果数量
        )
        
        # 4. 解析结果
        response_text = None
        if hasattr(result, 'get_response_text'):
            response_text = result.get_response_text()  # 提取回答文本
        elif isinstance(result, str):
            response_text = result  # 缓存结果直接为字符串
        
        # 5. 保存结果到文件
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        output_file = os.path.join(OUTPUT_DIR, f"result_{timestamp}.md")
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(f"# 查询结果

## 问题:{query}

## 回答:
{response_text}

")
            
            # 写入检索到的来源
            if hasattr(result, 'retriever_output') and result.retriever_output.docs:
                f.write("## 参考来源:
")
                for i, doc in enumerate(result.retriever_output.docs):
                    f.write(f"### 来源{i+1}{doc.text[:500]}...

")
        
        print(f"
回答:{response_text}")
        print(f"结果已保存至:{output_file}")
        
    except Exception as e:
        print(f"发生错误:{e}")
    finally:
        if rag:
            await rag.finalize_storages()  # 关闭存储连接

# 运行主函数
if __name__ == "__main__":
    asyncio.run(main())

查询结果包含两部分:LLM生成的回答,以及检索到的参考来源(文本片段)。通过retriever_output.docs可以获取这些来源,实现"溯源"功能——这正是RAG解决LLM"幻觉"的关键。

不同检索模式的区别:

  • naive:仅检索向量库,返回语义最类似的文本片段;
  • local:基于知识图谱,检索与查询实体直接关联的信息;
  • global:扩大知识图谱检索范围,包括间接关联的实体;
  • hybrid:融合上述三种方式,平衡语义相关性和结构关联性。

知识图谱可视化:让关系一目了然

LightRAG生成的知识图谱默认以NetworkX格式存储,我们可以用Streamlit搭建一个简单的可视化工具,直观展示实体间的关系。

可视化工具代码

import streamlit as st
import networkx as nx
import matplotlib.pyplot as plt
from io import StringIO

def visualize_graph(G: nx.Graph):
    # 提取节点标签和关系
    node_labels = nx.get_node_attributes(G, 'label')  # 实体名称
    edge_labels = nx.get_edge_attributes(G, 'text')  # 关系描述
    node_types = nx.get_node_attributes(G, 'type')   # 节点类型(实体/片段)
    
    # 定义节点颜色(实体为蓝色,文本片段为绿色)
    color_map = {
        'Entity': '#1f78b4',
        'Chunk': '#b2df8a',
        'Unknown': '#a6cee3'
    }
    node_colors = [color_map.get(node_types.get(node, 'Unknown'), color_map['Unknown']) 
                  for node in G.nodes()]
    
    # 绘制图形
    plt.figure(figsize=(12, 8))
    pos = nx.spring_layout(G, k=0.3, iterations=50)  # 布局
    
    nx.draw_networkx_nodes(G, pos, node_size=2000, node_color=node_colors, alpha=0.8)
    nx.draw_networkx_edges(G, pos, edge_color='gray', style='dashed', arrows=True)
    nx.draw_networkx_labels(G, pos, labels=node_labels, font_size=10)
    nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_color='red', font_size=8)
    
    plt.title(f"知识图谱({G.number_of_nodes()}个实体,{G.number_of_edges()}个关系)")
    plt.axis('off')
    st.pyplot(plt)

def app():
    st.title("LightRAG知识图谱可视化")
    uploaded_file = st.file_uploader("上传GraphML文件", type=["graphml"])
    
    if uploaded_file:
        try:
            # 读取GraphML文件(LightRAG默认存储格式)
            graph_data = uploaded_file.read().decode("utf-8")
            G = nx.read_graphml(StringIO(graph_data))
            visualize_graph(G)
        except Exception as e:
            st.error(f"解析失败:{e}")

if __name__ == "__main__":
    app()

使用方法

  1. 找到LightRAG存储知识图谱的文件(默认在./rag_storage_ollama/graph_store目录下,格式为GraphML);
  2. 运行上述Streamlit代码:streamlit run visualize_graph.py;
  3. 在网页上传GraphML文件,即可看到实体和关系的可视化结果。

通过可视化,我们能清晰看到"量子安全加密"与"传统加密"、"Shor算法"等实体的关联,这也是混合检索能提升回答准确性的核心缘由——不仅靠语义类似,还靠结构化的关系。

实战效果与优化方向

实际场景测试

我们用3篇关于"量子安全加密"的文档(包含技术原理、应用场景、与传统加密的对比)进行测试,查询"量子安全加密为何能抵抗量子计算攻击?",系统返回的结果准确引用了文档中的关键信息:

  • 明确区分了传统加密(依赖大数分解)与量子安全加密(基于格密码、哈希等抗量子算法)的底层差异;
  • 提到了Shor算法对RSA的威胁,以及量子安全加密如何规避这一风险;
  • 参考来源清晰标注了信息来自哪篇文档的哪个片段。

相比纯向量检索,混合检索模式能更精准地关联"量子计算"、“Shor算法”、"格密码"等实体,回答的逻辑性和完整性更优。

优化提议

  1. 模型选择:若对效果要求高,可替换为更大的本地模型(如Llama 3 70B),但需更多计算资源;
  2. 存储升级:大规模部署时,将默认的本地文件存储替换为Redis(缓存)、Milvus(向量库)、Neo4j(知识图谱),提升性能;
  3. 参数调优:在.env中调整CHUNK_SIZE(文本分割长度)、TOP_K(返回结果数量),平衡精度和速度;
  4. 错误处理:实际应用中需增加重试机制(如文档插入失败时重试)、超时控制(避免LLM响应过慢)。

总结

LightRAG结合Ollama搭建的RAG系统,既保留了本地化部署的隐私优势,又通过知识图谱解决了传统RAG的检索局限性。其模块化设计让开发者可以灵活替换组件(模型、存储、检索策略),而自动构建知识图谱的能力则降低了结构化知识处理的门槛。

无论是企业内部的知识库问答、客服系统,还是需要精准溯源的专业领域应用,这套方案都能提供可靠的技术支撑。随着本地大模型性能的提升,这种"本地模型+知识图谱+RAG"的架构,有望成为数据敏感场景下的主流选择。

如果你也在探索可控、可解释的AI应用,不妨试试LightRAG,用几行代码就能搭建起一个兼具深度和可靠性的智能检索系统。

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】告别死记硬背:词缀“家族”帮你批量记单词(2025-11-18 00:33)
【系统环境|】九年级上英语重点词汇,原来是这些!(2025-11-18 00:32)
【系统环境|】告别词穷!整理超实用的300个词语,请收好!(附带拼音)(2025-11-18 00:32)
【系统环境|】小学英语高频常用词汇,下载了好好练习一下,看看能对多少?(2025-11-18 00:31)
【系统环境|】【陕西】吴清西:说解《说文解字》中的渭南方言词语(三)(2025-11-18 00:31)
【系统环境|】2.4寸IPS :ILI9341带触摸高清240*320(2025-11-18 00:30)
【系统环境|】技术 | 多线并接应该如何测拉力?(2025-11-18 00:30)
【系统环境|】​华与华兄弟:卖符号和词语二十年(2025-11-18 00:29)
【系统环境|】手把手教你搭建 Kafka 集群,一文就够了!(2025-11-18 00:29)
【系统环境|】Kafka集群最全详解(图文全面总结)(2025-11-18 00:28)
手机二维码手机访问领取大礼包
返回顶部