Qwen3.8-27B-Uncensored 本地部署实录:P40 24G + llama.cpp + llama-swap(Q4_K_M / 192K 上下文 / 原生工具调用 / 实测 10 t/s)
关键词:Qwen3.8-27B · 192K 上下文 · Q4_K_M 量化 · llama.cpp · llama-swap · P40 24G · GGUF · KV 量化 · 本地大模型部署
继上一篇《P40 24G 显卡本地大模型部署全流程》之后,这套 llama.cpp + llama-swap 推理栈的"生产模型"已经升级到了 Qwen3.8-27B-Uncensored(Q4_K_M / 192K 上下文,另配思考变体)。本文单独记录这次升级的完整过程:模型文件、llama-server 启动参数、llama-swap 配置、实测性能、GPU 负载,以及客户端(OpenAI 兼容接口 / Agent 框架)的接入方式。
文中涉及的 API Key、frp token、公网 IP、内网 IP 均已做脱敏处理,请替换为你自己的值。基础环境(驱动、llama.cpp 编译、frp 穿透、风扇温控)沿用上一篇,本文不再重复,只在关键处交叉引用。
一、模型与量化方案
| 项目 | 配置 |
|---|---|
| 模型 | Qwen3.8-27B-Uncensored(本地主力模型) |
| 量化 | Q4_K_M(unsloth 转换) |
| 文件大小 | 16.8 GB(Q4_K_M.gguf) |
| 显存占用(实测) | 约 20 GB / 24 GB(含 KV cache 与运行时开销) |
| 上下文 | --ctx-size 196608(192K;两个变体同参数) |
| 推理引擎 | llama.cpp 0.4.0-dev(CUDA 12.8,commit 9113cc1) |
| NVIDIA 驱动 | 580.178.04(apt-mark hold 锁定) |
选 Q4_K_M 的原因:现在并发降到 --parallel 1(单路最稳),权重 16.8G + 192K KV cache(q4_0 量化约 4G)实测共占约 20G,24G 显存放得下还留 ~4G 余量,所以直接用精度更高的 Q4_K_M。早期为兼容 --parallel 2 + per-slot 才退到 Q3_K_M(13G),单并发下没必要再牺牲精度。
二、llama-server 启动参数
这是本次升级的核心。完整参数如下(llama-swap 里以 cmd 形式配置,见第三节):
/usr/local/bin/llama-server
--model /data/models/Qwen3.8-27B-Uncensored-Q4_K_M.gguf
--gpu-layers 99
--ctx-size 196608
--n-predict 49152
--parallel 1
--kv-unified
--cache-type-k q4_0
--cache-type-v q4_0
--batch-size 2048
--jinja
--chat-template-kwargs '{"enable_thinking": false}'
--host 127.0.0.1
--port ${PORT}
逐条解释:
| 参数 | 作用 |
|---|---|
--gpu-layers 99 | 全部层上 GPU(P40 单卡,99 即"全部") |
--ctx-size 196608 | 上下文窗口 192K(196608),给长文写作留余量;两个变体同值 |
--kv-unified | K/V 共用统一 KV 缓存池,省显存。单并发(--parallel 1)下不再需要 per-slot 分槽 |
--cache-type-k/v q4_0 | KV cache 量化到 4bit。192K 上下文的 KV 约 4G,是 24G 显存跑得动 27B 的关键 |
--batch-size 2048 | prompt 处理批大小。P40 显存大,开 2048 让长 prompt 的 prefill 明显更快 |
--jinja | 启用 Jinja 模板引擎,Qwen3.8 原生 chat 格式 + 原生工具调用(function calling)。不加这个参数工具调用不会生效 |
和上一篇 Qwen3-14B 的 YaRN 区别:Qwen3-14B 原生上下文只有 40K,上 64K 必须开 --rope-scaling yarn --rope-scale 1.6 --yarn-orig-ctx 40960。Qwen3.8-27B 直接开 --ctx-size 196608(192K)即可,不需要任何 rope 扩展,省掉了 YaRN 调参这一整类坑。
三、llama-swap 配置(新增模型条目)
配置文件 /opt/llama-swap/config.yaml。Qwen3.8 加入现有的 main-gpu 互斥组,与其他模型热切换:
listen: 0.0.0.0:8080
apiKeys:
- "你的API-Key"
groups:
main-gpu:
exclusive: true # 互斥组:一次只加载一个模型
models:
- qwen3.8-27b-uncensored-q4km-p40
- qwen3.8-27b-uncensored-q4km-think-p40
models:
- name: "qwen3.8-27b-uncensored-q4km-p40"
file: "/data/models/Qwen3.8-27B-Uncensored-Q4_K_M.gguf"
group: main-gpu
args:
--n-gpu-layers: 99
--ctx-size: 196608
--n-predict: 49152
--parallel: 1
--kv-unified: true
--cache-type-k: "q4_0"
--cache-type-v: "q4_0"
--batch-size: 2048
--jinja: true
--chat-template-kwargs: '{"enable_thinking": false}'
- name: "qwen3.8-27b-uncensored-q4km-think-p40"
file: "/data/models/Qwen3.8-27B-Uncensored-Q4_K_M.gguf"
group: main-gpu
args:
--n-gpu-layers: 99
--ctx-size: 196608
--n-predict: 49152
--parallel: 1
--kv-unified: true
--cache-type-k: "q4_0"
--cache-type-v: "q4_0"
--batch-size: 2048
--jinja: true
--chat-template-kwargs: '{"enable_thinking": true, "reasoning_effort": "low"}'
说明:主力是非思考版 qwen3.8-27b-uncensored-q4km-p40(192K,enable_thinking:false,日常最快),另配思考版 ...-think-p40(192K,q4_0 KV)。${PORT} 由 llama-swap 自动分配(每个模型一个本地端口),客户端永远只打 llama-swap 的 8080 端口,由代理路由到对应模型。新增模型后 systemctl restart llama-swap 即可生效。
四、实测性能
以下数据为部署后通过 API 实测(非估算):
| 指标 | 数值 | 说明 |
|---|---|---|
| 生成速度 | 约 10 t/s(230 token / 23.1s) | Q4_K_M 单卡 decode(parallel 1),P40 的正常水平 |
| KV cache | q4_0 量化 | 192K 上下文 KV 约 4G(q4_0) |
| 并行 | --parallel 1 | 单并发最稳,decode 速度最高 |
横向对比:相比早期 Q3_K_M + parallel 2 记录的 4.8 t/s,现在 Q4_K_M + parallel 1 的 ~10 t/s 提速明显(单并发不再争抢带宽)。~10 t/s 仍不适合做低延迟的实时对话,但跑长文生成(小说、报告、代码库分析)绰绰有余 —— 一个 4000 字的章节约 7 分钟生成完。
五、GPU 负载监控
满载推理时的 nvidia-smi 快照(可持续采样,见上一篇的 p40_hw_monitor 方案):
| 指标 | 数值 | 安全线 |
|---|---|---|
| GPU 温度 | 74~75°C | 83°C 降频线,余量充足 |
| GPU 利用率 | 96~98% | 满载正常 |
| 显存占用 | 20083 / 24576 MiB | 约 82%,有余量 |
| 功耗 | 约 200 W | TDP 250W,80% |
| SM 频率 | 1442 MHz | 无降频 |
结论:温度、功耗都在安全区,没有过热降频。P40 是被动散热(无风扇),温度能稳在 75°C 以下完全依赖上一篇讲的机箱风扇温控脚本(p40-fan.service),这套必须配,否则长时间满载温度会爬到 85°C+ 触发降频。
六、对外 API(frp 穿透)
沿用上一篇的 frp 方案,P40 上的 frpc 配置:
serverAddr = "你的公网服务器IP"
serverPort = 7000
auth.method = "token"
auth.token = "你的-frp-token"
[[proxies]]
name = "p40-llamaswap"
type = "tcp"
localIP = "127.0.0.1"
localPort = 8080
remotePort = 8082 # 公网侧端口,可按需修改
安全提醒(血泪教训):不要把 SSH、ComfyUI 之类的端口映射到公网。我这边只暴露了 8080(llama-swap 带 API Key 鉴权)一个端口,SSH 穿透和 ComfyUI 穿透都注释停用了。公网暴露的端口越少越好,llama-swap 的 API Key 一定要设成强随机值。
七、客户端接入
llama-swap 提供标准 OpenAI 兼容接口,任何支持自定义 base_url 的客户端都能直接接:
| 场景 | base_url |
|---|---|
| 内网直连 | http://你的内网IP:8080/v1 |
| 公网访问 | https://vanys.xyz/v1(vanys 主机 nginx 反代,不暴露端口) |
通用调用示例(curl):
curl http://你的内网IP:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer 你的API-Key" \
-d '{
"model": "qwen3.8-27b-uncensored-q4km-p40",
"messages": [{"role": "user", "content": "你好"}],
"max_tokens": 512,
"temperature": 0.9,
"stream": false
}'
Agent 框架接入(以 Hermes Agent 为例):配 custom provider 即可,model 填 llama-swap 里的模型 ID:
model:
default: qwen3.8-27b-uncensored-q4km-p40
provider: custom
base_url: http://你的内网IP:8080/v1
api_key: 你的API-Key
context_length: 196608
两个容易踩的坑:
- thinking 模式:Qwen3.8 带思考链,默认会消耗大量 token 在 reasoning_content 上,content 可能返回空。需要普通补全时在请求里加
"chat_template_kwargs": {"enable_thinking": false}。 - model 名必须精确匹配:llama-swap 按
models:下的 key 路由,写错一个字符就是 404(no model id could be identified)。切换模型时确认 llama-swap 已完成加载(冷加载 27B 约 3-5 分钟),加载期间的请求会失败,客户端要带重试。
八、踩坑记录
- --jinja 是工具调用的开关:模型文件带工具调用模板,但 llama-server 不加 --jinja 就不会走模板里的 tool 分支,function calling 直接失效。
- Q4_K_M 单并发才够:早期 --parallel 2 + per-slot 时 Q4_K_M(16.8G)显存吃紧,退到 Q3_K_M;现在降到 --parallel 1,Q4_K_M + 192K KV q4_0 约 20G/24G 稳稳运行,精度更高。
- per-slot KV 管理(--parallel 2 时代):并行 2 时不加 --kv-unified-per-slot,两槽 KV 会动态互串,显存峰值不可预测,固定每槽 64K 才可控。现在单并发(--parallel 1)已不需要。
- thinking 吃 token:不开 enable_thinking:false,max_tokens=200 的请求可能整个花光在思考链上,content 为空。批量调用脚本务必逐请求关闭。
- 切换冷加载:llama-swap 换模型要重新加载(27B 约 3-5 分钟)。TTL 设 900 秒,空闲 15 分钟自动卸载;高频切换场景建议把常用模型 ttl 调大或常驻。
- 被动散热必须配温控:P40 没有风扇,长时间满载 90%+ 利用率时温度会持续爬升。p40-fan.service 按温度调机箱风扇 PWM,是温度稳在 75°C 的前提。
九、Hermes Agent 部署踩坑:mnemosyne 记忆 + managed venv
本文的 llama-swap 除了喂 Open-WebUI,主要客户是 Hermes Agent(QQ 机器人 / 出图助手,跑在同一台 p40/k11c 机上)。Hermes 是独立 Python 应用,有自己的 venv 和插件系统,和 llama-swap 互不干扰,但有两个坑。
坑一:mnemosyne 持久记忆插件。Hermes 用 mnemosyne(3.15.1)做长期记忆——本地 embedding 模型(bge-small-zh,512 维)+ SQLite,把对话要点存下来、按语义召回。开关在 config.yaml 的 memory.provider: mnemosyne。引擎和依赖(mnemosyne/fastembed/onnxruntime)必须装在 Hermes 自己的 venv 里。踩点:本机 huggingface.co 直连会超时,embedding 模型一律走 hf-mirror.com(设 HF_ENDPOINT=hf-mirror.com);换过 embedding 模型要 mnemosyne reindex(先备份 DB)。
坑二:managed venv 切换(这次 k11c 的坑)。hermes update 会额外建一个 managed venv(托管 venv,独立于 /usr/local 里那个),gateway 升级切换过去后就用它跑。问题是 /usr/local venv 里手工装的 mnemosyne 插件,managed venv 默认没有——gateway 一切过去,mnemosyne 记忆就静默失效(日志 "reports unavailable",不报错)。排查:① ls -l /proc/$(pgrep -f 'gateway run')/exe 确认 gateway 到底用的哪个 python;② hermes memory status 看 mnemosyne 是否 active;③ 对比两个 venv 里有没有 mnemosyne。修法:给 managed venv 也装上——引擎是纯 Python,直接从 /usr/local venv 拷 site-packages/mnemosyne* 过去即可(不用重下),deps 用 uv 装。预防:以后每次 hermes update 重建 managed venv 后,顺手确认 mnemosyne 在不在,不在就补。
十、小结
一张二手 P40(24G)+ llama.cpp + llama-swap,就能稳定跑 27B 级别的模型:192K 上下文、Q4_K_M、KV q4_0 量化、原生工具调用,实测 decode 约 10 t/s,满载温度 75°C 以内不降频。配合 frp 穿透 + vanys 域名反代,对外就是一个标准的 OpenAI 兼容接口,Open-WebUI、Agent 框架、自写脚本都能直接接。
适合的场景:长文生成、代码分析、本地 Agent、隐私敏感的数据处理。不适合:低延迟实时对话(10 t/s 的体感仍是"打字机速度")。想体验低延迟可以把量化降到 Q2 换速度,或者把任务拆小,按需取舍。
基础环境搭建(llama.cpp 编译、驱动锁定、frp、风扇温控)见同板块的上一篇《P40 24G 显卡本地大模型部署全流程》,本文是它的"升级篇"。有问题欢迎楼下讨论。