最近看到AMD有个开发者计划的活动,提供GPU资源帮助学习LLM的一些知识,因为自己其实用的更多是生物大模型,多半是 transformers、PyTorch 直读开源权重、固定输入输出,和对话型 LLM 的在线 Serving 不是一套逻辑,而常见的商业大模型其实都是作为用户,通过api调用,其实对服务端的一系列工作都没有接触过,所以也想趁着这个机会学习一下。
所以这更像是一篇执行笔记(有一些知识内容的扩展补充):在 AMD ROCm 环境下,用 vLLM 把 Gemma 4 部署成可对外调用的推理服务。
段末注释:ROCm(Radeon Open Compute)是 AMD 的 GPU 计算软件栈;vLLM 是面向生产场景的大模型推理与服务框架,支持 OpenAI 兼容 API、高并发调度与多卡扩展。
这次项目提供了一台 48 GB 显存 的 ROCm 裸金属机器,要求完成「权重下载 → vLLM 起服 → API 验证」这条链路,并为后续微调、评测打底。下面按真实操作顺序展开,每一步遵循同一结构:先说要解决什么 → 再写怎么操作 → 结果里盯什么 → 踩坑与对策。
一、课题背景:为什么用 vLLM 做部署?
这一步要弄清什么?
本课题的目标不是「本地跑通一次推理」,而是把模型变成可持续对外提供服务的 API——后续微调完要能无缝接上、多路请求要能调度、业务侧最好能直接用 OpenAI 协议接入。选用 vLLM,正是冲着这类生产向需求去的。
vLLM 的核心优势(和本课题的关系)
| 能力 | 说明 | 对本课题的价值 |
|---|---|---|
| PagedAttention | 分页管理 KV Cache,减少显存碎片 | 48 GB 卡上跑 E4B 级模型时,显存利用率直接影响能不能起服、能开多长上下文 |
| 连续批处理(continuous batching) | 动态合并多条请求,提高 GPU 利用率 | 为多用户 / 多应用共享同一推理服务打基础 |
| OpenAI 兼容 API | 暴露 /v1/chat/completions 等标准端点 |
RAG、Agent、业务代码改 base_url 即可接入 |
| 架构覆盖广 | 持续跟进 Gemma、Qwen、Llama 等新模型 | 本次 Gemma 4 可直接 vllm serve 加载 |
| 可观测性强 | 启动日志暴露架构、后端、上下文上限等 | 便于排查 ROCm 环境下的兼容与 OOM 问题 |
| 多卡扩展 | 支持张量并行等 | 后续若换更大模型,Serving 层可横向扩展 |
段末注释:KV Cache 是解码阶段缓存历史 token 注意力键值的显存结构;PagedAttention 是 vLLM 用分页方式管理 KV Cache、提升吞吐与显存效率的关键技术。
本次实操目标
一句话概括:在 ROCm 上把 gemma-4-E4B-it 用 vLLM 跑成 OpenAI 兼容服务,并完成 API 冒烟验证。这也是课题后续「微调 → 评测 → 灰度替换」的前置环节。
二、Step 1:确认 GPU 和驱动是否就绪
这一步要解决什么?
在下载十几个 G 的模型之前,必须先确认三件事:
- 机器上的 AMD GPU 有没有被系统认出来;
- ROCm 和驱动版本是什么——后面 PyTorch、vLLM 能不能用,都绑在这上面;
- 显存到底有多大、当前干不干净——决定你能跑多大的模型、有没有别人占着的残留进程。
说白了:别急着下模型。硬件都没摸清,后面全是白忙活。
我们做了什么?
AMD 这边看 GPU,相当于 NVIDIA 的 nvidia-smi,命令是 amd-smi:
1 | amd-smi |

结果里重点看什么?
| 关注项 | 本次实测 | 说明 |
|---|---|---|
| ROCm 版本 | 7.2.1 | 装 PyTorch、vLLM 时要跟它对上 |
| 驱动版本 | amdgpu 6.14.14 | 内核态、用户态不匹配容易出怪问题 |
| 显存占用 | 26 / 49136 MB | 总容量约 48 GB,当前几乎空闲 |
| 温度 / 功耗 | 31 °C / 26 W | 空闲基线,后面加载模型好对比 |
进程表里几乎没有占显存的任务——说明环境是干净的,可以放心往下走。
可能遇到的问题 & 注意事项
| 问题 | 参考对策 |
|---|---|
| 命令找不到或报错 | 检查 ROCm 是否装全;云镜像有时要手动加载内核模块 |
| 显存总量和预期不符 | 云厂商「48G 卡」可能有预留;以 amd-smi 为准做容量规划 |
| 已有进程占显存 | 先 kill 或换干净节点;生产环境要排查僵尸进程 |
| 不知道能跑多大模型 | 48 GB 大致够 7B~14B 级 BF16/FP16 推理 + 一定 KV 余量;70B 或超长上下文要提前量化或多卡 |
段末注释:KV Cache 是解码时缓存历史 token 的显存结构,对话越长占得越多。
三、Step 2:确认 PyTorch 能不能真正用到 GPU
这一步要解决什么?
amd-smi 只能说明「硬件在」,还不能说明「你的 Python 代码能跑在 GPU 上」。
vLLM 是站在 PyTorch 上面的。如果 PyTorch 装错了版本——比如误装了 CUDA 版——后面 vllm serve 大概率直接挂。所以这一步的目的很单纯:验证「驱动 → ROCm → PyTorch」这条链是通的。
有个容易误会的地方:ROCm 上的 PyTorch 仍然走 torch.cuda 接口(底层是 HIP 兼容),看到 cuda 字样别慌,不代表你装错了 NVIDIA 的包。
我们做了什么?
一行 Python 做探活:
1 | python -c "import torch; print('PyTorch:', torch.__version__); print('ROCm available:', torch.cuda.is_available()); print('Device:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'N/A')" |

结果里重点看什么?
ROCm available: True—— 这是过关信号,说明 GPU 对 PyTorch 可见。PyTorch: 2.10.0+git8514f05—— 多半是 ROCm 专用构建,别随手换成 PyPI 默认的 CUDA 版。Device: AMD Radeon Graphics—— 设备0可用,后续推理会落在这张卡上。
三项都对,才可以进入下载模型环节。
可能遇到的问题 & 注意事项
| 问题 | 参考对策 |
|---|---|
ROCm available: False |
九成是 PyTorch 与 ROCm 版本不匹配;换课题方/厂商推荐的 wheel 或镜像 |
| 按 NVIDIA 教程装了一堆包仍无 GPU | AMD 机器不能照搬 CUDA 安装文档;核对 torch.version.hip |
| 探活过了但 vLLM 仍报错 | vLLM 还要单独装 ROCm 构建;三者版本要一起看 |
| 团队多人协作环境不一致 | 把「镜像 + 版本矩阵 + 探活脚本」写进文档,别靠口口相传 |
建议:把这条探活命令写进部署脚本的 preflight check,每次起服务前自动跑一遍。
四、Step 3:把模型权重下载到本地
这一步要解决什么?
环境没问题了,接下来要备「弹药」——模型权重。
vLLM 吃的是 HuggingFace 风格目录(config.json + tokenizer + safetensors),需要确认:
- 权重完整下到本地;
- 目录结构能被 vLLM 直接读取;
- 磁盘空间、下载源速度跟得上。
本次目标模型是 Google 的 gemma-4-E4B-it(指令微调版),体量不小,下载源选对能省不少时间。
我们做了什么?
用 ModelScope 拉取,并指定缓存目录,避免和代码仓库搅在一起:
1 | cd /workspace/repo/src/fine-tune/models/gemma4 |

结果里重点看什么?
下载完成后,目录里至少应有:
config.json、generation_config.json—— 模型结构和生成参数;tokenizer.json等 —— 分词器;model.safetensors—— 主权重,本次约 14.9 GB。
看到主权重文件大小合理、进度 100%,就可以准备起服务了。顺便记一下:Safetensors 比老式 .bin 更安全、加载也更快,是现在比较主流的选择。
显存粗算(判断 48 GB 够不够):
[
\text{权重显存(GB)} \approx 2 \times \text{参数量(B)}
]
BF16 下,E4B 量级权重就要吃掉不少显存;后面加载后显存冲到 95%,和这个量级是对得上的。
可能遇到的问题 & 注意事项
| 问题 | 参考对策 |
|---|---|
| Hugging Face 直连慢或断 | 国内优先 ModelScope、hf-mirror 等镜像 |
| 下到一半磁盘满了 | 提前预留 20 GB+ 余量;--cache_dir 指到大盘 |
| 只有 GGUF、没有 HF 目录 | 需先转换为 HuggingFace 格式,或换用支持 GGUF 的推理栈 |
| 能下载不代表能商用 | Gemma 有使用条款,上线前做法务确认 |
| 反复手工下载 | 生产流水线应固化「模型源 + 校验和 + 缓存路径」 |
五、Step 4:用 vLLM 把模型起成服务
这一步要解决什么?
权重到位了,核心任务是把模型变成对外可调用的 API 服务。vLLM 的优势在这里体现得最集中:一条 serve 命令即可拉起 OpenAI 兼容端点,背后自动处理模型加载、KV Cache 分配、请求调度与解码。
同时要心里有数:起服不等于「能跑就行」,日志里会告诉你架构有没有认对、上下文上限设了多少、注意力走的哪个后端——这些直接影响后面稳不稳、快不快。
我们做了什么?
1 | vllm serve ./models/google/gemma-4-E4B-it/ \ |
--served-model-name 是对外 API 里的模型名,和本地目录路径分开,后面换模型版本会省事。

结果里重点看什么?
别只看「有没有报错」,日志里这几行值得划重点:
| 日志信息 | 说明 |
|---|---|
Gemma4ForConditionalGeneration |
架构识别成功;新模型首发周常遇到「不认识这个架构」 |
max_model_len: 131072 |
理论上下文很长,实际能开多少还要看剩多少显存 |
Forcing TRITON_ATTN backend |
Gemma4 头维度特殊,强制走 Triton 注意力以保证数值稳定 |
Asynchronous scheduling is enabled |
异步调度开着,有利于吞吐 |
服务监听 0.0.0.0:8000 |
默认暴露 OpenAI 兼容的 /v1/chat/completions |
看到服务稳定监听、没有 OOM 退出,就可以做下一步验证了。
可能遇到的问题 & 注意事项
| 问题 | 参考对策 |
|---|---|
| 报「架构未注册」 | 升级 vLLM 到支持 Gemma4 的版本,或试 nightly |
| 启动时 OOM | 加 --max-model-len 缩短上下文;或换量化权重、多卡张量并行 |
| 装了 CUDA 版 vLLM 在 AMD 上跑 | 必须用 ROCm 构建,和 Step 2 的 PyTorch 一起看 |
| K8s 里 Pod 反复重启 | 大模型冷启动慢,readiness 探针超时别设太短 |
| 裸奔 8000 端口上线 | 生产要挂 Nginx/Ingress,加 TLS、限流、鉴权 |
| 客户端写死模型路径 | 用 served-model-name 做灰度切换,别绑本地目录 |
六、Step 5:确认模型真的加载进 GPU 了
这一步要解决什么?
服务进程起来,不代表权重一定在 GPU 上——有些配置错误会导致静默跑 CPU,能出字但慢到没法用。
所以还要再查一次显存:加载前后对比,确认模型吃进去了多少、还剩多少余量给并发和 KV Cache。这也是判断「这张卡还能不能扛业务流量」的关键依据。
我们做了什么?
再次执行 amd-smi,和 Step 1 的空闲状态对比:

结果里重点看什么?
- 显存:从 26 MB 涨到 46,680 / 49,136 MB,约 95% —— 说明权重确实进了 VRAM。
- 进程:PID
1231927独占约 45.6 GB,基本就是 vLLM 服务进程。 - 温度 / 功耗:仍不高,说明是「加载完等着接请求」,还没打满推理。
和 Step 1 一对,心里就有数了:这张 48 GB 卡跑 Gemma 4 E4B,几乎没有余量,并发一上来很容易顶满。
可能遇到的问题 & 注意事项
| 问题 | 参考对策 |
|---|---|
| 显存几乎不涨 | 怀疑 CPU offload 或设备映射配错;查 vLLM 启动参数和日志 |
| 显存 >90% 还上大并发 | 设告警;缩短 max_model_len,或 AWQ/GPTQ 量化 |
| 单卡已满还想扩容 | 多卡张量并行、换更大卡、或换更小/量化模型——这是架构决策,不是调个参能糊弄 |
| 只看进程在、不看显存 | 养成「起服后必跑一遍 smi」的习惯 |
七、Step 6:对话冒烟,验证 API 真能用的
这一步要解决什么?
前面都是「服务活着」。最后还要证明:请求能进来、模型能想、字能出去。
冒烟测试的目的:
- 验证中文对话、分词、解码全链路正常;
- 确认对外模型名
gemma-4-E4B-it和 API 路径没问题; - 留一份 baseline 输出,后面微调、换模型好对比。
注意:冒烟通过 ≠ 可以上线扛流量,但能拦住一大批「服务起了其实不能用」的低级错误。
我们做了什么?
用 vLLM 自带客户端连本地服务:
1 | vllm chat --url http://localhost:8000/v1 --model gemma-4-E4B-it |
测试提示词:你是谁,介绍下。

模型用中文结构化自我介绍,报出 Gemma 4、能力范围和知识截止——说明链路通了。
日志里有个小提示:argument 'url' is deprecated。CLI 参数会变,自动化脚本最好锁定 vLLM 版本,或改用当前推荐的 --base-url。
等价的 HTTP 冒烟(方便接 CI):
1 | curl http://localhost:8000/v1/chat/completions \ |
业务代码侧通常这样接:
1 | from openai import OpenAI |
结果里重点看什么?
- 能稳定返回、中文不乱码、内容符合模型人设 → 基本过关。
curl和 Python SDK 两条路径都过 → 更接近真实业务接入。- 记下首条回复当 baseline → 微调前后才有可比性。
可能遇到的问题 & 注意事项
| 问题 | 参考对策 |
|---|---|
| CLI 能聊,HTTP 404/422 | 核对 base_url 是否带 /v1、model 名是否和 served-model-name 一致 |
| 首 token 很慢 | 冷启动正常;生产要考虑预热或保活 |
| 冒烟过了就以为能上线 | 还要压并发、长上下文、多轮对话;看 P99 延迟而不只是 QPS |
| 后面要接 RAG / Agent | 同一 base_url 可直接给 LangChain、Open WebUI 等用 |
八、串起来看:整条链路长什么样?
把前面几步摞在一起,完整链路可以看成下面这张图。绿色实线框是本文已走完的实操;灰色虚线框是同一课题里后续还要做的环节,这次记录里尚未展开。

生图关键词(流程图):科普漫画风格竖向流程图;中文节点;AMD ROCm 48GB → amd-smi → PyTorch 探活 → ModelScope 下载 Gemma 4 → vllm serve → 显存复核 → 冒烟验证 → 微调 → 评测 → 灰度换模型;Step 1~6 绿色实心框「本次已完成」,后续三步灰色虚线框「后续开展」;白底扁平插画,公众号技术配图。
本次已执行(Step 1~6)
| 顺序 | 环节 | 做了什么 | 状态 |
|---|---|---|---|
| 环境 | 申请 AMD ROCm 48GB | 开发者计划裸金属,ROCm 7.2.1 | ✅ 本文环境 |
| Step 1 | amd-smi |
确认驱动、显存约 48 GB、环境干净 | ✅ 已执行 |
| Step 2 | PyTorch 探活 | torch.cuda.is_available() 为 True |
✅ 已执行 |
| Step 3 | ModelScope 下载 | gemma-4-E4B-it,主权重约 14.9 GB |
✅ 已执行 |
| Step 4 | vllm serve |
OpenAI 兼容服务监听 8000 端口 | ✅ 已执行 |
| Step 5 | amd-smi 复核 |
显存占用约 95%,确认权重在 GPU | ✅ 已执行 |
| Step 6 | vllm chat / curl |
中文对话冒烟通过 | ✅ 已执行 |
到这里,「权重落地 → 服务可调用 → API 验证通过」 这条最小闭环已经跑通,也是本次公众号文章的主体内容。
后续开展(课题下一步)
| 顺序 | 环节 | 打算做什么 | 状态 |
|---|---|---|---|
| Step 7 | 微调 | 在业务数据上继续训练 / 对齐,产出新 checkpoint | ⏳ 计划中 |
| Step 8 | 评测 | 对比微调前后指令遵循、领域问答、幻觉率等 | ⏳ 计划中 |
| Step 9 | 灰度换模型 | 用新 served-model-name 或新版本滚动替换,业务无感切换 |
⏳ 计划中 |
这三步和「把模型跑起来」是不同工种:部署解决的是 Serving 能不能用;微调 + 评测解决的是 模型够不够好;灰度替换解决的是 怎么安全上线。后面会在同系列文章里接着写。
文字版速览
1 | 【本次】申请 AMD ROCm 48GB 环境 |
九、一张表收拢常见坑
| 阶段 | 常见问题 | 怎么处理 |
|---|---|---|
| 环境 | ROCm / PyTorch / vLLM 版本对不上 | 用锁定镜像 + preflight 脚本 |
| 环境 | 误装 CUDA 版依赖 | 探活 + 看 torch.version.hip |
| 模型 | 下载慢、中断 | ModelScope / 内网镜像 + 校验 |
| 模型 | 许可证踩线 | 上线前做法务 review |
| 起服 | 不认识新架构 | 升 vLLM,盯 Gemma4 支持版本 |
| 起服 | OOM | 降 max_model_len、量化、多卡 |
| 运行 | 显存满、QPS 低 | 压测调度策略;固定 attention 后端做对比 |
| 接入 | 只测 CLI 没测 HTTP | curl + SDK 双路径冒烟 |
| 运维 | 没监控 | 显存、延迟、队列深度都要采 |
按本文流程在 ROCm 上走通一遍,至少能拿到一条可复盘、可交接的 vLLM Serving 最小闭环;后续再在此基础上叠微调与灰度发布。
十、写在最后
本次课题把 LLM 部署落到了一条可执行的链路上:
看硬件 → 探活 → 下权重 → vLLM 起服 → 复核显存 → API 冒烟
48 GB 的卡跑 Gemma 4 E4B,显存已经顶到 95%。这也提醒一件事:模型多大、上下文多长、并发多少,最好在下载权重之前就算账,别等服务 OOM 了再救火。
后续将继续记录微调、评测与灰度换模型;更多部署框架背景可参考 00.本地 LLM 部署框架选型与横向对比。
本次环境一览
| 项目 | 版本 / 规格 |
|---|---|
| GPU 显存 | ~48 GB(49136 MB) |
| ROCm | 7.2.1 |
| PyTorch | 2.10.0+git8514f05 |
| vLLM | 0.23.0 |
| 模型 | google/gemma-4-E4B-it(ModelScope) |
| 起服命令 | vllm serve ./models/google/gemma-4-E4B-it/ --served-model-name gemma-4-E4B-it |