ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

本地跑不动?把Qwen3 27B搬上云:vLLM+dsh完整实践

本地跑不动?把Qwen3 27B搬上云:vLLM+dsh完整实践 最近在折腾 dsh 这个本地 agent前面用 Qwen3 8B 跑日常任务还挺顺手结果一换到 27B本地推理速度直接崩到每秒两三个 token让它写一段稍长的分析能等得人犯困。没办法我只好把 Qwen3 27B 部署到 radeon cloud 的 GPU 实例上再用 vLLM 提供 OpenAI 兼容接口让本地的 dsh 通过这个接口接入云端模型。整套链路折腾了半个周末总算跑通期间还踩了 dsh 插件树加载失败、headless 子代理崩溃这类报错。这篇就把从选型、部署到接入的完整过程写出来给同样想把重模型扔上云、本地只留 agent 编排层的朋友做个参考。1. 开跑之前先算清楚账27B 到底需要多大的显存和算力1.1 本地点不亮 27B别硬扛很多人一开始的思路跟我一样本地显卡显存不够那就上量化4-bit 总能塞进去了吧。理论上没错但实际操作下来你会发现问题不只是塞得进去还有跑得动和跑得稳。Qwen3 27B 这类参数的密集模型单份 FP16/BF16 权重就要占大约 54GB 显存这还没算 KV cache、激活值和临时缓冲。换句话说即使是 4090 这种 24GB 的旗舰消费卡连权重都装不下。用 4-bit 量化确实能把权重压到 14GB 左右但推理时 KV cache 会随着上下文长度快速膨胀你开个 32K 上下文KV cache 又吃掉几个 GB算下来 24GB 还是紧巴巴生成长文时经常 OOM。我本地的主力是一台 64GB 统一内存的 Mac用 MLX 4-bit 倒是能跑起来但 Qwen3 27B 在这种环境下生成速度只有个位数 token/s。dsh 这种 agent 工具跑多轮工具调用的时候一轮要生成几百上千 token速度慢就变得没法用。所以结论很直接27B 这个量级的模型老老实实放到云上用专业 GPU 实例跑。1.2 四种常见量化方式的显存明细这里把 27B 模型常见的几种运行格式列个表方便大家对照自己手上的硬件做判断格式权重占用约32K 上下文时 KV cache约典型运行环境FP16 / BF1654GB4-8GB单张 64GB 以上 GPUFP8 量化27GB4-8GB40GB 以上 GPU 勉强可跑AWQ / GPTQ 4-bit14-16GB4-8GB24GB 消费卡临界云 GPU 很轻松GGUF Q8_029GB4-8GB32GB 以上 GPU 或大内存 MacMLX 4-bit14-16GB依赖统一内存Apple Silicon速度为瓶颈我在云端选的是 AWQ 4-bit原因后面会细说。这里先提一个容易被忽略的点很多人只看权重占用不看 KV cache。Qwen3 的 GQA 结构已经帮了大忙KV cache 比传统多头注意力小很多但 27B 模型开 32K 上下文依然要几 GB 的缓存空间做容量规划时把这部分算进去否则满上下文时必崩。1.3 按小时租用 Radeon Cloud 的算账逻辑既然本地跑不动那就租。Radeon Cloud 上提供的是带 ROCm 环境的 AMD Instinct 系列 GPU我这次用的是 MI210单卡 64GB HBM2e跑 27B AWQ 版本富余量很大。算账的方式很简单按小时租弹性开机。假设你每天实际跑重模型 3 小时按 MI210 每小时的单价大概 10-15 元计算一个月下来 900-1300 元左右。这比起买一张 48GB 以上的专业卡要划算得多而且云上的显存规格是本地很难配到的。关键是dsh 这种 agent 工具本来就不是每时每刻都需要 27B日常任务交给本地 8B重活才切云端这种混合用法让成本更可控。注意别把按小时租理解成开起来就放着。绝大多数云 GPU 是空闲不计费或按用量计费的模式跑完记得释放实例不然账单会教你做人。2. Radeon Cloud 实例上从零拉起 vLLM 服务的完整过程2.1 实例规格选择和 ROCm 环境预检创建实例的时候我选了单张 MI210系统镜像是带 ROCm 的 Ubuntu 版本。这里有个建议先确认系统里有没有 docker没有的话装一下因为 vLLM 官方推荐用容器方式跑环境隔离最省心。登录实例后第一步永远是检查 GPU 是否被系统正确识别。执行rocm-smi --showmeminfo vram rocm-smi --showuserocm-smi能看到每张显卡的显存总量和使用率。如果输出为空说明 ROCm 内核模块没加载先检查驱动apt list --installed | grep rocm我这次系统自带 ROCm 6.x直接可用。另外用df -h看一眼磁盘空间模型下载加容器镜像20GB 是起步别租了个 40GB 磁盘的小盘鸡解压个模型就满了。2.2 拉取 ROCm 版 vLLM 镜像并启动服务AMD GPU 上跑 vLLM 的关键是镜像选对。官方vllm/vllm-openai镜像本身支持 ROCm 后端但需要指定 ROCm 版本或使用对应的 tag。我这边是直接把ROCM_VERSION环境变量传给容器让 vLLM 识别 AMD 硬件。模型文件我提前下载到了实例的/root/models/Qwen3-27B-AWQ目录。下载地址方面Qwen 系列的模型在 Hugging Face 和 ModelScope 都有官方仓库国内环境用 ModelScope 拉取速度快很多命令行里指定 source 为 modelscope 即可这个细节能省下大量等待时间。启动命令如下docker run -d --name qwen3-27b \ --device/dev/kfd --device/dev/dri \ --group-add video \ -v /root/models:/workspace/models \ -p 8000:8000 \ -e ROCM_VERSION6.1 \ -e HF_ENDPOINThttps://hf-mirror.com \ vllm/vllm-openai:latest \ --model /workspace/models/Qwen3-27B-AWQ \ --quantization awq \ --max-model-len 32768 \ --gpu-memory-utilization 0.9 \ --served-model-name qwen3-27b逐项解释几个关键参数--max-model-len 32768限制最大上下文为 32K。27B 模型在 64GB 显存上支持 32K 没问题如果你想跑 128K需要换成更大显存的 MI300X 实例或者降低量化精度。--gpu-memory-utilization 0.9允许 vLLM 使用 90% 显存剩下 10% 留给驱动和临时分配。这个值在 MI210 上不用调太高我们后面积累了 32K 上下文也住得下。--served-model-name qwen3-27b给模型起个别名后面 dsh 配置里只要记住这个别名就行不用管实际模型文件叫什么。-e HF_ENDPOINT如果模型文件是第一次启动时自动从 Hugging Face 下载这个变量能帮你走镜像站点如果已经提前用 ModelScope 下好这一步可以不需要。这里要专门说下为什么选 AWQ 而不是 GGUF Q8_0。热词里我看到有人搜 vllm/vllm-openai:qwen3.8-27b(q8_0 量化版)这思路没错但 GGUF 格式在 ROCm 平台跑 vLLM 的支持度一直不如 AWQ 稳定q8_0 倒是精度高对 ROCm 的兼容性会带来不确定性。与其在环境兼容上浪费时间不如直接用 AWQ 4-bit实测下来质量损失很小。如果你确实想用 Q8_0考虑走 llama.cpp server不走 vLLM。启动完成后用docker logs -f qwen3-27b观察日志看到类似 Application startup complete 和 vLLM 的生成参数统计信息说明服务已经起来了。2.3 第一次 curl 验证让模型开口说话容器起来但还不敢说真跑通了第一件事是用 curl 打一发确认 OpenAI 兼容接口是活的curl http://localhost:8000/v1/chat/completions \ -H Content-Type: application/json \ -d { model: qwen3-27b, messages: [{role: user, content: 写一句 30 字以内的自我介绍}], max_tokens: 256 }正常响应会返回一个带choices字段的 JSON里面有生成的内容和 token 用量统计。我实测首 token 延迟大约 0.4 秒左右生成速度能到 45-60 token/s这个水平对 agent 工具来说非常舒服。如果你是在本地 curl 不通先检查两件事一是实例安全组有没有放行 8000 端口二是 vLLM 是否监听在 0.0.0.0 上默认是对外监听的但部分镜像会绑定 localhost这时需要额外加参数。3. 本地 dsh 接入云端模型的配置链路与 Web 认证3.1 给 dsh 新增一个指向云端的 profiledsh 的模型配置我这边走的是 profile 机制配置目录在~/.dsh/profiles/下。我的做法是新建一个cloud-qwen.yaml内容大概长这样name: cloud-qwen model: provider: openai-compatible base_url: http://云实例公网IP:8000/v1 api_key: vllm-not-needed name: qwen3-27b temperature: 0.7 max_tokens: 4096 timeout: 120几个字段说明一下base_url必须是 vLLM 的 OpenAI 兼容根路径也就是带/v1的那个。很多人第一次配漏了/v1导致 dsh 报到 404。api_keyvLLM 默认不校验 key任意非空字符串都行但建议不要留空免得某些 SDK 因为空 key 直接拒绝请求。timeout: 120云端实例如果闲置一阵子再被调用冷启动和模型重新加载可能要几十秒默认 timeout 太短会让 agent 直接报错。120 秒是个稳妥值。配置好后在 dsh 里激活这个 profile 就行。有的版本是dsh profile activate cloud-qwen有的是启动时加--profile参数看你的安装方式。3.2 dsh web 首次认证为什么需要重新打开 URL接入模型之后我顺手试了 dsh 的 Web 界面模式也就是dsh web。第一次访问时浏览器会提示 web authentication required这个被热词反复搜到的问题其实原因很简单dsh web 启动时会在终端里打印一个带临时认证 token 的 URL你只有在浏览器里打开那个完整 URL才能通过认证。如果你只打开了http://localhost:xxxx而没有带路径参数自然会被拦下来。我的做法是保持启动 web 的终端窗口别关把打印出来的完整 URL 复制到浏览器。万一终端关了也不用慌dsh 会把认证信息写到日志和状态文件里用dsh web status或者查看~/.dsh/logs/下最新的 web 日志能找到同一条带 token 的 URL。这个 token 是一次性的过期后再次运行dsh web会重新生成。顺带一提dsh 的插件市场也是走 profile 配置的比如热词里提到的dsh plugin --profile web add dshmarket dsh plugin --profile web add madage/dsh-self-improved这两条命令是给 web profile 添加插件源dshmarket是官方市场madage/dsh-self-improved是社区里的自改进插件。装完插件后记得重新启动 dsh web否则新插件不会出现在插件列表里。3.3 本地 8B 与云端 27B 的切换姿势接入成功后我保留了原来的本地 8B profile每天联调时打开两个终端分别跑两种任务简单问答和工具调用走本地 8B代码生成、长文本分析、复杂规划走云端 27B。切换本身很轻量就是改一下 profile。我的习惯是给 dsh 写一个简单的 shell 别名alias dsh-localdsh --profile local-qwen alias dsh-clouddsh --profile cloud-qwen这样不用每次敲一堆参数。对 agent 工具来说模型切换越轻量越好否则你会不自觉地在重模型上也跑轻任务成本就是这么涨上去的。4. 接入后踩过的坑插件树加载失败、子代理退出和超时问题4.1 error: dsh: plugin tree failed to load 的完整排查接入云端后第一天我开始往 dsh 里加各种插件结果某个节点开始启动 dsh 时报了一串吓人的错误error: dsh: plugin tree failed to load: dsh: plugin(s) failed to load: deep一开始我以为是安装的某个插件和当前 dsh 版本不兼容但报错里明确指向了deep这个 scoped 插件。所谓 scoped 插件就是带前缀命名空间的插件安装和加载时按完整名字解析。它加载失败意味着它本身没装好或者它依赖的插件没装全。我的排查链路是这样的先跑dsh plugin list看看当前哪些插件处于异常状态。deep状态显示为 failed。单独卸载再安装一次dsh plugin remove deep dsh plugin install deep问题依旧这就排除了单纯的安装损坏。查看deep插件描述文件里的 dependencies 字段发现它依赖dsh-self-improved这个插件。而我当时只装了dshmarket没装这个依赖插件。装上依赖清除插件缓存重建插件树dsh plugin install deep/dsh-self-improved rm -rf ~/.dsh/cache/plugin-tree然后重新启动 dsh报错消失。这个坑想说明一点如果你在安装 dshmarket 或社区插件时看到plugin tree failed to load大概率不是 dsh 本体坏了而是某个插件的依赖缺失。直接卸载重装 dsh 属于最后的手段大部分时候清缓存、补依赖就能解决。热词里出现的卸载 dsh和重新安装我实测绝大多数场景不需要走到那一步。4.2 headless 模式子代理崩溃拖垮主进程怎么隔离dsh 有 headless 模式能脱离终端在后台跑定时任务。有个很恶心的问题被很多人搜过headless 模式运行子代理时子代理报错退出会导致主进程也跟着退出。最初的表象是我挂了dsh headless去跑一个夜间任务第二天起来发现进程没了日志里只有子代理的堆栈然后就是主进程收到信号退出的记录。根因分析下来其实不复杂headless 模式没有交互终端很多错误处理走了非交互路径子代理的未捕获异常向上冒泡直接带崩了主进程。这跟父进程吞掉子进程错误不是一回事它更像是主进程自己当了兜底。我的处理方案有三层外层用tmux或nohup包裹整个 headless 进程就算崩了也不会丢失终端会话上下文。在主配置里开启子代理错误隔离让子代理的崩溃只影响它自己。如果 dsh 版本不支持这个选项就人为拆分把子代理任务放到单独的 profile 里用独立进程跑主 agent 只管编排。调高日志级别并输出到文件dsh headless --log-level debug /var/log/dsh-headless.log 21这样至少能拿到完整的崩溃现场不会出现进程没了但啥也没留下的情况。实测下来子代理的崩溃大多来自模型返回格式异常或者插件工具超时而这些在高负载的云端模型接入后反而更容易触发——因为云端网络抖动导致单次工具调用超时子代理判断为致命错误。所以这个坑和云端接入其实是相关的。4.3 远程调用的超时、冷启动和鉴权细节本地 dsh 连云端 vLLM和连本地模型完全是两种网络环境。最容易踩的三个点第一个是超时。我在 3.1 里把 timeout 调到了 120 秒实际不够的还有首 token 延迟。vLLM 在空闲一段时间后如果实例本身没有做常驻保活冷启动会非常慢。我的做法是加一个心跳任务每 60 秒打一次最小请求让模型保持热状态。成本几乎为零但能避免很多次卡住 40 秒后超时的假故障。第二个是连接池。dsh 这类 agent 工具每次对话会发多次请求每次新建 TCP 连接耗时明显。如果 dsh 底层走的是 OpenAI SDK通常会自带连接池如果是自己封装的建议全局复用同一个 HTTP client否则高并发调用时你会看到大量 TIME_WAIT 状态。第三个是鉴权。vLLM 的--api-key参数其实是可选的但裸奔在公网上很不安全。我的做法是只在云实例的防火墙层面把 8000 端口限制为只允许我本地出口 IP 访问再加一层简单的反向代理做 Basic Auth。注意这里千万别把云实例的 API 直接暴露给所有人你部署的是能生成内容的模型别人拿来跑什么你都控制不了。更稳妥的方式是用 SSH 端口转发把远端 8000 端口映射到本地ssh -L 8000:localhost:8000 root云实例IP这样 dsh 配置里的base_url直接写http://localhost:8000/v1就行公网完全不暴露端口。5. 跑通后的实测对比云端 27B 与本地 MLX 4-bit 值不值5.1 生成速度与首 token 延迟的实测对比写这篇的时候我做了一次并排测试同一段代码生成任务分别跑在本地 Mac 的 MLX 4-bit 和云端 MI210 的 AWQ 上对比项本地 MLX 4-bitM2 Max 64GB云端 AWQMI210首 token 延迟1.2-1.8 秒0.4 秒稳定生成速度8-12 token/s45-60 token/s32K 上下文稳定性长上下文后明显降速偶尔卡顿全程稳定2000 token 代码生成约 3 分钟约 40 秒这个差距在 dsh 的 agent 场景里会被拉得更大。因为 agent 是多轮迭代的每一步都要调用模型总耗时基本是本地跑法的 4-5 倍。那天我用 dsh 让它分析一个开源项目并生成改造方案全程调用模型十几次云端模式几分钟跑完本地模式等得我心慌。5.2 多轮 agent 场景下的上下文稳定性本地 MLX 4-bit 除了慢还有长上下文时的稳定性问题。32K 上下文对 64GB 统一内存来说不算超配但 MLX 实现里长上下文的 KV cache 管理和量化引入的精度损失叠加会导致模型在后面的轮次里开始重复输出或者漏掉前面提到过的关键信息。云端 AWQ 版本没有这个问题。vLLM 的 PagedAttention 对 KV cache 的管理很成熟AWQ 的精度损失在 27B 参数规模下也几乎感知不到。同样是一轮 8000 token 的上下文本地跑到后半段开始输出降智云端依然能把前文提到的变量名、路径、约束条件全部对上。这一点对 agent 场景非常关键因为 dsh 的核心工作方式就是来回调度工具、翻阅结果、继续推理上下文连续性差了整个链路就崩了。5.3 成本核算与混合部署建议按 MI210 大约每小时 12 元、每天实际占用 3 小时算一个月大概 1000 元出头。对比本地解决方案你要么花大价钱买一张 48GB 专业卡要么等着 64GB 的 Mac 慢慢吞吞地跑前者一次性投入大后者时间成本高。我的建议是混合部署日常轻量对话、工具调用、短文档处理走本地 8B 的 Q8_0 或 4-bit 量化响应快零边际成本。代码生成、长文本分析、多步规划切到云端 27B AWQ质量和速度都很稳。夜间批量任务headless 模式下全部走云端利用低峰时段的实例优惠价。最后分享一个小技巧如果你和我一样要同时维护本地 8B 和云端 27B 两套环境尽量把它们都封装成 OpenAI 兼容接口dsh 里的 profile 切换只是改一行base_url的事。把模型服务标准化之后以后想换更大的模型、换更强的 GPU 实例dsh 这边完全不用动你只需要在云端重新拉起一个容器就好。这个架构带来的灵活度是这次折腾下来我觉得最值的地方。
返回列表