使用 DeepSeek R1 和 Ollama 開發(fā) RAG 系統(tǒng)(包含完整代碼)
是否想過直接向PDF文檔或技術(shù)手冊(cè)提問?本文將演示如何通過開源推理工具DeepSeek R1與本地AI模型框架Ollama搭建檢索增強(qiáng)生成(RAG)系統(tǒng)。
高效工具推薦:用Apidog簡(jiǎn)化API測(cè)試流程
圖片
Apidog作為一體化API解決方案,可實(shí)現(xiàn):
- 零腳本自動(dòng)化核心流程
- 無縫對(duì)接CI/CD管道
- 精準(zhǔn)定位性能瓶頸
- 可視化接口管理
DeepSeek R1核心優(yōu)勢(shì)
相比OpenAI o1模型成本降低95%,具備:
- 精準(zhǔn)檢索:每次僅調(diào)用3個(gè)文檔片段
- 嚴(yán)謹(jǐn)輸出:未知問題主動(dòng)返回"暫不了解"
- 本地運(yùn)行:徹底消除云端API延遲
環(huán)境準(zhǔn)備
1. Ollama本地部署
# 安裝基礎(chǔ)框架
ollama run deepseek-r1 # 默認(rèn)使用7B模型
Ollama官網(wǎng)下載:https://ollama.ai
圖片
2. 模型選擇策略
# 輕量級(jí)場(chǎng)景推薦1.5B版本
ollama run deepseek-r1:1.5b
硬件建議:70B大模型需32GB內(nèi)存支持
RAG系統(tǒng)構(gòu)建全流程
Step 1: 導(dǎo)入依賴庫
- 用于文檔處理和檢索的 LangChain。
- 流利使用用戶友好的Web界面。
import streamlit as st
from langchain_community.document_loaders import PDFPlumberLoader
from langchain_experimental.text_splitter import SemanticChunker
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_community.llms import Ollama
圖片
Step 2: PDF文件上傳與解析
利用 Streamlit 的文件上傳器選擇本地 PDF。使用 PDFPlumberLoader 高效提取文本,無需手動(dòng)解析。
# 創(chuàng)建Streamlit文件上傳組件
uploaded_file = st.file_uploader("上傳PDF文件", type="pdf")
if uploaded_file:
# 臨時(shí)存儲(chǔ)PDF文件
with open("temp.pdf", "wb") as f:
f.write(uploaded_file.getvalue())
# 加載PDF內(nèi)容
loader = PDFPlumberLoader("temp.pdf")
docs = loader.load()
Step 3: 文檔語義分塊
利用 Streamlit 的文件上傳器選擇本地 PDF。使用 PDFPlumberLoader 高效提取文本,無需手動(dòng)解析。
# 初始化語義分塊器
text_splitter = SemanticChunker(
HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
)
# 執(zhí)行分塊操作
documents = text_splitter.split_documents(docs)
圖片
Step 4: 構(gòu)建向量數(shù)據(jù)庫
# 生成文本嵌入
embeddings = HuggingFaceEmbeddings()
vector_store = FAISS.from_documents(documents, embeddings)
# 配置檢索器
retriever = vector_store.as_retriever(search_kwargs={"k": 3})
Step 5: 配置DeepSeek R1模型
# 初始化本地模型
llm = Ollama(model="deepseek-r1:1.5b")
# 定義提示模板
prompt_template = """
根據(jù)以下上下文:
{context}
問題:{question}
回答要求:
1. 僅使用給定上下文
2. 不確定時(shí)回答"暫不了解"
3. 答案控制在四句話內(nèi)
最終答案:
"""
QA_PROMPT = PromptTemplate.from_template(prompt_template)
Step 6: 組裝RAG處理鏈
# 創(chuàng)建LLM處理鏈
llm_chain = LLMChain(llm=llm, prompt=QA_PROMPT)
# 配置文檔組合模板
document_prompt = PromptTemplate(
template="上下文內(nèi)容:\n{page_content}\n來源:{source}",
input_variables=["page_content", "source"]
)
# 構(gòu)建完整RAG管道
qa = RetrievalQA(
combine_documents_chain=StuffDocumentsChain(
llm_chain=llm_chain,
document_prompt=document_prompt
),
retriever=retriever
)
Step 7: 啟動(dòng)交互界面
# 創(chuàng)建問題輸入框
user_question = st.text_input("輸入您的問題:")
if user_question:
with st.spinner("正在生成答案..."):
# 執(zhí)行查詢并顯示結(jié)果
response = qa(user_question)["result"]
st.success(response)
完整的代碼:https://gist.github.com/lisakim0/0204d7504d17cefceaf2d37261c1b7d5.js
技術(shù)實(shí)現(xiàn)要點(diǎn)
語義分塊優(yōu)化:采用SemanticChunker替代傳統(tǒng)滑動(dòng)窗口,提升上下文連貫性
# 示例:調(diào)整分塊策略
text_splitter = SemanticChunker(
embeddings,
breakpoint_threshold=0.85 # 調(diào)整語義分割閾值
)
檢索優(yōu)化配置:動(dòng)態(tài)調(diào)整檢索數(shù)量
# 根據(jù)問題復(fù)雜度動(dòng)態(tài)調(diào)整k值
def dynamic_retriever(question):
complexity = len(question.split())
return vector_store.as_retriever(search_kwargs={"k": min(complexity, 5)})
混合檢索策略:結(jié)合關(guān)鍵詞與向量搜索
from langchain.retrievers import BM25Retriever, EnsembleRetriever
bm25_retriever = BM25Retriever.from_documents(documents)
ensemble_retriever = EnsembleRetriever(
retrievers=[bm25_retriever, vector_retriever],
weights=[0.4, 0.6]
)
最后
DeepSeek R1 只是一個(gè)開始。憑借即將推出的自我驗(yàn)證和多跳推理等功能,未來的 RAG 系統(tǒng)可以自主辯論和完善其邏輯。