DeepSeek R1重磅开源!一文读懂训练方法与RAG应用搭建
DeepSeek R1学习方法概述
DeepSeek R1的特点在于使用强化学习(RL)进行后期训练。一般来说,大规模语言模型的开发要经过以下几个步骤:
- 预训练:利用大规模语料库创建一个 “预测下一个单词” 的模型。
- 监督微调(SFT):使用高质量的、人工创建的指令-响应配对数据,针对特定任务对模型进行微调。
- 基于人类反馈的强化学习(RLHF):由人类评估模型的输出,并将评分作为奖励来更新模型。
据说,DeepSeek R1在大规模地进行强化学习,尤其是上述的第三步。此外,他们还探索了一种新方法,即直接应用强化学习(有一个版本叫DeepSeek-R1-Zero),不经过传统的SFT,之后再加入SFT完成DeepSeek R1的训练。这种方法据说能够促进模型的内部思维过程(思维链)和自我验证。
通常情况下,要有效处理思维链需要一些SFT数据和人工标注。然而,DeepSeek-R1-Zero宣称仅通过强化学习就实现了推理能力,无需经过SFT。这种方法有以下优点:
- 降低大规模数据收集的成本。
- 能够在未知任务和复杂情况下进行自我修正。
不过,完全没有经过SFT的模型仍然存在一些问题,比如生成的文本可读性欠佳,还可能出现一些意外的多语言内容。
构建应用程序
现在,让我们一步步探索如何创建RAG应用程序。首先,要安装支持模型的库,在命令行输入:
pip install -r requirements.txt
接下来就是常规操作了,导入相关库,随着后续的操作,这些库的作用就会显现出来。
import os
import streamlit as st
from langchain_community.document_loaders import PDFPlumberLoader
from langchain_experimental.text_splitter import SemanticChunker
from langchain_huggingface import HuggingFaceEmbeddings
import os
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains.retrieval import create_retrieval_chain
from langchain_core.messages import AIMessage, HumanMessage
import tempfile
from langchain_openai.chat_models.base import BaseChatOpenAI
PDFPlumberLoader是一个功能强大的工具,可用于处理PDF文件中的表格等复杂结构化数据,它能提取文本、图像、表格、字段等内容。SemanticChunker则基于语义相似度将文本分割成块,确保相关内容都在同一个块中。
我创建了一个函数,用于处理上传的文件。这个函数会使用临时文件存储文件内容,接着用PDFPlumberLoader处理PDF文件中的复杂结构化数据,处理完后还会清理临时文件,以保持系统整洁,最后返回提取的数据供后续使用。
def process_uploaded_file(uploaded_file):
with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
tmp_file.write(uploaded_file.getvalue())
loader = PDFPlumberLoader(tmp_file.name)
documents = loader.load()
os.unlink(tmp_file.name)
return documents
我还创建了一个函数,用于处理文档列表并构建一个基于相似度搜索的检索器。首先,使用带有OpenAIEmbeddings的SemanticChunker将文档分割成较小的块,同时保留语义关系,确保相关内容聚集在一起。在确认分割过程无误后,使用FAISS开发一个向量存储,它会对文本块进行组织,以实现高效的相似度搜索。最后,返回一个检索器,它能为给定的查询找到最相似的前3个文本块,让文档检索过程既准确又高效。
def get_vs_retriever_from_docs(doc_list):
text_splitter = SemanticChunker(HuggingFaceEmbeddings())
documents = text_splitter.split_documents(doc_list)
st.write('Document splitting done')
embedder = HuggingFaceEmbeddings()
vector = FAISS.from_documents(documents, embedder)
return vector.as_retriever(search_type="similarity", search_kwargs={"k": 3})
init_ui()函数的作用是使用Streamlit搭建一个便于用户上传和分析PDF文档的界面。首先,配置页面标题和描述性的头部信息。然后初始化会话状态变量,用于管理检索器、聊天历史记录和上传状态。接着提供一个文件上传小部件,方便用户上传PDF文件。一旦有文件上传,就处理文件提取内容,用get_vs_retriever_from_docs创建一个检索器,并将其存储在会话状态中供后续使用。最后,用一条成功消息通知用户文档处理成功。
def init_ui():
st.set_page_config(page_title='Document uploader')
st.markdown('#### :books:🧙Gao Dalie (高達烈): Your Document Summarizer')
st.markdown("<h8 style='text-align: right; color: green;'>*Share the pdf of the book you want to read*</h8>", unsafe_allow_html=True)
if "vector_store" not in st.session_state:
st.session_state.vector_store = None
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
if "doc_upload" not in st.session_state:
st.session_state.doc_upload = False
uploaded_file = st.file_uploader("Upload PDF", type=["pdf"])
if uploaded_file:
docs = process_uploaded_file(uploaded_file)
if docs:
retriever = get_vs_retriever_from_docs(docs)
st.session_state.vector_store = retriever
st.session_state.doc_upload = True
st.success("Document processed successfully")
get_related_context()函数用于在对话系统中优化相关信息的检索。首先,初始化Ollama模型(deepseek-r1)来处理用户输入。然后定义一个提示模板,将聊天历史和用户输入结合起来,指示模型根据当前对话生成一个搜索查询。最后,使用create_history_aware_retriever增强智能体将整个对话历史融入检索过程的能力。
def get_related_context(vector_store):
# llm = Ollama(model="deepseek-r1")
llm = BaseChatOpenAI(
model='deepseek-reasoner',
openai_api_key='sk-68f459660c7b4d179e074cbedce962c0',
openai_api_base='https://api.deepseek.com',
max_tokens=1024
)
prompt = ChatPromptTemplate.from_messages([
("system", "Generate a search query based on the conversation."),
("user", "{input}")
])
return create_history_aware_retriever(llm, vector_store, prompt)
在这个函数中,我设计了一个整合了两个核心链的函数:
- context_chain:负责查找外部输入数据。
docs_chain:负责查找对话记录。
最后,使用retrieval_chain = create_retrieval_chain(context_chain, docs_chain)
创建一个能够检索对话和外部输入数据的链,从而完成一个支持自然对话的链。对话记录需要自行创建一个列表存储,也就是chat_history这部分。def get_context_aware_prompt(context_chain): # llm_! = Ollama(model="deepseek-r1") llm = BaseChatOpenAI( model='deepseek-reasoner', openai_api_key='sk-68f459660c7b4d179e074cbedce962c0', openai_api_base='https://api.deepseek.com', max_tokens=1024 ) prompt = ChatPromptTemplate.from_messages([ ("system", "Answer questions using the provided context:\n\n{context}"), ("user", "{input}") ]) # st.write(docs_chain) return create_retrieval_chain(context_chain, docs_chain)
在这个函数中,我处理了针对给定查询生成上下文感知响应的过程。首先检查是否上传了必要的文档,如果没有上传,则返回错误信息。确认文档已上传后,检索上下文链以从上传的文档中获取相关信息,如果检索上下文失败,同样返回错误信息。接着创建一个RAG链,将上下文、对话历史和用户查询结合起来生成回复。最后调用RAG链,处理回复并返回生成的答案。
def get_response(query: str) -> str: if not st.session_state.vector_store: return "Error: Please upload documents first" try: context_chain = get_related_context(st.session_state.vector_store) # st.write(context_chain) if not context_chain: return "Error: Failed to process context" rag_chain = get_context_aware_prompt(context_chain) # st.write(rag_chain) current_history = st.session_state.chat_history[-2:] if len(st.session_state.chat_history) > 1 else [] return rag_chain.invoke({ "chat_history": current_history, "input": query })["answer"].do except Exception as e: return f"Error: {str(e)}"
在这个函数中,我设置并展示了一个供用户交互的聊天界面。首先,遍历存储的聊天历史记录,在聊天窗口中展示用户和AI的消息。然后提供一个输入框,用户可以在其中输入新问题。如果用户提交查询,就调用get_response函数生成答案,之后将新消息和回复更新到聊天历史记录中。
def init_chat_interface(): for message in st.session_state.chat_history: with st.chat_message("user" if isinstance(message, HumanMessage) else "assistant"): st.write(message.content) if prompt := st.chat_input("Ask a question...", disabled=not st.session_state.doc_upload): st.session_state.chat_history.append(HumanMessage(content=prompt)) response = get_response(prompt) st.session_state.chat_history.append(AIMessage(content=response))
if __name__ == "__main__": init_ui() if st.session_state.vector_store: init_chat_interface()
参考链接
https://github.com/deepseek-ai/DeepSeek-R1
近日热文:全网最全的神经网络数学原理(代码和公式)直观解释
欢迎关注知乎和公众号的专栏内容
LLM架构专栏
知乎LLM专栏
知乎【柏企】
公众号【柏企科技说】【柏企阅文】
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。