DeepSeek-R1聊天机器人开发教程

AI 领域的进步速度确实在以前所未有的速度前进。短短一周多的时间,DeepSeek-R1 LLM 模型的发布就以其令人印象深刻的准确性震撼了 AI 世界,其准确性与现有模型相当,但创建成本仅为典型成本的一小部分。

DeepSeek 团队成功地将其庞大的 671B 参数模型的推理能力提炼为基于 Qwen(DeepSeek-R1-Distill-Qwen-1.5B、7B、14B 和 32B)和 Llama(DeepSeek-R1-Distill-Llama-8B 和 70B)的 6 个小模型。这实际上意味着你可以使用自己的模型副本 - 自定义它、进行更改、在本地运行它或将其托管在云平台上。

在本博客中,我们用 Python 构建一个 DeepSeek-R1 聊天机器人。简而言之,Streamlit 用于前端,而在后端,通过对托管在 Snowflake 中的 DeepSeek-R1 模型的 API 调用,可以实现为应用程序的响应提供支持的 LLM 模型。

点击这里查看本教程的 GitHub 存储库。

1、什么是 DeepSeek-R1?

简而言之,DeepSeek-R1 是一种推理模型,它利用强化学习来教授基本语言模型 DeepSeek-V3 进行推理,而无需人工监督。

以下是 DeepSeek-R1 的 5 个主要功能:

  • 最先进的推理:DeepSeek-R1 在高级数学任务上可以达到 97.3% 的准确率,优于早期的基准。同样,它在 AIME 2024 上的得分为 79.8%,在 SWE-bench Verified 上的得分为 49.2%,也优于其他模型。
  • 成本效率:与行业标准相比,DeepSeek 模型的训练成本显著降低
  • 应用广泛:在创意写作、长上下文理解和事实问答方面表现出色。
  • 可扩展性:模型有多个精简版本(1.5B 到 70B 个参数),从而优化了能力和资源使用之间的平衡。
  • 可访问性:开源可用性使开发人员和研究人员能够尝试该模型,以将高级 AI 工具应用于实际项目。

尽管其性能出色,但人们仍可能对其使用方面的安全问题感到担忧。鉴于此,由于模型是开源的,因此可以检查底层代码,而模型本身可以在用户自己的计算资源上自行部署。

在本教程中,我们将使用托管在 Snowflake 平台中的 DeepSeek-R1 模型

2、应用程序概述

以下是 DeepSeek-R1 聊天机器人应用程序的高级概述:

  • 用户提供提示输入(即提出问题)。
  • 通过使用 SNOWFLAKE.CORTEX.COMPLETE() 进行 LLM 调用,其中提交提示输入,并获取 LLM 生成的响应,并将其显示在应用程序中。

3、聊天机器人的运行

让我们看看聊天机器人的实际运行,启动聊天机器人并在聊天输入中输入问题:

作为推理模型,LLM 首先进入思考阶段:

思考过程完成后,最终答案将在下面显示:

应该注意的是,思考和答案的深度直接受到最大令牌参数的影响。在这里,我们将最大令牌限制为 800 个以进行测试,但你可以将其增加到 20,480。

4、构建 DeepSeek-R1 聊天机器人

现在让我们继续在 Snowflake 平台上构建 DeepSeek-R1 聊天机器人。

4.1 设置开发环境

要访问必要的工具,请确保你可以访问 Snowflake 帐户

接下来,导航到 Snowflake 中的 Streamlit,转到项目→Streamlit,然后单击 + Streamlit App 以创建应用程序(然后你将指定应用程序位置和仓库):

接下来,你将看到一个示例入门应用程序来帮助入门:

Snowflake 中的 Streamlit 界面类似于在线代码编辑器,您可以在左侧编辑代码并在右侧查看呈现的应用程序。

继续将其替换为我们今天要构建的应用程序。

4.2 检索代码

我们今天要构建的 DeepSeek-R1 聊天机器人应用程序由以下部分组成:

  • environment.yml — 应用程序的环境依赖项
  • streamlit_app.py — Streamlit 应用程序文件

首先,environment.yml 文件的内容如下所示:

name: app_environment
channels:
  - snowflake
dependencies:
  - python=3.11.*
  - snowflake-ml-python
  - snowflake-snowpark-python
  - streamlit

其次,sis_app.py 文件的内容如下所示:

import streamlit as st
from snowflake.snowpark.context import get_active_session
import pandas as pd
import json
import re

# App configuration
st.set_page_config(page_title="🐳💬 DeepSeek R1 Chatbot", initial_sidebar_state="expanded")
session = get_active_session()

# Helper functions
def clear_chat_history():
    st.session_state.messages = [{"role": "assistant", "content": "How may I assist you today?"}]

def escape_sql_string(s):
    return s.replace("'", "''")

def extract_think_content(response):
    think_pattern = r'<think>(.*?)</think>'
    think_match = re.search(think_pattern, response, re.DOTALL)
    
    if think_match:
        think_content = think_match.group(1).strip()
        main_response = re.sub(think_pattern, '', response, flags=re.DOTALL).strip()
        return think_content, main_response
    return None, response

def generate_deepseek_response(prompt, **params):
    string_dialogue = "".join(
        f"{msg['content']}\n\n" 
        for msg in st.session_state.messages
    )
    
    cortex_prompt = f"'[INST] {string_dialogue}{prompt} [/INST]'"
    prompt_data = [{'role': 'user', 'content': cortex_prompt}], params
    prompt_json = escape_sql_string(json.dumps(prompt_data))
    response = session.sql(
        "select snowflake.cortex.complete(?, ?)", 
        params=['deepseek-r1', prompt_json]
    ).collect()[0][0]
    
    return response

# Model parameters configuration
MODEL_PARAMS = {
    'temperature': {'min': 0.01, 'max': 1.0, 'default': 0.7, 'step': 0.01},
    'top_p': {'min': 0.01, 'max': 1.0, 'default': 1.0, 'step': 0.01},
    'max_tokens': {'min': 10, 'max': 100, 'default': 20, 'step': 10},
    'presence_penalty': {'min': -1.0, 'max': 1.0, 'default': 0.0, 'step': 0.1},
    'frequency_penalty': {'min': -1.0, 'max': 1.0, 'default': 0.0, 'step': 0.1}
}

# Sidebar UI
with st.sidebar:
    st.title('🐳💬 DeepSeek R1 Chatbot')
    st.write('This chatbot is created using the DeepSeek R1 LLM model via Snowflake Cortex.')
    
    st.subheader('⚙️ Model parameters')
    params = {
        param: st.sidebar.slider(
            param.replace('_', ' ').title(),
            min_value=settings['min'],
            max_value=settings['max'],
            value=settings['default'],
            step=settings['step']
        )
        for param, settings in MODEL_PARAMS.items()
    }
    
    st.button('Clear Chat History', on_click=clear_chat_history)

# Initialize chat history
if "messages" not in st.session_state:
    st.session_state.messages = [{"role": "assistant", "content": "How may I assist you today?"}]

# Display chat messages
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.write(message["content"])

# Handle user input
if prompt := st.chat_input():
    with st.chat_message("user"):
        st.write(prompt)
    st.session_state.messages.append({"role": "user", "content": prompt})
    
    if st.session_state.messages[-1]["role"] != "assistant":
        with st.chat_message("assistant"):
            status_container = st.status("Thinking ...", expanded=True)
            
            with status_container:
                response = generate_deepseek_response(prompt, **params)
                think_content, main_response = extract_think_content(response)
                if think_content:
                    st.write(think_content)
            
            status_container.update(label="Thoughts", state="complete", expanded=False)
            st.markdown(main_response)
            st.session_state.messages.append({"role": "assistant", "content": main_response})

你还可以从此 DeepSeek-R1 聊天机器人 Github 存储库下载必要的应用文件。

4.3 运行应用

要运行应用,请复制粘贴上述代码,然后单击“运行”按钮。

你可以将鼠标光标放在代码/应用程序面板的分隔线上,然后将其向左移动,直到代码面板消失(见下文)。这会将应用程序面板扩展至全屏。

继续并输入提示以开始你的聊天会话:

此外,请参阅上面的 Chatbot 实际操作部分,了解 LLM 生成的思维过程和答案。

5、代码说明

让我们探索每个代码块在做什么……

5.1 导入库

我们首先从导入先决条件库开始。

import streamlit as st
from snowflake.snowpark.context import get_active_session
import pandas as pd
import json
import re

5.2 应用程序配置

接下来,我们使用 st.set_page_config() 定义应用程序页面并设置其初始页面参数,我们将设置 initial_sidebar_state="expanded",以便它们完全按照那样做,展开侧边栏。在这里,我们还设置了会话变量,我们稍后会用到它。

# App configuration
st.set_page_config(page_title="🐳💬 DeepSeek R1 Chatbot", initial_sidebar_state="expanded")
session = get_active_session()

5.3 辅助函数

在此部分中,我们定义了几个将在应用程序的后面部分使用的辅助函数:

  • clear_chat_history() — 这允许我们将聊天记录清除到初始状态
  • escape_sql_string() — 在执行一些文本格式化时替换 SQL 字符串
  • extract_think_content() — 解析并分离包含在 XML 样式“think”标签( 和 )中的内容,并将其与最终响应分开。
# Helper functions
def clear_chat_history():
    st.session_state.messages = [{"role": "assistant", "content": "How may I assist you today?"}]

def escape_sql_string(s):
    return s.replace("'", "''")

def extract_think_content(response):
    think_pattern = r'<think>(.*?)</think>'
    think_match = re.search(think_pattern, response, re.DOTALL)
    
    if think_match:
        think_content = think_match.group(1).strip()
        main_response = re.sub(think_pattern, '', response, flags=re.DOTALL).strip()
        return think_content, main_response
    return None, response

例如,假设我们有以下生成的响应:

<think>Let me analyze this problem step by step...</think>
Here's the solution you're looking for...

它将解析并分离为:

  • think_content:“让我一步一步分析这个问题……”
  • main_response:“这是您正在寻找的解决方案……”

让我们继续使用最后一个辅助函数:

  • generate_deepseek_response() — 使用 Snowflake 的 Cortex 服务和 DeepSeek R1 模型生成 LLM 响应
def generate_deepseek_response(prompt, **params):
    string_dialogue = "".join(
        f"{msg['content']}\n\n" 
        for msg in st.session_state.messages
    )
    
    cortex_prompt = f"'[INST] {string_dialogue}{prompt} [/INST]'"
    prompt_data = [{'role': 'user', 'content': cortex_prompt}], params
    prompt_json = escape_sql_string(json.dumps(prompt_data))
    response = session.sql(
        "select snowflake.cortex.complete(?, ?)", 
        params=['deepseek-r1', prompt_json]
    ).collect()[0][0]
    
    return response

5.4 侧边栏 UI

我们首先将 MODEL_PARAMS 变量定义为字典格式,其中包含模型参数以及相关的最小值、最大值、默认值和步长值。

接下来,我们将定义以应用程序标题和应用程序描述开头的侧边栏。在这里,我们还包括几个通过 for 循环迭代创建的滑块小部件。最后,我们有一个清除聊天历史记录按钮,它调用 clear_chat_history 回调函数将历史记录重置为初始状态。

# Model parameters configuration
MODEL_PARAMS = {
    'temperature': {'min': 0.01, 'max': 1.0, 'default': 0.7, 'step': 0.01},
    'top_p': {'min': 0.01, 'max': 1.0, 'default': 1.0, 'step': 0.01},
    'max_tokens': {'min': 10, 'max': 100, 'default': 20, 'step': 10},
    'presence_penalty': {'min': -1.0, 'max': 1.0, 'default': 0.0, 'step': 0.1},
    'frequency_penalty': {'min': -1.0, 'max': 1.0, 'default': 0.0, 'step': 0.1}
}

# Sidebar UI
with st.sidebar:
    st.title('🐳💬 DeepSeek R1 Chatbot')
    st.write('This chatbot is created using the DeepSeek R1 LLM model via Snowflake Cortex.')
    
    st.subheader('⚙️ Model parameters')
    params = {
        param: st.sidebar.slider(
            param.replace('_', ' ').title(),
            min_value=settings['min'],
            max_value=settings['max'],
            value=settings['default'],
            step=settings['step']
        )
        for param, settings in MODEL_PARAMS.items()
    }
    
    st.button('Clear Chat History', on_click=clear_chat_history)

5.5 聊天元素

在应用程序的最后部分,我们将初始化聊天历史记录的会话状态变量,迭代显示传入的聊天消息,并最终定义处理用户/应用程序聊天逻辑的条件流。后一部分利用先前定义的辅助函数来处理 LLM 生成的响应。

# Initialize chat history
if "messages" not in st.session_state:
    st.session_state.messages = [{"role": "assistant", "content": "How may I assist you today?"}]

# Display chat messages
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.write(message["content"])

# Handle user input
if prompt := st.chat_input():
    with st.chat_message("user"):
        st.write(prompt)
    st.session_state.messages.append({"role": "user", "content": prompt})
    
    if st.session_state.messages[-1]["role"] != "assistant":
        with st.chat_message("assistant"):
            status_container = st.status("Thinking ...", expanded=True)
            
            with status_container:
                response = generate_deepseek_response(prompt, **params)
                think_content, main_response = extract_think_content(response)
                if think_content:
                    st.write(think_content)
            
            status_container.update(label="Thoughts", state="complete", expanded=False)
            st.markdown(main_response)
            st.session_state.messages.append({"role": "assistant", "content": main_response})

将这些代码块拼凑在一起,我们就得到了 DeepSeek-R1 聊天机器人!

6、结束语

构建自己的聊天机器人,该聊天机器人由强大的 DeepSeek-R1 模型提供支持。这在不到 100 行代码中令人印象深刻地实现。

你可能会注意到,代码的很大一部分涉及“思考”标签和大量内联注释的处理,如果删除这些注释,应用程序会大大缩小。


原文链接:How to build a DeepSeek-R1 chatbot

汇智网翻译整理,转载请标明出处