【学习记录】DeepSeek 代码助手:FastAPI 后端 + Streamlit 前端完整实现

在上一篇文章中,我们展示了如何将 DeepSeek 大模型封装为 FastAPI 服务。今天,我们为其打造一个友好的 Web 界面——DeepSeek 代码助手。用户可以通过浏览器输入编程问题,系统调用后端 DeepSeek 模型生成代码或解答,并以高亮代码块的形式展示。本文详细讲解前后端代码、运行方法、原理及注意事项,帮助你快速搭建属于自己的 AI 编程助手。


📌 目录

  1. 项目概览
  2. 后端实现:FastAPI + DeepSeek
    • 2.1 依赖安装与配置
    • 2.2 代码详解
  3. 前端实现:Streamlit 界面
    • 3.1 页面布局与组件
    • 3.2 调用后端 API
    • 3.3 结果展示与错误处理
  4. 运行指南
    • 4.1 启动后端服务
    • 4.2 启动前端界面
    • 4.3 测试效果
  5. 注意事项与优化建议
  6. 总结

一、项目概览

本系统由两部分组成:

组件 技术栈 职责
后端 API FastAPI + LlamaIndex + DeepSeek 接收用户问题及系统提示词,调用 DeepSeek 模型生成回答
前端 UI Streamlit 提供 Web 交互界面,发送请求并展示模型返回的代码/文本

工作流程

  1. 用户在 Streamlit 界面输入问题(可附带系统提示词)。
  2. 前端向 FastAPI 后端发送 HTTP POST 请求。
  3. 后端调用 DeepSeek 模型,返回生成的回答。
  4. 前端将回答以代码块形式展示,并显示模型信息。

二、后端实现:FastAPI + DeepSeek

2.1 依赖安装

创建虚拟环境并安装以下包:

pip install fastapi uvicorn llama-index-core llama-index-llms-deepseek

2.2 完整代码(app.py

import os
import logging
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from llama_index.llms.deepseek import DeepSeek
from llama_index.core.llms import ChatMessage

# 日志配置
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# DeepSeek 配置(请勿硬编码!生产环境使用环境变量)
DEEPSEEK_API_KEY = "sk-xxxxxxxxxxxx"   # 替换为你的真实 Key
DEFAULT_MODEL = "deepseek-chat"

llm = DeepSeek(
    model=DEFAULT_MODEL,
    api_key=DEEPSEEK_API_KEY,
    temperature=0.3,
    max_tokens=2048,
    timeout=60.0,
)

# 请求/响应模型
class GenerateRequest(BaseModel):
    prompt: str = Field(..., description="用户输入的提示词")
    system_prompt: str | None = Field(None, description="可选的系统提示词")

class GenerateResponse(BaseModel):
    response: str
    model: str

# FastAPI 应用
app = FastAPI(title="DeepSeek LLM API")

@app.get("/health")
async def health():
    return {"status": "ok", "model": DEFAULT_MODEL}

@app.post("/generate", response_model=GenerateResponse)
async def generate_text(request: GenerateRequest):
    try:
        messages = []
        if request.system_prompt:
            messages.append(ChatMessage(role="system", content=request.system_prompt))
        messages.append(ChatMessage(role="user", content=request.prompt))
        
        response = llm.chat(messages)
        answer = response.message.content
        
        return GenerateResponse(response=answer, model=DEFAULT_MODEL)
    except Exception as e:
        logger.error(f"推理失败: {str(e)}", exc_info=True)
        raise HTTPException(status_code=500, detail=f"模型推理失败: {str(e)}")

代码要点

  • 使用 DeepSeek 类初始化模型,配置 temperature(控制随机性)、max_tokens(输出长度)、timeout(超时)。
  • ChatMessage 支持多轮对话,这里构造了可选的 system 消息和必填的 user 消息。
  • /generate 端点接收 JSON 格式的请求,返回模型生成的文本。
  • 统一异常处理,避免将内部错误直接暴露给客户端。

⚠️ 安全警告:API Key 硬编码在代码中,是严重的安全隐患。生产环境请使用环境变量(如 os.getenv("DEEPSEEK_API_KEY"))或密钥管理服务。


三、前端实现:Streamlit 界面

3.1 依赖安装

pip install streamlit requests

3.2 完整代码(ui.py

import streamlit as st
import requests
import json

# ---------- 页面配置 ----------
st.set_page_config(
    page_title="DeepSeek 代码助手",
    page_icon="🤖",
    layout="centered"
)

st.title("🤖 DeepSeek 代码助手")
st.markdown("基于 DeepSeek 模型,专注代码生成与解答")

# ---------- 侧边栏配置 ----------
with st.sidebar:
    st.header("⚙️ 设置")
    backend_url = st.text_input("后端 API 地址", value="http://localhost:8000")
    system_prompt = st.text_area(
        "系统提示词(可选)",
        value="你是一个严谨的代码助手,只输出代码和简洁注释,不要额外解释。",
        help="设定模型行为风格"
    )
    st.markdown("---")
    st.markdown("### 使用说明")
    st.markdown("1. 在下方输入你的编程问题")
    st.markdown("2. 点击「生成回答」按钮")
    st.markdown("3. 等待模型返回代码或解答")

# ---------- 主区域 ----------
st.header("💬 问题输入")
user_prompt = st.text_area(
    "请输入你的问题:",
    height=150,
    placeholder="例如:用Python写一个计算斐波那契数列的函数",
    key="prompt_input"
)

col1, col2 = st.columns([1, 5])
with col1:
    submit = st.button("🚀 生成回答", type="primary", use_container_width=True)

# ---------- 结果展示区 ----------
if submit:
    if not user_prompt.strip():
        st.warning("⚠️ 请输入问题内容")
        st.stop()
    
    api_endpoint = f"{backend_url.rstrip('/')}/generate"
    payload = {
        "prompt": user_prompt,
        "system_prompt": system_prompt if system_prompt.strip() else None
    }
    
    with st.spinner("🤔 DeepSeek 正在思考中,请稍候..."):
        try:
            response = requests.post(
                api_endpoint,
                json=payload,
                headers={"Content-Type": "application/json"},
                timeout=60
            )
            response.raise_for_status()
            result = response.json()
            
            st.success("✅ 生成成功")
            st.subheader("📄 回答内容")
            # 使用代码块展示(如果是代码会自动高亮)
            st.code(result["response"], language="python" if "python" in result["response"].lower() else "text")
            st.caption(f"模型:{result['model']}")
            st.info("💡 提示:点击代码块右上角的复制图标可直接复制代码")
            
        except requests.exceptions.ConnectionError:
            st.error(f"❌ 无法连接到后端服务,请确认后端已启动且地址正确:{backend_url}")
            st.info("启动后端命令:`uvicorn app:app --host 0.0.0.0 --port 8000`")
        except requests.exceptions.Timeout:
            st.error("⏰ 请求超时,请稍后重试或检查模型响应时间")
        except requests.exceptions.HTTPError as e:
            st.error(f"❌ 后端返回错误:{e}\n{response.text}")
        except json.JSONDecodeError:
            st.error("❌ 解析响应失败,后端可能返回了非 JSON 内容")
        except Exception as e:
            st.error(f"❌ 未知错误:{str(e)}")

st.markdown("---")
st.markdown("📌 提示:如果生成内容不全,可尝试在侧边栏修改系统提示词或检查后端 `max_tokens` 设置。")

前端要点

  • 侧边栏配置:允许用户修改后端 API 地址和系统提示词,增强灵活性。
  • 错误处理:覆盖连接失败、超时、HTTP 错误、JSON 解析错误等常见情况,给出友好提示。
  • 结果展示:使用 st.code 自动识别代码语言(简单判断是否包含“python”),支持复制功能。
  • 用户体验:提交时显示加载动画(st.spinner),成功/失败有明确的状态反馈。

四、运行指南

4.1 启动后端服务

在终端中执行:

# 设置 API Key(Linux/macOS)
export DEEPSEEK_API_KEY="sk-xxxxxxxxxxxx"

# 或 Windows (cmd)
set DEEPSEEK_API_KEY=sk-xxxxxxxxxxxx

# 启动 FastAPI 服务
uvicorn app:app --host 0.0.0.0 --port 8000 --reload

看到类似输出表示成功:

INFO:     Uvicorn running on http://0.0.0.0:8000
INFO:     Application startup complete.

4.2 启动前端界面

打开另一个终端,运行:

streamlit run ui.py

浏览器将自动打开 http://localhost:8501

4.3 测试效果

  1. 在 Streamlit 界面的输入框中输入问题,例如:用Python写一个快速排序函数
  2. 点击「生成回答」按钮。
  3. 稍等片刻,后端返回的代码会显示在代码块中,并标注模型名称。

在这里插入图片描述

五、注意事项与优化建议

方面 注意事项 优化建议
API Key 安全 代码中硬编码了 Key,有泄露风险 使用环境变量 os.getenv("DEEPSEEK_API_KEY");生产环境使用密钥管理服务
CORS 问题 前端和后端可能端口不同,但 Streamlit 默认请求后端时属于跨域?实际上 Streamlit 是客户端发送请求到后端,不涉及浏览器跨域限制。 无需额外配置。若前端部署在独立域名,后端需启用 CORSMiddleware
请求超时 模型生成较长内容可能超过 60 秒 可适当调高 timeout 参数,或改为异步任务队列
并发处理 FastAPI 的同步 llm.chat 会阻塞事件循环 使用 asyncio.to_thread 将同步调用放入线程池,或改用 DeepSeek 的异步 API(如果提供)
前端代码高亮 当前仅通过判断字符串中是否含“python”来决定高亮语言 可根据返回代码块中的语言标记(如 ```python)更精确高亮;也可使用 pygments
对话历史 当前仅支持单轮对话 扩展前端维护 messages 历史,并通过 API 传递完整的对话列表

六、总结

通过本文,我们构建了一个完整的DeepSeek 代码助手,包括:

  • ✅ 基于 FastAPI 的模型调用后端,支持系统提示词和用户问题。
  • ✅ 基于 Streamlit 的 Web 前端,提供直观的交互界面。
  • ✅ 完善的错误处理和用户提示,提升可用性。
  • ✅ 清晰的代码注释和运行指南,方便二次开发。

你可以将此系统部署在个人服务器上,作为团队内部的 AI 编程辅助工具。后续还可以扩展:

  • 支持多轮对话(保存历史消息)。
  • 集成代码执行环境(如 Jupyter 内核)。
  • 添加用户认证与计费功能。

希望这篇文章能帮助你快速搭建自己的大模型应用。如果在实践过程中遇到问题,欢迎在评论区留言交流。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐