vLLM 部署实战:用 Streamlit + OpenAI 兼容 API 快速搭建 LLM 聊天 Web 应用
Streamlit 能在几分钟内把 Python 脚本变成交互式 Web 应用,而 vLLM 提供 OpenAI 兼容的 HTTP 推理服务,两者组合即可低成本搭建一个带会话管理、流式输出的本地 LLM 聊天界面。本文基于 vLLM 官方文档 docs/deployment/frameworks/streamlit.md 及其配套示例脚本 streamlit_openai_chatbot_webserver.py,完整讲解从环境安装、服务启动到脚本源码级功能的部署全流程,读完后你可以独立复现一个可切换多会话、支持推理过程可视化的 vLLM 聊天前端。
方案架构:Streamlit 前端 + vLLM 后端
这套方案的核心思路是前后端解耦:
- 后端:
vllm serve启动一个 OpenAI 兼容的 HTTP 服务器,暴露/v1/chat/completions、/v1/models等标准接口。vLLM 的完整 API 支持范围可在 OpenAI-Compatible Server 文档 中查阅,Chat Completions API 仅适用于带 chat template 的文本生成模型。 - 前端:Streamlit 脚本通过官方
openaiPython 客户端连接后端,复用 OpenAI SDK 的生态(流式响应、多轮对话消息结构),无需自行编写 HTTP 请求逻辑。
从示例脚本的 docstring 看,它明确列出了功能清单:多聊天会话管理、流式响应展示、可配置的 API 端点、实时聊天历史、以及可选的推理过程(thinking process)可视化展示(脚本文件头注释)。
一、环境准备:安装依赖
按官方文档,一条命令即可装齐全部依赖:
pip install vllm streamlit openai
其中:
vllm提供推理引擎与vllm serve命令行;streamlit提供 Web UI 运行时;openai是标准 Python 客户端,脚本用它调用 vLLM 的兼容接口(脚本中from openai import OpenAI,见 脚本第 36 行)。
二、部署步骤(完整可复现)
1. 启动 vLLM 服务端
使用任意受支持的 chat 模型启动服务,文档给出的示例是:
vllm serve Qwen/Qwen1.5-0.5B-Chat
服务默认监听 http://localhost:8000。这个默认地址在 vLLM CLI 源码中得到印证——CLI 的 --url 参数 的默认值就是 http://localhost:8000/v1。如果模型较大,可追加 --gpu-memory-utilization、--max-model-len 等参数控制显存占用(完整参数参见 serve 参数文档)。
安全提示:若给服务端配置了
--api-key(或VLLM_API_KEY),该密钥仅保护/v1、/v2、/inference路径前缀下的端点,其他端点不受保护。生产环境建议反向代理加固,详见 OpenAI-Compatible Server 文档中的警告 与 安全指南。
2. 获取示例脚本
官方脚本位于仓库 examples/applications/chatbot/streamlit_openai_chatbot_webserver.py,将其拷贝到工作目录即可。同目录下还有 Gradio 版本的备选实现(gradio_openai_chatbot_webserver.py),可按需选择。
3. 启动 Streamlit Web UI
# 最简方式:默认连接 http://localhost:8000/v1
streamlit run streamlit_openai_chatbot_webserver.py
# 或显式指定 vLLM 服务端地址(远程服务器场景)
VLLM_API_BASE="http://vllm-server-host:vllm-server-port/v1" \
streamlit run streamlit_openai_chatbot_webserver.py
# 以 debug 日志级别启动,便于排查问题
streamlit run streamlit_openai_chatbot_webserver.py --logger.level=debug
启动后浏览器访问 Streamlit 给出的地址(默认 http://localhost:8501),即可开始对话。
三、配置参数详解:环境变量与默认值
脚本通过两个环境变量配置后端连接,均提供了合理的默认值:
| 环境变量 | 作用 | 默认值 | 源码依据 |
|---|---|---|---|
VLLM_API_BASE |
vLLM OpenAI 兼容 API 的 Base URL,必须包含 /v1 路径前缀 |
http://localhost:8000/v1 |
脚本第 40 行 |
VLLM_API_KEY |
请求端点时使用的 API Key;vLLM 未开启鉴权时任意值均可 | EMPTY |
脚本第 39 行 |
# 从脚本源码看,环境变量在模块加载时一次性读取
openai_api_key = os.getenv("VLLM_API_KEY", "EMPTY")
openai_api_base = os.getenv("VLLM_API_BASE", "http://localhost:8000/v1")
值得注意的设计是:API Base URL 还可以在 Web 界面运行时动态修改。脚本把 URL 存入 st.session_state.api_base_url,侧边栏提供文本输入框,检测到变化后写入 session state 并 st.rerun() 触发整页重载(侧边栏 API Settings 逻辑)。也就是说,环境变量的值只是初始默认值,切换后端服务器无需重启 Streamlit。
四、脚本源码解析:四个核心机制
1. 基于 Streamlit session state 的多会话管理
脚本用 st.session_state 维护全部会话数据,初始化了以下状态键(脚本第 42-61 行):
sessions:字典,以时间戳字符串(%Y-%m-%d %H:%M:%S格式)为键,值为该会话的消息列表;current_session/active_session:当前与激活会话 ID,用于侧边栏高亮(激活会话显示 📍 主按钮);messages:当前会话的消息列表,供st.chat_message渲染;show_reasoning:记录每条助手消息对应的推理过程文本;api_base_url:可运行时修改的后端地址。
两个核心函数支撑会话操作:create_new_chat_session() 用当前时间戳生成唯一会话 ID 并重置消息列表;switch_to_chat_session(session_id) 切换激活会话并从字典中回填历史消息(实现)。侧边栏按时间倒序列出所有会话按钮,点击即可切换(会话列表渲染)。
2. 流式响应与推理过程分离展示
get_llm_response() 是与后端交互的核心函数(实现),关键逻辑:
params = {"model": model, "messages": messages, "stream": True}
if reason:
# 通过 vLLM 的 chat_template_kwargs 开启 thinking 模式
params["extra_body"] = {"chat_template_kwargs": {"enable_thinking": True}}
response = client.chat.completions.create(**params)
for chunk in response:
delta = chunk.choices[0].delta
# 先流式渲染 reasoning 到上方 expander,再流式渲染 content 到下方占位符
几个实现细节:
- 请求参数固定
stream: True,逐 chunk 读取choices[0].delta; - 推理开关通过 vLLM 特有的
extra_body.chat_template_kwargs.enable_thinking传入,这是 vLLM 在 OpenAI 协议之上扩展的 chat template 参数通道; - 用
st.empty()占位符 + 拼接全文 +▌光标实现"打字机"效果的实时刷新; - 异常被捕获并以
st.error展示,函数返回(完整正文, 完整推理文本)元组供上层持久化到 session state。
3. 模型名自动发现
脚本不要求用户手动填写模型名,而是调用 client.models.list() 取返回列表的第一个模型 ID 并展示在页面标题下方(脚本第 226-229 行):
models = client.models.list()
model = models.data[0].id
st.markdown(f"**Model**: {model}")
这与 vLLM /v1/models 端点的行为一致——vllm serve 启动时会把 HuggingFace 模型 ID 注册为服务端的 model id。
4. 推理能力探测(reasoning toggle)
脚本用一个带缓存的探测函数判断当前模型是否支持推理输出:向服务端发一条非流式 Hi 请求,检查响应消息是否带非空 reasoning 属性(server_supports_reasoning 实现):
@st.cache_data(show_spinner=False)
def server_supports_reasoning():
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "Hi"}],
stream=False,
)
return hasattr(resp.choices[0].message, "reasoning") and bool(
resp.choices[0].message.reasoning
)
探测为真时,侧边栏出现 "Enable Reasoning" 复选框;为假时显示灰色提示 "Reasoning unavailable for this model"。注意该函数用 @st.cache_data 缓存,每次页面交互不会重复请求探测。
五、消息渲染流程
主界面按序执行(脚本第 231-311 行):
- 若尚无任何会话,自动创建一个初始会话;
- 遍历
st.session_state.messages渲染历史:用户消息走st.chat_message("user");助手消息先检查show_reasoning中是否有对应索引的推理文本,有则先用折叠的 "💭 Thinking Process" expander 展示,再渲染正文; - 捕获
st.chat_input输入,追加用户消息到会话并渲染; - 以当前全部历史构造
msgs,进入st.chat_message("assistant")上下文,创建两个空占位符(reasoning 在上、content 在下),调用get_llm_response()流式生成; - 生成结束后把完整助手回复 append 进消息列表;若开启了推理且有推理文本,按消息索引存入
show_reasoning,保证刷新页面后历史中的思考过程仍可展开查看。
六、排障与实用建议
- 连接不上后端:先确认
vllm serve已就绪(可用curl http://localhost:8000/v1/models验证),再检查VLLM_API_BASE是否带/v1前缀、端口是否与--port参数一致; - 查看细节日志:使用文档给出的 debug 模式
streamlit run ... --logger.level=debug; - 鉴权失败:服务端用
--api-key token-xxx启动时,客户端必须通过VLLM_API_KEY=token-xxx传入同一密钥; - 只想试跑:文档示例选用
Qwen/Qwen1.5-0.5B-Chat这类小模型,单卡甚至消费级 GPU 即可运行; - 替换前端框架:同一 chatbot 目录下有 Gradio 版本脚本(examples/applications/chatbot/gradio_openai_chatbot_webserver.py),架构完全同构,仅 UI 框架不同。
小结
vLLM 的部署扩展生态中,Streamlit 方案代表了一条"最小成本获得可视化聊天界面"的路径:后端只需一条 vllm serve 命令,前端是约 300 行、无状态数据库依赖的纯 Python 脚本。理解了本文解析的会话状态管理、流式双通道渲染(reasoning + content)、chat_template_kwargs.enable_thinking 扩展参数与模型自动发现四个机制后,你可以在此基础上轻松扩展出系统提示词配置、温度滑块、模型切换下拉框等自定义功能。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
