在人工智能技术飞速发展的今天,大型语言模型(LLM)已经成为推动各行各业智能化转型的核心力量。然而,当我们需要处理企业内部的私密文档、技术手册或者业务数据时,使用云端 API 服务就会面临数据泄露的风险。
为什么需要本地知识库问答系统
Ollama 是一个开源项目,让用户能够在自己的电脑上运行各种主流的大语言模型,包括 Llama 2、Mistral、Gemma 等。这意味着你可以完全控制自己的数据,所有的文本处理、向量计算和答案生成都在本地完成。
LangChain 则是构建 LLM 应用的框架,提供了文档加载器、文本分割器、向量存储、检索链等组件。通过 LangChain,我们可以轻松地将 Ollama 提供的本地大模型与向量数据库结合起来,实现 RAG(检索增强生成)技术。
核心问题与解决方案
RAG 的原理是:当用户提出问题时,系统首先会在本地的知识库中检索出与问题最相关的文档片段,然后将这些片段作为上下文提供给大模型,让大模型基于这些真实的内容来生成答案。
完整实现代码
#!/usr/bin/env python3
"""
本地知识库问答系统
基于 LangChain + Ollama + Chroma
"""
import os
from pathlib import Path
from langchain_community.document_loaders import (
TextLoader,
PyPDFLoader,
Docx2txtLoader
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_ollama import OllamaEmbeddings
from langchain.chains import RetrievalQA
from langchain_ollama import OllamaLLM
# 配置部分
DOCS_DIR = Path("docs")
DB_DIR = Path("vector_db")
MODEL_NAME = "mistral"
EMBEDDING_MODEL = "nomic-embed-text"
# 1. 文档加载
def load_documents(docs_path: Path):
documents = []
loaders = {
".txt": TextLoader,
".pdf": PyPDFLoader,
".docx": Docx2txtLoader,
}
for file_path in docs_path.rglob("*"):
if file_path.suffix in loaders:
try:
loader = loaders[file_path.suffix](str(file_path))
docs = loader.load()
print(f"已加载: {file_path.name} ({len(docs)} 页/段)")
documents.extend(docs)
except Exception as e:
print(f"加载 {file_path.name} 失败: {e}")
return documents
# 2. 文本分割
def split_documents(documents, chunk_size=1000, chunk_overlap=200):
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=["\n\n", "\n", "。", " ", ""]
)
return text_splitter.split_documents(documents)
# 3. 向量存储
def create_vector_store(texts, persist_directory: str):
embeddings = OllamaEmbeddings(
model=EMBEDDING_MODEL,
base_url="http://localhost:11434"
)
vectordb = Chroma.from_documents(
documents=texts,
embedding=embeddings,
persist_directory=persist_directory
)
return vectordb
# 4. 构建问答链
def create_qa_chain(vectordb):
llm = OllamaLLM(
model=MODEL_NAME,
base_url="http://localhost:11434",
temperature=0.7
)
retriever = vectordb.as_retriever(
search_type="similarity",
search_kwargs={"k": 3}
)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=retriever,
return_source_documents=True
)
return qa_chain
def main():
print("=" * 50)
print("本地知识库问答系统")
print("=" * 50)
if not DOCS_DIR.exists():
DOCS_DIR.mkdir(parents=True)
print(f"\n请在 {DOCS_DIR} 目录下放入文档文件")
return
print("\n[步骤1] 加载文档...")
documents = load_documents(DOCS_DIR)
if not documents:
print("未找到任何文档")
return
print(f"共加载 {len(documents)} 个文档")
print("\n[步骤2] 分割文本...")
texts = split_documents(documents)
print(f"共分割成 {len(texts)} 个文本块")
print("\n[步骤3] 创建向量数据库...")
vectordb = create_vector_store(texts, str(DB_DIR))
print(f"向量数据库已保存到: {DB_DIR}")
print("\n[步骤4] 初始化问答系统...")
qa_chain = create_qa_chain(vectordb)
print("问答系统已准备就绪!")
print("\n" + "=" * 50)
print("问答系统已启动! 输入问题开始咨询 (输入 q 退出)")
print("=" * 50)
while True:
query = input("\n你: ").strip()
if query.lower() == "q":
print("再见!")
break
if not query:
continue
print("\n思考中...")
try:
result = qa_chain.invoke({"query": query})
print("\n" + "-" * 40)
print("回答:")
print(result["result"])
print("-" * 40)
except Exception as e:
print(f"发生错误: {e}")
if __name__ == "__main__":
main()
部署步骤
- 安装依赖:
pip install langchain langchain-community langchain-ollama ollama chromadb beautifulsoup4 pypdf python-docx - 下载模型:
ollama pull mistral - 准备文档:在 docs 目录下放入 TXT、PDF、Word 文件
- 运行系统:
python rag_demo.py
总结
本文详细介绍了如何使用 LangChain 和 Ollama 在本地构建知识库问答系统。通过这个方案,可以实现数据隐私安全、成本显著降低、响应速度快、定制化灵活等目标。
这个方案特别适合企业内部知识库建设、个人文档助手、私密数据的智能问答、开发者本地调试等场景。