基于 DeepSeek R1 和 Ollama 開發(fā) RAG 系統(tǒng) 原創(chuàng)
今天,我們探討一下如何利用目前最受歡迎的開源推理工具 DeepSeek R1 和輕量級(jí)的本地AI模型執(zhí)行框架 Ollama,來(lái)構(gòu)建一個(gè)功能強(qiáng)大的 RAG (Retrieval-Augmented Generation)系統(tǒng)。
1、DeepSeek R1:RAG 系統(tǒng)的卓越之選
DeepSeek R1,被譽(yù)為開啟 AI 推理新時(shí)代的開源先鋒,在構(gòu)建 RAG 系統(tǒng)方面表現(xiàn)卓越,擁有眾多引人注目的優(yōu)勢(shì),成為開發(fā)者不可或缺的利器。相較于OpenAI 的 o1 模型,DeepSeek R1 在性能上與之媲美,但成本卻大幅下降,僅占 o1 的 5%,這一經(jīng)濟(jì)性使得更廣泛的開發(fā)者和企業(yè)能夠輕松采用,推動(dòng)了 RAG 技術(shù)的普及。
在信息檢索方面,DeepSeek R1 展現(xiàn)了其卓越的專注力。在生成答案的過(guò)程中,僅需引用3個(gè)文檔片段,便能精確提煉關(guān)鍵信息,有效排除了無(wú)關(guān)內(nèi)容的干擾,顯著提高了檢索效率和回答的精確度。這一特性使得即便在處理大量文檔時(shí),系統(tǒng)也能迅速鎖定關(guān)鍵內(nèi)容,向用戶提供簡(jiǎn)潔而高效的答案。
面對(duì)復(fù)雜問(wèn)題或不確定答案的情況,DeepSeek R1 的嚴(yán)格提示機(jī)制發(fā)揮了關(guān)鍵作用。與其他模型可能隨意生成答案不同,DeepSeek R1 在不確定時(shí)會(huì)坦白回答“我不知道”,這種嚴(yán)謹(jǐn)性有效防止了幻覺(jué)現(xiàn)象,確保了答案的真實(shí)性和可靠性,讓用戶獲得值得信賴的信息。
對(duì)于眾多開發(fā)者而言,數(shù)據(jù)安全和快速響應(yīng)是極為重要的考量。DeepSeek R1 支持本地化運(yùn)行,無(wú)需依賴云端 API,這不僅減少了網(wǎng)絡(luò)延遲帶來(lái)的問(wèn)題,還使用戶能夠在本地環(huán)境中安全處理敏感數(shù)據(jù),無(wú)需擔(dān)心數(shù)據(jù)泄露的風(fēng)險(xiǎn),為特定行業(yè)和場(chǎng)景的應(yīng)用提供了強(qiáng)有力的支持。
2、Ollama:本地模型運(yùn)行的理想框架
Ollama,作為一個(gè)輕量級(jí)框架,為本地運(yùn)行 AI 大模型提供了一個(gè)便捷且高效的平臺(tái),成為構(gòu)建本地 RAG 系統(tǒng)的重要組成部分。它的推出,使得開發(fā)者能夠減少對(duì)云端計(jì)算資源的依賴,輕松在本地設(shè)備上部署和執(zhí)行模型,顯著降低了開發(fā)與部署的成本,并增強(qiáng)了系統(tǒng)的獨(dú)立性和數(shù)據(jù)隱私保護(hù)。
在 Ollama 上下載和安裝模型的過(guò)程異常簡(jiǎn)便。以 DeepSeek R1 模型為例,開發(fā)者只需在終端輸入幾條簡(jiǎn)單的命令即可完成。例如,要運(yùn)行默認(rèn)的7B模型,只需執(zhí)行“ollama run deepseek-r1”命令;而若想體驗(yàn)適用于輕量級(jí) RAG 應(yīng)用場(chǎng)景的1.5B模型,則運(yùn)行“ollama run deepseek-r1:1.5b”命令即可。這種簡(jiǎn)便的操作流程,讓即便是技術(shù)背景較淺的開發(fā)者也能迅速掌握,開始 RAG 系統(tǒng)的開發(fā)工作。
Ollama 支持多種 AI 大模型,為開發(fā)者提供了廣泛的選擇余地。這些模型在性能、適用場(chǎng)景和資源需求上各有特點(diǎn),開發(fā)者可以根據(jù)項(xiàng)目的具體需求,靈活選擇最合適的模型,以達(dá)到系統(tǒng)性能的最優(yōu)化和資源的有效配置。不論是追求更強(qiáng)的推理性能還是注重資源的高效使用,Ollama 都能迎合開發(fā)者的多元需求。
3、構(gòu)建本地 RAG 系統(tǒng)的詳細(xì)步驟
第一步:導(dǎo)入必要的庫(kù)
?在構(gòu)建 RAG 系統(tǒng)時(shí),需要利用一系列強(qiáng)大的庫(kù)來(lái)執(zhí)行不同的功能。LangChain 庫(kù)在文檔處理和檢索方面表現(xiàn)卓越,它提供了眾多的工具和接口,能夠簡(jiǎn)化文檔的加載、文本的分段、嵌入的生成以及檢索等復(fù)雜流程;而 Streamlit 庫(kù)則專注于創(chuàng)建易于使用的 Web 界面,使用戶能夠輕松地與系統(tǒng)互動(dòng),提交問(wèn)題并接收答案。同時(shí),構(gòu)建過(guò)程中還涉及到 PDFPlumberLoader,它用于高效地從 PDF 文件中抽取文本;SemanticChunker 則用于智能地將文本劃分為有意義的語(yǔ)義單元;HuggingFaceEmbeddings 用于生成文本的向量表示;FAISS 用于構(gòu)建可搜索的向量數(shù)據(jù)庫(kù);以及 Ollama,它用于與本地運(yùn)行的 DeepSeek R1 模型進(jìn)行交互。這些庫(kù)的集成,為系統(tǒng)的后續(xù)構(gòu)建打下了堅(jiān)實(shí)的基礎(chǔ)。
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
第二步:上傳與處理 PDF 文件
通過(guò) Streamlit 提供的文件上傳功能,用戶能夠輕松地挑選并上傳本地 PDF 文件。文件上傳成功后,系統(tǒng)會(huì)將其內(nèi)容暫存為“temp.pdf”的臨時(shí)文件,以備后續(xù)操作使用。隨后,利用 PDFPlumberLoader 庫(kù),可以迅速且精確地從 PDF 文件中提取文本,免去了開發(fā)者手動(dòng)執(zhí)行復(fù)雜文本解析的麻煩(ParseStudio:通過(guò)統(tǒng)一語(yǔ)法簡(jiǎn)化 PDF 文檔解析流程)。這一步驟既高效又精確,保障了系統(tǒng)能夠全面地獲取文檔信息,為后續(xù)的文本處理和分析提供了穩(wěn)定的數(shù)據(jù)基礎(chǔ)。
# Streamlit file uploader
uploaded_file = st.file_uploader("Upload a PDF file", type="pdf")
if uploaded_file:
# Save PDF temporarily
with open("temp.pdf", "wb") as f:
f.write(uploaded_file.getvalue())
# Load PDF text
loader = PDFPlumberLoader("temp.pdf")
docs = loader.load()
第三步:策略性分割文件
將提取的文本劃分為適當(dāng)?shù)恼Z(yǔ)義單元是提升檢索效率和回答準(zhǔn)確性的關(guān)鍵所在。(檢索增強(qiáng)生成(RAG)的創(chuàng)新性分塊策略)。使用 SemanticChunker 配合 HuggingFaceEmbeddings,可以根據(jù)文本的語(yǔ)義內(nèi)容智能地進(jìn)行分割。這種方法不僅關(guān)注文本的篇幅,更重要的是它能夠?qū)⒄Z(yǔ)義上相關(guān)的內(nèi)容歸入同一單元,從而在檢索和生成回答階段,使模型能夠更深入地理解上下文,給出更加邏輯性和語(yǔ)義連貫的回應(yīng)。例如,在處理技術(shù)文檔時(shí),這種方法能夠?qū)⑸婕巴患夹g(shù)概念的段落集中在一起,便于模型精確地獲取和利用這些信息。
# Split text into semantic chunks
text_splitter = SemanticChunker(HuggingFaceEmbeddings())
documents = text_splitter.split_documents(docs)
第四步:創(chuàng)建可搜索的知識(shí)庫(kù)
為了達(dá)到快速且精確的檢索目的,我們需要為分割后的文本塊創(chuàng)建向量嵌入(在構(gòu)建非英語(yǔ)RAG系統(tǒng)時(shí),嵌入的重要性不言而喻),并將這些嵌入存儲(chǔ)于 FAISS 索引中。向量嵌入能夠?qū)⑽谋緝?nèi)容轉(zhuǎn)換成計(jì)算機(jī)易于操作的數(shù)值向量,從而提高文本相似度計(jì)算的效率。HuggingFaceEmbeddings 提供了強(qiáng)大的嵌入生成能力,能夠產(chǎn)出高質(zhì)量的向量表示。FAISS 則是一個(gè)高效的向量搜索數(shù)據(jù)庫(kù),它支持高速的相似性查詢,能夠在龐大的向量集合中迅速定位到與查詢向量最匹配的文本塊。通過(guò)設(shè)置檢索參數(shù)為“k=3”,系統(tǒng)在執(zhí)行搜索時(shí)會(huì)返回三個(gè)最相關(guān)的文本塊,這與 DeepSeek R1 模型專注于精確檢索的特性相契合,確保了系統(tǒng)能夠迅速捕捉到關(guān)鍵信息,為生成精準(zhǔn)的回答提供了堅(jiān)實(shí)的后盾。
# Generate embeddings
embeddings = HuggingFaceEmbeddings()
vector_store = FAISS.from_documents(documents, embeddings)
# Connect retriever
retriever = vector_store.as_retriever(search_kwargs={"k": 3}) # Fetch top 3 chunks
第五步:配置 DeepSeek R1 模型
當(dāng)運(yùn)用 DeepSeek R1 模型時(shí),首先需要通過(guò) Ollama 來(lái)初始化一個(gè)擁有 1.5B參數(shù)的模型實(shí)例(關(guān)于 DeepSeek-R1 的蒸餾模型及如何利用 Ollama 在本地運(yùn)行 DeepSeek-R1)。接下來(lái),需要精心構(gòu)建一個(gè)提示模板,該模板的作用是指導(dǎo)模型生成回答。這個(gè)提示模板清晰地界定了模型回答的準(zhǔn)則:必須基于所提供的上下文信息來(lái)作答;在答案不確定的情況下,應(yīng)當(dāng)回答“我不知道”;并且將回答限制在四句話以內(nèi)。這樣的提示模板有助于確保模型給出的回答既精確又簡(jiǎn)明,防止了無(wú)關(guān)信息的混入和長(zhǎng)篇累牘的回答,從而提升了用戶的體驗(yàn)。通過(guò)設(shè)置這樣的提示模板,可以確保模型在生成回答時(shí)緊密跟隨文檔內(nèi)容,最大限度地發(fā)揮 RAG 系統(tǒng)的長(zhǎng)處。
llm = Ollama(model="deepseek-r1:1.5b") # Our 1.5B parameter model
# Craft the prompt template
prompt = """
1. Use ONLY the context below.
2. If unsure, say "I don’t know".
3. Keep answers under 4 sentences.
Context: {context}
Question: {question}
Answer:
"""
QA_CHAIN_PROMPT = PromptTemplate.from_template(prompt)
第六步:組裝 RAG 鏈
將文檔上傳、文本分割、檢索以及模型回答等多個(gè)步驟融合為一,構(gòu)建出一個(gè)連貫的 RAG 流程。利用 LLMChain和StuffDocumentsChain 的結(jié)合,將檢索到的文檔塊與提示模板相融合,使得模型能夠依據(jù)上下文生成相應(yīng)的回答。RetrievalQA 則將檢索與回答環(huán)節(jié)緊密結(jié)合,打造出最終的 RAG 處理管道。這種架構(gòu)設(shè)計(jì)使得系統(tǒng)能夠自動(dòng)執(zhí)行從接收用戶提問(wèn)、檢索相關(guān)文檔塊到生成回答的一系列任務(wù),實(shí)現(xiàn)了信息處理的高度自動(dòng)化和智能化,為用戶帶來(lái)了順暢的問(wèn)答互動(dòng)。
# Chain 1: Generate answers
llm_chain = LLMChain(llm=llm, prompt=QA_CHAIN_PROMPT)
# Chain 2: Combine document chunks
document_prompt = PromptTemplate(
template="Context:\ncontent:{page_content}\nsource:{source}",
input_variables=["page_content", "source"]
)
# Final RAG pipeline
qa = RetrievalQA(
combine_documents_chain=StuffDocumentsChain(
llm_chain=llm_chain,
document_prompt=document_prompt
),
retriever=retriever
)
第七步:?jiǎn)?dòng) Web 界面
借助 Streamlit 搭建的 Web 界面,用戶可以直接在輸入框中輸入問(wèn)題,與系統(tǒng)進(jìn)行交互。當(dāng)用戶提交問(wèn)題后,系統(tǒng)會(huì)迅速檢索匹配的文本塊,并將其輸入到 DeepSeek R1 模型中進(jìn)行分析和生成回答?;卮鸾Y(jié)果會(huì)實(shí)時(shí)顯示在頁(yè)面上,讓用戶能夠快速獲取所需信息。在用戶等待回答的過(guò)程中,Streamlit 的加載提示功能會(huì)顯示 “Thinking...”,告知用戶系統(tǒng)正在處理請(qǐng)求,提升了用戶體驗(yàn)的友好性和交互性。通過(guò)這個(gè) Web 界面,RAG 系統(tǒng)變得更加易用,即使是非技術(shù)人員也能輕松使用,大大拓寬了系統(tǒng)的應(yīng)用范圍。?
# Streamlit UI
user_input = st.text_input("Ask your PDF a question:")
if user_input:
with st.spinner("Thinking..."):
response = qa(user_input)["result"]
st.write(response)
利用 DeepSeek R1和 Ollama 來(lái)構(gòu)建 RAG 系統(tǒng),為開發(fā)者帶來(lái)了一種高效、經(jīng)濟(jì)且安全穩(wěn)定的解決方案。通過(guò)詳盡的操作指南和技術(shù)資源,開發(fā)者可以迅速構(gòu)建出符合自己需求的智能問(wèn)答系統(tǒng),從而充分發(fā)掘文檔數(shù)據(jù)中的潛在價(jià)值。
本文轉(zhuǎn)載自公眾號(hào)玄姐聊AGI 作者:玄姐
