我一个前端仔,居然用 Python 搞起了 AI?从零到一,撸了个 AI 聊天框小 demo

前言

作为一个平时跟 React、Vue 打交道的前端人,谁能想到某天我会抱着 Python 文件抓耳挠腮?起因很简单 ------ 我想搞个属于自己的极简 AI 聊天框,不用复杂的前端框架,不用写 HTML 和 CSS,几行 Python 代码搞定,主打一个 "能用就行,还得有点排面"

一、先搭骨架:把依赖和环境变量安排明白

写代码第一步,永远是 "先把工具备好" 。就像做饭得先买菜,写 Python 项目得先装依赖、配环境

首先,我得把需要的库都 import 进来:

Python 复制代码
import os  # 管环境变量的工具人
from dotenv import load_dotenv  # 从.env文件里加载密钥,避免硬编码泄露
from openai import OpenAI  # 连接LLM的通用SDK,DeepSeek也能用
import streamlit as st  # 一键生成Web界面的神器,前端人的福音

这里得重点说一下dotenv和环境变量。很多新手写代码喜欢把 API 密钥直接写在代码里,比如api_key="sk-xxxx",这要是不小心传到 GitHub 上,分分钟被薅秃。用dotenv就不一样了,密钥写在.env文件里,load_dotenv()一调用就能读出来,安全又优雅。

Python 复制代码
# 加载.env文件里的环境变量
load_dotenv()
# 优先读环境变量,没有的话读Streamlit的secrets(部署的时候用)
api_key = os.getenv('API_KEY') or st.secrets.get('API_KEY')

二、打通 AI 接口:让 Python 和 DeepSeek 说上话

骨架搭好了,接下来得让代码能连上 DeepSeek 的 API。OpenAI 的 SDK 对兼容接口非常友好,只要把base_url改成 DeepSeek 的地址,就能直接用,完全不用改太多逻辑。

Python 复制代码
client = OpenAI(
    api_key=api_key,
    base_url="https://api.deepseek.com"
)

搞定客户端,就可以试试调用接口了。一开始我写了个最简单的请求,看看能不能拿到回复:

Python 复制代码
response = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[
        {"role": "system", "content": "你是一个友好的 AI 助手"},
        {"role": "user", "content": "用三句话解释什么是人工智能"}
    ]
)
print(response.choices[0].message.content)
print(response.usage)

运行一下,控制台直接打印出了 AI 的回复和 token 消耗,以及 DeepSeek 确实是扣钱了,完成!

不过光有控制台输出肯定不行,我要的是一个能交互的 Web 界面,不然怎么叫聊天框呢?

三、搞个 Web 界面:Streamlit 五分钟救我狗命

作为一个前端人,本来还想着要写 HTML、CSS、JS,结果 Streamlit 直接给我整明白了。几行代码就能生成一个带标题、聊天框、输入框的界面。

1. 先给界面整个 "门面"

Python 复制代码
st.title("🤖 我是你的专属助理")
st.caption("基于 deepseek-v4-flash 模型")

运行一下,页面上直接出现了标题和副标题,比我写 HTML 快了 100 倍。

2.初始化对话历史:让 AI 记得我们聊过啥

聊天嘛,总得有上下文,不然每次提问都是 "裸奔",AI 根本不知道我们聊了啥。Streamlit 的session_state就派上用场了,它能在用户交互过程中保存数据,相当于一个全局状态管理器。

Python 复制代码
# 如果会话里没有messages列表,就初始化一个空的
if "messages" not in st.session_state:
    st.session_state.messages = []

3. 显示历史消息:让聊天记录 "看得见"

每次刷新页面,我们得把之前的聊天记录重新渲染出来,不然用户一刷新,对话就没了,体验太差。

Python 复制代码
for message in st.session_state.messages:
    # 根据消息的role创建对应的聊天容器(user是用户,assistant是AI)
    with st.chat_message(message["role"]):
        st.write(message["content"])

4. 接收用户输入:做个能打字的输入框

Streamlit 的chat_input方法直接给你生成一个聊天输入框,还自带样式,不用自己写:

Python 复制代码
if prompt := st.chat_input("请输入你的问题..."):
    # 把用户的问题加到对话历史里
    st.session_state.messages.append({"role": "user", "content": prompt})
    # 在页面上显示用户的问题
    with st.chat_message("user"):
        st.write(prompt)

到这里,界面的交互逻辑就差不多了,接下来就是把 AI 的回复也加上。

四、流式回复:让聊天框更有 "灵魂"

普通的请求要等 AI 生成完所有内容才会一次性返回,用户体验不好,看着干等很容易以为程序卡了。所以我给它加上了流式回复,让文字像打字机一样一点点出来。

首先,调用接口的时候加上stream=True参数,开启流式返回:

Python 复制代码
response = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[
        {"role": "system", "content": "你是一个友好的 AI 助手"},
        # 用解包运算符把历史消息都传进去,这样AI就能记住上下文
        *st.session_state.messages
    ],
    stream=True
)

然后用 Streamlit 的write_stream方法处理流式数据,实现打字机效果:

Python 复制代码
with st.chat_message("assistant"):
    full_response = st.write_stream(
        # 把每个chunk里的delta内容拿出来,没有就返回空字符串
        chunk.choices[0].delta.content or ""
        for chunk in response
        if chunk.choices[0].delta.content
    )
# 把AI的回复也加到对话历史里,下次提问就能带上上下文了
st.session_state.messages.append({"role": "assistant", "content": full_response})

运行一下,输入问题,AI 的回复就像真人打字一样一点点出来,那一刻我感觉自己离 "AI 产品经理" 又近了一步。

五、完整代码

Python 复制代码
import os  # 导入 os 模块,用于获取环境变量
from dotenv import load_dotenv  # 导入 load_dotenv 函数,用于加载环境变量
from openai import OpenAI  # 专门用来连接 LLM 的库
import streamlit as st  # 专门用来创建应用页面的库

load_dotenv() # 从.env 文件中读取内容

api_key = os.getenv('API_KEY') or st.secrets.get('API_KEY')

client = OpenAI(
    api_key=api_key,
    base_url="https://api.deepseek.com"
)

# ============================== 创建 Web 应用 ============================== #
st.title("🤖 我是你的专属助理")  # 有一个 html 文件,里面写了一个 <h1>🤖 我是你的专属助理</h1>
st.caption("基于 deepseek-v4-flash 模型")

# ============================== 初始化对话历史 ============================== #
# session_state 是 st 提供的会话状态管理器,用于在用户的交互过程中保存数据
if "messages" not in st.session_state:
    st.session_state.messages = []

# ==============================  显示历史消息 =============================== #
for message in st.session_state.messages:
    with st.chat_message(message["role"]):  # 创建一个消息容器
        st.write(message["content"])        # 往容器中写入内容

# ========================= 处理用户输入的内容  =============================== #
if prompt := st.chat_input("请输入你的问题..."):  # 创建一个 input 框,用于接收用户的问题

    # 将用户的问题添加到对话历史中
    st.session_state.messages.append({"role": "user", "content": prompt})
    
    # 在页面上展示用户的问题
    with st.chat_message("user"):
        st.write(prompt)
    
    # 创建一个 AI 响应的容器
    with st.chat_message("assistant"):

        # 调用 deepseek,并获取到响应,写入容器中
        response = client.chat.completions.create(
            model="deepseek-v4-flash",
            messages=[  # 用户的问题
                {"role": "system", "content": "你是一个友好的 AI 助手"},
                # * 解包运算符,将一个数组中的内容,解包到另一个数组中
                *st.session_state.messages
            ],
            stream=True
        )
    
        # 处理流式资源
        full_response = st.write_stream(
            chunk.choices[0].delta.content or ""
            for chunk in response
            if chunk.choices[0].delta.content
        )

         # 将 AI 返回的内容添加到历史消息中
        st.session_state.messages.append({"role": "assistant", "content": full_response})

DeepSeek API 文档:api-docs.deepseek.com/zh-cn/

streamlit官网:streamlit.io/

六、踩坑记录:写 demo 哪有不踩坑的?

当然,写代码的过程也不是一帆风顺的,这里给大家分享几个我踩过的坑,帮你们少走弯路:

  1. API 密钥泄露风险 :一开始我直接把密钥写在代码里,后来想想太危险了,赶紧改成了.env文件 +dotenv的方式,部署的时候用 Streamlit 的 secrets,安全多了。
  2. 忘记加stream=True:一开始没开流式,用户要等好久才能看到回复,体验极差,加上之后瞬间丝滑。
  3. 对话历史没传全 :第一次调用接口的时候,只传了用户的当前问题,没传历史消息,AI 根本不知道上下文,每次回答都像失忆了一样,加上*st.session_state.messages就好了。
  4. Streamlit 会话状态的坑 :一开始没初始化messages,刷新页面就报错,后来加上if "messages" not in st.session_state:就解决了。

结语

短短几十分钟,一个极简的 AI 聊天框 demo 就搞定了。它没有复杂的 UI,没有花哨的功能,但麻雀虽小五脏俱全 ------ 环境变量配置、API 调用、流式回复、对话历史、Web 界面,一个 AI 聊天应用该有的基础功能它都有了。

如果你也想试试,那就来!毕竟,谁不是从写 demo 开始的呢?

相关推荐
装不满的克莱因瓶1 小时前
图像尺寸调整:缩放矩阵如何改变像素坐标?
人工智能·线性代数·数学·算法·机器学习·矩阵
GlobalInfo1 小时前
八旋翼无人机产业洞察与市场占有率演变:2026年趋势分析报告
人工智能·无人机
GISer_Jing1 小时前
Claude Code插件系统全解析
前端·人工智能·ai·架构
AI前沿资讯1 小时前
2026年AI 3D赛道新势力崛起:一体化创作平台成主流,V2Fun凭全流程能力突围
人工智能·3d
逍遥运德1 小时前
PostgreSQL ---【序列】用法详解
后端·sql·postgresql
猫头虎1 小时前
Cursor推出的Composer 2.5 是什么?从定向 RL 到合成数据,AI 编程智能体再进化
人工智能·开源·prompt·aigc·copilot·ai编程·composer
小茴香3531 小时前
Vue3路由权限动态管理
前端·前端框架·vue3
RANxy1 小时前
零基础全栈 React 入门(四):React Router 路由配置
前端·react.js
触底反弹1 小时前
给 Claude 装上 27 个「外挂」后,我直接起飞了!
人工智能·react.js