在大语言模型(LLM)主导的AI应用浪潮中,检索增强生成(RAG)技术因其能解决LLM"幻觉"问题、提升输出可靠性而被广泛采用。但传统RAG多依赖单一向量检索,在复杂知识关联场景下常显不足。今天要介绍的LightRAG框架,通过融合知识图谱与向量检索,为构建可控、可解释的RAG系统提供了新思路。更重大的是,结合Ollama运行本地大模型,我们能在保护数据隐私的前提下,搭建一套全本地化的智能检索系统。
LightRAG是一款开源的模块化RAG框架,核心优势在于将"知识图谱"深度融入检索流程。与传统RAG仅依赖向量类似度不同,它会先从文本中提取实体(如人物、组织、概念)和关系(如"包含"“影响”),构建结构化的知识网络,再结合向量检索实现"语义+结构"的混合检索。这种设计让LLM在生成回答时,既能理解文本语义,又能依托实体间的关联关系,输出更精准、可追溯的结果。

从实用性来看,LightRAG的亮点很突出:
搭建系统的第一步是准备环境。LightRAG的安装过程很简洁,通过pip即可完成核心依赖安装,再配合Ollama运行本地模型,整个流程无需复杂配置。
打开终端,执行以下命令:
# 创建虚拟环境(可选但推荐)
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
Ollama是运行本地大模型的工具,需先安装Ollama客户端(官网:https://ollama.com/),再拉取所需模型。本文以IBM的Granite系列为例(轻量且性能均衡):
# 拉取LLM模型(用于生成回答)
ollama pull granite4:latest
# 拉取嵌入模型(用于文本向量化)
ollama pull granite-embedding:latest
启动Ollama服务后,模型会在本地11434端口运行,后续LightRAG将通过该端口调用模型。
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实例、插入文档构建知识库、发起查询获取增强回答。
第一需要定义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是初始化存储和处理管道的必须步骤,确保数据能正确读写。
有了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方法会自动完成一系列处理:
文档插入后,就可以通过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"幻觉"的关键。
不同检索模式的区别:
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()
通过可视化,我们能清晰看到"量子安全加密"与"传统加密"、"Shor算法"等实体的关联,这也是混合检索能提升回答准确性的核心缘由——不仅靠语义类似,还靠结构化的关系。
我们用3篇关于"量子安全加密"的文档(包含技术原理、应用场景、与传统加密的对比)进行测试,查询"量子安全加密为何能抵抗量子计算攻击?",系统返回的结果准确引用了文档中的关键信息:
相比纯向量检索,混合检索模式能更精准地关联"量子计算"、“Shor算法”、"格密码"等实体,回答的逻辑性和完整性更优。
LightRAG结合Ollama搭建的RAG系统,既保留了本地化部署的隐私优势,又通过知识图谱解决了传统RAG的检索局限性。其模块化设计让开发者可以灵活替换组件(模型、存储、检索策略),而自动构建知识图谱的能力则降低了结构化知识处理的门槛。
无论是企业内部的知识库问答、客服系统,还是需要精准溯源的专业领域应用,这套方案都能提供可靠的技术支撑。随着本地大模型性能的提升,这种"本地模型+知识图谱+RAG"的架构,有望成为数据敏感场景下的主流选择。
如果你也在探索可控、可解释的AI应用,不妨试试LightRAG,用几行代码就能搭建起一个兼具深度和可靠性的智能检索系统。