Ornith 开源模型本地部署:替代 Qwen3.6 的完整实战
本文最后更新于 2026年7月12日 晚上
背景:为什么需要替代 Qwen3.6
本地部署大语言模型,硬件永远是第一约束。双卡 RTX 2080 Ti(22GB 魔改版)的显存总量约 22GB,面对 35B 参数的 MoE 模型,可用选项其实不多。
此前使用的 Qwen3.6-35B-A3B 在多数场景下表现尚可,但有两个问题一直悬而未决:
推理速度不理想:在本地硬件上,Qwen3.6 的 token 生成速度始终在 40-60 t/s 区间,长输出场景下延迟明显
社区活跃度下降:Qwen3.6 发布后,社区微调版本和优化方案较少,后续迭代前景不明
某天,社区中出现了一个新的名字——Ornith。基于 Qwen3.5-35B-A3B 优化训练,社区基准测试显示多项指标超越 Qwen3.6。更关键的是,这个模型完全兼容现有的 llama.cpp 部署方案,不需要额外适配。
部署全流程
硬件与软件环境
组件
规格
显卡
双 RTX 2080 Ti(22GB 魔改版)
推理引擎
llama.cpp(models-preset 多模型模式)
量化格式
Q4_K_M GGUF
代理层
new-api(透明转发,注册模型名)
张量分片
tensor-split 0.7:0.3
第一步:下载与量化
Ornith 的 GGUF 量化版可以从 Hugging Face 直接下载。选择 Q4_K_M 量化级别——这是一个平衡点:Q4_K_M 相比 Q4_K_S 保留更多关键层精度,相比 Q5/Q6 则节省约 4-6GB 显存。
1 | |
第二步:llama.cpp 配置(models.ini)
本地 llama.cpp 运行在 models-preset 模式下,通过 INI 文件管理多个模型。Ornith 的配置如下:
1 | |
注意 tensor-split = 0.7,0.3 在全局配置中设定——这是双卡张量分片的关键参数。0.7:0.3 的比例意味着第一张卡承担 70% 的计算量,第二张卡承担 30%。这个比例根据显存大小和 PCIe 带宽反复调优得出。
第三步:new-api 模型注册
在 new-api 代理层将 Ornith 注册为 Qwen/Qwen3.5-35B-A3B-Ornith。这样做的好处是:
可追溯:模型名包含基座和优化版本信息
兼容性:客户端无需修改,只需换模型名
区分度:和原版 Qwen3.5 区分开来,方便对比测试
1 | |
第四步:重启与验证
修改 models.ini 后,必须重启 llama.cpp 主进程(systemd service)才能生效。局部卸载或 reload API 都不行——主进程缓存了 preset 配置。
1 | |
验证方式:发送测试请求,用 GET /v1/models 确认子进程命令行参数中包含 --jinja 和 --chat-template-file。
踩坑实录:Chat Template 兼容性
部署中遇到的最大问题不是性能,而是 chat template 兼容性。
Ornith 的 GGUF 内嵌 jinja 模板中包含 raise_exception() 调用——这是 Qwen 系列模板的常规做法,用于校验输入格式。但 llama.cpp 的 minijinja 引擎实现不完全兼容标准 Python Jinja2,导致 raise_exception() 在解析阶段就崩溃。
错误现象:
1 | |
100% 可复现:任何没有 role: user 的请求(包括 tools 探测请求)都会触发。这意味着正常的 MoA 聚合请求、system-only 消息都会失败。
修复方案:使用 --chat-template-file 覆盖 GGUF 内嵌模板,不修改模型文件本身。
1 | |
修复版模板删除了两处 raise_exception:
raise_exception('No user query found in messages.')raise_exception('System message must be the beginning.')
对正常输入(有 system + user),渲染输出 byte-for-byte 一致,不影响任何功能。
性能实测:104 t/s 背后的 MoE 原理
测试结果
测试项
数值
模型参数量
35B(MoE,激活参数约 3.5B)
量化
Q4_K_M
上下文长度
262K
长输出速度
104 t/s
首 token 延迟
~1.2s
理论分析:为什么 104 t/s 是合理的
Ornith 是 MoE(Mixture of Experts)架构。35B 总参数中,每次推理只激活约 3.5B 参数(10% 激活率)。Q4_K_M 量化后,激活参数大约占用 3.5B × 0.5 bytes ≈ 1.75 GB。
但实际上,推理过程中需要加载的不仅仅是激活参数。MoE 路由机制需要读取所有 expert 的权重头部信息来决定路由。加上 KV cache(262K 上下文约 2-3 GB)、中间激活值,单次推理的实际显存占用约 8-9 GB/token。
对双卡 RTX 2080 Ti(22GB 总显存),理论计算如下:
全参数加载(假设没有 MoE 路由优化):35B × 0.5 bytes ≈ 17.5 GB → 接近显存上限,速度约 40-50 t/s
MoE 路由优化生效(只读取激活 expert):8-9 GB/token → 显存压力小,带宽利用率更高
理论全参数吞吐上限约 47 t/s。实测 104 t/s 超出理论值一倍以上——这成为 MoE 路由优化生效的铁证:llama.cpp 的 MoE 实现只读取被路由选中的 expert 权重,而非加载全部参数。
全网 Benchmark 对比
硬件配置
模型
量级
速度
来源
2×RTX 2080 Ti (22GB)
Ornith-35B
Q4_K_M
104 t/s
本文
2×RTX 2080 Ti
Mixtral 8x7B
Q4_K_M
~100 t/s
Level1Techs
2×RTX 2080 Ti
Qwen3.6-35B
Q4_K_M
~42 t/s
社区实测
2×RTX 2080 Ti
DeepSeek-V2-Lite
Q4_K_M
~120 t/s
insiderllm
1×RTX 4090 (24GB)
Ornith-35B
Q4_K_M
~45 t/s
社区估算
2000 系列的双卡方案在 35B 量级 MoE 模型上,天花板大约是 100-130 t/s。Ornith 的 104 t/s 达到了约 70% 的硬件利用率,属于合理的高水平。
Qwen3.6 vs Ornith:性能对比
维度
Qwen3.6-35B-A3B
Ornith-1.0-35B (基于 Qwen3.5)
推理速度
~42 t/s
104 t/s (2.5×)
社区基准
基准线
多项超越 Qwen3.6
模板兼容性
原生支持
需 chat-template-file 修复
社区活跃度
下降
上升(新模型)
部署复杂度
低
中(模板修复 + 首次配置)
经验总结
-
MoE 的路由优化不是理论概念,而是可实测的:实测值超过全参理论值,是验证路由优化是否生效最直接的方法。如果实测速度接近全参理论值,说明路由优化可能未生效(比如某些推理引擎的 MoE 实现是全部加载再路由)。
-
Chat template 兼容性是跨模型部署的常见坑点:不同推理引擎(llama.cpp vs vLLM vs SGLang)对 jinja 的解析能力不同。raise_exception() 在 Python Jinja2 中正常,在 minijinja 中崩溃。跨模型迁移时,务必检查模板兼容性。
-
模型名注册策略很重要:用 基座-优化版本 的命名格式(如 Qwen3.5-35B-A3B-Ornith),既保留了可追溯性,又便于在代理层做 A/B 测试。
-
双卡 2080 Ti 的 104 t/s 不是极限:从全网数据看,相同硬件配置下的天花板是 100-130 t/s。如果优化 tensor-split 比例、调整 batch size,还有约 25% 的提升空间。