# 从零构建个人知识库助手:基于 RAG 的本地文档问答系统实战
## 背景介绍
在日常工作和学习中,我们会积累大量的文档资料:技术笔记、项目文档、会议记录、阅读笔记等。当这些文档散落在各个角落时,想要快速找到需要的信息就变得困难重重。虽然市面上有各种笔记软件和搜索工具,但它们通常只能进行简单的关键词匹配,无法真正理解我们的查询意图。
近年来,大语言模型(LLM)快速发展,一种名为 RAG(Retrieval-Augmented Generation,检索增强生成)的技术方案逐渐成为构建知识库问答系统的首选。RAG 的核心思想是将文档先进行向量化处理并存入向量数据库,当用户提问时,系统会从知识库中检索最相关的内容,然后将这些内容作为上下文提供给大语言模型,从而生成更加准确和有依据的回答。
本文将手把手教你如何使用 Python 从零构建一个基于 RAG 的个人知识库问答系统,能够对你的本地文档进行智能问答。
## 问题描述
传统的关键词搜索存在以下几个明显痛点:
1. **语义理解缺失**:无法理解同义词和近似表达,例如搜索”机器学习”时,找不到”ML”或”机器学习算法”相关的内容
2. **上下文丢失**:搜索结果往往是孤立的文档片段,缺乏全局视角
3. **无法推理**:不能进行多步推理和综合分析
4. **体验单一**:仅仅返回搜索结果,没有对话式的交互体验
基于 RAG 的问答系统则能很好地解决这些问题。它支持语义检索、对话式交互、答案溯源,并且可以处理本地文档(PDF、Markdown、TXT 等)。
## 详细步骤
### 1. 环境准备
首先安装必要的依赖库。推荐使用 Python 3.10 及以上版本。
“`bash
pip install langchain langchain-community langchain-huggingface
pip install chroma qdrant-client
pip install sentence-transformers
pip install unstructured[md] pdfminer
pip install openai tiktoken
“`
### 2. 文档加载与处理
使用 LangChain 提供的文档加载器可以方便地处理各类文档。以下是处理 Markdown 和纯文本文件的示例:
“`python
from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
import os
# 配置文档目录
DOCS_DIR = “./my-knowledge-base”
# 加载文档
def load_documents():
“””加载指定目录下的所有文档”””
loader = DirectoryLoader(
DOCS_DIR,
glob=”**/*.md”,
loader_cls=TextLoader,
encoding=”utf-8″
)
documents = loader.load()
return documents
# 文档分块
def split_documents(documents):
“””将长文档分割成较小的块”””
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
length_function=len,
)
chunks = text_splitter.split_documents(documents)
return chunks
print(f”成功加载 {len(documents)} 个文档”)
“`
### 3. 向量数据库构建
将文档块转换为向量并存储到向量数据库中:
“`python
# 初始化 Embedding 模型
def get_embedding_model():
“””获取嵌入模型”””
model_name = “sentence-transformers/all-MiniLM-L6-v2”
embeddings = HuggingFaceEmbeddings(
model_name=model_name,
model_kwargs={device: cpu}
)
return embeddings
# 构建向量数据库
def build_vector_store(chunks, embeddings):
“””构建 Chroma 向量数据库”””
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embeddings,
persist_directory=”./vector_store”
)
vectorstore.persist()
return vectorstore
“`
### 4. 构建 RAG 问答链
整合检索和大语言模型,构建完整的问答系统:
“`python
from langchain_community.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
# 配置 LLM
llm = ChatOpenAI(
model_name=”gpt-3.5-turbo”,
openai_api_key=”your-api-key”,
temperature=0
)
# 自定义提示词模板
qa_prompt = PromptTemplate(
template=”””你是一个专业的知识库助手。请根据以下参考文档回答用户的问题。
参考文档:
{context}
用户问题:{question}
请基于参考文档给出准确回答。如果文档中没有相关信息,请明确告知用户。”””,
input_variables=[“context”, “question”]
)
# 构建问答链
def build_qa_chain(vectorstore, llm):
“””构建 RAG 问答链”””
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type=”stuff”,
retriever=vectorstore.as_retriever(
search_kwargs={“k”: 3}
),
chain_type_kwargs={“prompt”: qa_prompt},
return_source_documents=True
)
return qa_chain
“`
### 5. 完整示例
以下是一个完整的、可直接运行的示例:
“`python
from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_community.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
class KnowledgeBaseQA:
“””个人知识库问答系统”””
def __init__(self, docs_dir, api_key):
self.docs_dir = docs_dir
self.llm = ChatOpenAI(
model_name=”gpt-3.5-turbo”,
openai_api_key=api_key,
temperature=0
)
self.embeddings = HuggingFaceEmbeddings(
model_name=”sentence-transformers/all-MiniLM-L6-v2″,
model_kwargs={device: cpu}
)
self.vectorstore = None
self.qa_chain = None
def build_knowledge_base(self):
“””构建知识库”””
# 1. 加载文档
loader = DirectoryLoader(
self.docs_dir,
glob=”**/*.md”,
loader_cls=TextLoader,
encoding=”utf-8″
)
documents = loader.load()
print(f”加载了 {len(documents)} 个文档”)
# 2. 分割文档
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50
)
chunks = text_splitter.split_documents(documents)
print(f”分割成 {len(chunks)} 个文本块”)
# 3. 构建向量数据库
self.vectorstore = Chroma.from_documents(
documents=chunks,
embedding=self.embeddings,
persist_directory=”./chroma_db”
)
self.vectorstore.persist()
print(“向量数据库构建完成”)
# 4. 构建问答链
self.qa_chain = RetrievalQA.from_chain_type(
llm=self.llm,
chain_type=”stuff”,
retriever=self.vectorstore.as_retriever(search_kwargs={“k”: 3}),
return_source_documents=True
)
print(“问答链构建完成”)
def ask(self, question):
“””提问”””
if not self.qa_chain:
raise ValueError(“请先构建知识库”)
result = self.qa_chain({“query”: question})
return {
“answer”: result[“result”],
“sources”: [doc.metadata.get(“source”, “未知”)
for doc in result[“source_documents”]]
}
# 使用示例
if __name__ == “__main__”:
qa_system = KnowledgeBaseQA(
docs_dir=”./my-knowledge-base”,
api_key=”your-openai-api-key”
)
# 构建知识库(首次运行需要执行)
qa_system.build_knowledge_base()
# 提问
result = qa_system.ask(“什么是 RAG 技术?”)
print(f”\n回答:{result[answer]}”)
print(f”参考来源:{result[sources]}”)
“`
## 运行结果
准备好文档并配置好 API Key 后,运行上述代码:
“`
加载了 15 个文档
分割成 287 个文本块
向量数据库构建完成
问答链构建完成
回答:RAG(Retrieval-Augmented Generation,检索增强生成)是一种将信息检索与文本生成相结合的技术方案。它首先从知识库中检索相关文档,然后将这些文档作为上下文提供给大语言模型,从而生成更加准确和有依据的回答。RAG 技术可以有效解决大语言模型知识过时、幻觉、胡编乱造等问题。
参考来源:[./my-knowledge-base/ai/rag-intro.md, ./my-knowledge-base/notes/llm-study.md]
“`
系统不仅给出了准确的回答,还列出了参考来源,方便追溯原始文档。
## 总结
通过本文我们学习了如何从零构建一个基于 RAG 的个人知识库问答系统。这个系统具有以下特点:
1. **语义检索**:基于向量的相似度匹配,能够理解语义相近的表达
2. **对话式交互**:像与人对话一样获取知识,而不是简单的关键词搜索
3. **答案可溯源**:每条回答都标注了参考来源,便于核实
4. **本地部署**:文档存储在本地,保护隐私安全
在实际使用中,可以根据自己的需求进行扩展:添加 PDF、Word 等格式支持、切换不同的 Embedding 模型、使用本地部署的开源大模型等。RAG 技术的应用场景非常广泛,除了个人知识库,还可以用于企业知识管理、智能客服、辅助编程等场景。