# QWen 3.8 27B 新手部署指南

> Qwen3.8-27B 本地部署新手指南：llama.cpp router + pi 在 M4 Pro 上从下模型到跑通 agent，实测 11.4 tok/s。四个真踩进去的坑，以及当模型每秒只吐 11 个 token 时，prompt 该怎么写才能一次成型。

- 原文链接: https://laojin.blog/blog/20260826_local_qwen38_27b_pi_llamacpp
- 作者: 老金
- 发布日期: 2026-08-26
- 标签: 本地大模型, llama.cpp, Qwen3, Apple Silicon, AI Agent

---

![QWen 3.8 27B 新手部署指南](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260826/00_cover.png)

> 最近 Qwen 3.8-27B 很火，因为它几乎能达到近似 Opus 4.6 的效果。去年底，使用 Opus 4.6 可以干很多活了，如果将 Qwen 3.8-27B 部署在本地，相当于有了无限 token 的 Opus 4.6。但在部署过程中还是遇到一些曲折，老金将它们总结成这篇新手指南文章，供大家阅读。

---

## 为什么是这套组合

老金本地部署的组合是 pi + llama.cpp + Qwen3.8-27B。

llama.cpp 负责把模型跑起来。相比 Ollama，它的 router 模式允许一个常驻进程管理多个 GGUF、按需装卸，并且暴露标准的 OpenAI 兼容接口，任何支持自定义 base URL 的客户端都能接。

pi 是 harness，把"模型"变成"能读写文件、能执行命令的 agent"的那一层。它自带 llama.cpp 的一等支持，这点后面会看到既是优势也是坑。

Qwen3.8-27B 在 Q4_K_M 量化下约 16.8 GB，64GB 内存的 M4 Pro 跑起来毫无压力。它带 vision projector 和原生 tool calling，后者是做 agent 的硬门槛。

> **前提**：本文假设你已经装好 Homebrew 和 Node 22.19+（pi 通过 npm 分发），以及 18 GB 以上的可用磁盘空间。

---

## 部署三步：从下载到跑通

![从模型下载到 pi agent 的部署链路](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260826/01_pipeline.png)

### 下载模型

要下两个文件：GGUF 本体（Q4_K_M 约 16.8 GB）和 vision projector（mmproj，约 1.4 GB）。后者别漏，router 靠它开多模态，缺了图片输入就是不可用。

别用浏览器点下载。17 GB 中途断一次网就得从头来，用官方 CLI 走，它自带断点续传和并发分片：

```bash
pip install -U "huggingface_hub[cli]"

mkdir -p ~/models/Qwen3.8-27B-Q4_K_M

# 新版命令是 hf，老的 huggingface-cli 还能用但已标记废弃
hf download Qwen/Qwen3.8-27B-GGUF \
  Qwen3.8-27B-Q4_K_M.gguf \
  mmproj-F16.gguf \
  --local-dir ~/models/Qwen3.8-27B-Q4_K_M
```

`--local-dir` 一定要加。不加的话文件会落进 `~/.cache/huggingface` 的哈希目录结构里，你拿到的路径是一堆摘要文件名，router 扫不出来，之后还得自己捞。

国内网络慢的话换个镜像端点，命令不用改：

```bash
export HF_ENDPOINT=https://hf-mirror.com
```

下完先确认它确实是 GGUF，顺便看一眼架构标识：

```bash
head -c4 ~/models/Qwen3.8-27B-Q4_K_M/Qwen3.8-27B-Q4_K_M.gguf
# → GGUF
# 头部元数据里 general.architecture = qwen35

ls -lh ~/models/Qwen3.8-27B-Q4_K_M/
# Qwen3.8-27B-Q4_K_M.gguf   16.8G
# mmproj-F16.gguf            1.4G
```

mmproj 的文件名必须以 `mmproj-` 开头，router 认的是这个前缀，不是文件内容。仓库里如果叫别的名字，下完自己 `mv` 一下。

### 启动 llama.cpp router

```bash
brew install llama.cpp
```

装完先确认两件事。一是这个 build 认不认识 Qwen3.8 的架构标识 `qwen35`，新模型经常跑在旧版本前面；二是 Metal 后端在不在。

```bash
llama-server --list-devices
# Available devices:
#   BLAS: Accelerate
#   MTL0: Apple M4 Pro (53084 MiB, 53083 MiB free)   ← 要看到这行
```

然后以 router 模式启动。关键是不要传 `-m` 或 `--model`。一旦传了，它就退化成单模型模式，router 的按需装卸就没了。

```bash
llama-server \
  --models-dir ~/models \
  --no-models-autoload \
  --jinja \
  --host 127.0.0.1 --port 8081 \
  -ngl 999 -c 32768 --flash-attn on
```

- `--jinja` 启用模型自带的 chat template，tool calling 依赖它
- `-ngl 999` 尽可能多的层交给 GPU
- `-c 32768` 每个 slot 的上下文。这个模型原生支持 262144，但全开的话 KV cache 会吃掉大量内存

```bash
curl -X POST http://127.0.0.1:8081/models/load \
  -H 'Content-Type: application/json' \
  -d '{"model":"Qwen3.8-27B-Q4_K_M"}'

# 27B 装载约 22 秒，轮询 GET /models 看 status
```

### 接入 pi

pi 通过 npm 全局安装。这里有两个容易踩的点：包名和命令名不一样，以及它对 Node 版本有硬要求（`engines` 写的是 22.19+），Node 20 上启动会直接被引擎检查拦掉。

```bash
node -v    # 低于 v22.19 先升，nvm 用户记得 nvm use

npm i -g @earendil-works/pi-coding-agent
# 装的是 @earendil-works/pi-coding-agent，可执行文件叫 pi

pi --version
```

pi 内置了 llama.cpp provider，文档里写的是进 TUI 后执行 `/login llama.cpp`，填入 router 地址，之后用 `/llama` 装卸模型、`/model` 选择模型。这条路是通的，而且能在 pi 里直接搜索下载 HuggingFace 上的 GGUF，体验最好。

> **坑： provider_not_found**
> 但这个内置 provider 只在 TUI 里注册。一旦你想用 `pi -p` 做非交互调用，或者跑 `pi auth check --provider llama.cpp`，都会得到 `provider_not_found`。脚本化场景下这条路直接堵死。

解法是再配一份 `~/.pi/agent/models.json`，把 router 当作普通的 OpenAI 兼容服务接入。两条路指向同一个 router，互不冲突：

```json
{
  "providers": {
    "llamacpp": {
      "baseUrl": "http://127.0.0.1:8081/v1",
      "api": "openai-completions",
      "apiKey": "local",
      "compat": {
        "supportsDeveloperRole": false,
        "supportsReasoningEffort": false,
        "thinkingFormat": "qwen-chat-template"
      },
      "models": [{
        "id": "Qwen3.8-27B-Q4_K_M",
        "reasoning": true,
        "input": ["text", "image"],
        "contextWindow": 32768,
        "maxTokens": 16384,
        "samplingParams": {
          "temperature": 1.0, "top_p": 0.95,
          "top_k": 20, "min_p": 0.0
        }
      }]
    }
  }
}
```

几个字段值得解释：

- `apiKey` 填个占位符就行，llama.cpp 不校验。但 pi 要求模型有 auth 配置才会在 `/model` 里显示，留空会导致模型"加载了但选不到"。
- `thinkingFormat: "qwen-chat-template"` 是关键。Qwen3.8 的 chat template 里带 `enable_thinking` / `preserve_thinking` 两个开关，这个格式会把 pi 的思考等级翻译成对应的 `chat_template_kwargs`。填错的话思考链要么关不掉，要么开不起来。
- `supportsReasoningEffort: false`，llama.cpp 不认 OpenAI 的 `reasoning_effort` 参数，不关掉会报错。
- `samplingParams` 直接用了 Qwen 官方推荐值（模型卡和仓库里的 `generation_config.json` 都有）。

配好之后验证：

```bash
pi --list-models | grep llamacpp
# llamacpp  Qwen3.8-27B-Q4_K_M  32.8K  16.4K  yes  yes

pi -p --model llamacpp/Qwen3.8-27B-Q4_K_M "读取 calc.py 并修复其中的 bug"
```

---

## 性能实测：11.4 tok/s 意味着什么

同机对比，均为 4-bit 级别量化，均运行在 Metal 上：

| 指标 | llama.cpp Q4_K_M | MLX 4-bit |
| --- | ---: | ---: |
| 解码速度 | 11.4 tok/s | 15.4 tok/s |
| 预填充（11.6k prompt） | 88.7 tok/s | 95.9 tok/s |
| 相同 prompt 重发 | 0.38 s | 需手动开启 |
| 权重体积 | 16.8 GB | 16.1 GB |

### 解码慢 35%，但这不是配置问题

llama.cpp 在 Apple Silicon 上的解码确实不如 MLX，瓶颈在权重的内存带宽，不在内存容量。每生成一个 token 都要把 16.8 GB 权重完整读一遍，M4 Pro 约 273 GB/s 的带宽算下来上限就在 16 tok/s 附近。内存够用就行，富余多少不影响。

> **怎么确认真的跑在 GPU 上**
> 除了 `--list-devices`，更直接的办法是生成过程中看进程 CPU 占用。老金实测是 3–7%。如果掉回 CPU 推理，这个数字会是 600% 以上。

### prompt cache 比解码速度重要

![同一 prompt 冷启动 131 秒，命中缓存后 0.38 秒](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260826/02_prompt_cache.png)

预填充两者几乎持平，因为这个阶段是计算受限而非带宽受限。11.6k token 的长 prompt 冷启动要 131 秒，这个数字在 agent 场景里相当致命，每轮对话都要重新吃一遍上下文的话根本没法用。

好在 llama.cpp 的 prompt cache 默认就开着，效果极好：同一个 prompt 重发，131 秒直接变成 0.38 秒（11623 / 11627 命中缓存）。多轮 agent 循环里，这个差距的分量远大于解码那 35%。

所以纯对话、单轮生成我会用 MLX。多轮 agent 还是 llama.cpp 划算。

---

## 运行本地编码任务

老金用来测试的任务是让它写一个 AI 冥想应用的落地页。完整 prompt 如下：

```text
请作为一名前端专家，为一款名为 'Aura' 的 AI 冥想应用
编写一个现代、极简风格的 Landing Page（落地页）。

要求：
只输出一个单一的 index.html 文件，将 CSS 写在 <style> 标签内。
不要使用任何外部图片，可以使用 CSS 渐变、Emoji 或简单的 SVG 作为占位符。
页面包含：一个带有渐变文字的 Hero Section（主视区）、
一个包含三个特点的 Grid 布局功能区、以及一个底部的邮件订阅表单。
必须是纯响应式设计，在手机端和 PC 端都有完美的内边距和排版。
使用柔和的莫兰迪色系。
```

### 每条约束都在防一个具体的崩法

![每条约束挡掉一种典型故障](https://pic-1258874139.cos.ap-hongkong.myqcloud.com/laojinblog/posts/20260826/03_constraints.png)

这个 prompt 看起来平平无奇，但每条都对应本地模型的一种典型故障。

「作为一名前端专家」。对 27B 这个量级，角色设定的实际收益比对旗舰模型明显得多，它会改变默认的代码风格和细节密度。

「只输出一个单一的 index.html，CSS 写在 style 标签内」防的是跨文件协调，这是本地模型最容易崩的地方：生成 HTML 时引用了 `style.css`，写 CSS 时类名又对不上。单文件把这个失败模式整个删掉。

「不要使用任何外部图片」切断幻觉 URL。不加这条，模型几乎必然编造 `unsplash.com/photo-xxx` 之类根本不存在的图片地址，页面一打开全是碎图。同时要给出替代方案（渐变 / Emoji / SVG），否则它会卡住或留空白。

「Hero + 三特点 Grid + 邮件订阅表单」把开放式创作变成填空。明确的区块清单让模型不需要自己做信息架构决策，而这恰恰是小模型最不稳定的部分。

「纯响应式，手机端和 PC 端都有完美的内边距」，注意它同时点名了两种设备。只说"响应式"的话，模型往往只写一个 `@media` 就交差。

「柔和的莫兰迪色系」是唯一的审美约束，但极其具体。"好看"、"现代"这类词对模型没有信息量；"莫兰迪"是一个有明确色彩特征的专有名词，直接对应到低饱和度调色板。

> **核心思路**
> 描述得详细没什么用，得把审美要求翻译成结构要求。"现代极简"你没法验证。"单文件 / 无外部资源 / 三个指定区块 / 双端响应式 / 莫兰迪"这五条，每一条都能用眼睛或脚本当场判定。

### 思考等级要开

这次运行老金把 pi 的 thinking level 设成了 `medium`，模型产出了 18,883 字符的思考过程，占掉了 20 分钟里相当大一部分。但这部分投入值得。落地页这类任务需要模型先把配色、断点、区块结构想清楚再动笔，否则写到一半改主意，以 11 tok/s 的速度重来一次代价太高。

### 模型自己写了个校验脚本

有个细节老金觉得比页面本身更有意思。写完 `index.html` 之后，模型没有直接收工，而是主动调用 bash 工具，现场写了一段 Python `HTMLParser` 脚本来检查标签闭合：

```python
# 模型自发执行
python3 - <<'EOF'
from html.parser import HTMLParser
...
EOF
# → errors: none / unclosed: none
```

同样的模型放在纯聊天界面里只能吐一段文本，放进能执行命令的 agent 框架，它就会开始自我验证。功劳更多在 harness。这次运行总共三轮工具调用：写文件 → 校验结构 → 输出设计说明。

---

## 结果验收：20 分 07 秒之后

563 行、17 KB 的单文件 HTML，零外部依赖。

最终效果如下：

### 命中的部分

- 渐变文字用 `background-clip: text` 实现，落在标题的关键词上而非整句
- 功能区用 `repeat(auto-fit, minmax(min(260px, 100%), 1fr))`，是真流体网格，不是三个写死的断点
- 间距和字号大量使用 `clamp()`，在断点之间也能平滑过渡
- 外部资源引用数：0

还有两处是我没要求、但它自己加上的：9 处 aria / label 无障碍标注，包括给订阅输入框配了视觉隐藏的 label；以及 `prefers-reduced-motion` 支持，呼吸光晕动画会对晕动敏感用户自动关闭。

### 没做好的部分

中文标题的换行处理不到位。桌面端 Hero 的"交还给此刻的呼吸"里，"吸"字被孤零零挤到了第三行；移动端"安静的窗"也有同样的孤字问题。模型对 CJK 断行规则没有概念，这需要一句追加 prompt 来修：

```text
给所有标题加上 text-wrap: balance，
并确保渐变关键词不被拆到两行。
```

---

## 所以本地 27B 到底能干什么

我会交给它的活儿：单文件、结构明确的产出，落地页、配置文件、脚本这一类；有客观验收标准的任务；涉及敏感代码、不能出网的场景。还有批量的、不赶时间的重复劳动。

暂时别指望的：

- 需要快速多轮试错的探索型任务，一轮 20 分钟
- 跨文件的大型重构
- 需要最新框架知识的工作
- 你盯着屏幕等结果的交互式编码

11 tok/s 很慢，但它可以整晚不停地跑，不计费，不上传任何东西。派给它那些"结果明确、就是懒得写"的活儿，体验会好很多。
