使用 Streamlit 部署 BlueLM-7B-Chat WebDemo:self-llm 中文大模型对话界面的完整实战指南
【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm
本篇指南以 models/BlueLM/03-BlueLM-7B-Chat WebDemo 部署.md 为核心脉络,系统讲解如何基于 AutoDL 云服务器将 vivo 开源的 BlueLM-7B-Chat 大模型部署为带流式输出的 Streamlit 聊天 WebDemo。读完本文,你将掌握完整的云端环境搭建、模型下载、对话模板构造、流式生成封装以及端口映射访问的实操能力,并可结合仓库中的 FastApi、LangChain 部署方案横向理解 BlueLM 的接入方式。
BlueLM-7B-Chat 模型与对话格式概览
BlueLM-7B 是 vivo AI 全球研究院自主研发的大规模预训练语言模型,参数规模为 70 亿。根据仓库文档记载,该模型在 C-Eval 和 CMMLU 中文评测上均取得领先结果,对比同尺寸开源模型具有较强的竞争力(截至文档记录的 11 月 1 号)。本次发布共包含 7B 模型的 Base 基座版与 Chat 对齐版两个系列,其中 Chat 系列又细分如下模型版本:
| 基座模型(Base) | 对齐模型(Chat) |
|---|---|
| BlueLM-7B-Base | BlueLM-7B-Chat |
| BlueLM-7B-Base-32K | BlueLM-7B-Chat-32K |
| BlueLM-7B-Chat-4bits |
其中-32K后缀表示支持 32K 上下文长度的版本,-4bits为量化版本。本教程使用的是BlueLM-7B-Chat标准版本。
与多数模型使用<|im_start|>、<|user|>等特殊 token 标记角色的做法不同,BlueLM 的对话模板极为简洁,仅有[|Human|](用户)与[|AI|](模型)两个角色标识,模板形态如下:
[|Human|]:你的问题[|AI|]:这一格式在仓库的 FastApi 部署、LangChain 接入 与 LoRA 微调 文档中保持一致,是理解 BlueLM 一切应用方式的关键约定,后文 WebDemo 的提示词构造同样基于此格式。
环境准备:租用 GPU 机器与安装依赖
租用 AutoDL 显卡机器
本教程在 AutoDL 平台中租赁一张3090 等 24G 显存的显卡机器。在创建实例时,镜像选择如下组合(CUDA 版本在 11.3 以上均可):
PyTorch --> 1.11.0 --> 3.8(ubuntu20.04) --> 11.3租用完成后,打开服务器的 JupyterLab(也可以使用 VSCode SSH 远程连接服务器),并在其中打开终端开始环境配置、模型下载和运行 Demo。
pip 换源加速并安装依赖包
为加速依赖安装,先升级 pip 并配置清华镜像源,然后安装本 Demo 所需的全部依赖:
# 升级pip python -m pip install --upgrade pip # 设置pip镜像源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple # 安装软件依赖 pip install modelscope==1.11.0 pip install transformers==4.37.0 pip install streamlit==1.24.0 pip install sentencepiece==0.1.99 pip install accelerate==0.24.1 pip install transformers_stream_generator==0.0.4各依赖在本次部署中的职责如下:
| 依赖包 | 版本 | 作用 |
|---|---|---|
modelscope | 1.11.0 | 从 ModelScope 魔搭社区下载模型权重 |
transformers | 4.37.0 | 加载模型与分词器、执行推理生成 |
streamlit | 1.24.0 | 构建 Web 聊天界面的核心框架 |
sentencepiece | 0.1.99 | 分词器依赖的文本切分库(BlueLM 基于 SentencePiece 训练分词器) |
accelerate | 0.24.1 | 支持device_map="auto"自动设备映射加载 |
transformers_stream_generator | 0.0.4 | 流式生成时的相关依赖 |
其中pip config set global.index-url属于环境通用配置,仓库 General-Setting/01-pip、conda换源.md 中还有更完整的换源说明可供参考。
模型下载:使用 ModelScope API 拉取权重
使用 ModelScope API 将BlueLM-7B-Chat模型下载到/root/autodl-tmp(AutoDL 的数据盘目录,容量更大)。在/root/autodl-tmp下创建model_download.py文件,内容如下:
from modelscope import snapshot_download model_dir = snapshot_download("vivo-ai/BlueLM-7B-Chat", cache_dir='/root/autodl-tmp', revision="master")运行后模型会被下载到/root/autodl-tmp/vivo-ai/BlueLM-7B-Chat目录(vivo-ai为模型仓库命名空间,cache_dir指定缓存根目录,revision="master"指定下载主分支版本)。仓库 General-Setting/03-模型下载.md 中对该步骤有更详细的说明,下载完成后的路径即为后文代码中的模型加载路径。
编写 chatBot.py:Streamlit WebDemo 代码全解析
在/root/autodl-tmp路径下新建chatBot.py文件,完整代码如下(对原文档中的模型路径笔误做了修正,其余逻辑与原文一致):
# 导入所需的库 from transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfig, TextStreamer import torch import streamlit as st # 在侧边栏中创建一个标题和一个链接 with st.sidebar: st.markdown("## BlueLM-7B-Chat") "[开源大模型食用指南 self-llm](https://link.gitcode.com/i/554b59465d658921c269846c0f574915)" # 创建一个滑块,用于选择最大长度,范围在0到1024之间,默认值为512 max_length = st.slider("max_length", 0, 1024, 512, step=1) # 创建一个标题和一个副标题 st.title("💬 BlueLM Chatbot") st.caption("🚀 A streamlit chatbot powered by Self-LLM") # 定义模型路径 mode_name_or_path = '/root/autodl-tmp/vivo-ai/BlueLM-7B-Chat' # 定义一个函数,用于获取模型和tokenizer @st.cache_resource def get_model(): # 从预训练的模型中获取tokenizer tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True) # 从预训练的模型中获取模型,并设置模型参数 model = AutoModelForCausalLM.from_pretrained(mode_name_or_path, trust_remote_code=True, torch_dtype=torch.bfloat16, device_map="auto") # 从预训练的模型中获取生成配置 model.generation_config = GenerationConfig.from_pretrained(mode_name_or_path) # 设置生成配置的pad_token_id为生成配置的eos_token_id model.generation_config.pad_token_id = model.generation_config.eos_token_id # 设置模型为评估模式 model.eval() return tokenizer, model # 加载BlueLM的model和tokenizer tokenizer, model = get_model() def build_prompt(messages, prompt): """ 构建会话提示信息。 参数: messages - 包含会话历史的元组列表,每个元组是(用户查询,AI响应)。 prompt - 当前用户输入的文本。 返回值: res - 构建好的包含会话历史和当前用户提示的字符串。 """ res = "" # 遍历历史消息,构建会话历史字符串 for query, response in messages: res += f"[|Human|]:{query}[|AI|]:{response}</s>" # 添加当前用户提示 res += f"[|Human|]:{prompt}[|AI|]:" return res class BlueLMStreamer(TextStreamer): """ BlueLM流式处理类,用于处理模型的输入输出流。 参数: tokenizer - 用于分词和反分词的tokenizer实例。 """ def __init__(self, tokenizer: "AutoTokenizer"): self.tokenizer = tokenizer self.tokenIds = [] self.prompt = "" self.response = "" self.first = True def put(self, value): """ 添加token id到流中。 参数: value - 要添加的token id。 """ if self.first: self.first = False return self.tokenIds.append(value.item()) # 将token ids解码为文本 text = tokenizer.decode(self.tokenIds, skip_special_tokens=True) def end(self): """ 结束流处理,将当前流中的文本作为响应,并重置流状态。 """ self.first = True # 将token ids解码为文本 text = tokenizer.decode(self.tokenIds, skip_special_tokens=True) self.response = text self.tokenIds = [] # 初始化session状态,如果messages不存在则初始化为空,并添加欢迎信息 if "messages" not in st.session_state: st.session_state.messages = [] st.session_state.messages.append(("", "你好,有什么可以帮助你吗?")) # 遍历并显示历史消息 for msg in st.session_state.messages: st.chat_message("assistant").write(msg[1]) # 处理用户输入 if prompt_text := st.chat_input(): prompt_text = prompt_text.strip() st.chat_message("user").write(prompt_text) messages = st.session_state.messages # 使用BlueLMStreamer处理流式模型输入 streamer = BlueLMStreamer(tokenizer=tokenizer) # 构建当前会话的提示信息 prompt = build_prompt(messages=messages, prompt=prompt_text) # 将提示信息编码为模型输入 inputs_tensor = tokenizer(prompt, return_tensors="pt") inputs_tensor = inputs_tensor.to("cuda:0") input_ids = inputs_tensor["input_ids"] # 通过模型生成响应 outputs = model.generate(input_ids=input_ids, max_new_tokens=max_length, streamer=streamer) # 将模型的响应显示给用户 st.chat_message("assistant").write(streamer.response) # 更新会话历史 st.session_state.messages.append((prompt_text, streamer.response))下面按功能模块拆解这段代码的关键设计。
侧边栏参数控制
with st.sidebar: st.markdown("## BlueLM-7B-Chat") max_length = st.slider("max_length", 0, 1024, 512, step=1)侧边栏通过st.slider暴露了max_length(生成的最大新 token 数)滑杆,范围 0~1024,默认 512,运行时可实时调整,无需重启服务。
模型加载与缓存
@st.cache_resource def get_model(): tokenizer = AutoTokenizer.from_pretrained(mode_name_or_path, trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained(mode_name_or_path, trust_remote_code=True, torch_dtype=torch.bfloat16, device_map="auto") model.generation_config = GenerationConfig.from_pretrained(mode_name_or_path) model.generation_config.pad_token_id = model.generation_config.eos_token_id model.eval() return tokenizer, modeltrust_remote_code=True:BlueLM 模型的代码定义托管在模型仓库中,需开启远程代码信任才能加载其自定义的 modeling 文件;torch_dtype=torch.bfloat16:以 BF16 精度加载权重,兼顾显存占用与数值稳定性(仓库 FastApi 部署文档中同样使用torch_dtype=torch.bfloat16,api.py 实现 与之一致);device_map="auto":借助 accelerate 自动将模型分布到可用设备(多卡场景下自动分片);- 将
pad_token_id显式设置为eos_token_id:由于生成时输入只有一个样本,padding 与结束符共用同一 token id,可避免生成过程中的 pad 告警与异常; @st.cache_resource:Streamlit 的资源级缓存,保证页面每次交互重跑脚本时不会重复加载 7B 模型,而是复用已加载的模型与分词器实例。
build_prompt:多轮对话模板构造
def build_prompt(messages, prompt): res = "" for query, response in messages: res += f"[|Human|]:{query}[|AI|]:{response}</s>" res += f"[|Human|]:{prompt}[|AI|]:" return res该函数将历史消息(messages中的(query, response)元组)拼接为 BlueLM 官方对话格式,历史轮次之间以</s>(结束符)分隔,最后拼接当前用户输入并以[|AI|]:收尾,等待模型续写。这与 FastApi 部署 中messages = f"[|Human|]:{prompt}[|AI|]:"的构造方式同源,也印证了该模板是 BlueLM 全系列接入方案统一遵守的约定。
BlueLMStreamer:基于 TextStreamer 的流式输出封装
class BlueLMStreamer(TextStreamer): def __init__(self, tokenizer: "AutoTokenizer"): self.tokenizer = tokenizer self.tokenIds = [] self.prompt = "" self.response = "" self.first = True def put(self, value): if self.first: self.first = False return self.tokenIds.append(value.item()) text = tokenizer.decode(self.tokenIds, skip_special_tokens=True) def end(self): self.first = True text = tokenizer.decode(self.tokenIds, skip_special_tokens=True) self.response = text self.tokenIds = []BlueLMStreamer继承自 transformers 的TextStreamer,通过重写put(每生成一个新 token 时被调用)与end(生成结束时被调用)来捕获生成过程:
put中通过self.first标志跳过首个 token(通常为序列开始符或首 token,避免输出污染),随后将新 token id 追加到self.tokenIds并实时解码;end中把累积的全部 token ids 解码为完整文本并存入self.response,同时重置流状态,供主程序在生成结束后一次性写入聊天界面。
从代码结构看,这里的流式实现是"边生成边累积 token、结束时统一取结果"的简化策略,put内每次都对整个累积序列做解码。在交互体验上,由于主程序最终是通过streamer.response一次性写入消息,当前版本的逐 token 推送效果有限,你可以基于put中的解码文本结合st.chat_message的增量写入进一步改造,实现真正的逐字流式渲染。
会话状态管理与交互渲染
if "messages" not in st.session_state: st.session_state.messages = [] st.session_state.messages.append(("", "你好,有什么可以帮助你吗?")) for msg in st.session_state.messages: st.chat_message("assistant").write(msg[1])st.session_state.messages保存整个会话历史,首次进入时写入一条欢迎语;每次页面重跑都会遍历历史并以"助手"气泡渲染(欢迎语、历史回复均以 assistant 身份展示)。
用户输入处理部分则完成「写入用户气泡 → 构造提示词 → tokenizer 编码并转移到cuda:0→model.generate生成(传入max_new_tokens=max_length与streamer)→ 展示助手回复 → 追加会话历史」的完整闭环:
if prompt_text := st.chat_input(): prompt_text = prompt_text.strip() st.chat_message("user").write(prompt_text) messages = st.session_state.messages streamer = BlueLMStreamer(tokenizer=tokenizer) prompt = build_prompt(messages=messages, prompt=prompt_text) inputs_tensor = tokenizer(prompt, return_tensors="pt") inputs_tensor = inputs_tensor.to("cuda:0") input_ids = inputs_tensor["input_ids"] outputs = model.generate(input_ids=input_ids, max_new_tokens=max_length, streamer=streamer) st.chat_message("assistant").write(streamer.response) st.session_state.messages.append((prompt_text, streamer.response))注意,max_length滑杆值在此处作为max_new_tokens传入(而不是max_length),意味着它限制的是新增生成的 token 数量而非包含输入在内的总长度,这与滑杆名称的直觉略有差异,是原文档代码中一处值得留意的语义细节。
启动 WebDemo 服务并访问
在终端中运行以下命令启动 Streamlit 服务:
streamlit run /root/autodl-tmp/chatBot.py --server.address 127.0.0.1 --server.port 6006--server.address 127.0.0.1:仅监听本机回环地址,避免服务直接暴露到公网;--server.port 6006:指定端口,与 AutoDL 自定义服务端口约定保持一致。
由于服务运行在云服务器上,需要按照 AutoDL 平台的指示将6006端口映射到本地(AutoDL 的"自定义服务"功能会给出对应的本地访问地址与 SSH 端口转发命令,具体操作参见仓库 General-Setting/02-AutoDL开放端口.md)。完成端口映射后,在浏览器打开http://localhost:6006/即可看到聊天界面:
从运行截图可以看到,左侧边栏展示模型名称与max_length滑杆(默认 512),右侧为聊天主区域,用户输入问题后模型会基于[|Human|]:...[|AI|]:模板返回对应回复,并支持多轮上下文对话。
与仓库其他部署方案的横向关联
本 WebDemo 是 BlueLM-7B-Chat 在 models/BlueLM 目录下的三种接入方式之一,与仓库中另外两份文档形成完整的部署矩阵,值得对照阅读:
- FastApi 部署:提供
/POST 接口,通过curl或 Pythonrequests调用,适合作为后端 API 服务,模型加载方式(torch_dtype=torch.bfloat16、device_map="auto"、pad_token_id=eos_token_id)与 WebDemo 完全一致; - LangChain 接入:自定义
BlueLM(LLM)子类重写_call,内部同样以f"[|Human|]:{prompt}[|AI|]:"构造输入,将模型无缝接入 LangChain 生态; - LoRA 微调:微调数据的目标格式即
"[|Human|]:... [|AI|]:"形态,说明对话模板贯穿"微调—部署—应用"全链路,微调后的模型可直接套用本 WebDemo 的提示词构造方式。
如果你的目标是快速验证模型能力,本教程的 WebDemo 最为直观;若需要面向业务系统提供服务,建议结合 FastApi 方案;若需构建 Agent 应用,则参考 LangChain 方案。
常见问题与排查建议
- 模型路径报错(FileNotFoundError / OSError):原文档中模型路径写作
/root/autodl-tvivo-ai/BlueLM-7B-Chat,对照 ModelScope 下载目录的命名规则(cache_dir/命名空间/模型名)可确认正确路径应为/root/autodl-tmp/vivo-ai/BlueLM-7B-Chat,即上文代码中采用的路径。建议在终端先执行ls /root/autodl-tmp/vivo-ai/BlueLM-7B-Chat确认权重完整存在。 - 显存不足(CUDA out of memory):BlueLM-7B 以 BF16 加载约需 14GB 显存,24G 显存机器完全够用;若在更低显存的机器上运行,可考虑换用 BlueLM-7B-Chat-4bits 量化版本。
- 生成异常或出现重复 pad 内容:检查
model.generation_config.pad_token_id是否已按文档设置为eos_token_id。 - 端口无法访问:确认
--server.address 127.0.0.1 --server.port 6006参数与 AutoDL 自定义服务的端口映射一致,详见 AutoDL 开放端口。
至此,你已经完成了 BlueLM-7B-Chat 从云端环境准备、模型下载、Streamlit 界面编写到端口映射访问的全流程部署,并理解了其[|Human|]:...[|AI|]:对话模板在仓库多个部署方案中的统一约定,可以在此基础上进一步扩展多轮记忆、角色设定或接入 LangChain 构建更复杂的应用。
【免费下载链接】self-llm《开源大模型食用指南》针对中国宝宝量身打造的基于Linux环境快速微调(全参数/Lora)、部署国内外开源大模型(LLM)/多模态大模型(MLLM)教程项目地址: https://gitcode.com/GitHub_Trending/se/self-llm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考