国庆节10月1日
--


用 Streamlit + openai 库搭出能与大模型对话的网页:页面配置、会话状态初始化、消息渲染与发送

做一个”AI 智能伴侣”网页:左边是控制面板(会话列表、伴侣昵称、性格),右边是聊天窗口,输入问题后大模型以伴侣的口吻流式回复。
做完整个章节后,页面长这样:

本篇是第一步:把基本交互跑通(对应课程代码 03. ai_partner_1.py)。后续依次叠加流式输出、会话记忆、会话管理。
11. 设置页面配置 st.set_page_config22. 展示标题和 Logo st.title / st.logo33. 初始化会话状态 st.session_state44. 渲染历史消息 for + st.chat_message55. 创建大模型客户端 OpenAI(...)66. 等待用户输入 st.chat_input77. 调用大模型并展示 client.chat.completions.create88. 把这一轮对话存入 session_state1import streamlit as st2import os3from openai import OpenAI4
5print("----------> 重新执行此文件 , 渲染展示页面")6
7# 设置页面的配置项8st.set_page_config(9 page_title="AI智能伴侣",10 page_icon="🤖",11 layout="wide",12 initial_sidebar_state="expanded",13 menu_items={}14)15
16# 大标题17st.title("AI智能伴侣")18
19# Logo20st.logo("resources/logo.png")21
22# 系统提示词23system_prompt = "你是一名非常可爱的AI助理, 你的名字叫小甜甜, 请你使用温柔可爱的语气回答用户的问题"24
25# 初始化聊天信息26if "messages" not in st.session_state:27 st.session_state.messages = []28
29# 展示聊天信息30for message in st.session_state.messages: # {"role": "user", "content": prompt}31 st.chat_message(message["role"]).write(message["content"])32
33# 创建与AI大模型交互的客户端对象 (DEEPSEEK_API_KEY 环境变量的名字, 值就是DeepSeek的API_KEY的)34client = OpenAI(api_key=os.environ.get('DEEPSEEK_API_KEY'), base_url="https://api.deepseek.com")35
36# 消息输入框37prompt = st.chat_input("请输入您要问的问题")38if prompt: # 字符串会自动转换为布尔值, 如果字符串非空, 则为True; ""否则为False39 st.chat_message("user").write(prompt)40 print("----------> 调用AI大模型, 提示词: ", prompt)41
42 # 保存用户输入的提示词43 st.session_state.messages.append({"role": "user", "content": prompt})44
45 # 调用AI大模型46 response = client.chat.completions.create(47 model="deepseek-chat",48 messages=[49 {"role": "system", "content": system_prompt},50 {"role": "user", "content": prompt},51 ],52 stream=False53 )54
55 # 输出大模型返回的结果56 print("<---------- 大模型返回的结果: ", response.choices[0].message.content)57 st.chat_message("assistant").write(response.choices[0].message.content)58
59 # 保存大模型返回的结果60 st.session_state.messages.append({"role": "assistant", "content": response.choices[0].message.content})1print("----------> 重新执行此文件 , 渲染展示页面")因为 Streamlit 每次交互都会重新执行整个脚本(见 Streamlit入门)。这行 print 打在终端里,用来亲眼确认”脚本又跑了一遍”——理解这一点,才能理解后面为什么必须用 st.session_state。
1if "messages" not in st.session_state:2 st.session_state.messages = []| 写法 | 含义 |
|---|---|
if "messages" not in st.session_state | 只在第一次运行时初始化(字典里没有这个 key 才创建空列表) |
| 以后每次重跑 | 条件不成立,直接沿用已有的列表,历史消息不会丢 |
不能写成 st.session_state.messages = [](不加 if 判断)。那样每次重跑都会把聊天记录清空,界面会一直只剩当前这一句。
1for message in st.session_state.messages:2 st.chat_message(message["role"]).write(message["content"])messages 列表里的每个元素都带 role,直接把它传给 st.chat_message(),user 显示在右侧、assistant 显示在左侧,样式自动区分。
这个 messages 列表的格式({"role": ..., "content": ...})就是发给大模型 API 的格式,界面展示和接口调用用的是同一份数据,不需要单独维护两套。
1if prompt:st.chat_input() 在用户还没输入内容时返回 None,输入并回车后返回字符串。字符串在 if 中会自动转成布尔值:非空为 True,"" 为 False。所以 if prompt: 等价于”用户这次真的发了消息”。
1messages=[2 {"role": "system", "content": system_prompt},3 {"role": "user", "content": prompt},4]这一版只把当前这一句发给模型,所以此时 AI 还记不住上一轮(模型是无状态的)。下一步就要改造成”带上历史消息”,见 会话记忆。
st.set_page_config / st.title / st.logoif "messages" not in st.session_state: st.session_state.messages = []for message in st.session_state.messages: st.chat_message(message["role"]).write(message["content"])prompt = st.chat_input("请输入您要问的问题")if prompt: 能判断”用户这次真的发了消息”,是因为非空字符串转布尔值是 Truest.session_state.messages.append({"role": "user", "content": prompt})response.choices[0].message.contentst.session_state?因为 Streamlit 每次交互都会重新执行整个脚本,普通变量会丢2-1 先把”记忆”跑起来 不接大模型:先在页面状态里塞两条假消息(一条用户、一条 AI),把它们渲染成聊天气泡;再放一个输入框,用户输入后追加到消息列表并回显(刷新页面后消息还在)。
一级 · 思路:页面每次重跑都要能”看到”历史 → 把消息列表存进会话状态;渲染就是遍历这个列表
二级 · 方法:st.session_state.messages / st.chat_message / st.chat_input
三级 · 骨架:for message in ...: st.chat_message(message["role"]).write(message["content"])
1import streamlit as st2
3# 先塞两条假消息,检验"渲染 + 追加"这条链路4if "messages" not in st.session_state:5 st.session_state.messages = [6 {"role": "user", "content": "你好"},7 {"role": "assistant", "content": "你好呀,我是小甜甜~"},8 ]9
10st.title("AI智能伴侣(暂不接模型)")11
12# 每次重跑都按列表渲染一遍历史13for message in st.session_state.messages:14 st.chat_message(message["role"]).write(message["content"])15
16prompt = st.chat_input("请输入您要问的问题")17if prompt:18 st.session_state.messages.append({"role": "user", "content": prompt})19 st.chat_message("user").write(prompt)20
21# 刷新页面后消息还在 —— 因为列表存在 session_state 里,不是普通变量2-2 接上大模型 在 2-1 的基础上接上 deepseek-chat:用户发消息 → 调模型 → 把回复也渲染出来并存进消息列表。
一级 · 思路:存 → 调 → 显示 → 再存,四步都要在 if prompt: 里面
二级 · 方法:client.chat.completions.create / st.session_state.messages.append
三级 · 骨架:messages=[{"role": "system", "content": system_prompt}, {"role": "user", "content": prompt}](这一版只发当前这一句,看看 AI 记不记得上一轮)
1import os2import streamlit as st3from openai import OpenAI4
5st.set_page_config(page_title="AI智能伴侣", page_icon="🤖", layout="wide")6st.title("AI智能伴侣")7
8system_prompt = "你是一名非常可爱的AI助理, 你的名字叫小甜甜, 请你使用温柔可爱的语气回答用户的问题"9
10if "messages" not in st.session_state:11 st.session_state.messages = []12
13for message in st.session_state.messages:14 st.chat_message(message["role"]).write(message["content"])15
16client = OpenAI(api_key=os.environ.get("DEEPSEEK_API_KEY"), base_url="https://api.deepseek.com")17
18prompt = st.chat_input("请输入您要问的问题")19if prompt:20 st.chat_message("user").write(prompt)21 st.session_state.messages.append({"role": "user", "content": prompt})22
23 response = client.chat.completions.create(24 model="deepseek-chat",25 messages=[26 {"role": "system", "content": system_prompt},27 {"role": "user", "content": prompt},28 ],29 stream=False,30 )31 reply = response.choices[0].message.content32 st.chat_message("assistant").write(reply)33 st.session_state.messages.append({"role": "assistant", "content": reply})如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"生活不是等待暴风雨过去,而是学会在雨中跳舞。"—— 塞维涅夫人


