使用 DeepSeek R1 和 Ollama 开发 RAG 系统(包含完整代码)
是否想过直接向PDF文档或技术手册提问?本文将演示如何通过开源推理工具DeepSeek R1与本地AI模型框架Ollama搭建检索增强生成(RAG)系统。高效工具推荐:用Apidog简化API测试流程
图片
Apidog作为一体化API解决方案,可实现:
[*]零脚本自动化核心流程
[*]无缝对接CI/CD管道
[*]精准定位性能瓶颈
[*]可视化接口管理
https://apidog.com
DeepSeek R1核心优势
相比OpenAI o1模型成本降低95%,具备:
[*]精准检索:每次仅调用3个文档片段
[*]严谨输出:未知问题主动返回"暂不了解"
[*]本地运行:彻底消除云端API延迟
环境准备
1. Ollama本地部署
# 安装基础框架ollama run deepseek-r1# 默认使用7B模型
[*]1.
[*]2.
Ollama官网下载:https://ollama.ai
图片
2. 模型选择策略
# 轻量级场景推荐1.5B版本ollama run deepseek-r1:1.5b
[*]1.
[*]2.
硬件建议:70B大模型需32GB内存支持
RAG系统构建全流程
Step 1: 导入依赖库
[*]用于文档处理和检索的 LangChain。
[*]流利使用用户友好的Web界面。
import streamlit as stfrom langchain_community.document_loaders import PDFPlumberLoaderfrom langchain_experimental.text_splitter import SemanticChunkerfrom langchain_community.embeddings import HuggingFaceEmbeddingsfrom langchain_community.vectorstores import FAISSfrom langchain_community.llms import Ollama
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
图片
Step 2: PDF文件上传与解析
利用 Streamlit 的文件上传器选择本地 PDF。使用 PDFPlumberLoader 高效提取文本,无需手动解析。
# 创建Streamlit文件上传组件uploaded_file = st.file_uploader("上传PDF文件", type="pdf")if uploaded_file: # 临时存储PDF文件 with open("temp.pdf", "wb") as f: f.write(uploaded_file.getvalue()) # 加载PDF内容 loader = PDFPlumberLoader("temp.pdf") docs = loader.load()
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
[*]7.
[*]8.
[*]9.
[*]10.
[*]11.
Step 3: 文档语义分块
利用 Streamlit 的文件上传器选择本地 PDF。使用 PDFPlumberLoader 高效提取文本,无需手动解析。
# 初始化语义分块器text_splitter = SemanticChunker( HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2"))# 执行分块操作documents = text_splitter.split_documents(docs)
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
[*]7.
图片
Step 4: 构建向量数据库
# 生成文本嵌入embeddings = HuggingFaceEmbeddings()vector_store = FAISS.from_documents(documents, embeddings)# 配置检索器retriever = vector_store.as_retriever(search_kwargs={"k": 3})
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
Step 5: 配置DeepSeek R1模型
# 初始化本地模型llm = Ollama(model="deepseek-r1:1.5b")# 定义提示模板prompt_template = """根据以下上下文:{context}问题:{question}回答要求:1. 仅使用给定上下文2. 不确定时回答"暂不了解"3. 答案控制在四句话内最终答案:"""QA_PROMPT = PromptTemplate.from_template(prompt_template)
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
[*]7.
[*]8.
[*]9.
[*]10.
[*]11.
[*]12.
[*]13.
[*]14.
[*]15.
[*]16.
[*]17.
[*]18.
Step 6: 组装RAG处理链
# 创建LLM处理链llm_chain = LLMChain(llm=llm, prompt=QA_PROMPT)# 配置文档组合模板document_prompt = PromptTemplate( template="上下文内容:\n{page_content}\n来源:{source}", input_variables=["page_content", "source"])# 构建完整RAG管道qa = RetrievalQA( combine_documents_chain=StuffDocumentsChain( llm_chain=llm_chain, document_prompt=document_prompt ), retriever=retriever)
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
[*]7.
[*]8.
[*]9.
[*]10.
[*]11.
[*]12.
[*]13.
[*]14.
[*]15.
[*]16.
[*]17.
Step 7: 启动交互界面
# 创建问题输入框user_question = st.text_input("输入您的问题:")if user_question: with st.spinner("正在生成答案..."): # 执行查询并显示结果 response = qa(user_question)["result"] st.success(response)
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
[*]7.
[*]8.
完整的代码:https://gist.github.com/lisakim0/0204d7504d17cefceaf2d37261c1b7d5.js
技术实现要点
语义分块优化:采用SemanticChunker替代传统滑动窗口,提升上下文连贯性
# 示例:调整分块策略text_splitter = SemanticChunker( embeddings, breakpoint_threshold=0.85# 调整语义分割阈值)
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
检索优化配置:动态调整检索数量
# 根据问题复杂度动态调整k值def dynamic_retriever(question): complexity = len(question.split()) return vector_store.as_retriever(search_kwargs={"k": min(complexity, 5)})
[*]1.
[*]2.
[*]3.
[*]4.
混合检索策略:结合关键词与向量搜索
from langchain.retrievers import BM25Retriever, EnsembleRetrieverbm25_retriever = BM25Retriever.from_documents(documents)ensemble_retriever = EnsembleRetriever( retrievers=, weights=)
[*]1.
[*]2.
[*]3.
[*]4.
[*]5.
[*]6.
[*]7.
最后
DeepSeek R1 只是一个开始。凭借即将推出的自我验证和多跳推理等功能,未来的 RAG 系统可以自主辩论和完善其逻辑。
页:
[1]