本地 AI 知识库助手
Python
Ollama
ChromaDB
LangChain
Streamlit
项目简介
一个基于本地 Ollama 大模型的 RAG(检索增强生成)知识库问答系统。可以上传文档,在本地进行智能问答,完全离线,保护隐私。特别适合处理敏感文档的研究人员和开发者~
💡 核心特性:完全本地运行 · 支持多种文档格式 · 无需 API 费用 · 隐私安全
主要功能
- PDF、TXT、Markdown 文档解析和向量化
- 基于向量数据库的语义检索
- 结合检索结果生成准确回答
- 友好的 Web 界面(Streamlit)
- 支持自定义知识库和对话历史
- 可连接 Ollama 或 OpenAI API
环境准备
确保你已安装以下环境:
- Python 3.10+
- Ollama(官网)
- 16GB+ RAM(推荐)
详细搭建步骤
1
安装依赖
创建项目目录并安装 Python 依赖:
mkdir local-rag-assistant
cd local-rag-assistant
pip install langchain langchain-community chromadb streamlit
pip install pypdf python-docx tiktoken sentence-transformers
或者一次性安装所有依赖:
pip install -r requirements.txt
2
下载 Ollama 模型
确保 Ollama 服务正在运行,然后下载需要的模型:
# 下载嵌入模型(用于文档向量化)
ollama pull nomic-embed-text
# 下载对话模型
ollama pull llama3
# 验证模型已下载
ollama list
预期输出
NAME ID SIZE MODIFIED
llama3 365c0c14b0e3 4.7GB 2026-03-21
nomic-embed-text 0a109f422b47 274MB 2026-03-21
⚠️ 注意:首次运行会自动下载模型,请确保网络畅通。模型文件较大(数GB),请耐心等待。
3
创建核心代码文件
创建项目主文件 app.py:
"""
本地 AI 知识库助手
基于 Ollama + ChromaDB + Streamlit
"""
import streamlit as st
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.chat_models import ChatOllama
from langchain.chains import RetrievalQA
import tempfile
import os
# 配置页面
st.set_page_config(page_title="本地知识库助手", page_icon="🤖")
st.title("🤖 本地 AI 知识库助手")
# 初始化向量数据库
@st.cache_resource
def get_vectorstore():
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
return vectorstore
# 初始化聊天模型
@st.cache_resource
def get_llm():
return ChatOllama(model="llama3", temperature=0.7)
# 上传文档
def process_document(uploaded_file):
# 保存上传文件到临时目录
with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmp_file:
tmp_file.write(uploaded_file.getvalue())
tmp_path = tmp_file.name
# 加载文档
if uploaded_file.name.endswith(".pdf"):
loader = PyPDFLoader(tmp_path)
else:
from langchain_community.document_loaders import TextLoader
loader = TextLoader(tmp_path)
documents = loader.load()
# 文本分块
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
chunks = text_splitter.split_documents(documents)
# 向量化并存入数据库
embeddings = OllamaEmbeddings(model="nomic-embed-text")
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory="./chroma_db"
)
os.unlink(tmp_path)
return len(chunks)
# 问答
def answer_question(question, vectorstore, llm):
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever
)
return qa_chain.run(question)
# 侧边栏 - 上传文档
with st.sidebar:
st.header("📁 上传文档")
uploaded_file = st.file_uploader(
"选择 PDF 或 TXT 文件",
type=["pdf", "txt"],
help="支持 PDF 和纯文本文件"
)
if uploaded_file and st.button("处理文档", type="primary"):
with st.spinner("正在处理文档..."):
chunk_count = process_document(uploaded_file)
st.success(f"✅ 文档处理完成!共 {chunk_count} 个文本块")
st.divider()
st.markdown("### 使用说明")
st.markdown("""
1. 上传 PDF 或 TXT 文档
2. 点击「处理文档」按钮
3. 在下方输入问题并提问
""")
# 主界面 - 问答
if "messages" not in st.session_state:
st.session_state.messages = []
for message in st.session_state.messages:
with st.chat_message(message["role"]):
st.markdown(message["content"])
question = st.chat_input("请输入你的问题...")
if question:
with st.chat_message("user"):
st.markdown(question)
st.session_state.messages.append({"role": "user", "content": question})
with st.spinner("思考中..."):
try:
vectorstore = get_vectorstore()
llm = get_llm()
answer = answer_question(question, vectorstore, llm)
with st.chat_message("assistant"):
st.markdown(answer)
st.session_state.messages.append({"role": "assistant", "content": answer})
except Exception as e:
st.error(f"出错了: {str(e)}")
4
创建依赖文件
创建 requirements.txt 方便管理依赖:
langchain>=0.1.0
langchain-community>=0.0.10
chromadb>=0.4.0
streamlit>=1.28.0
pypdf>=3.0.0
python-docx>=1.0.0
tiktoken>=0.5.0
sentence-transformers>=2.2.0
5
启动服务
确保 Ollama 服务正在运行(如果没有,自动启动):
# 在另一个终端启动 Ollama(如果未运行)
ollama serve
# 启动 Streamlit 应用
streamlit run app.py --server.port 8501
预期效果
浏览器自动打开 http://localhost:8501
可以看到带有侧边栏的上传区域和主聊天界面
6
测试使用
完整使用流程:
- 上传一个 PDF 文档(如论文、技术文档)
- 点击「处理文档」按钮,等待处理完成
- 在底部输入框输入问题,如:「这篇文章的主要观点是什么?」
- 查看 AI 返回的基于文档内容的回答
预期效果截图描述
左侧边栏:文件上传区域 + 使用说明
右侧主区域:聊天历史 + 输入框
深色主题,紫色强调色,现代简洁界面
代码说明
核心组件
- PyPDFLoader:加载 PDF 文档
- RecursiveCharacterTextSplitter:将长文本分割成小块
- OllamaEmbeddings:使用本地 Ollama 生成文本向量
- Chroma:向量数据库,存储和检索文档向量
- RetrievalQA:RAG 问答链,结合检索和生成
向量检索原理
系统会:
- 将上传的文档分割成 500 字符的小块
- 使用 nomic-embed-text 模型将每块文本转换为向量
- 将向量存储在 ChromaDB 中
- 用户提问时,将问题也转为向量
- 在向量数据库中找到最相似的文档块
- 将相关文档块作为上下文发送给大模型生成回答
常见问题
Q: 报错 "Connection refused"?
确保 Ollama 服务正在运行:
ollama serve
Q: 模型下载太慢?
可以尝试使用国内镜像源,或选择更小的模型如 phi 或 qwen。
Q: 内存不足?
减少同时加载的模型,或使用更小的模型:
ollama run phi # 较小但速度更快
项目结构
local-rag-assistant/
├── app.py # 主应用
├── requirements.txt # 依赖列表
├── chroma_db/ # 向量数据库(自动生成)
└── README.md # 项目说明
扩展方向
- 添加更多文档格式支持(Word、Excel)
- 支持多文档同时检索
- 添加对话历史管理
- 集成 Web 搜索功能
- 添加文档摘要功能
🎉 完成! 现在你拥有了一个完全本地运行的知识库问答系统,可以安全地处理敏感文档了!