在 2×16GB RTX 4080 的受限环境里,我最终把 Qwen3.5-35B-A3B 跑到了 120 tokens/s,并且把 262K 上下文稳定接进了 Dify 工作流。
这篇文章不是“理论解析”,而是一次完整的实战复盘:从 vLLM 踩坑到 llama.cpp 落地,再到 Dify 集成与排错闭环。
如果你也在做本地大模型部署,可以重点看这 4 块:
vLLM 为什么暂时不适合这次场景llama.cpp + GGUF 在双 16G 卡上的参数组合Dify 接入时 No user query found 的根因可直接复用的运维与排错命令
一、背景与硬件环境
1.1 部署背景
原有的dify日志分析工作流基于 Qwen3-32B-AWQ 模型,虽然能工作,但在处理超长上下文(如一天的全量日志)时显得力不从心。得知阿里新开源的 Qwen3.5-35B-A3B 模型支持 262K 上下文,我决定升级模型以获得更好的长文本处理能力。
1.2 硬件配置
我的部署环境是一台双卡服务器,但说实话配置并不豪华:
- GPU:2 × NVIDIA GeForce RTX 4080(每张只有 16GB 显存,共 32GB)
- 内存:128GB
- 存储:4TB
- 操作系统:Ubuntu 24.04
尴尬的现实:两张 16G 4080 总显存 32GB,而 Qwen3.5-35B 即使量化后也需要约 12-14GB。这意味着我必须精打细算每一兆显存,tensor-split 参数必须精确分配。
二、第一轮尝试:vLLM 部署
2.1 安装依赖
一开始我沿用之前部署 Qwen3-32B-AWQ 的经验,选择 vLLM:
# 创建虚拟环境(Ubuntu 24.04 强制要求)
cd /vllm
python3 -m venv vllm-env
source vllm-env/bin/activate
# 安装 vLLM
pip install vllm
2.2 下载模型(FP8 版)
从 ModelScope 下载 FP8 量化版,约 37.5GB:
# 安装 modelscope
pip install modelscope
# 下载模型到指定目录
modelscope download --model Qwen/Qwen3.5-35B-A3B-FP8 --local_dir ./Qwen/Qwen3.5-35B-A3B-FP8
下载过程:37.5GB 的文件,企业内网下载了约 40 分钟。
2.3 首次启动尝试
vllm serve /vllm/models/Qwen/Qwen3.5-35B-A3B-FP8 \
--tensor-parallel-size 2 \
--max-model-len 262144 \
--gpu-memory-utilization 0.9
报错 1: Value error, The checkpoint you are trying to load has model type 'qwen3_5_moe' but Transformers does not recognize this architecture
解决: Transformers 版本太旧,需要升级
pip install --upgrade transformers
2.4 版本冲突的噩梦
升级后发现新问题:
vllm 0.16.0 requires transformers<5,>=4.56.0, but you have transformers 5.3.0
这就是 Python 依赖地狱的典型场景——vLLM 要求 transformers <5,但 Qwen3.5 需要较新的版本。我尝试了各种组合:
- transformers 4.48.3 + vLLM 0.16.0(报错:缺少 Gemma3Config)
- transformers 4.49.0 + vLLM 0.16.0(同样缺少 Gemma3Config)
- transformers 5.3.0 + 升级 vLLM(但 vLLM 最新版仍未完全支持)
最终报错:
Model architectures ['Qwen3_5MoeForConditionalGeneration'] are not supported for now.
查看 vLLM 支持的模型列表,确实没有 Qwen3.5 的 MoE 架构。这意味着 vLLM 官方还未支持 Qwen3.5-35B-A3B。
三、转向 llama.cpp(成功方案)
3.1 为什么选择 llama.cpp
- 对新模型的支持通常比 vLLM 更快
- GGUF 格式在社区中广泛使用,量化版本更成熟
- 对双卡并行有完善支持,特别适合我这种 8G*2 的尴尬配置
3.2 编译安装
# 浅克隆(避免网络问题)
git clone --depth 1 https://github.com/ggml-org/llama.cpp
cd llama.cpp
mkdir build && cd build
# 配置 CUDA 支持(RTX 4080 是 sm89)
cmake .. -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES="89"
# 编译
make -j$(nproc)
# 编译完成后,可执行文件在 build/bin/ 下
ls -la bin/llama-server # 确认编译成功
3.3 下载 GGUF 模型(详细过程)
根据社区反馈,unsloth 的 MXFP4_MOE 量化版效果最好,模型文件约 21GB,比 FP8 版小了近一半,更适合我的 16GB 显存环境。
方法一:使用 huggingface-cli
# 安装 huggingface-hub
pip install huggingface-hub
# 注意:这是 GGUF 格式,不是 FP8!
~/.local/bin/huggingface-cli download unsloth/Qwen3.5-35B-A3B-GGUF \
--include "Qwen3.5-35B-A3B-MXFP4_MOE.gguf" \
--local-dir /vllm/models/llama.cpp \
--local-dir-use-symlinks False
方法二:使用 Python 脚本(支持断点续传,推荐)
# 创建 download_model.py 文件
cat > /vllm/download_model.py << 'EOF'
from huggingface_hub import hf_hub_download
import os
repo_id = "unsloth/Qwen3.5-35B-A3B-GGUF"
filename = "Qwen3.5-35B-A3B-MXFP4_MOE.gguf" # GGUF 格式!
local_dir = "/vllm/models/llama.cpp"
os.makedirs(local_dir, exist_ok=True)
print(f"开始下载 {filename} (约 21GB,请耐心等待)...")
downloaded_path = hf_hub_download(
repo_id=repo_id,
filename=filename,
local_dir=local_dir,
local_dir_use_symlinks=False,
resume_download=True # 支持断点续传!
)
print(f"下载完成!文件保存在: {downloaded_path}")
EOF
# 执行下载脚本
python /vllm/download_model.py
下载过程实录:
Qwen3.5-35B-A3B-MXFP4_MOE.gguf: 1%| 252M/21.6G [01:05<1:07:47, 5.24MB/s]
Qwen3.5-35B-A3B-MXFP4_MOE.gguf: 29%| 6.31G/21.6G [17:11<1:07:06, 3.79MB/s]
Qwen3.5-35B-A3B-MXFP4_MOE.gguf: 100%| 21.6G/21.6G [55:46<00:00, 6.45MB/s]
整整下载了 55 分钟,中间网络断了一次,好在 resume_download=True 自动续传。
3.4 启动服务(双卡并行,8G*2 的精确分配)
关键参数是 --tensor-split 8,8,将模型按显存比例分配到两张卡——每张卡刚好 8GB,这是为我的硬件量身定制的:
# 进入 llama.cpp 的 build 目录
cd /vllm/llama.cpp/build
# 启动服务器(注意:模型名称去掉了 .gguf 后缀,只保留别名)
./bin/llama-server \
--model /vllm/models/llama.cpp/Qwen3.5-35B-A3B-MXFP4_MOE.gguf \
--alias "Qwen3.5-35B-A3B" \ # 这里去掉了 gguf,只保留模型名
--host 0.0.0.0 \
--port 8000 \
--ctx-size 262144 \
--n-gpu-layers 99 \
--tensor-split 8,8 \ # 8G + 8G,精确分配!
--main-gpu 0 \
--flash-attn auto \
--mlock \
--no-mmap
成功标志:
ggml_cuda_init: found 2 CUDA devices:
Device 0: NVIDIA GeForce RTX 4080, compute capability 8.9, VMM: yes
Device 1: NVIDIA GeForce RTX 4080, compute capability 8.9, VMM: yes
llama_model_load: using multiple GPUs: tensor split 8,8
HTTP server listening on http://0.0.0.0:8000
3.5 性能验证
新开一个终端,用 nvidia-smi 查看显存占用:
nvidia-smi
真实占用情况:
GPU 0: 15639MiB / 16376MiB # 约 15.6GB
GPU 1: 14171MiB / 16376MiB # 约 14.2GB
双卡均衡负载,各留约 1-2GB 余量——对于两张 8G 卡来说,这已经是极限压榨了。
测试推理速度:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3.5-35B-A3B", # 注意:这里用的是 alias,不带 gguf
"messages": [{"role": "user", "content": "你好,介绍一下你自己"}]
}'
返回结果中包含 predicted_per_second: 120.71,即 120 tokens/s——这个速度让我很惊喜,毕竟显存已经快撑爆了。
3.6 设置系统服务(开机自启)
为了让模型服务在后台稳定运行,并确保服务器重启后自动启动,我配置了 systemd 服务。
创建服务配置文件
sudo vim /etc/systemd/system/llama-server.service
写入以下内容:
[Unit]
Description=llama.cpp server for Qwen3.5-35B-A3B
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/vllm/llama.cpp/build
ExecStart=/vllm/llama.cpp/build/bin/llama-server \
--model /vllm/models/llama.cpp/Qwen3.5-35B-A3B-MXFP4_MOE.gguf \
--alias "Qwen3.5-35B-A3B" \
--host 0.0.0.0 \
--port 8000 \
--ctx-size 262144 \
--n-gpu-layers 99 \
--tensor-split 8,8 \
--main-gpu 0 \
--flash-attn auto \
--mlock \
--no-mmap
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
启用并启动服务
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 启用开机自启
sudo systemctl enable llama-server
# 启动服务
sudo systemctl start llama-server
# 查看服务状态
sudo systemctl status llama-server
# 查看实时日志
sudo journalctl -u llama-server -f
服务管理常用命令:
sudo systemctl stop llama-server # 停止服务
sudo systemctl restart llama-server # 重启服务
sudo journalctl -u llama-server --since "5 minutes ago" # 查看最近5分钟日志
3.7 使用 screen 作为备选方案
如果不想配置 systemd,也可以使用 screen 临时后台运行:
# 安装 screen
apt install screen -y
# 创建新的 screen 会话
screen -S llama
# 在 screen 中启动服务
cd /vllm/llama.cpp/build
./bin/llama-server \
--model /vllm/models/llama.cpp/Qwen3.5-35B-A3B-MXFP4_MOE.gguf \
--alias "Qwen3.5-35B-A3B" \
--host 0.0.0.0 \
--port 8000 \
--ctx-size 262144 \
--n-gpu-layers 99 \
--tensor-split 8,8 \
--main-gpu 0 \
--flash-attn auto \
--mlock \
--no-mmap
# 按 Ctrl+A 然后按 D 退出 screen(服务继续后台运行)
# 重新连接查看状态
screen -r llama
四、Dify 集成配置
4.1 添加模型供应商
在 Dify 中,选择 OpenAI-API-compatible 供应商:
| 配置项 | 值 |
|---|---|
| 模型名称 | Qwen3.5-35B-A3B(和 --alias 保持一致) |
| API Key | 任意(如 sk-no-key-required) |
| API Endpoint URL | http://10.128.253.45:8000(注意不加 /v1) |
| 模型上下文长度 | 262144(从模型元数据获取) |
| Function calling | 根据需要选择 |
关键点:
- Endpoint URL 不要加
/v1,Dify 会自动拼接 - 模型名称必须和启动时的
--alias一致,我的是Qwen3.5-35B-A3B,不带 .gguf 后缀
4.2 模型参数配置
根据日志分析场景,我最终选择了以下参数:
- Temperature: 0.6(平衡准确性与创造性)
- Top P: 0.95
- Top K: 20
- Max Tokens: 4096
五、Dify 工作流中的关键问题
5.1 问题现象
在工作流中配置好 LLM 节点后,反复出现错误:
No user query found in messages
Error: Jinja Exception: No user query found in messages
5.2 排查过程
-
检查变量引用:前节点输出是
result,LLM 节点 context 已正确关联 - 添加调试代码节点:确认数据确实传递到了 LLM 节点
- 查看 Dify 日志:错误发生在模型调用前的模板渲染阶段
5.3 根本原因
Qwen3.5-35B-A3B 模型模板必须要求存在 user message。我的初始提示词配置只有 system role,缺少 user role。
5.4 解决方案
修改 LLM 节点的 prompt_template,显式添加 user role:
prompt_template:
- role: system
text: |
###角色
你是一名资深网络运维专家和日志分析专家。
...(详细的 system prompt)
- role: user
text: |
以下是网络设备异常日志的聚合 JSON 数据:
{{#context#}}
请按照 system 中的规则生成日志异常分析报告。
5.5 经验总结
对于 Qwen3.5 系列模型,在 Dify 中配置 LLM 节点时必须注意:
- 必须有 user message,不能只有 system message
- user message 中要明确说明输入数据是什么
- 变量引用
{{#context#}}必须放在 user message 中 - 模型名称不要带
.gguf后缀
六、最终工作流结构
我的完整工作流如下:

七、排错思路总结
7.1 模型部署阶段
| 问题 | 排查方向 | 解决方案 |
|---|---|---|
| Transformers 版本不兼容 | 检查 vLLM 支持的模型 | 改用 llama.cpp |
| 下载中断 | 网络稳定性 | Python 脚本 + resume_download |
| 双卡负载不均 | 检查 tensor-split | 按显存精确分配 8,8 |
| 显存不足 | 查看 nvidia-smi | 调整 n-gpu-layers,使用 GGUF |
| 服务不能后台运行 | 进程管理 | systemd 服务或 screen |
7.2 Dify 集成阶段
| 问题 | 排查方向 | 解决方案 |
|---|---|---|
| API Endpoint 错误 | 检查是否加了 /v1 | 去掉 /v1 |
| 模型调用失败 | curl 直接测试 | 验证模型服务:curl http://localhost:8000/v1/models
|
| 变量引用错误 | 添加调试代码节点 | 打印实际传递的数据 |
| No user query found | 检查 prompt_template | 添加 user role |
| 模型名称错误 | 检查 alias | 确保和启动时的 --alias 一致,不带 .gguf |
7.3 服务运维常用命令
# 查看服务状态
systemctl status llama-server
# 查看实时日志
journalctl -u llama-server -f
# 测试模型服务
curl http://localhost:8000/v1/models
# 查看显存占用
watch -n 1 nvidia-smi
八、性能数据与结论
最终部署成功的 Qwen3.5-35B-A3B 在两张 8G 4080 上表现如下:
- 模型格式:GGUF (MXFP4_MOE 量化),21GB
- 服务别名:Qwen3.5-35B-A3B(不带 .gguf 后缀)
- 推理速度:120 tokens/s
- 上下文长度:262K(满血)
- 显存占用:约 30GB(双卡分摊,GPU0 15.6G,GPU1 14.2G)
- 服务稳定性:systemd 管理,开机自启,持续运行一周无崩溃
这次从 vLLM 转向 llama.cpp 的经历让我深刻体会到:
- 8G2 的显卡也能跑 35B 模型*,关键在于选对量化格式(GGUF)和精确分配 tensor-split
- 新模型发布初期,llama.cpp 往往比 vLLM 支持更快
- 模型名称不要带 .gguf 后缀,alias 要单独设置
- Dify 中配置 LLM 节点时,user message 是必须的
- systemd 服务配置对于生产环境至关重要
希望这份记录能帮助其他同样在探索 Qwen3.5 本地部署的同行少走弯路。
CTA:资料包领取
如果你需要我这次实战里的可复用材料,关注公众号后私信关键词:Qwen35部署,我会把以下资料发你:
- Qwen3.5 的 LLM 提示词模板(含 system + user 结构)
- llama.cpp 启动与 systemd 服务模板