DeepSeek 网摘deepseek.wang
EN
📄 查看英文原文

教程 · 2026-04-25 · 机器翻译,仅供参考

如何在Python中构建DeepSeek Streamlit应用程序

Tutorials·April 25, 2026·By DS指南编辑
DeepSeek Streamlit-app tutorial card showing the five steps to build an 80-line single-file chat UI in front of V4: pip install streamlit and openai, build the chat with st.chat_input, persist message history in st.session_state because the API is stateless, stream tokens via client.chat.completions, and show live token totals and cost in the sidebar.

你想在DeepSeek前面实现一个工作的聊天用户界面,而不需要花费一个周末的时间来搭建React、websockets和后端。一个DeepSeek Streamlit应用可以在大约80行Python代码中实现:文本输入、流式响应、V4级别的模型选择器以及运行中的令牌计数器。这正是本教程从头到尾讲解的项目。

到最后,你将拥有一个单独的`app.py`文件,它可以与`deepseek-v4-flash`进行通信以实现低成本默认聊天,在需要前沿推理时切换到`deepseek-v4-pro`,切换思考模式,流式传输到达的令牌,并显示每场对话的实时成本。代码在本地运行,部署到Streamlit社区云时无需更改。

What you’ll build

Laptop displaying a Streamlit chat app powered by DeepSeek V4 with sidebar controls and a streamed reply.

完成的应用是一个单文件Streamlit聊天应用,与DeepSeek的OpenAI兼容API进行通信。它支持V4级别,具有思考模式切换、服务器发送事件流、会话内对话持久化以及一个侧边栏,在聊天时总计令牌和美元。聊天请求击中 POST /chat/completions, the OpenAI-compatible endpoint at https://api.deepseek.com因此,一旦您进行交换,官方OpenAI Python SDK将保持不变 base_url and api_key.

两个设计选择从一开始就很重要。首先,DeepSeek API是 stateless ——服务器不记住之前的回合,因此客户端必须在每个请求中重新发送完整的 messages 数组。Streamlit的 st.session_state 是保存该历史记录的绝佳位置。其次,V4作为两个开放重量的MoE模型家族发货,具有共享功能—— deepseek-v4-pro (总容量1.6T / 活跃容量49B) 用于前沿工作,以及 deepseek-v4-flash (284B / 活跃容量13B) 用于成本效益的聊天——思维是一个 request parameter,而不是一个单独的模型ID。我们将在侧边栏中展示这两个选项。

截图占位符:一个展示用户消息、流式助手回复以及带有模型选择器、思考切换和实时成本计数的侧边栏的青琥珀色Streamlit聊天面板。

Prerequisites

  • Python 3.10或更高版本 with pip 已添加到您的PATH中。
  • A DeepSeek API密钥。如果您还没有,请在继续之前遵循 get a DeepSeek API密钥 演示指南。
  • 一个虚拟环境工具—— venv, uv or poetry。我们将使用 venv.
  • 大约5分钟和大约0.01美元的API信用额度来测试V4-Flash的端到端功能。
  • 可选但推荐:一个免费的Streamlit社区云账户用于部署。

如果这是您第一次调用API,请先运行——它涵盖了身份验证和将任何内容包裹在UI之前的最小curl调用。 DeepSeek API getting started 首先——它涵盖了身份验证和将任何内容包裹在UI之前的最小curl调用。

第1步:创建项目并安装依赖项

打开终端并创建一个干净的项目文件夹。以下命令为bash;PowerShell用户可以交换激活行。

mkdir deepseek-streamlit && cd deepseek-streamlit
python -m venv .venv
source .venv/bin/activate   # Windows: .venvScriptsactivate
pip install streamlit openai tiktoken

三个包,没有其他。 streamlit 是UI框架, openai 是我们指向DeepSeek基础URL的官方SDK,以及 tiktoken 为成本计数的客户端令牌估计提供了一个合理的估计。(DeepSeek的标记器与OpenAI的不完全相同,因此将计数视为几个百分比内的估计——或者使用) DeepSeek token counter 在您向客户承诺定价之前进行合理性检查。)

第2步:安全存储API密钥

Streamlit从 .streamlit/secrets.toml 本地以及从生产环境中的仪表板读取机密。创建该文件:

mkdir -p .streamlit
cat > .streamlit/secrets.toml <<'EOF'
DEEPSEEK_API_KEY = "sk-your-key-here"
EOF
echo ".venv/" > .gitignore
echo ".streamlit/secrets.toml" >> .gitignore

The .gitignore 入口很重要。提交 secrets.toml 将密钥泄露给GitHub是读者泄露密钥最常见的方式。如果您更喜欢环境变量,可以使用以下Python导出。它大约有90行,涵盖了所有内容:模型选择、思考切换、流式传输、历史记录和实时成本。 DEEPSEEK_API_KEY 以下代码将读取任一源。

第3步:编写聊天应用程序

创建 app.py 因此DeepSeek返回一个包含提示和完成令牌计数的最终使用块——这就是实时成本计数的准确性而不是估计的原因。

import os
import streamlit as st
from openai import OpenAI

# --- Pricing (USD per 1M tokens) — update from the official pricing page ---
PRICING = {
    "deepseek-v4-flash": {"in_请求kwargs中的。": 0.14, "in_hit": 0.028, "out": 0.28},
    "deepseek-v4-pro":   {"in_请求kwargs中的。": 1.74, "in_hit": 0.145, "out": 3.48},
}

st.set_page_config(page_title="DeepSeek Chat", page_icon="·", layout="centered")
st.title("DeepSeek Streamlit App")

# --- Sidebar: model, thinking, temperature, cost ---
with st.sidebar:
    model = st.selectbox("Model", list(PRICING.keys()), index=0)
    thinking = st.toggle("Thinking mode", value=False,
                         help="Enables reasoning_effort=high")
    temperature = st.slider("Temperature", 0.0, 2.0, 1.3, 0.1,
                            help="0.0 code/math, 1.0 analysis, 1.3 chat, 1.5 creative")
    max_tokens = st.number_input("Max output tokens", 256, 8192, 1024, 256)
    if st.button("清晰对话"):
        st.session_state.messages = []
        st.session_state.cost = 0.0
        st.rerun()
    st.metric("Session cost (USD)", f"${st.session_state.get('cost', 0.0):.4f}")

# --- Client (OpenAI SDK pointed at DeepSeek) ---
api_key = st.secrets.get("DEEPSEEK_API_KEY") or os.getenv("DEEPSEEK_API_KEY")
if not api_key:
    st.error("Set DEEPSEEK_API_KEY in .streamlit/secrets.toml or your environment.")
    st.stop()
client = OpenAI(base_url="https://api.deepseek.com", api_key=api_key)

# --- State ---
if "messages" not in st.session_state:
    st.session_state.messages = []
if "cost" not in st.session_state:
    st.session_state.cost = 0.0

# --- Replay prior turns ---
for m in st.session_state.messages:
    with st.chat_message(m["role"]):
        st.markdown(m["content"])

# --- Handle new input ---
if prompt := st.chat_input("Ask DeepSeek anything"):
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    # Build the request — stateless, so we resend full history every time.
    kwargs = {
        "model": model,
        "messages": st.session_state.messages,
        "temperature": temperature,
        "max_tokens": max_tokens,
        "stream": True,
        "stream_options": {"include_usage": True},
    }
    if thinking:
        kwargs["reasoning_effort"] = "high"
        kwargs["extra_body"] = {"thinking": {"type": "enabled"}}

    with st.chat_message("assistant"):
        placeholder = st.empty()
        thinking_box = st.expander("Reasoning", expanded=False) if thinking else None
        full_text, reasoning_text, usage = "", "", None
        stream = client.chat.completions.create(**kwargs)
        for chunk in stream:
            if chunk.usage:
                usage = chunk.usage
            if not chunk.choices:
                continue
            delta = chunk.choices[0].delta
            if getattr(delta, "reasoning_content", None) and thinking_box:
                reasoning_text += delta.reasoning_content
                thinking_box.markdown(reasoning_text)
            if delta.content:
                full_text += delta.content
                placeholder.markdown(full_text + " ")
        placeholder.markdown(full_text)

    st.session_state.messages.append({"role": "assistant", "content": full_text})

    # --- Cost calculation: enumerate all three buckets ---
    if usage:
        rates = PRICING[model]
        cached = getattr(usage, "prompt_cache_hit_tokens", 0) or 0
        请求kwargs中的。 = usage.prompt_tokens - cached
        cost = (cached * rates["in_hit"]
                + 请求kwargs中的。 * rates["in_请求kwargs中的。"]
                + usage.completion_tokens * rates["out"]) / 1_000_000
        st.session_state.cost += cost
        st.rerun()

在该代码中,有几个值得注意的点。我们传递 stream_options={"include_usage": True} 代码、命令、URL、数字保持原样。 reasoning_content 处理是V4思考模式合约:当启用思考时,流返回 reasoning_content alongside the final content,并且我们在可折叠展开器中渲染跟踪,以便它不会主导UI。

第4步:本地运行

从项目文件夹中:

streamlit run app.py

Streamlit打印一个本地URL(通常是 http://localhost:8501然后将其在您的浏览器中打开。输入一个问题,逐个查看响应流,并检查侧边栏的成本计数器是否上升。使用V4-Flash,简短对话的成本应该只占几分之一美分。

Verify it worked

  1. 发送“回复以单字:pong。”——你应该看到 pong 流入。
  2. 将侧边栏模型切换到 deepseek-v4-pro 提出一个多步骤推理问题。确认响应到达,并且与类似令牌计数相比,会话成本大约增加了十倍。
  3. 切换 Thinking mode 打开并提问一个规划问题。"推理"展开器应该填充跟踪信息,最终答案应在主消息体中跟随。
  4. Click 清晰对话 并确认历史记录和费用计数器已重置。

第5步:成本工作示例

Flat diagram of a Streamlit DeepSeek chat app with a sidebar cost meter tracking input and output token spend.

假设您的Streamlit应用每月处理100万次聊天调用。 deepseek-v4-flash,使用DeepSeek的上下文缓存在第一次调用后拾取的2,000个令牌的系统提示,每轮200个令牌的用户消息,以及300个令牌的回复。以下是所有三个桶的数学计算:

Bucket Tokens Rate (per 1M) Cost
Input, cache hit 2,000,000,000 $0.0028 $56.00
Input, cache 请求kwargs中的。 200,000,000 $0.14 $28.00
Output 300,000,000 $0.28 $84.00
Total $117.60

在同一工作负载上运行。 deepseek-v4-pro ,总成本攀升至约1,421美元——大约是十倍——因为Pro列出了0.0145美元的缓存命中、1.74美元的缓存未命中和3.48美元的输出(目前为每1M令牌0.003625美元/0.435美元/0.87美元,在2026年5月31日前的75%促销期间有效)。定价率截至2026年4月;请与以下信息核对。 DeepSeek API pricing 在生产中报价之前,先在页面上运行。对于更大的扫描,这比手动重建表格要快。 DeepSeek pricing calculator 是比手动重建表格更快的。

有两点需要注意。每条新的用户消息都是一个缓存未命中。 请求kwargs中的。 即使系统提示完全缓存,也要与缓存前缀进行比较——这就是为什么未缓存输入行不为零的原因。并且,老教程中提到的非高峰时段折扣已于2025年9月5日结束;不要围绕它进行预算。

第6步:添加有用功能

结构化输出的JSON模式

如果您希望助手返回结构化数据——例如表单提取或分类结果——请设置为返回有效的JSON,但不保证:它偶尔会返回空内容,提示信息中必须包含单词“json”以及一个简短的示例模式,并且您应该设置 response_format={"type": "json_object"} DeepSeek的JSON模式是 designed 上面的应用程序仅支持文本,但DeepSeek支持在V4级别(无论是思考模式还是非思考模式)上调用OpenAI格式的功能。传递一个 max_tokens 高到足以避免截断。始终使用try/except结构,并优雅地回退。 json.loads 列出并处理

Tool calling

为了让用户能够与自己的文件进行聊天,在聊天调用之前添加一个检索步骤:嵌入文档,查询向量存储,并将顶部片段注入到系统消息中。该 tools=[...] 流中的增量。对于更完整的模式,教程涵盖了从工具调度到端到端的全过程。 tool_calls 使用与DeepSeek基础URL相同的OpenAI-SDK指针遍历该模式。 DeepSeek Python integration ; 确认密钥以

在您的文档上使用RAG

部分使用与TOML相同的格式。部署大约需要90秒。因为API是无状态的,历史记录存储在 DeepSeek RAG tutorial 重新检查

Common errors and fixes

Symptom Likely cause Fix
; 确认密钥以 Missing or wrong API key 开头,并且没有复制尾随空格。 .streamlit/secrets.toml; confirm the key starts with sk- and was copied without trailing whitespace.
模型未找到 for deepseek-chat 迁移后使用旧ID Switch to deepseek-v4-flash. Legacy IDs deepseek-chat and deepseek-reasoner 目前路由到V4-Flash,但将于2026年7月24日15:59 UTC停用。
流式传输卡住,没有渲染令牌 Streamlit placeholder.markdown 在循环内未刷新 确认您正在调用 placeholder.markdown(full_text + " ") 在for循环内,而不是循环之后。
JSON mode returns empty content 提示中缺少单词“json”或 max_tokens too low 在提示中添加一个示例模式;引发 max_tokens; 将解析包裹在try/except中。
费用计价器保持在 $0.00 未请求使用块 Pass stream_options={"include_usage": True}; 检查最终块是否 chunk.usage 已填充。
在负载下出现429速率限制错误 低配额下的并发用户 添加指数退避;审查 DeepSeek API rate limits.

部署到Streamlit社区云

将项目推送到公共或私有GitHub仓库(无需 secrets.toml),在share.streamlit.io上连接仓库,指向 app.py,并将您的 DEEPSEEK_API_KEY 粘贴到应用的 机密 ,每个用户都会获得自己的对话,而无需您在后台进行任何工作——但请注意,会话状态在容器重启时会消失。对于持久历史记录,您需要添加数据库;对于大多数内部工具来说,这可能是过度设计。 st.session_state, each user gets their own conversation without any backend work on your side — but note that session state evaporates on container restart. For persistent history you would add a database; for most internal tools that is overkill.

为什么选择这些默认值

温度滑块默认设置为1.3,因为这已是DeepSeek针对一般对话和翻译的官方设置。将其降至0.0用于代码生成或数学计算,保持1.0用于数据分析,推至1.5用于创意写作。默认模型为V4-Flash,因为不同层级的成本差距大约是输出端的7倍,而Flash足以应对大部分聊天负载——需要更多时请选择 DeepSeek V4-Pro 当基准或任务质量真正需要提升时。

100万个token的上下文窗口在两个层级上都是相同的,输出可达384,000个token,因此您可以在不改变架构的情况下粘贴整个代码库。大多数聊天用户界面都无法达到这个上限;如果您的可以达到,请利用上下文缓存并在发送前检查token数量。

Next steps

Architecture diagram of a Streamlit Python app calling DeepSeek V4 and rendering replies in a browser.

DeepSeek AI Guide is an independent resource and is not affiliated with DeepSeek or its parent company. Model IDs, pricing and API behaviour change; check the official DeepSeek documentation and pricing page before committing to a production decision.

Frequently asked questions

我该如何将Streamlit连接到DeepSeek API?

使用官方OpenAI Python SDK,并将其指向DeepSeek的基础URL: OpenAI(base_url="https://api.deepseek.com", api_key=...). Chat requests hit POST /chat/completions 与OpenAI相同的网络格式,因此无需更改调用位置。将密钥存储在 .streamlit/secrets.toml 并使用 st.secrets读取。完整的设置在 DeepSeek OpenAI SDK compatibility guide.

运行DeepSeek Streamlit应用程序的成本是多少?

On deepseek-v4-flash,截至2026年4月,预计每百万个输入缺失token的费用约为0.14美元,缓存命中为0.0028美元,每百万个输出为0.28美元。典型的简短聊天费用仅为几分之一美分。V4-Pro层级的输出成本大约是6-7倍。在预算时始终列举所有三个token类别;请 DeepSeek API pricing 页面是事实来源。

我能否在Streamlit聊天中启用思考模式?

是的。在V4中,思考是任一层的请求参数,而不是一个单独的模型。传递 reasoning_effort="high" with extra_body={"thinking": {"type": "enabled"}}. 流随后返回 reasoning_content alongside the final content,您可以在Streamlit展开器中渲染它。参见 DeepSeek V4 了解完整的参数合约。

为什么我的应用程序在请求之间会忘记之前的消息?

DeepSeek API是无状态的——服务器不会记住之前的回合,因此客户端必须重新发送整个对话以 messages 数组在每个请求上。Streamlit指南涵盖了权衡。 st.session_state 是在会话期间保存历史记录的正确位置。网页聊天表现不同,因为它的UI会为您保持状态。更多关于底层API的信息在 DeepSeek API documentation.

公开部署DeepSeek Streamlit应用程序是否安全?

是的,但请注意以下几点:将API密钥保存在Streamlit的秘密中,绝不要存放在代码仓库中;如果URL是公开的,请为每个用户添加速率限制;在部署前审查用户将要发送的数据。DeepSeek在受中国法律约束的服务器上处理请求,因此请相应地路由敏感数据。 DeepSeek privacy guide covers the trade-offs.

Sources & Methodology

Last source check: April 30, 2026

Primary sources

Methodology

Information in this article was checked against the official DeepSeek documentation, the article's cited primary sources, and the deepseekai.guide pricing dataset on the date shown above. Where third-party numbers are quoted, the originating source is linked inline so the reader can verify and re-check.

Data confidence

High for facts cited inline with primary-source links; medium for context narrative.

Editorial note

AI tooling moves quickly. If you spot an outdated number or a broken link, the contact link in the footer is the fastest way to flag it for the editorial team.