GLM-4V-9B Streamlit实战教程:自定义系统提示词与对话上下文管理
GLM-4V-9B Streamlit实战教程:自定义系统提示词与对话上下文管理
你是不是也遇到过这种情况:好不容易部署了一个多模态大模型,上传了图片,问了问题,结果它要么给你一堆乱码,要么就只会复读你的问题,完全答非所问?
我之前用GLM-4V-9B的官方示例时就经常被这个问题困扰。模型明明很强大,但用起来就是不对劲。后来我发现,问题出在两个方面:一是官方代码在某些环境下有兼容性问题,二是对话的上下文管理不够灵活。
今天,我就带你一步步搭建一个基于Streamlit的GLM-4V-9B本地部署方案。这个方案不仅解决了官方的兼容性问题,还增加了两个超实用的功能:自定义系统提示词和完整的对话上下文管理。这意味着你可以像调教ChatGPT一样,告诉模型“你是一个专业的图像分析师”,然后它就会用更专业的口吻来回答你的问题。
更重要的是,我们实现了4-bit量化加载,这意味着你不需要昂贵的专业显卡,用消费级的RTX 4060 Ti(16GB)甚至更低的配置就能流畅运行这个百亿参数的多模态大模型。
1. 环境准备与一键部署
在开始之前,我们先看看需要准备什么。整个过程比你想的要简单得多。
1.1 硬件与软件要求
硬件要求(最低配置):
- GPU:NVIDIA显卡,显存 ≥ 12GB(推荐16GB以上)
- 内存:16GB RAM
- 存储:至少20GB可用空间(用于下载模型)
软件要求:
- 操作系统:Linux(Ubuntu 20.04+)或 Windows(WSL2)
- Python:3.8 - 3.10版本
- CUDA:11.7或11.8(与PyTorch版本匹配)
如果你不确定自己的环境,可以运行以下命令检查:
# 检查Python版本
python --version
# 检查CUDA是否可用(如果已安装PyTorch)
python -c "import torch; print(f'PyTorch版本: {torch.__version__}')"
python -c "import torch; print(f'CUDA可用: {torch.cuda.is_available()}')"
1.2 快速安装步骤
我们的项目已经打包好了所有依赖,你只需要几个命令就能完成部署:
# 1. 克隆项目代码
git clone https://github.com/your-repo/glm-4v-9b-streamlit.git
cd glm-4v-9b-streamlit
# 2. 创建并激活虚拟环境(推荐)
python -m venv venv
# Linux/Mac
source venv/bin/activate
# Windows
venv\Scripts\activate
# 3. 安装依赖包
pip install -r requirements.txt
# 4. 下载模型(如果首次运行会自动下载,也可以手动下载加速)
# 模型会自动下载到 ~/.cache/huggingface/hub 目录
这里有个小技巧:如果你在国内,下载Hugging Face模型可能会比较慢。可以设置镜像源来加速:
# 设置Hugging Face镜像(在运行程序前设置环境变量)
export HF_ENDPOINT=https://hf-mirror.com
# Windows系统用这个命令
# set HF_ENDPOINT=https://hf-mirror.com
1.3 启动应用
安装完成后,启动应用只需要一行命令:
# 启动Streamlit应用
streamlit run app.py --server.port 8080
启动后,打开浏览器访问 http://localhost:8080,你就能看到清爽的聊天界面了。
第一次运行时会自动下载GLM-4V-9B模型(约20GB),根据你的网速可能需要一些时间。下载完成后,模型会缓存在本地,下次启动就很快了。
2. 核心功能上手:从看图说话到专业分析
现在应用已经跑起来了,让我们看看它能做什么。界面很简单,主要分三个区域:左侧是设置面板,中间是聊天区域,右侧是历史记录。
2.1 基础使用:让模型看懂图片
我们先从最简单的开始。在左侧面板上传一张图片,然后在底部的输入框问问题。
试试这几个问题:
- "详细描述这张图片的内容"
- "图片里有多少个人?"
- "提取图片中的所有文字"
- "这张图是在哪里拍的?"
你会发现,模型不仅能识别物体,还能理解场景、情感甚至一些隐含信息。比如你上传一张餐桌照片,它不仅能说出有什么菜,还能推断出这可能是一顿家庭晚餐。
2.2 自定义系统提示词:让模型扮演特定角色
这是我们的核心功能之一。在左侧面板的"系统提示词"输入框中,你可以定义模型的角色和行为。
几个实用的提示词示例:
# 专业图像分析师
你是一个专业的图像分析师,擅长从图片中提取结构化信息。请用专业的术语描述图片内容,并给出详细的分析报告。
# 创意故事讲述者
你是一个富有想象力的故事讲述者。请根据图片内容创作一个有趣的故事,包含人物、情节和结局。
# 技术文档助手
你是一个技术文档助手,擅长从图表和截图中提取技术信息。请用清晰、准确的语言描述图片中的技术细节。
# 语言学习伙伴
你是一个语言学习伙伴,请用简单的中文描述图片内容,适合中文学习者理解。可以适当加入词汇解释。
设置好系统提示词后,你再问同样的问题,模型的回答风格会完全不同。比如用"专业图像分析师"提示词时,它会用更结构化的方式回答,可能还会加上"分析结论"、"建议"这样的部分。
2.3 对话上下文管理:实现真正的多轮对话
多模态对话的难点在于如何管理历史记录。我们的方案完美解决了这个问题。
上下文管理的特点:
- 完整的对话历史:每次对话(图片+问题+回答)都会被记录下来
- 智能上下文截断:当对话轮数太多时,会自动保留最重要的部分
- 可视化历史记录:右侧面板可以查看所有历史对话
- 一键清除:可以随时清空对话历史,开始新的会话
实际使用场景: 假设你上传了一张设计稿,可以这样对话:
- 第一轮:"描述这个UI设计的主要元素"
- 第二轮:"登录按钮的颜色是什么?"(模型能记住这是同一张图)
- 第三轮:"这个配色方案有什么优缺点?"
- 第四轮:"如果要把主色调改为蓝色,需要调整哪些部分?"
模型能记住整个对话过程,回答会越来越精准。
3. 代码深度解析:我们解决了哪些问题
你可能好奇,为什么我们的版本比官方示例更稳定、功能更强大?下面我拆解几个关键的技术点。
3.1 解决兼容性问题:动态类型适配
官方代码在某些PyTorch/CUDA环境下会报错,主要是因为数据类型不匹配。我们是这样解决的:
def prepare_image_tensor(image_path, model, device):
"""
准备图片张量,自动适配模型视觉层的参数类型
解决 RuntimeError: Input type and bias type should be the same 错误
"""
from PIL import Image
import torch
from transformers import AutoProcessor
# 加载图片
image = Image.open(image_path).convert('RGB')
# 获取处理器
processor = AutoProcessor.from_pretrained("THUDM/glm-4v-9b")
# 处理图片
processed = processor(images=image, return_tensors="pt")
raw_tensor = processed['pixel_values']
# 关键:动态获取视觉层的数据类型
try:
# 从模型视觉层获取实际使用的数据类型
visual_dtype = next(model.transformer.vision.parameters()).dtype
except AttributeError:
# 备用方案
visual_dtype = torch.float16
# 将图片张量转换为与模型视觉层相同的数据类型和设备
image_tensor = raw_tensor.to(device=device, dtype=visual_dtype)
return image_tensor
这个方案的好处是自适应。无论你的环境用的是float16还是bfloat16,代码都能自动匹配,避免了手动指定类型可能导致的冲突。
3.2 正确的Prompt构造顺序
官方示例有个bug:Prompt顺序不对,导致模型把图片当成了系统背景图,而不是用户输入的一部分。这会导致模型输出乱码(如</credit>)或者直接复读问题。
我们修正后的逻辑:
def build_multimodal_prompt(model, processor, image_tensor, question_text, system_prompt=""):
"""
构建多模态Prompt,确保正确的顺序:系统提示 -> 用户 -> 图片 -> 文本
"""
# 1. 系统提示词(如果有)
system_part = []
if system_prompt:
system_ids = processor.encode(system_prompt, add_special_tokens=False)
system_part = [model.bos_token_id] + system_ids
# 2. 用户标识
user_ids = processor.encode("[gMASK]sop", add_special_tokens=False)
# 3. 图片部分
# 获取图片token(模型内部处理)
image_token_ids = model.process_images(image_tensor)
# 4. 问题文本
text_ids = processor.encode(question_text, add_special_tokens=False)
# 5. 按正确顺序拼接:系统 -> 用户 -> 图片 -> 文本
if system_part:
input_ids = torch.cat([
torch.tensor(system_part).unsqueeze(0),
torch.tensor(user_ids).unsqueeze(0),
image_token_ids,
torch.tensor(text_ids).unsqueeze(0)
], dim=1)
else:
input_ids = torch.cat([
torch.tensor(user_ids).unsqueeze(0),
image_token_ids,
torch.tensor(text_ids).unsqueeze(0)
], dim=1)
return input_ids
这个顺序很重要:[用户标识] + [图片token] + [问题文本]。这样模型才知道"先看这张图,然后回答这个问题"。
3.3 4-bit量化实现:让大模型在消费级显卡上运行
GLM-4V-9B有90亿参数,全精度加载需要约18GB显存。我们通过4-bit量化(QLoRA)将其降低到约7GB,这样RTX 4060 Ti(16GB)就能流畅运行了。
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
import torch
def load_quantized_model(model_name="THUDM/glm-4v-9b"):
"""
使用4-bit量化加载模型
"""
# 配置4-bit量化
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, # 启用4-bit加载
bnb_4bit_compute_dtype=torch.float16, # 计算时使用float16
bnb_4bit_use_double_quant=True, # 双重量化,进一步压缩
bnb_4bit_quant_type="nf4", # 使用NF4量化类型
)
# 加载模型
model = AutoModelForCausalLM.from_pretrained(
model_name,
quantization_config=bnb_config,
device_map="auto", # 自动分配设备
trust_remote_code=True, # 信任远程代码
torch_dtype=torch.float16,
)
# 设置模型为评估模式
model.eval()
return model
量化后的模型精度损失很小(通常<1%),但显存占用减少了60%以上。这对于个人开发者和小团队来说,意味着不需要投入大量硬件成本就能用上最先进的多模态模型。
4. 高级功能与实用技巧
掌握了基础用法后,我们来看看一些高级功能和实用技巧,让你的使用体验更上一层楼。
4.1 批量图片处理
虽然界面是单张图片上传,但你可以通过修改代码实现批量处理。比如,你想分析一个文件夹里的所有产品图片:
import os
from glob import glob
def batch_process_images(image_folder, questions, system_prompt=""):
"""
批量处理图片
"""
results = []
# 获取所有图片文件
image_files = glob(os.path.join(image_folder, "*.jpg")) + \
glob(os.path.join(image_folder, "*.png")) + \
glob(os.path.join(image_folder, "*.jpeg"))
for img_path in image_files:
print(f"处理: {os.path.basename(img_path)}")
# 对每张图片问所有问题
for question in questions:
# 这里调用我们的对话函数
answer = chat_with_image(
image_path=img_path,
question=question,
system_prompt=system_prompt
)
results.append({
"image": os.path.basename(img_path),
"question": question,
"answer": answer
})
return results
# 使用示例
if __name__ == "__main__":
# 定义要问的问题
questions = [
"描述图片中的主要产品",
"产品的颜色是什么?",
"估计产品的尺寸",
"这个产品可能用在什么场景?"
]
# 批量处理
results = batch_process_images(
image_folder="./product_images",
questions=questions,
system_prompt="你是一个电商产品分析师,请详细描述产品特征"
)
# 保存结果
import json
with open("analysis_results.json", "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
4.2 结合其他工具使用
GLM-4V-9B可以和其他工具结合,实现更强大的功能:
1. 与OCR结合,提取结构化信息
def extract_structured_info(image_path):
"""
从图片中提取结构化信息
"""
# 先用GLM-4V理解图片内容
description = chat_with_image(
image_path=image_path,
question="详细描述图片中的所有文字和数字信息",
system_prompt="你是一个数据提取专家,请准确提取所有文字和数字信息"
)
# 然后用规则或NLP模型解析成结构化数据
# 这里可以根据你的具体需求定制解析逻辑
return structured_data
2. 自动生成图片描述文件
def generate_image_alt_text(image_folder):
"""
为文件夹中的所有图片生成alt文本(用于网页无障碍访问)
"""
alt_texts = {}
for img_file in os.listdir(image_folder):
if img_file.lower().endswith(('.png', '.jpg', '.jpeg')):
img_path = os.path.join(image_folder, img_file)
# 生成简洁的alt文本
alt_text = chat_with_image(
image_path=img_path,
question="用一句话描述这张图片的主要内容,适合作为网页图片的alt文本",
system_prompt="你是一个网页内容助手,请生成简洁准确的图片描述"
)
alt_texts[img_file] = alt_text
return alt_texts
4.3 性能优化建议
如果你发现生成速度比较慢,可以尝试这些优化:
1. 调整生成参数
# 在生成回答时调整这些参数
generation_config = {
"max_new_tokens": 512, # 减少生成的最大长度
"temperature": 0.7, # 降低随机性,加快速度
"do_sample": False, # 使用贪婪解码,速度更快
"repetition_penalty": 1.1, # 防止重复
}
2. 使用缓存 对于相同的图片和问题,可以使用缓存避免重复计算:
from functools import lru_cache
import hashlib
@lru_cache(maxsize=100)
def cached_chat_with_image(image_hash, question, system_prompt):
"""
带缓存的图片对话函数
"""
# 这里实现你的对话逻辑
pass
def get_image_hash(image_path):
"""计算图片的哈希值作为缓存键"""
with open(image_path, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
5. 常见问题与解决方案
在实际使用中,你可能会遇到一些问题。这里我总结了一些常见情况和解决方法。
5.1 模型输出乱码或奇怪字符
问题: 模型输出像</credit>、<|im_end|>这样的标记,或者中英文混杂很奇怪。
原因: 通常是Prompt构造不正确,或者模型没有正确识别图片和文本的关系。
解决:
- 确保使用我们修正后的Prompt构造逻辑
- 检查系统提示词是否合适,有时候过于复杂的提示词会干扰模型
- 尝试简化问题,先问简单的问题测试
5.2 显存不足错误
问题: 出现CUDA out of memory错误。
原因: 图片太大,或者对话历史太长。
解决:
- 压缩图片尺寸(Streamlit界面上传时会自动压缩)
- 清空对话历史,重新开始
- 如果使用自己的代码,可以限制图片分辨率:
from PIL import Image
def resize_image(image_path, max_size=1024):
"""调整图片尺寸"""
img = Image.open(image_path)
# 计算缩放比例
ratio = min(max_size / img.width, max_size / img.height)
new_size = (int(img.width * ratio), int(img.height * ratio))
# 调整尺寸
img = img.resize(new_size, Image.Resampling.LANCZOS)
return img
5.3 生成速度慢
问题: 模型回答需要很长时间。
原因: 生成长度太长,或者硬件性能有限。
解决:
- 设置
max_new_tokens参数,限制生成长度 - 使用性能更好的GPU
- 关闭不必要的后台程序,释放显存
5.4 模型回答不准确
问题: 模型识别错误,或者回答与图片内容不符。
原因: 多模态模型对某些类型的图片识别能力有限。
解决:
- 尝试不同的提问方式
- 使用更具体的系统提示词引导模型
- 如果涉及专业领域,在问题中提供一些背景信息
6. 总结
通过这个教程,我们完成了一个完整的GLM-4V-9B多模态大模型本地部署方案。相比官方示例,我们的版本有三个显著优势:
第一是稳定性。我们解决了官方代码在特定环境下的兼容性问题,通过动态类型适配和正确的Prompt构造,确保了模型在各种环境下都能稳定运行。
第二是实用性。新增的自定义系统提示词功能,让你可以根据不同场景调整模型的角色和行为。完整的对话上下文管理,让多轮对话成为可能。
第三是易用性。4-bit量化技术让这个百亿参数的大模型能在消费级显卡上运行,大大降低了使用门槛。基于Streamlit的界面简洁直观,无需编程基础也能轻松使用。
这个方案可以应用在很多实际场景中:电商产品分析、社交媒体内容理解、教育辅助、无障碍服务等等。你可以根据自己的需求,调整系统提示词,让模型成为你的专属助手。
最重要的是,所有代码都是开源的,你可以根据自己的需求进行修改和扩展。比如添加语音输入输出、集成到现有系统、或者训练自己的LoRA适配器。
多模态AI正在改变我们与计算机交互的方式。以前我们需要用文字描述图片,现在可以直接让AI"看"图片并理解它。这个技术还在快速发展,未来会有更多令人兴奋的应用出现。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐

所有评论(0)