最近折腾了一件惦记很久的事:在自己的 Windows 机器上跑一个本地大模型,前端接 DeepSeek Harness,顺便让局域网里的其他设备也能用。最后跑通的是 PrismML 出的 Bonsai 2 27B——一个三值量化、权重压到 6~7GB 的 27B 模型。
过程不算顺利,中间有几个坑只有亲手跑一遍才会发现。这篇把完整过程记下来,给同样想在本地跑模型的人省点时间。
为什么选 Bonsai 2
吸引我的就两点:一是显存占用低,16G 显存的消费级显卡能把整个模型装下,不用再做量化妥协;二是它用了混合注意力架构,KV Cache 比常规模型小不少,开长上下文时显存压力小很多。
但天下没有白捡的便宜。Bonsai 2 用的是非标准 GGUF 类型(type 142/143),只有 PrismML 定制的 llama.cpp 分支能加载。我一开始拿普通版 llama.cpp 试,直接报 invalid ggml type;Ollama 和 LM Studio 也一样不行。所以推理引擎这一步没有替代品,必须用 PrismML 的预编译包。
我的环境
- 显卡:RTX 4070 Ti SUPER 16G,内存 32G
- 系统:Windows 11,显卡驱动 560+
- 推理引擎:PrismML 预编译的
llama-server.exe - 前端:DeepSeek Harness(下文简称 DSH)
顺带说一个很多人纠结的问题:装了 CUDA 13.4 的驱动,能不能跑 CUDA 13.3 编译的包?答案是能。驱动对 CUDA 的支持是向下兼容的,PrismML 包里自带的 runtime DLL 跑在更高版本的驱动上没有任何问题。我在这件事上白白犹豫了半小时,希望你们不用。
模型放在哪:别动它
模型是从 Unsloth Desktop 下载的,默认路径很深,长这样:
1 | D:\UnslothModels\hub\models--prism-ml--...\snapshots\...\Ternary-Bonsai-2-27B-PQ2_0.gguf |
我第一反应是把它挪到一个”干净”的目录里,后来忍住了,事实证明是对的:
llama-server支持绝对路径,-m直接指过去就行,文件放哪根本无所谓;- Unsloth 的目录自带版本哈希,挪出来反而丢了更新记录;
- GGUF 是通用格式,引擎只认路径,不需要你替它”整理”。
唯一要注意的是:路径里别有中文和空格,否则命令行解析可能直接挂掉。
启动命令
最后稳定运行的命令长这样:
1 | llama-server.exe ^ |
几个关键参数:
-ngl 99:所有层卸载到 GPU;-c 32768:上下文 32K,后面会讲这个值怎么定的;--flash-attn on:开 Flash Attention,提速明显;--load-mode none:禁用内存映射,避免 Windows 下页面抖动;--cache-type-k/v q4_0:KV Cache 量化到 Q4,省显存的大头在这里;--host 0.0.0.0:向局域网开放,只在本地用的话可以不写。
一个真实的坑:–load-mode
这个值得单独说。旧版 llama.cpp 用 --no-mmap 禁用内存映射,但新版把这个参数废弃了,启动时会打印:
1 | DEPRECATED: --mmap and --no-mmap are deprecated. use --load-mode instead |
新的合法取值是 auto / none / mmap / mlock / mmap+mlock / dio,对应旧 --no-mmap 语义的是 --load-mode none。我最开始凭直觉填了个 off,程序直接报错退出,连警告都没有。网上不少教程还停留在 --no-mmap 时代,照抄会踩坑。
接入 DeepSeek Harness
DSH 兼容 OpenAI API 格式,配置很简单:
- Provider ID:
local-bonsai(任意小写标识) - 显示名称:
Bonsai 27B - API 地址:
http://127.0.0.1:8080/v1——注意结尾的/v1,漏了就连不上 - API 协议:
OpenAI Chat Completions - API 密钥:
abc-12345,跟启动命令里的一致就行,本地用随便填个占位符
保存切换后,DSH 自带的联网搜索、Agent 这些功能都能正常挂在本地模型上用。
让局域网设备也能用
服务端这边,启动命令里已经有 --host 0.0.0.0,只差防火墙放行 8080 端口(管理员 PowerShell 执行一次即可):
1 | netsh advfirewall firewall add rule name="llama-server-8080" dir=in action=allow protocol=TCP localport=8080 |
客户端那边,把 DSH 里 API 地址的 127.0.0.1 换成服务端的局域网 IP,比如 http://192.168.x.x:8080/v1。
验证网络是否通有个笨办法但很直接:用另一台设备的浏览器访问 http://服务端IP:8080,能打开 llama-server 自带的页面,就说明通路没问题。
上下文到底能开多大
Bonsai 2 官方标称上下文上限 262K。我在 16G 显存上实测了一圈:
| 上下文 | 实际表现 |
|---|---|
| 32K | 稳定,速度正常 |
| 64K | 稳定,速度略有下降 |
| 128K | 没崩,但显存基本顶满 |
| 160K+ | 能跑,首 token 延迟明显变长 |
测试方法很朴素:每次只改 -c 重启服务,发一条固定的 prompt,盯三个指标——任务管理器里的专用显存是不是顶到 15.5G 以上、首 token 延迟是不是从几秒变成几十秒、生成速度有没有断崖式下跌。
我的结论是:日常用 32K 到 64K 最舒服;128K 留给偶尔的长文档;160K 往上属于”能跑但不想用”,首 token 等得让人失去耐心。
踩坑速查
把这次遇到的问题归拢一下,方便以后自己查:
| 现象 | 原因 | 解法 |
|---|---|---|
invalid ggml type 142 |
用了非 PrismML 版 llama.cpp | 换 PrismML 预编译包 |
--load-mode: invalid value |
填了 off 之类的非法值 |
改成 none |
| 局域网连不上 | 防火墙拦截 | 放行 8080 端口 |
| 生成速度异常慢 | Windows WDDM 内存管理抖动 | 加 --load-mode none,必要时降低 -c |
| 启动报端口占用 | 8080 被别的程序占了 | 换 --port 8081 之类的端口 |
一键启动脚本
最后把启动命令固化成了一个 bat,放在 llama-server.exe 同目录,双击就跑:
1 | @echo off |
用的时候只需要把 MODEL 那一行换成你自己的实际路径。
写在最后
回头看,这套方案其实挺朴素的:专用引擎 + 绝对路径 + OpenAI 兼容前端 + 防火墙放行。没有 Docker,没有 Python 环境,双击一个 bat 文件就能跑。对只想安安静静用本地模型的人来说,这种”没什么技术含量但真的能用”的方案,可能才是最需要的。
本地模型的意义对我来说很实际:不烧 token、不担心内容出域、断网也能用。16G 显存能跑动 27B,这件事本身就值得记录一下。
我是一个正在走新西兰技术移民流程的独立开发者,这个博客记录我的 Vibe Coding 实战、一人公司踩坑实录和移民亲历。