基于 DeepSeek R1 和 Ollama 开发 RAG 系统 原创
今天,我们探讨一下如何利用目前最受欢迎的开源推理工具 DeepSeek R1 和轻量级的本地AI模型执行框架 Ollama,来构建一个功能强大的 RAG (Retrieval-Augmented Generation)系统。
1、DeepSeek R1:RAG 系统的卓越之选
DeepSeek R1,被誉为开启 AI 推理新时代的开源先锋,在构建 RAG 系统方面表现卓越,拥有众多引人注目的优势,成为开发者不可或缺的利器。相较于OpenAI 的 o1 模型,DeepSeek R1 在性能上与之媲美,但成本却大幅下降,仅占 o1 的 5%,这一经济性使得更广泛的开发者和企业能够轻松采用,推动了 RAG 技术的普及。
在信息检索方面,DeepSeek R1 展现了其卓越的专注力。在生成答案的过程中,仅需引用3个文档片段,便能精确提炼关键信息,有效排除了无关内容的干扰,显著提高了检索效率和回答的精确度。这一特性使得即便在处理大量文档时,系统也能迅速锁定关键内容,向用户提供简洁而高效的答案。
面对复杂问题或不确定答案的情况,DeepSeek R1 的严格提示机制发挥了关键作用。与其他模型可能随意生成答案不同,DeepSeek R1 在不确定时会坦白回答“我不知道”,这种严谨性有效防止了幻觉现象,确保了答案的真实性和可靠性,让用户获得值得信赖的信息。
对于众多开发者而言,数据安全和快速响应是极为重要的考量。DeepSeek R1 支持本地化运行,无需依赖云端 API,这不仅减少了网络延迟带来的问题,还使用户能够在本地环境中安全处理敏感数据,无需担心数据泄露的风险,为特定行业和场景的应用提供了强有力的支持。
2、Ollama:本地模型运行的理想框架
Ollama,作为一个轻量级框架,为本地运行 AI 大模型提供了一个便捷且高效的平台,成为构建本地 RAG 系统的重要组成部分。它的推出,使得开发者能够减少对云端计算资源的依赖,轻松在本地设备上部署和执行模型,显著降低了开发与部署的成本,并增强了系统的独立性和数据隐私保护。
在 Ollama 上下载和安装模型的过程异常简便。以 DeepSeek R1 模型为例,开发者只需在终端输入几条简单的命令即可完成。例如,要运行默认的7B模型,只需执行“ollama run deepseek-r1”命令;而若想体验适用于轻量级 RAG 应用场景的1.5B模型,则运行“ollama run deepseek-r1:1.5b”命令即可。这种简便的操作流程,让即便是技术背景较浅的开发者也能迅速掌握,开始 RAG 系统的开发工作。
Ollama 支持多种 AI 大模型,为开发者提供了广泛的选择余地。这些模型在性能、适用场景和资源需求上各有特点,开发者可以根据项目的具体需求,灵活选择最合适的模型,以达到系统性能的最优化和资源的有效配置。不论是追求更强的推理性能还是注重资源的高效使用,Ollama 都能迎合开发者的多元需求。
3、构建本地 RAG 系统的详细步骤
第一步:导入必要的库
在构建 RAG 系统时,需要利用一系列强大的库来执行不同的功能。LangChain 库在文档处理和检索方面表现卓越,它提供了众多的工具和接口,能够简化文档的加载、文本的分段、嵌入的生成以及检索等复杂流程;而 Streamlit 库则专注于创建易于使用的 Web 界面,使用户能够轻松地与系统互动,提交问题并接收答案。同时,构建过程中还涉及到 PDFPlumberLoader,它用于高效地从 PDF 文件中抽取文本;SemanticChunker 则用于智能地将文本划分为有意义的语义单元;HuggingFaceEmbeddings 用于生成文本的向量表示;FAISS 用于构建可搜索的向量数据库;以及 Ollama,它用于与本地运行的 DeepSeek R1 模型进行交互。这些库的集成,为系统的后续构建打下了坚实的基础。
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 文件
通过 Streamlit 提供的文件上传功能,用户能够轻松地挑选并上传本地 PDF 文件。文件上传成功后,系统会将其内容暂存为“temp.pdf”的临时文件,以备后续操作使用。随后,利用 PDFPlumberLoader 库,可以迅速且精确地从 PDF 文件中提取文本,免去了开发者手动执行复杂文本解析的麻烦(ParseStudio:通过统一语法简化 PDF 文档解析流程)。这一步骤既高效又精确,保障了系统能够全面地获取文档信息,为后续的文本处理和分析提供了稳定的数据基础。
# 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()
第三步:策略性分割文件
将提取的文本划分为适当的语义单元是提升检索效率和回答准确性的关键所在。(检索增强生成(RAG)的创新性分块策略)。使用 SemanticChunker 配合 HuggingFaceEmbeddings,可以根据文本的语义内容智能地进行分割。这种方法不仅关注文本的篇幅,更重要的是它能够将语义上相关的内容归入同一单元,从而在检索和生成回答阶段,使模型能够更深入地理解上下文,给出更加逻辑性和语义连贯的回应。例如,在处理技术文档时,这种方法能够将涉及同一技术概念的段落集中在一起,便于模型精确地获取和利用这些信息。
# Split text into semantic chunks
text_splitter = SemanticChunker(HuggingFaceEmbeddings())
documents = text_splitter.split_documents(docs)
第四步:创建可搜索的知识库
为了达到快速且精确的检索目的,我们需要为分割后的文本块创建向量嵌入(在构建非英语RAG系统时,嵌入的重要性不言而喻),并将这些嵌入存储于 FAISS 索引中。向量嵌入能够将文本内容转换成计算机易于操作的数值向量,从而提高文本相似度计算的效率。HuggingFaceEmbeddings 提供了强大的嵌入生成能力,能够产出高质量的向量表示。FAISS 则是一个高效的向量搜索数据库,它支持高速的相似性查询,能够在庞大的向量集合中迅速定位到与查询向量最匹配的文本块。通过设置检索参数为“k=3”,系统在执行搜索时会返回三个最相关的文本块,这与 DeepSeek R1 模型专注于精确检索的特性相契合,确保了系统能够迅速捕捉到关键信息,为生成精准的回答提供了坚实的后盾。
# 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 模型
当运用 DeepSeek R1 模型时,首先需要通过 Ollama 来初始化一个拥有 1.5B参数的模型实例(关于 DeepSeek-R1 的蒸馏模型及如何利用 Ollama 在本地运行 DeepSeek-R1)。接下来,需要精心构建一个提示模板,该模板的作用是指导模型生成回答。这个提示模板清晰地界定了模型回答的准则:必须基于所提供的上下文信息来作答;在答案不确定的情况下,应当回答“我不知道”;并且将回答限制在四句话以内。这样的提示模板有助于确保模型给出的回答既精确又简明,防止了无关信息的混入和长篇累牍的回答,从而提升了用户的体验。通过设置这样的提示模板,可以确保模型在生成回答时紧密跟随文档内容,最大限度地发挥 RAG 系统的长处。
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 链
将文档上传、文本分割、检索以及模型回答等多个步骤融合为一,构建出一个连贯的 RAG 流程。利用 LLMChain和StuffDocumentsChain 的结合,将检索到的文档块与提示模板相融合,使得模型能够依据上下文生成相应的回答。RetrievalQA 则将检索与回答环节紧密结合,打造出最终的 RAG 处理管道。这种架构设计使得系统能够自动执行从接收用户提问、检索相关文档块到生成回答的一系列任务,实现了信息处理的高度自动化和智能化,为用户带来了顺畅的问答互动。
# 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
)
第七步:启动 Web 界面
借助 Streamlit 搭建的 Web 界面,用户可以直接在输入框中输入问题,与系统进行交互。当用户提交问题后,系统会迅速检索匹配的文本块,并将其输入到 DeepSeek R1 模型中进行分析和生成回答。回答结果会实时显示在页面上,让用户能够快速获取所需信息。在用户等待回答的过程中,Streamlit 的加载提示功能会显示 “Thinking...”,告知用户系统正在处理请求,提升了用户体验的友好性和交互性。通过这个 Web 界面,RAG 系统变得更加易用,即使是非技术人员也能轻松使用,大大拓宽了系统的应用范围。
# 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 来构建 RAG 系统,为开发者带来了一种高效、经济且安全稳定的解决方案。通过详尽的操作指南和技术资源,开发者可以迅速构建出符合自己需求的智能问答系统,从而充分发掘文档数据中的潜在价值。
本文转载自公众号玄姐聊AGI 作者:玄姐