最近折腾了一件惦记很久的事:在自己的 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

我第一反应是把它挪到一个”干净”的目录里,后来忍住了,事实证明是对的:

  1. llama-server 支持绝对路径,-m 直接指过去就行,文件放哪根本无所谓;
  2. Unsloth 的目录自带版本哈希,挪出来反而丢了更新记录;
  3. GGUF 是通用格式,引擎只认路径,不需要你替它”整理”。

唯一要注意的是:路径里别有中文和空格,否则命令行解析可能直接挂掉。

启动命令

最后稳定运行的命令长这样:

1
2
3
4
5
6
7
8
9
10
11
llama-server.exe ^
-m "你的模型.gguf 完整路径" ^
-ngl 99 ^
-c 32768 ^
--flash-attn on ^
--load-mode none ^
--cache-type-k q4_0 ^
--cache-type-v q4_0 ^
--api-key abc-12345 ^
--host 0.0.0.0 ^
--port 8080

几个关键参数:

  • -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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@echo off
chcp 65001 >nul
title Bonsai-27B-PQ2 - PrismML Server

set MODEL=D:\UnslothModels\hub\models--prism-ml--...\Ternary-Bonsai-2-27B-PQ2_0.gguf

llama-server.exe ^
-m "%MODEL%" ^
-ngl 99 ^
-c 32768 ^
--flash-attn on ^
--load-mode none ^
--cache-type-k q4_0 ^
--cache-type-v q4_0 ^
--api-key abc-12345 ^
--host 0.0.0.0 ^
--port 8080

pause

用的时候只需要把 MODEL 那一行换成你自己的实际路径。

写在最后

回头看,这套方案其实挺朴素的:专用引擎 + 绝对路径 + OpenAI 兼容前端 + 防火墙放行。没有 Docker,没有 Python 环境,双击一个 bat 文件就能跑。对只想安安静静用本地模型的人来说,这种”没什么技术含量但真的能用”的方案,可能才是最需要的。

本地模型的意义对我来说很实际:不烧 token、不担心内容出域、断网也能用。16G 显存能跑动 27B,这件事本身就值得记录一下。


我是一个正在走新西兰技术移民流程的独立开发者,这个博客记录我的 Vibe Coding 实战、一人公司踩坑实录和移民亲历。