首页
/ vLLM 部署实战:用 Streamlit + OpenAI 兼容 API 快速搭建 LLM 聊天 Web 应用

vLLM 部署实战:用 Streamlit + OpenAI 兼容 API 快速搭建 LLM 聊天 Web 应用

2026-09-06 21:57:07作者:范靓好Udolf

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 脚本通过官方 openai Python 客户端连接后端,复用 OpenAI SDK 的生态(流式响应、多轮对话消息结构),无需自行编写 HTTP 请求逻辑。

从示例脚本的 docstring 看,它明确列出了功能清单:多聊天会话管理、流式响应展示、可配置的 API 端点、实时聊天历史、以及可选的推理过程(thinking process)可视化展示(脚本文件头注释)。

在 Streamlit 中与 vLLM 助手聊天

一、环境准备:安装依赖

按官方文档,一条命令即可装齐全部依赖:

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 行):

  1. 若尚无任何会话,自动创建一个初始会话;
  2. 遍历 st.session_state.messages 渲染历史:用户消息走 st.chat_message("user");助手消息先检查 show_reasoning 中是否有对应索引的推理文本,有则先用折叠的 "💭 Thinking Process" expander 展示,再渲染正文;
  3. 捕获 st.chat_input 输入,追加用户消息到会话并渲染;
  4. 以当前全部历史构造 msgs,进入 st.chat_message("assistant") 上下文,创建两个空占位符(reasoning 在上、content 在下),调用 get_llm_response() 流式生成;
  5. 生成结束后把完整助手回复 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 扩展参数与模型自动发现四个机制后,你可以在此基础上轻松扩展出系统提示词配置、温度滑块、模型切换下拉框等自定义功能。

登录后查看全文
热门项目推荐
相关项目推荐