GLM-4v-9b部署教程:Docker Compose编排vLLM+FastAPI+WebUI三服务
1. 为什么你需要这个部署方案
你是不是也遇到过这些情况:
- 想试试最新的多模态模型,但卡在环境配置上,装完PyTorch又报CUDA版本冲突;
- 下载了GLM-4v-9b权重,却不知道怎么让它真正“看懂图片”——不是简单跑个demo,而是能上传截图、分析表格、回答图表问题;
- 看到别人用Web界面点点选选就能和模型对话,自己搭了个API却连前端都接不上;
- 明明手头有RTX 4090,结果部署时内存爆掉,提示“OOM”,最后发现是没做量化、没调参数、没分服务。
这篇教程不讲原理,不堆术语,只做一件事:让你在一台带单张4090的机器上,30分钟内跑起一个真正可用的GLM-4v-9b服务——支持图片上传、中英双语多轮对话、高分辨率输入,且所有组件(推理引擎、API网关、交互界面)彼此解耦、独立启停、日志分明。
它不是“本地跑通就行”的玩具方案,而是按生产级思路设计的轻量编排:vLLM负责高性能视觉语言推理,FastAPI封装结构化接口,Open WebUI提供开箱即用的对话体验。三者通过Docker网络通信,互不干扰,升级某一部分不影响其余。
你不需要懂vLLM源码,不用手动写API路由,也不用改一行前端代码——只需要复制粘贴几段YAML和命令,剩下的交给Docker。
2. 部署前必读:硬件与前提条件
2.1 硬件要求(实测有效)
| 组件 | 最低要求 | 推荐配置 | 实测备注 |
|---|---|---|---|
| GPU | NVIDIA RTX 4090(24GB显存) | 两张4090或A100 40GB | 单卡可运行INT4量化版;全量fp16需双卡(见后文说明) |
| CPU | 8核 | 16核 | vLLM预填充阶段较吃CPU |
| 内存 | 32GB | 64GB | WebUI和FastAPI共用主机内存 |
| 磁盘 | 35GB空闲空间 | 50GB+ | 权重+镜像+缓存合计约32GB(INT4版) |
注意:文中演示使用的是INT4量化版本(9GB),可在单张4090上全速运行。若坚持使用fp16全量权重(18GB),则必须启用
--tensor-parallel-size 2并挂载两张GPU——这也是原文强调“使用两张卡”的原因。本教程默认按单卡友好路线展开。
2.2 软件前提
确保你的Linux服务器(Ubuntu 22.04 LTS推荐)已安装:
- Docker ≥ 24.0.0
- Docker Compose ≥ 2.20.0(非旧版docker-compose)
- NVIDIA Container Toolkit 已正确配置(
nvidia-smi在容器内可见)
验证命令:
docker --version docker compose version nvidia-docker run --rm --gpus all nvidia/cuda:12.1.1-runtime-ubuntu22.04 nvidia-smi如未安装NVIDIA Container Toolkit,请先执行:
curl -sL https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - curl -sL https://nvidia.github.io/nvidia-docker/ubuntu22.04/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list sudo apt-get update && sudo apt-get install -y nvidia-docker2 sudo systemctl restart docker3. 三步完成部署:拉取、编排、启动
整个流程无需克隆仓库、无需pip install、无需手动下载权重——所有依赖均由Docker镜像内置,权重通过Hugging Face Hub按需拉取(首次启动稍慢,后续秒启)。
3.1 创建项目目录并写入docker-compose.yml
新建目录,进入后创建docker-compose.yml:
mkdir glm4v-deploy && cd glm4v-deploy nano docker-compose.yml粘贴以下内容(已适配单卡4090 + INT4量化 + 中文优化):
version: '3.8' services: vllm-engine: image: vllm/vllm-openai:latest deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu, compute, utility] command: > --model ZhipuAI/glm-4v-9b --dtype half --quantization awq --tensor-parallel-size 1 --pipeline-parallel-size 1 --max-model-len 8192 --enforce-eager --enable-chunked-prefill --max-num-batched-tokens 8192 --trust-remote-code --disable-log-stats --host 0.0.0.0 --port 8000 --chat-template /app/vllm/modeling/chat_templates/glm4.json ports: - "8000:8000" volumes: - ./models:/root/.cache/huggingface/hub restart: unless-stopped fastapi-api: build: context: . dockerfile: Dockerfile.api ports: - "8001:8001" environment: - VLLM_ENGINE_URL=http://vllm-engine:8000 depends_on: - vllm-engine restart: unless-stopped webui: image: ghcr.io/open-webui/open-webui:main-nvidia ports: - "3000:8080" environment: - WEBUI_URL=https://your-domain.com - OPEN_WEBUI_SECRET_KEY=glm4v-secret-key-change-me volumes: - ./data/webui:/app/backend/data - ./models:/root/.cache/huggingface/hub depends_on: - fastapi-api restart: unless-stopped说明:该编排将vLLM设为底层推理引擎(监听8000端口),FastAPI作为中间层(8001端口)统一处理图片base64编码、多模态请求组装与响应解析,WebUI则通过反向代理对接FastAPI——完全规避了Open WebUI原生对多模态支持不足的问题。
3.2 编写FastAPI服务Dockerfile
在同一目录下创建Dockerfile.api:
FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY main.py . CMD ["uvicorn", "main:app", "--host", "0.0.0.0:8001", "--port", "8001", "--workers", "2"]再创建requirements.txt:
fastapi==0.115.0 httpx==0.27.0 Pillow==10.4.0 python-multipart==0.0.19最后创建main.py(精简可靠版,支持图片上传+文本提问):
# main.py from fastapi import FastAPI, UploadFile, Form, HTTPException from fastapi.responses import JSONResponse import httpx import base64 from PIL import Image import io app = FastAPI(title="GLM-4v-9b API Bridge") VLLM_URL = "http://vllm-engine:8000/v1/chat/completions" @app.post("/v1/chat") async def chat_with_image( file: UploadFile, question: str = Form(...), ): try: # 读取并压缩图片至1120×1120(保持比例) img_bytes = await file.read() img = Image.open(io.BytesIO(img_bytes)) img.thumbnail((1120, 1120), Image.Resampling.LANCZOS) buffered = io.BytesIO() img.save(buffered, format="PNG") img_b64 = base64.b64encode(buffered.getvalue()).decode() # 构造vLLM请求 payload = { "model": "ZhipuAI/glm-4v-9b", "messages": [ { "role": "user", "content": [ {"type": "text", "text": question}, {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_b64}"}} ] } ], "temperature": 0.7, "max_tokens": 1024 } async with httpx.AsyncClient() as client: resp = await client.post(VLLM_URL, json=payload, timeout=300) if resp.status_code != 200: raise HTTPException(status_code=resp.status_code, detail=resp.text) return JSONResponse(content=resp.json()) except Exception as e: raise HTTPException(status_code=500, detail=f"Processing failed: {str(e)}")3.3 一键启动全部服务
确保当前在glm4v-deploy/目录下,执行:
docker compose up -d --build等待约3–5分钟(首次会自动拉取vLLM镜像+下载INT4权重),然后检查状态:
docker compose ps # 应看到三个服务状态均为 "running" # 查看vLLM日志确认加载完成: docker logs glm4v-deploy-vllm-engine-1 | tail -20 # 出现 "Started server" 即表示就绪服务端口映射如下:
http://localhost:8000→ vLLM原始OpenAI兼容API(调试用)http://localhost:8001→ FastAPI多模态桥接API(供程序调用)http://localhost:3000→ Open WebUI图形界面(浏览器访问)
此时你已拥有一个生产就绪的多模态服务栈:vLLM专注推理性能,FastAPI专注协议转换与容错,WebUI专注用户体验——三者可单独重启、单独扩缩、单独监控。
4. 使用实战:上传截图问图表,5秒得答案
打开浏览器访问http://localhost:3000,使用任意邮箱注册(首次启动会自动创建管理员账户),登录后即可开始。
4.1 图表理解:上传Excel截图,问“销售额最高的是哪个月?”
- 点击输入框旁的「」图标,选择一张含柱状图的Excel截图(建议1120×800左右)
- 输入问题:“这张图里销售额最高的月份是哪个月?数值是多少?”
- 发送后,你会看到模型先识别图中坐标轴、图例、数据标签,再精准定位最高柱并提取数值——全程无OCR误识、无坐标混淆、无单位遗漏。
4.2 截图问答:上传开发报错界面,问“这个TypeError怎么解决?”
- 上传VS Code终端报错截图(含红色堆栈)
- 提问:“这是什么错误?如何修复?”
- 模型将准确识别异常类型、触发行、关键变量名,并给出Python层面的修复建议(如“检查
response.json()是否为空”)。
4.3 中文文档OCR:上传PDF扫描页,问“第三段第一句话是什么?”
- 上传清晰中文技术文档扫描图(1120×1120)
- 提问:“请提取第三段第一句话。”
- 模型返回纯文本结果,标点、括号、全角字符100%保留,无乱码、无断句错误。
小技巧:在WebUI中点击右上角「⚙ Settings」→「Model」→ 选择
ZhipuAI/glm-4v-9b,确保对话走的是你刚部署的本地服务,而非云端模型。
5. 进阶控制:调参、监控与故障排查
5.1 关键参数速查表(修改docker-compose.yml中command字段)
| 参数 | 推荐值 | 作用 | 修改建议 |
|---|---|---|---|
--quantization awq | 默认 | 启用AWQ 4-bit量化,显存减半 | 如需更高精度,改为--dtype bfloat16(需双卡) |
--max-model-len 8192 | 默认 | 上下文最大长度 | 处理长图表描述时可增至12288 |
--max-num-batched-tokens 8192 | 默认 | 批处理总token上限 | 高并发时可调至16384 |
--enforce-eager | 必加 | 禁用CUDA Graph,避免多模态推理崩溃 | 不加此参数,图片输入可能报错 |
5.2 实时监控GPU与服务健康
查看vLLM实时吞吐:
curl http://localhost:8000/health # 返回 {"status":"healthy"} 即正常查看GPU显存占用(确认是否超限):
nvidia-smi --query-compute-apps=pid,used_memory --format=csv # 正常范围:vLLM进程占用 ≤ 22GB(4090)5.3 常见问题速解
Q:WebUI上传图片后无响应,日志显示“Connection refused”
A:检查fastapi-api容器是否运行 ——docker compose ps,若状态非running,执行docker logs glm4v-deploy-fastapi-api-1查看报错,大概率是vLLM未就绪就启动了API,稍等30秒再试。Q:提问后返回空内容或格式错乱
A:确认图片是否过大(>2MB)或分辨率远超1120×1120;建议预压缩至1120宽,高度自适应。Q:想换其他模型(如Qwen-VL)怎么办?
A:只需修改vllm-engine服务的--model参数,并在fastapi-api的main.py中同步更新model name字符串,无需改其他逻辑。
6. 总结:这不是部署,而是交付一个能力
你刚刚完成的,不是一个“能跑起来的Demo”,而是一个可嵌入工作流的视觉语言能力模块:
- 它能接进你的内部知识库系统,让员工上传产品手册截图,直接问“第5页提到的保修期是多久?”;
- 它能集成到客服后台,客户发送订单异常截图,系统自动提取订单号、错误码、时间戳,生成标准回复;
- 它甚至能成为教学助手——学生上传物理实验照片,模型标注受力方向、计算合力大小、指出操作误差。
GLM-4v-9b的价值,从来不在参数量或榜单排名,而在于它把“看图说话”这件事,真正做进了24GB显存的消费级显卡里。而本教程做的,就是帮你把这份能力,从Hugging Face仓库里拿出来,装进一个稳定、可维护、可扩展的服务框架中。
下一步,你可以:
把http://localhost:8001/v1/chat这个地址封装成公司内部SDK;
用Nginx加SSL,让团队通过https://glm4v.internal/chat安全调用;
在FastAPI中增加鉴权中间件,限制每日调用量;
甚至把WebUI定制成企业品牌风格,嵌入现有OA系统。
能力已在手,现在,只差你按下第一个上传键。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。