sparkle/README.md
fiser_jun 4745f264b2
2026-08-04 14:34:00 +08:00

188 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Sparkle
本地 **Qwen3-Next-80B-A3B Instruct 8bit** 流式推理引擎,对接 ccSparkle Agent模型源**Sparkle**)。
在约 64GB 统一内存的 Apple Silicon 上,把约 77GB 专家权重放在 SSD运行时按需装入 + 预取,从而跑通 80B 8bitoMLX / Ollama 全量加载做不到的档位)。动机见 [`models/README.md`](./models/README.md):用 80B@64G 验证流式路径,对应下游 **30B 8bit A3B** 进 32G/16G、统一内存省 50%+。
| 项 | 值 |
|----|----|
| Python | **3.14.***(与 `native_moe_ext.cpython-314-darwin.so` 对齐;见 `pyproject.toml` |
| 已验证机器 | MacBook Pro M2 Max / 64GB |
| 安装目录 | 本仓库根目录(下文记为 `$SPARKLE_HOME`,即 `clone` 后的路径) |
| 引擎端口 | `8317`(经中台 `8088` 启停与代理) |
| 模型 / 专家 / MTP | 见 [`models/README.md`](./models/README.md)(不入库,约 160GB |
| 性能基线 | 稳态约 910 tok/s贪心+MTP采样约 46 tok/s常驻约 2333GB 量级 |
依赖安装走清华 PyPI 镜像(`pyproject.toml` 的 `tool.uv.index`)。
---
## 1. 系统组成
```
浏览器前端(8090) ← 日常对话界面
│ 顶部选 Sparkle 源
中台代理(8088) ← 转发请求,规避跨域
Sparkle 引擎(8317) ← 80B 8bit 流式推理
├─ /v1/chat/completions OpenAI 兼容接口
└─ /admin 调参页(槽位 / 投机宽度 / 状态)
```
专家权重留在 SSD运行时按需读取 + 预测式预取;首次启动和切换话题时偶有停顿(读盘)。
**AUTOPIN**(默认开启):记录专家路由热度(`models/experts_8bit_g64/pool_usage.json`),启动时把最热一批 pin 进常驻池(默认占槽位 50%,定死不驱逐)。冷启动命中率可从约 72% 升到 **98%+**。`AUTOPIN=0` 关闭;`AUTOPIN_BUDGET_FRAC` 调比例01
---
## 2. 启动
**推荐**:打开对话界面 → 顶部选 **Sparkle** → 中台自动加载引擎(约 90 秒,状态变绿后再对话)。
1. 中台(桌面应用常会自动拉起;路径按你本机 Agent 工程根目录,下文记 `$AGENT_HOME`
```bash
cd "$AGENT_HOME" && node scripts/zhongtai-server.js
```
2. 前端静态服务:
```bash
cd "$AGENT_HOME/<前端静态目录>" && python3 -m http.server 8090
```
3. 浏览器打开对话页,顶部点 **Sparkle**——未运行时会自动启动(也可在 `配` → Sparkle tab「引擎管理」点**加载**)。
就绪:`配` → Sparkle 状态点变绿,或 `curl -s http://127.0.0.1:8088/sparkle-engine/status``"loaded":true`
**手动启动(调试)**
```bash
cd "$SPARKLE_HOME" # 本仓库根目录
.venv/bin/python -m mlx_streaming.server --port 8317 \
--model models/Qwen3-Next-80B-A3B-Instruct-MLX-8bit \
--expert-dir models/experts_8bit_g64 \
--qn-config models/Qwen3-Next-80B-A3B-Instruct-MLX-8bit/config.json \
--mtp-out models/qn_mtp_weights.safetensors \
--expert-slots 96
```
- Admin`http://127.0.0.1:8317/admin`
- 健康:`curl -s http://127.0.0.1:8317/api/stats``unplaced_experts` 应为 `0`
中台默认 `SPARKLE_ENGINE_DIR` → 本目录。改目录名后若「卸载」失灵,先杀 `8317` 再重启中台。
> **工具白名单**:默认只放画像 4 工具(`profile_list_employees` / `profile_get_portrait_overview` / `profile_get_person_report` / `profile_get_team_report`)。中台动态工具集会改 system 头部哈希,导致前缀快照 miss钉死工具集后快照才稳定。排班 `metro_*` 等会被裁掉。临时放开:`TOOLS_ALLOW=`;换名单:`TOOLS_ALLOW=a,b,c`。裁剪结果见 `logs/server.log` 的 `[TOOLS_ALLOW]`。
> **不要自己设 `PREFILL_CHUNK`**。安全上限由槽位决定引擎启动时按槽位自算96 槽 → 464 槽 → 3超限会被钳制并打日志。
---
## 3. 日常对话
1. 打开对话页(`http://localhost:8090`),顶部选 **Sparkle**
2. 首次:`配` → Sparkle tabBase URL `http://127.0.0.1:8317`API Key 任意非空(如 `sparkle`),刷新选模型 `Qwen3-Next-80B-A3B-Instruct-MLX-8bit`,保存
3. 正常对话;工具调用链路与 oMLX 源相同
---
## 4. 调参与引擎管理
`配`**本地 Sparkle** tab「引擎管理」`http://127.0.0.1:8317/admin` 等价):
状态点:灰(未启动)→ 黄(加载中,约 90 秒)→ 绿(就绪)。`加载` / `卸载` 启停;就绪时显示 tok/s 与 RSS。
| 参数 | 范围 | 说明 | 生效 |
|------|------|------|------|
| expert-slots | 32160 | 常驻专家数,越大命中率越高、越占内存(每槽 ~160MB。64GB + AUTOPIN64 槽约 9 tok/s**96 槽约 10.3 tok/s推荐**≥128 近红线;**160 会卡死,勿用** | 应用后进程级重启(约 90 秒) |
| K投机宽度 | 15 | MTP 草稿 token 数,默认 3只影响速度 | 即时 |
| max_tokens | — | 单次回答最大长度 | 即时 |
日常 64 够用;长文档可试 96128系统开始 swap 就降回 64。
---
## 5. 故障排查
| 现象 | 原因 | 处理 |
|------|------|------|
| 503 / engine reloading | 加载或重建中 | 等 6090 秒后再试 |
| `EADDRINUSE ... 8317` | 旧 server 未关 | `lsof -tiTCP:8317 -sTCP:LISTEN \| xargs kill` |
| 中台 `EADDRINUSE ... 8088` | 已有健康中台 | 直接用;要重启先 kill |
| 改名后「卸载」无效 | 旧进程挂在旧路径 | 杀 8317重启中台再加载 |
| 明显变慢 | swap 或槽位太低 | 看内存压力;调槽;关其他大应用 |
| 首轮特别慢 | 冷启动 | 正常,第二轮起恢复 |
| 长文中途停顿 | 读盘装冷门专家 | 正常;调高槽位可缓解 |
| 刷新拉不到模型 | server 未起或端口错 | `curl http://127.0.0.1:8317/v1/models -H "Authorization: Bearer x"` |
---
## 6. 常见问题
**Q: 为什么 oMLX / Ollama 里看不到这个 8bit 模型?**
A: 权重远超 64GB 整模上限,只有 Sparkle 流式能跑。oMLX 继续跑中小模型即可。
**Q: 投机宽度 K 是什么?**
A: MTP 每步草稿 token 数;主模型批量验证,猜中白赚。只影响速度,不影响内容。
**Q: 回答乱编 / 不调工具 / 幻觉?**
A: Qwen3-Next 官方要求采样temp 0.7 / top_p 0.8 / top_k 20。贪心+MTP 在该模型上易幻觉。默认走采样(约 46 tok/s显式 `temperature: 0` 才走贪心+MTP约 10 tok/s。Sparkle 客户端对真实对话会把 `0` 改回采样。
**Q: 模块分析比 oMLX 7B 还空?**
A: 多为分析轮传了 `temperature: 0` 进贪心导致指令遵循崩坏,不是花名册数据错。另查 `unplaced_experts`(非 0 = 错专家)与是否需清空 `prefix_snapshots`
**Q: 回答里夹「<E5A4B9>」乱码**
A: 已修byte-level BPE 流式反分词用 `StreamingDetokenizer`,避免半字符 U+FFFD 丢字。
**Q: 8bit 比 7B 还笨?**
A: 曾因 prefill 超槽静默映射到 0 号专家。现自动算 `PREFILL_CHUNK`、超容量走正确慢路径,并用 `unplaced_experts` 告警(健康值恒为 0。非 0 时回答不可信;若错算过,删 `models/prefix_snapshots/` 再预热。
**Q: 和云端略有不同?**
A: 量化 + KV 压缩的正常差异;语义质量不受影响。
**Q: 首轮为什么要等?**
A: 新对话要 prefill 系统提示+工具定义。有前缀快照后:重启后首会话约百秒级,之后新会话约数十秒,同会话追问约数秒。`PREFIX_SNAPSHOT_HEAD` 调长度(默认 20480 关闭)。
**Q: 速度还能再快吗?**
A: 96 槽 + AUTOPIN + prefill 分块约 910 tok/s接近本机 8bit 上限。160 槽会卡死,勿试。
**Q: 能跑多长上下文?**
A: KV 量化默认开;对话侧另有约 24k token 压缩阈值(中台配置)。
**Q: 想换模型或其它量化档?**
A: 本引擎面向 Qwen3-Next-80B 流式 8bit 部署;换档需按当前模型重新准备专家 blob 与 MTP。
---
## 7. 目录要点
```
sparkle/
├── mlx_streaming/ # 引擎 Python 包(含已编译 native_moe_ext*.so
├── native/ext/ # C++/Metal 扩展源码(重编 .so 用)
├── models/ # 权重与专家 blob约 160GB勿删
│ ├── Qwen3-Next-80B-A3B-Instruct-MLX-8bit/
│ ├── experts_8bit_g64/
│ └── qn_mtp_weights.safetensors
├── .venv/
├── pyproject.toml / uv.lock
└── benchmarks/reports/ # 性能基线报告
```
`models/` 三者缺一不可。不要把模型目录移进 oMLX 等其它运行时的模型扫描目录(会列出但整模加载不了)。
换 Python 小版本时需 `make -C native/ext native_moe_ext` 重编 `.so`。`native/ext/build/` 已忽略。
---
## 8. 质量与速度(摘要)
- **默认应对话走采样解码**(约 temperature 0.7 / top_p 0.8 / top_k 20。`temperature=0` 会进贪心+MTP本机实测指令遵循差于同表 oMLX 7B。
- 稳态 decode采样约 **46 tok/s**;贪心+MTP 约 **910 tok/s**(速度更高,但质量风险大,生产默认勿用)。
- 专家池命中率健康时约 **94%+**`unplaced_experts ≠ 0` 表示曾用错专家权重,回答不可信。
---
## 9. 相关文档
| 文档 | 内容 |
|------|------|
| [models/README.md](./models/README.md) | 为何做流式、NAS 下载与专家/MTP 准备 |
| [benchmarks/reports/8bit-g64-baseline-2026-07-25.md](./benchmarks/reports/8bit-g64-baseline-2026-07-25.md) | 8bit 性能基线 |