📌 新手提示:本文结尾提供了一键部署脚本(Windows / macOS / Linux 通用),自动装好 Python 环境、配好 API Key、生成一个能直接跑的 AI 聊天网页应用。
前言
你已经学会了调 Claude API(本站《Claude API 开发实战》),但都是"黑乎乎的终端输出"——能不能把自己写的 AI 变成一个带聊天框、带按钮、别人点开就能用的网页?
Streamlit 就是干这个的:一个开源的 Python 库,纯 Python 写网页——没有 HTML、没有 CSS、没有前后端分离,几十行代码就能出一个漂亮的 Web 工具。
它的口号很诚实:“The fastest way to build and share data apps”(构建和分享数据应用的最快方式)。对 AI 应用来说尤其合适:你有 API 逻辑,Streamlit 帮你把外壳(输入框/聊天气泡/按钮/状态)全包了。
本文基于官方教程(https://docs.streamlit.io/develop/tutorials/llms/build-conversational-apps,海外站点国内访问需科学上网)编写,最终产出:一个 ChatGPT 式的聊天网页应用,可以在浏览器里和 AI 连续对话。
一、安装与首跑(30 秒)
pip install streamlit
写一个 app.py:
import streamlit as st
st.title("我的第一个 AI 应用")
name = st.text_input("你叫什么?")
if st.button("打招呼"):
st.write(f"你好,{name}!")
运行:
streamlit run app.py
浏览器自动打开 http://localhost:8501——你已经有一个网页应用了。
power point:改代码保存,页面自动刷新(Streamlit 的"热重载")。根本不用重启服务。
二、5 个核心 API(掌握这些就能写 90% 的页面)
| API | 干什么 | 一句话理解 |
|---|---|---|
st.title / st.write | 标题 / 任意内容 | 往页面打印东西 |
st.text_input | 单行文本输入框 | 让用户输入 |
st.button | 按钮 | 点击触发逻辑 |
st.chat_message | 聊天气泡(user/assistant) | 像微信那样两边对话 |
st.chat_input | 聊天输入框(底部) | 聊天气泡式输入 |
再加一个进阶必知:st.session_state——Streamlit 每次交互都会把整个脚本重跑一遍(这叫 rerun),普通变量会被清空。想"记住"东西(比如对话历史、计数器),就放进 st.session_state(一个像字典一样的东西,跨重跑存活):
if "count" not in st.session_state:
st.session_state.count = 0
if st.button("+1"):
st.session_state.count += 1
st.write(f"计数:{st.session_state.count}")
三、核心代码:ChatGPT 式聊天应用(官方原版)
这是官方教程的完整代码(约 50 行),实现"流式打字机聊天":
from openai import OpenAI
import streamlit as st
st.title("ChatGPT-like clone")
client = OpenAI(api_key=st.secrets["OPENAI_API_KEY"])
if "openai_model" not in st.session_state:
st.session_state["openai_model"] = "gpt-3.5-turbo"
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.markdown(message["content"])
# 接收用户输入(同时判空并赋值)
if prompt := st.chat_input("What is up?"):
# 追加并显示用户消息
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
# 流式生成助手回复(打字机效果)
with st.chat_message("assistant"):
stream = client.chat.completions.create(
model=st.session_state["openai_model"],
messages=[
{"role": m["role"], "content": m["content"]}
for m in st.session_state.messages
],
stream=True,
)
response = st.write_stream(stream)
st.session_state.messages.append({"role": "assistant", "content": response})
逐段理解:
- 开头初始化:
OpenAI客户端 + 模型名 + 空的messages列表(对话历史就存在st.session_state里) - 每次页面刷新(rerun),把历史消息用
st.chat_message全部回放出来——这就是为什么刷新后聊天记录还在 st.chat_input拿到用户输入后:追加历史 → 显示 user 气泡 → 带完整历史调用 API(stream=True 流式)→st.write_stream边生成边显示(打字机效果)→ 追加 assistant 进历史
原理一句话:ChatGPT 的"上下文"= 每次把全部历史重发给模型。Streamlit 只是把历史存起来、渲染出来。
四、API Key 放哪?两种安全姿势
方式 A:secrets 文件(官方推荐)
项目目录建 .streamlit/secrets.toml:
OPENAI_API_KEY = "你的key"
代码里 st.secrets["OPENAI_API_KEY"] 读取。这个文件不要提交到 GitHub(记得加进 .gitignore)。
方式 B:环境变量
export OPENAI_API_KEY="你的key"
streamlit run app.py
代码里 os.environ["OPENAI_API_KEY"] 读取。
五、一键脚本帮你跑通(重点)
文末脚本完成三件事:装环境、写 .streamlit/secrets.toml、生成上面完整代码——运行后打开 http://localhost:8501 就能和 AI 对话。
唯一要你决定的:用谁的 Key。脚本默认配置云间 API 中转站(OpenAI 兼容格式,所以上面的 OpenAI() 代码原样可用,只需拼上中转站地址):注册即取 Key,一把 Key 同时调 GPT、Claude、DeepSeek、GLM 等 90+ 模型(按 token 计费、Claude 系列约官方 0.4~0.6 倍起、国内直连免翻墙)——切换"对话模型"时,改 15 行那个 model 变量就行。输入 N 也可用自己的任意 OpenAI 兼容 Key(DeepSeek 官方等都行)。
六、常见问题速查
| 问题 | 解决 |
|---|---|
streamlit run app.py 报 No module named openai | pip install openai streamlit 两个都要装 |
| 页面一直转圈 | Key 无效或网络不通:先跑通本文第一部分的 curl 直测,再看 secrets 文件 |
| 聊天记录刷新就没了 | 确认用了 st.session_state(消息列表存里面) |
| 端口 8501 被占 | streamlit run app.py --server.port 8502 |
| 想部署到公网(给朋友用) | Streamlit Community Cloud 免费托管,或用你自己的服务器 |
尾声
你现在的技能栈已经闭环了:调 API(Claude/DeepSeek 篇)→ 写逻辑(提示词工程篇)→ 套壳上线(本篇)。200 行代码级别的 Streamlit 应用,足以支撑个人工具、团队内部工具,甚至小型产品的 MVP(最小可行产品)。
下一步三选一:给应用加输入(st.text_area 多行文本、st.file_uploader 上传文件);接知识库(配合本站《LangChain RAG 实战》的检索逻辑);或者部署上线分享给朋友。
动手吧——跑一次文末脚本,10 分钟内你就能把 AI 聊天应用发给身边人用了。别忘了 Key 用云间 API(https://cloudzone-api.cyou/)注册的话,对比换模型会非常省心。
附:一键部署脚本
不方便下载的同学可以直接复制下方完整源码,新建文本文档粘贴后改后缀为 .sh(macOS/Linux/WSL)或 .ps1(Windows)运行。也可以下载现成文件:
- 下载
install-streamlit-llm-app.sh(macOS / Linux / WSL):https://cleanresolver.com/scripts/install-streamlit-llm-app.sh - 下载
install-streamlit-llm-app.ps1(Windows):https://cleanresolver.com/scripts/install-streamlit-llm-app.ps1
macOS / Linux / WSL(.sh)
#!/usr/bin/env bash
set -u
# ============================================================
# Streamlit LLM 应用 一键脚本(macOS / Linux / WSL)
# 公开源码,欢迎审查 —— 不放心可先复制给 AI 判断
# 默认配置:云间 API 中转站(https://cloudzone-api.cyou/)
# 生成:.streamlit/secrets.toml + chat_app.py(ChatGPT 式聊天应用)
# ============================================================
GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
step() { echo -e "${CYAN}[STEP]${NC} $1"; }
CLOUDZONE_URL="https://cloudzone-api.cyou"
CLOUDZONE_API_BASE="https://cloudzone-api.cyou/v1"
detect_network() {
step "检测网络环境(国内 / 国外)..."
if curl -fsI --max-time 5 "https://claude.ai" >/dev/null 2>&1; then
info "可直连 claude.ai,判定为海外网络"
echo "overseas"
else
warn "无法直连 claude.ai,判定为国内网络环境(将自动切换国内镜像)"
echo "domestic"
fi
}
check_python() {
step "检查 Python 3..."
if command -v python3 >/dev/null 2>&1 && python3 --version >/dev/null 2>&1; then
PY="python3"
info "找到 python3:$(python3 --version 2>&1)"
return 0
fi
error "未找到 python3。请先安装:https://www.python.org/downloads/ (Windows 建议使用 WSL 后执行本脚本)"
return 1
}
setup_env() {
local net="$1"
step "创建虚拟环境并安装 streamlit + openai(约 1-2 分钟)..."
mkdir -p streamlit-app && cd streamlit-app || return 1
python3 -m venv .venv 2>/dev/null || { error "创建虚拟环境失败,手动执行:python3 -m venv .venv"; return 1; }
# shellcheck disable=SC1091
source .venv/bin/activate || { warn "激活虚拟环境失败,继续使用系统环境"; }
step "安装依赖..."
local pypi="https://pypi.org/simple"
if [ "$net" = "domestic" ]; then
pypi="https://pypi.tuna.tsinghua.edu.cn/simple"
fi
if pip install streamlit openai -i "$pypi" --timeout 90 >/dev/null 2>&1; then
info "依赖安装成功"
return 0
fi
warn "主源失败,回退备用镜像(阿里云 PyPI)..."
if pip install streamlit openai -i "https://mirrors.aliyun.com/pypi/simple" --timeout 90 >/dev/null 2>&1; then
info "备用镜像安装成功"
return 0
fi
error "依赖安装失败。请手动执行:pip install streamlit openai -i https://pypi.tuna.tsinghua.edu.cn/simple"
return 1
}
configure_api() {
step "配置 API Key..."
echo ""
echo "聊天应用需要一个 OpenAI 兼容的 Key。默认推荐云间 API 中转站:"
echo " · OpenAI 兼容格式,代码无需改动,模型随便换"
echo " · 国内直连免翻墙,一把 Key 调 GPT / Claude / DeepSeek / GLM 等 90+ 模型"
echo ""
echo "是否现在跳转注册并获取 API Key?"
echo " Y - 立即跳转至 ${CLOUDZONE_URL}"
echo " N - 我已有 Key(OpenAI / DeepSeek 官方或第三方),自行输入"
read -r -p "请选择 [Y/N]: " choice
local API_KEY=""
local BASE_URL="$CLOUDZONE_API_BASE"
if [ "${choice:-N}" = "Y" ] || [ "${choice:-N}" = "y" ]; then
info "正在打开浏览器..."
if command -v xdg-open >/dev/null 2>&1; then
xdg-open "$CLOUDZONE_URL" >/dev/null 2>&1
elif command -v open >/dev/null 2>&1; then
open "$CLOUDZONE_URL" >/dev/null 2>&1
else
warn "无法自动打开浏览器,请手动访问:$CLOUDZONE_URL"
fi
echo "注册后在控制台复制 Key(以 sk- 开头)。"
read -r -p "粘贴你的 API Key: " API_KEY
read -r -p "API 地址(直接回车用默认 ${CLOUDZONE_API_BASE}): " input_base
[ -n "${input_base:-}" ] && BASE_URL="$input_base"
else
read -r -s -p "请输入你的 API Key (sk-...): " API_KEY
echo
echo "OpenAI 官方 Key 则地址填 https://api.openai.com/v1;DeepSeek 官方填 https://api.deepseek.com。"
read -r -p "API 地址(直接回车用默认 ${CLOUDZONE_API_BASE}): " input_base
[ -n "${input_base:-}" ] && BASE_URL="$input_base"
fi
if [ -z "${API_KEY:-}" ]; then
error "未输入 API Key,跳过配置。可稍后手动编辑 .streamlit/secrets.toml。"
return 1
fi
mkdir -p .streamlit
cat > .streamlit/secrets.toml <<TOMEOF
# Streamlit secrets —— 请勿提交到 GitHub(含密钥)
OPENAI_API_KEY = "$API_KEY"
OPENAI_BASE_URL = "$BASE_URL"
TOMEOF
info "已写入 .streamlit/secrets.toml(密钥文件,已自动加入 .gitignore 说明)"
warn "注意:该文件含密钥,别提交到公开仓库!"
if [ -f ".gitignore" ] && ! grep -q "secrets.toml" .gitignore; then
echo ".streamlit/secrets.toml" >> .gitignore
elif [ ! -f ".gitignore" ]; then
echo ".streamlit/secrets.toml" > .gitignore
fi
return 0
}
write_app() {
step "生成 chat_app.py(ChatGPT 式聊天应用)..."
cat > chat_app.py <<'PYEOF'
import os
from openai import OpenAI
import streamlit as st
st.title("🤖 我的 AI 聊天室")
client = OpenAI(
api_key=st.secrets.get("OPENAI_API_KEY", os.environ.get("OPENAI_API_KEY")),
base_url=st.secrets.get("OPENAI_BASE_URL", os.environ.get("OPENAI_BASE_URL")),
)
if "model" not in st.session_state:
st.session_state.model = "gpt-5.5" # 换成支持模型名,如 deepseek-v4-pro / claude-sonnet-5
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.markdown(message["content"])
if prompt := st.chat_input("说点什么…"):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
with st.chat_message("assistant"):
stream = client.chat.completions.create(
model=st.session_state.model,
messages=[
{"role": m["role"], "content": m["content"]}
for m in st.session_state.messages
],
stream=True,
)
response = st.write_stream(stream)
st.session_state.messages.append({"role": "assistant", "content": response})
PYEOF
info "已生成 streamlit-app/chat_app.py"
}
main() {
echo "============================================"
echo " Streamlit LLM 应用 一键脚本"
echo " 适用于 macOS / Linux / WSL"
echo " 默认接入:云间 API 中转站"
echo "============================================"
echo ""
local NET
NET=$(detect_network)
if ! check_python; then
error "缺少 Python 3,脚本终止。请先安装 Python 后重跑。"
exit 1
fi
if ! setup_env "$NET"; then
error "环境准备失败,脚本终止。请按上方提示手动处理。"
exit 1
fi
configure_api || warn "Key 未配置,应用仍会生成,运行时需自行补全 secrets"
write_app
echo ""
echo "============================================"
info "全部完成!启动你的 AI 聊天网页:"
echo " cd streamlit-app && source .venv/bin/activate && streamlit run chat_app.py"
echo "浏览器访问 http://localhost:8501"
echo "换模型:改 chat_app.py 里 model 那一行"
echo "============================================"
}
main "$@"
Windows(.ps1)
Windows 运行 .ps1 若提示执行策略限制:打开 PowerShell 输入
Set-ExecutionPolicy -Scope Process Bypass后回车,再运行脚本。-Scope Process仅对当前窗口生效,关掉即恢复,不会改动系统全局策略(系统默认限制来自安全设计,不要为了省事永久 Bypass)。
# ============================================================
# Streamlit LLM 应用 一键脚本(Windows PowerShell)
# 公开源码,欢迎审查 -- 不放心可先复制给 AI 判断
# 默认配置:云间 API 中转站(https://cloudzone-api.cyou/)
# 生成:.streamlit/secrets.toml + chat_app.py(ChatGPT 式聊天应用)
# ============================================================
$ErrorActionPreference = "Stop"
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
function Write-Err { Write-Host "[ERROR] $args" -ForegroundColor Red }
function Write-Step { Write-Host "[STEP] $args" -ForegroundColor Cyan }
$CLOUDZONE_URL = "https://cloudzone-api.cyou"
$CLOUDZONE_API_BASE = "https://cloudzone-api.cyou/v1"
function Detect-Network {
Write-Step "检测网络环境(国内 / 国外)..."
try {
$null = Invoke-WebRequest -Uri "https://claude.ai" -Method Head -TimeoutSec 5 -UseBasicParsing
Write-Info "可直连 claude.ai,判定为海外网络"
return "overseas"
} catch {
Write-Warn "无法直连 claude.ai,判定为国内网络环境(将自动切换国内镜像)"
return "domestic"
}
}
function Find-Python {
Write-Step "检查 Python 3..."
$python = $null
foreach ($candidate in @("python", "py")) {
try {
$out = & $candidate --version 2>&1
if ($LASTEXITCODE -eq 0) { $python = $candidate; break }
} catch { }
}
if ($null -eq $python) {
Write-Err "未找到 Python。请先安装:https://www.python.org/downloads/ (安装时勾选 Add Python to PATH)"
return $null
}
Write-Info "找到 Python:$(& $python --version 2>&1)"
return $python
}
function Setup-Env {
param([string]$Net)
Write-Step "创建虚拟环境并安装 streamlit + openai(约 1-2 分钟)..."
New-Item -ItemType Directory -Force -Path "streamlit-app" | Out-Null
Set-Location "streamlit-app"
& $script:PY -m venv .venv
if ($LASTEXITCODE -ne 0) {
Write-Err "创建虚拟环境失败,手动执行:$script:PY -m venv .venv"
return $false
}
$script:PY = Join-Path (Get-Location) ".venv\Scripts\python.exe"
Write-Step "安装依赖..."
$pypi = if ($Net -eq "domestic") { "https://pypi.tuna.tsinghua.edu.cn/simple" } else { "https://pypi.org/simple" }
& $script:PY -m pip install streamlit openai -i $pypi --timeout 90 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Info "依赖安装成功"
return $true
}
Write-Warn "主源失败,回退备用镜像(阿里云 PyPI)..."
& $script:PY -m pip install streamlit openai -i "https://mirrors.aliyun.com/pypi/simple" --timeout 90 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Info "备用镜像安装成功"
return $true
}
Write-Err "依赖安装失败。请手动执行:$script:PY -m pip install streamlit openai -i https://pypi.tuna.tsinghua.edu.cn/simple"
return $false
}
function Configure-Api {
Write-Step "配置 API Key..."
Write-Host ""
Write-Host "聊天应用需要一个 OpenAI 兼容的 Key。默认推荐云间 API 中转站:"
Write-Host " · OpenAI 兼容格式,代码无需改动,模型随便换"
Write-Host " · 国内直连免翻墙,一把 Key 调 GPT / Claude / DeepSeek / GLM 等 90+ 模型"
Write-Host ""
Write-Host "是否现在跳转注册并获取 API Key?"
Write-Host " Y - 立即跳转至 $CLOUDZONE_URL"
Write-Host " N - 我已有 Key(OpenAI / DeepSeek 官方或第三方),自行输入"
$choice = Read-Host "请选择 [Y/N]"
$apiKey = ""
$baseUrl = $CLOUDZONE_API_BASE
if ($choice -eq "Y" -or $choice -eq "y") {
Write-Info "正在打开浏览器..."
try {
Start-Process "$CLOUDZONE_URL"
} catch {
Write-Warn "无法自动打开浏览器,请手动访问:$CLOUDZONE_URL"
}
Write-Host "注册后在控制台复制 Key(以 sk- 开头)。"
} else {
Write-Host "OpenAI 官方 Key 则地址填 https://api.openai.com/v1;DeepSeek 官方填 https://api.deepseek.com。"
}
$sec = Read-Host "粘贴你的 API Key(输入时不显示字符)" -AsSecureString
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec)
$apiKey = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
if ([string]::IsNullOrWhiteSpace($apiKey)) {
Write-Err "未输入 API Key,跳过配置。可稍后手动编辑 .streamlit/secrets.toml。"
return $false
}
$inputBase = Read-Host "API 地址(直接回车用默认 ${baseUrl})"
if (-not [string]::IsNullOrWhiteSpace($inputBase)) { $baseUrl = $inputBase }
New-Item -ItemType Directory -Force -Path ".streamlit" | Out-Null
@"
# Streamlit secrets -- 请勿提交到 GitHub(含密钥)
OPENAI_API_KEY = "$apiKey"
OPENAI_BASE_URL = "$baseUrl"
"@ | Set-Content -Path ".streamlit\secrets.toml" -Encoding UTF8
Write-Info "已写入 .streamlit/secrets.toml"
Write-Warn "注意:该文件含密钥,别提交到公开仓库!"
return $true
}
function Write-App {
Write-Step "生成 chat_app.py(ChatGPT 式聊天应用)..."
@'
import os
from openai import OpenAI
import streamlit as st
st.title("🤖 我的 AI 聊天室")
client = OpenAI(
api_key=st.secrets.get("OPENAI_API_KEY", os.environ.get("OPENAI_API_KEY")),
base_url=st.secrets.get("OPENAI_BASE_URL", os.environ.get("OPENAI_BASE_URL")),
)
if "model" not in st.session_state:
st.session_state.model = "gpt-5.5" # 换成支持模型名,如 deepseek-v4-pro / claude-sonnet-5
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.markdown(message["content"])
if prompt := st.chat_input("说点什么…"):
st.session_state.messages.append({"role": "user", "content": prompt})
with st.chat_message("user"):
st.markdown(prompt)
with st.chat_message("assistant"):
stream = client.chat.completions.create(
model=st.session_state.model,
messages=[
{"role": m["role"], "content": m["content"]}
for m in st.session_state.messages
],
stream=True,
)
response = st.write_stream(stream)
st.session_state.messages.append({"role": "assistant", "content": response})
'@ | Set-Content -Path "chat_app.py" -Encoding UTF8
Write-Info "已生成 streamlit-app/chat_app.py"
}
Write-Host "============================================"
Write-Host " Streamlit LLM 应用 一键脚本"
Write-Host " 适用于 Windows(PowerShell)"
Write-Host " 默认接入:云间 API 中转站"
Write-Host "============================================"
Write-Host ""
$net = Detect-Network
$script:PY = Find-Python
if ($null -eq $script:PY) {
Write-Err "缺少 Python,脚本终止。请先安装 Python 后重跑。"
exit 1
}
if (-not (Setup-Env -Net $net)) {
Write-Err "环境准备失败,脚本终止。请按上方提示手动处理。"
exit 1
}
if (-not (Configure-Api)) {
Write-Warn "Key 未配置,应用仍会生成,运行时需自行补全 secrets"
}
Write-App
Write-Host ""
Write-Host "============================================"
Write-Info "全部完成!启动你的 AI 聊天网页:"
Write-Host " cd streamlit-app; .\.venv\Scripts\streamlit run chat_app.py"
Write-Host "浏览器访问 http://localhost:8501"
Write-Host "换模型:改 chat_app.py 里 model 那一行"
Write-Host "============================================"
请完成验证后查看评论区