DeepSeek-R1-Distill-Qwen-1.5B实战教程:对接RAG增强本地知识库检索能力

1. 引言:为什么需要给本地对话助手“装个大脑”?

想象一下,你有一个非常聪明的本地AI助手,它能和你流畅聊天、解答逻辑题、甚至写点代码。但当你问它一些关于你公司内部文档、个人笔记或者某个特定领域(比如法律、医疗)的专业问题时,它可能就“卡壳”了,因为它只知道自己训练时学到的通用知识。

这就是我们今天要解决的问题:如何让这个本地的、聪明的DeepSeek-R1-Distill-Qwen-1.5B模型,也能回答你私有的、特定的知识问题?

答案就是给它“装个大脑”——一个基于你自有文档构建的本地知识库。通过RAG(检索增强生成)技术,我们能让模型在回答问题时,先从这个知识库里找到相关材料,然后结合这些材料生成更准确、更专业的回答。

本教程将手把手带你,在已有的“DeepSeek-R1-Distill-Qwen-1.5B本地智能对话助手”基础上,无缝集成RAG能力。整个过程完全在本地运行,你的数据不出本地,隐私安全有保障,而且效果立竿见影。

学完本教程,你将能:

  1. 理解RAG技术如何让大模型“记住”你的专属知识。
  2. 掌握一套完整的本地知识库构建流程(文档处理、向量化、存储)。
  3. 改造现有的Streamlit聊天应用,使其具备“先检索后回答”的智能。
  4. 拥有一个完全私有化、能回答你特定领域问题的AI助手。

前置准备:

  • 一个已经部署好的“DeepSeek-R1-Distill-Qwen-1.5B本地智能对话助手”(基于Streamlit)。
  • 一些你想要让AI学习的文档(支持.txt, .md, .pdf等格式)。
  • 基础的Python编程环境。

2. RAG核心原理:三分钟搞懂“检索增强生成”

别被“RAG”这个词吓到,它的核心思想非常简单,就像我们人类回答问题时一样:

  1. 遇到问题:先不急着回答,而是去“资料库”(比如书本、笔记、记忆)里查找相关的信息。
  2. 找到资料:把找到的最相关的几段资料拿出来。
  3. 组织答案:结合找到的资料和自己的理解,组织成完整的回答。

RAG技术就是让AI模仿这个过程:

传统大模型回答:

用户问题 -> 大模型 -> 生成答案

(模型只能依赖训练时学到的通用知识)

RAG增强后的大模型回答:

用户问题 -> 检索器(从知识库找资料)-> (问题 + 相关资料)-> 大模型 -> 生成答案

(模型在回答时,手里多了你提供的“参考资料”)

对我们这个项目来说,关键就是构建一个本地的“资料库”(向量知识库)和一个高效的“检索器”。

3. 环境搭建与核心库安装

我们需要在原有项目环境的基础上,新增几个专门用于处理文档和向量检索的库。打开终端,执行以下命令:

pip install langchain langchain-community sentence-transformers faiss-cpu pypdf

简单解释一下这些库是干什么的:

  • langchain & langchain-community:当今构建AI应用最流行的框架之一,它提供了处理文档、构建检索链等一系列好用的工具,能让我们省去大量底层代码。
  • sentence-transformers:一个专门用于将文本转换成“向量”(一种计算机能理解的数字表示)的库。我们将用它来把我们的文档和用户问题都转换成向量。
  • faiss-cpu:Facebook开源的向量数据库库(CPU版本)。想象它是一个超级高效的“图书馆索引系统”,能快速从海量向量中找到和问题最相关的几个。
  • pypdf:用来读取PDF格式的文档。

安装完成后,我们就可以开始构建知识库了。

4. 实战第一步:构建你的本地向量知识库

知识库不是简单地把文档堆在一起,而是需要经过“读取->切分->向量化->存储”四步。我们在项目根目录下创建一个新的Python脚本,比如叫 build_knowledge_base.py

# build_knowledge_base.py
import os
from langchain_community.document_loaders import DirectoryLoader, TextLoader, PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS

# 1. 指定你的文档所在文件夹
documents_folder = "./my_documents" # 创建一个文件夹,把你的txt、md、pdf文档放进去
if not os.path.exists(documents_folder):
    os.makedirs(documents_folder)
    print(f"请将您的文档放入 '{documents_folder}' 文件夹,然后重新运行此脚本。")
    exit()

# 2. 加载文档(支持多种格式)
print("开始加载文档...")
loaders = []
# 加载文本文件
if any(fname.endswith('.txt') for fname in os.listdir(documents_folder)):
    loaders.append(DirectoryLoader(documents_folder, glob="**/*.txt", loader_cls=TextLoader))
# 加载Markdown文件
if any(fname.endswith('.md') for fname in os.listdir(documents_folder)):
    loaders.append(DirectoryLoader(documents_folder, glob="**/*.md", loader_cls=TextLoader))
# 加载PDF文件
if any(fname.endswith('.pdf') for fname in os.listdir(documents_folder)):
    loaders.append(DirectoryLoader(documents_folder, glob="**/*.pdf", loader_cls=PyPDFLoader))

all_documents = []
for loader in loaders:
    try:
        all_documents.extend(loader.load())
    except Exception as e:
        print(f"加载部分文档时出错: {e}")

if not all_documents:
    print(f"在 '{documents_folder}' 中未找到支持的文档(.txt, .md, .pdf)。")
    exit()
print(f"成功加载 {len(all_documents)} 个文档。")

# 3. 切分文档(大文档切成小片段,方便检索)
print("正在切分文档...")
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,  # 每个片段的字符数,可根据需要调整
    chunk_overlap=50  # 片段间的重叠字符,保证上下文连贯
)
doc_splits = text_splitter.split_documents(all_documents)
print(f"文档被切分为 {len(doc_splits)} 个文本片段。")

# 4. 向量化并存储
print("正在生成向量并构建知识库(这可能需要几分钟)...")
# 使用一个轻量且效果不错的中文嵌入模型
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
# 创建向量存储
vectorstore = FAISS.from_documents(doc_splits, embeddings)
# 保存到本地
save_path = "./faiss_index"
vectorstore.save_local(save_path)
print(f"✅ 知识库构建完成!已保存至 '{save_path}' 文件夹。")
print(f"你可以删除或更新 '{documents_folder}' 中的文档,然后重新运行此脚本以更新知识库。")

运行这个脚本:

  1. 在项目根目录下创建一个名为 my_documents 的文件夹。
  2. 把你想要AI学习的文档(比如公司制度.txt、产品手册.pdf、学习笔记.md)放进这个文件夹。
  3. 在终端运行 python build_knowledge_base.py
  4. 等待程序运行完毕,你会看到一个名为 faiss_index 的新文件夹,里面就是构建好的向量知识库。

关键点说明:

  • 文档切分:为什么要把文档切碎?因为直接检索整篇文档效率低,且可能包含无关信息。切成500字左右的小片段,检索更精准。
  • 向量模型:我们选用 BAAI/bge-small-zh-v1.5,这是一个专门为中文优化的轻量级模型,效果和速度平衡得很好。
  • 完全本地:整个过程,从文档读取到向量生成,全部在你的机器上完成,数据不会上传到任何地方。

5. 实战第二步:改造Streamlit应用,集成RAG问答链

现在,我们有了知识库,需要修改原来的Streamlit聊天应用,让它具备检索能力。我们主要修改模型加载和回答生成的部分。

找到你原来的Streamlit应用主文件(比如叫 app.py),我们需要在其中添加RAG相关的代码。以下是关键的修改和新增部分:

# 在原有导入的基础上,新增以下导入
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

# ... (原有的模型和分词器加载代码保持不变) ...

# --- 新增:加载本地向量知识库 ---
print("🚀 加载本地知识库...")
try:
    embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh-v1.5")
    vectorstore = FAISS.load_local("./faiss_index", embeddings, allow_dangerous_deserialization=True)
    retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 检索最相关的3个片段
    print("✅ 知识库加载成功!")
except Exception as e:
    st.error(f"加载知识库失败: {e}")
    retriever = None

# --- 新增:定义RAG提示词模板 ---
# 这个模板告诉模型如何利用检索到的资料来回答问题
rag_prompt_template = """请根据以下提供的背景资料来回答问题。如果资料中包含答案,请基于资料回答;如果资料不相关或没有答案,请根据你自己的知识来回答,并说明这一点。

背景资料:
{context}

问题:
{question}

请用中文给出清晰、有条理的回答:"""
RAG_PROMPT = PromptTemplate.from_template(rag_prompt_template)

# --- 修改:在侧边栏添加RAG开关 ---
with st.sidebar:
    st.title("⚙️ 设置")
    # ... (原有的清空按钮等) ...
    use_rag = st.checkbox("启用知识库增强 (RAG)", value=True, help="开启后,AI将优先从您上传的文档中寻找答案。")
    st.divider()

# --- 修改:处理用户消息的函数 ---
def generate_response(user_input):
    """生成AI回复,集成RAG逻辑"""
    if not user_input:
        return "请输入您的问题。"

    # 准备对话历史(原有逻辑)
    messages_for_model = st.session_state.messages + [{"role": "user", "content": user_input}]
    prompt = tokenizer.apply_chat_template(messages_for_model, tokenize=False, add_generation_prompt=True)

    # **RAG核心逻辑:如果开启且知识库加载成功,先检索**
    context_text = ""
    if use_rag and retriever is not None:
        try:
            # 1. 检索相关文档片段
            relevant_docs = retriever.invoke(user_input)
            # 2. 将检索结果拼接成上下文
            context_text = "\n\n".join([doc.page_content for doc in relevant_docs])
            # 3. 将原始问题 + 检索到的上下文,构造成新的、更详细的问题给模型
            # 这里我们采用一种简单有效的方式:将上下文直接插入到最新一轮用户消息前
            enhanced_user_message = f"请参考以下资料回答问题:\n【资料开始】\n{context_text}\n【资料结束】\n\n我的问题是:{user_input}"
            # 替换最后一轮用户消息为增强版
            messages_for_model[-1]["content"] = enhanced_user_message
            # 重新生成prompt
            prompt = tokenizer.apply_chat_template(messages_for_model, tokenize=False, add_generation_prompt=True)
        except Exception as e:
            st.warning(f"知识库检索出错,将使用模型通用知识回答: {e}")

    # 原有生成逻辑(保持不变)
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    with torch.no_grad():
        outputs = model.generate(**inputs,
                                 max_new_tokens=2048,
                                 temperature=0.6,
                                 top_p=0.95,
                                 do_sample=True,
                                 pad_token_id=tokenizer.eos_token_id)
    response = tokenizer.decode(outputs[0][inputs['input_ids'].shape[1]:], skip_special_tokens=True)
    # 原有的标签格式化逻辑(保持不变)
    response = format_response(response)
    return response

# ... (Streamlit聊天界面主循环代码保持不变) ...

关键改造点解析:

  1. 加载知识库:应用启动时,除了加载大模型,还会加载我们之前构建好的 faiss_index 向量库。
  2. 添加控制开关:在侧边栏增加了一个复选框,让你可以随时开启或关闭RAG功能。关闭时,模型就变回原来的通用聊天模式。
  3. 增强提问逻辑:在 generate_response 函数中,如果RAG开启,会先进行检索。我们将检索到的资料,以清晰的标记(【资料开始】...【资料结束】)插入到用户的最新问题之前。这样,模型在生成回答时,就能“看到”这些资料。
  4. 优雅降级:如果检索过程出错(比如知识库没加载),代码会发出警告并回退到使用模型的通用知识来回答,保证服务可用性。

6. 效果对比与使用演示

完成改造后,重启你的Streamlit应用。现在你的聊天界面侧边栏会多出一个“启用知识库增强 (RAG)”的选项。

让我们来做个对比测试:

测试1:关闭RAG(通用模式)

  • 你问:“我们公司的年假制度是怎样的?”
  • AI答:(基于训练数据泛泛而谈)“年假制度通常根据国家法律法规和公司规定制定,一般员工工作满一年后享有5-15天不等的年假...”(可能不准确)

测试2:开启RAG(增强模式)

  • 你问:“我们公司的年假制度是怎样的?”
  • AI内部动作:先从你的my_documents文件夹里的《员工手册.pdf》中,检索到关于年假的段落。
  • AI答:“根据您提供的资料《员工手册》第三章第四节规定:本公司员工转正后,每年享有10天带薪年假。工作每满一年增加1天,上限为15天。年假申请需提前一周在OA系统提交...”(回答具体、准确、有出处)

你可以尝试的各种玩法:

  • 问答个人笔记:上传你的读书笔记.md,然后问它“这本书第三章主要讲了什么观点?”
  • 分析技术文档:上传某个软件API文档.pdf,然后问它“如何调用用户登录接口?”
  • 总结会议纪要:上传会议记录.txt,然后让它“总结一下上周项目会的主要决议和待办事项。”

7. 总结与进阶思考

恭喜!你现在已经拥有了一个具备“专属大脑”的本地AI助手。我们来回顾一下核心成果:

  1. 能力升级:你的DeepSeek-R1助手不再只是一个通用的聊天机器人,而是一个能深度理解并运用你私有知识的智能伙伴。
  2. 全程私有:从文档处理、向量化、存储到检索和生成,所有环节均在本地完成,确保了最高级别的数据隐私和安全。
  3. 开箱即用:我们提供了一键构建知识库的脚本和即插即用的应用改造方案,你只需要准备好文档,几步操作就能完成部署。

可能的进阶优化方向:

  • 知识库更新:当你有新文档时,重新运行 build_knowledge_base.py 脚本即可更新整个索引。对于频繁更新的场景,可以考虑增量更新策略。
  • 检索优化:调整 search_kwargs={"k": 3} 中的 k 值,控制每次检索返回的文档片段数量。太多可能引入噪音,太少可能信息不足。
  • 提示词工程:微调 rag_prompt_template,让模型更好地利用上下文。例如,要求它注明答案来源于哪份资料。
  • 前端展示:可以在AI回答旁边,增加一个“查看参考来源”的折叠区域,展示它具体引用了哪几个文档片段,增加可信度。
  • 混合检索:结合基于关键词的传统检索和向量检索,提升召回率。

这个项目展示了如何将强大的开源大模型与灵活的RAG技术相结合,以极低的成本(一个轻量模型+本地CPU)构建出真正实用、私有的企业级或个人知识助手。希望你能在此基础上,继续探索,打造出更贴合自己需求的AI应用。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐