【开源大赛】把 30B 大模型塞进 16 GB 开发板:Kestrel-LLM 入围 2026 上海开源软件应用创新大赛·智算云赛道决赛
一句话结论:纯 C11、零第三方运行时、单文件约 1.4 MB 的推理引擎,在 16 GB 内存的 RK3588 开发板上,把 17.67 GB 的 Qwen3-30B-A3B 跑到 serve 峰值 1.11 GB;推荐档 8B serve 峰值 0.82 GB、热态 TTFT 1.73 s / tpot 330 ms。
项目已入围 2026 上海开源软件应用创新大赛 · 智算云赛道决赛(10 支队伍,10 月 29 日上海张江总决赛)。
这篇文章不讲愿景,只讲三件事:我们解决了什么问题、数字是怎么测出来的、哪些地方我们还没做好。
一、先说消息
2026 年 10 月 21 日,2026 上海开源软件应用创新大赛「智算云赛道」决赛名单公布:Kestrel-LLM 入围决赛,是 10 支晋级队伍之一,将于 10 月 29 日在 上海张江人工智能创新小镇参加总决赛。
- 官方入围名单:https://www.oschina.net/news/503144
- 大赛官网:https://www.oschina.net/os2026/
- 项目名:Kestrel-LLM(Kestrel 红隼,工程名
vllm_kestrel),团队负责人:裴晓光
本届大赛由开源中国主办,主题是「开源向实(Open Source, Real Impact)」,设 AI+ 工业软件、智算云、开源 AI 工具三大赛道。
Kestrel 是一个用纯 C11 写的 ARM / x86 双端 CPU 推理引擎。仓库里没有 Python 运行时,没有 PyTorch,没有 ggml,也没有 CUDA 依赖——编译出来就是一个 1.4 MB 左右的单文件可执行程序,跑起来就是一个 OpenAI 兼容的 HTTP 服务。
能进决赛,说明"用 CPU 把大模型跑在低内存设备上"这件事,至少值得被认真看一眼。下面把它拆开讲清楚。
二、我们对"智算云"的理解:算力不该只有 GPU 一条腿
提到智算云,第一反应通常是 GPU 集群、卡时、调度、模型服务化。这些当然重要。
本届智算云赛道的征集方向写得很具体:异构算力调度与 GPU 池化、分布式训练与推理加速、RAG 与智能体框架、多云管理与成本优化。Kestrel 对应的是后三个方向:推理加速(逐层驻留 + 长上下文优化)、RAG 与多链编排(/v1/ask)、以及把单机部署成本压下来。它不调度 GPU,而是把"CPU 这一极"的推理成本压到可部署的范围内。
但在真实项目里,还有另一类算力长期被忽略:已经部署在现场的 CPU。工厂的工控机、车载盒子、门店小主机、园区的边缘节点——它们没有 GPU,也常常不适合把数据传回云端(合规、带宽、断网)。
Kestrel 不是要替代 GPU 云,而是回答一个很具体的问题:
当只有 CPU、内存只有 16 GB、网络还不稳定时,大模型还能不能提供"可用"的服务?
我们的答案是把"内存"这道墙拆掉,而不是把模型换小。核心手段叫逐层推理(Per-layer Residency):
mmap 直挂 VQF 权重单文件
→ 每层只在参与计算时建立文件页
→ 算完立刻 MADV_DONTNEED 释放
→ 只有 keep 层(默认 1 层)常驻
映射是只读的,页面是干净的,驱逐不需要回写;下次用到再从文件重建。于是权重常驻内存与模型体积解耦:模型 17.67 GB,权重常驻可以只有 0.51 GB。
代价也很明确:用时间换内存。这一点后面"泼冷水"一节会讲透。
三、三个数字(先把硬指标摆出来)
测试平台:Orange Pi 5 Plus(RK3588,4×Cortex-A76 + 4×Cortex-A55),MemTotal 15.6 GiB,governor=performance,全程纯 CPU,不调用 GPU / NPU。
| 指标 | 实测 | 口径(必须写清,否则数字会对不上) |
|---|---|---|
| 30B-A3B 权重常驻 | 11.73 GB → 0.51 GB(23.2×) | --stream-test,冷页缓存,纯权重,q4,17.67 GB 模型 |
| 30B-A3B serve 峰值 | 14.23 GB → 1.11 GB(12.8×) | serve 稳态,含 KV |
| 8B 权重常驻 | 4.19 GB → 0.48 GB(8.7×) | --stream-test,冷页缓存,纯权重,q4,6.60 GB 模型 |
| 8B serve 峰值 | 0.82 GB | serve 逐层档,含 KV |
| 8B 热态 | TTFT 1.734 s / tpot 330.2 ms | 2026-09-15 远程复测,连续 5 次同请求中位数,70 token 端到端约 24.5 s |
| 8B 热态稳定性 | tpot 5 次极差 0.5% | 同一远程板、同一二进制 |
| 30B 短请求(关 thinking) | 20.82 s 拿到完整短答 | 峰值 VmHWM 0.92 GB;thinking 开则可能 256 token 都走不完思考段 |
推荐档是 8B,不是 30B。
原因不是"30B 跑不动",而是 30B 的权重 16.4 GiB 装不进 15.6 GiB 页缓存,热态稳定性没有物理保障;8B 的 6.15 GiB 装得下,所以 5 次重发同一请求,tpot 只在 328.9~330.6 ms 之间波动。这是"能跑"和"能稳定服务"的区别。
四、怎么做到的:四个关键设计
4.1 逐层驻留:把"装不下"变成"算得慢"
传统推理引擎要求权重全量常驻。30B 模型 17.67 GB,比整块板的 15.6 GiB 内存还大,全层档 serve 峰值 14.23 GB,KV 和系统进程只能捡剩下的渣。
逐层档把同一模型的 serve 峰值压到 1.11 GB,代价是热态 tpot 上升。语义不变:--stream-test 的贪心 TOKIDS 序列在全层 / 逐层两档下逐位一致——驱逐只丢弃干净文件页,内容由文件重建。
边界:逐层只支持明文 VQF。VQF-Enc 加密权重、内嵌 SM2 签名的权重会被显式拒绝,必须全层驻留。
4.2 VQF:单文件 mmap,没有"加载期"
引擎只认自研 VQF v2 单文件。权重、量化参数、词表元数据都在一个文件里,启动时 mmap 直挂、按需建页,没有"先把几十 GB 读进内存"的加载阶段。
转换由随版工具 vqf_convert/ 完成:
cd vqf_convert && ./build.sh
./vqf_conv --model <safetensors-dir> --convert-vqf <out.vqf> --wmode q4
# 可选:存储态加密(SM4-CTR + HMAC-SM3)
VLLM_VQF_KEY='<pass>' ./vqf_conv --model <safetensors-dir> --convert-vqf <out.vqf> --wmode q4
4.3 一个进程,五类模型
同一个二进制里承载五类模型,各占独立槽位,按端点切换:
- Qwen3-VL 2B / 8B:文本 + 图片 / 视频
- Qwen3-30B-A3B:MoE
- Qwen3-Embedding-0.6B:向量
- Laya:决策
- YOLO v5 / v8 / v11:检测
再往上是一个统一联合入口 /v1/ask:带 image 走 scene 链(YOLO → 场景叙事 → LLM),带 kb_dir 走 rag 链(embedding → top-k → LLM),带 questions 走 decide 链,否则走 chat。只认显式字段,不做语义猜测,响应里回带 route 说明本次由哪条链作答。
4.4 长上下文三板斧:L3 驱逐 × 前缀复用 × 稀疏注意力
- L3 分层驻留 + 驱逐:把 KV 前缀块落盘,需要时回填;
- 前缀复用:多轮追问只算增量,8B 追问轮 prefill −80% ~ −81%;
- 规则包:把反复使用的现场规程 / 术语 / 参数离线构建成可复用前缀。5,791 token 的短手册,命中后 194.3 s → 2.4 s(≈82×);超过 8K token 的手册不落盘,退回全量 prefill。
稀疏注意力有长度门控,默认关闭:
- decode 侧自 4K 起转正:4K 1.58× / 8K 2.16× / 16K 2.92×(2B);
- prefill 侧更苛刻:ctx 1067 时仍 +18.4%,4.4K 才转正(−11.1%),16K −45.1%。
两条轴都默认关,因为不是所有场景都划算。
五、和 llama.cpp 的公平 A/B:同权重、同板、同线程
只跟自己比没有说服力。2026-09-16 我们做了一轮对 llama.cpp 的权重公平对照:同一块板、同一份 4-bit 量化权重、两侧各开各的优化、都 4 线程、每个 arm 前清页缓存。
16K 上下文档(15,616~15,654 token):
| 指标 | llama.cpp Q4_0 | Kestrel 逐层 | Kestrel 全层 |
|---|---|---|---|
| prefill | 7.25 t/s | 11.61 t/s(1.60×) | 11.68 t/s(1.61×) |
| decode | 0.48 t/s | 1.42 t/s(2.96×) | 1.74 t/s(3.63×) |
| 峰值内存 | 10.77 GB | 6.71 GB | 10.15 GB |
| 多轮复用轮 prefill 时延 | 29.52~29.56 s | 8.68~9.23 s(3.2~3.4×) | 8.85~9.01 s |
短上下文不是我们的主场:2K prefill 慢 1.32 倍,4K 慢 1.15 倍,交叉点在 4K~8K 之间;decode 的交叉点在 1K 之后。差距的真正来源是衰减率——2K 到 16K,llama.cpp prefill 掉了 58.8%、decode 掉了 81.6%,我们分别是 12.2% 和 37.7%。
口径提醒:16K 档跑在
governor=ondemand下,绝对值可能偏保守 5~8%;两侧同档同 governor,所以对照关系仍有效。原始产物、md5 留证、脚本都在仓库docs/bench/20260916-rk3588-llama-ab/。
六、安全:不只是"能跑"
边缘部署经常被问一个问题:模型权重被拷走怎么办?推理结果被篡改怎么证明?
目前仓库里有四层:
- VQF-Enc:SM4-CTR + HMAC-SM3 存储态加密;
- SM2 供应链签名:权重来源可验,可与加密叠加;
- 可验证推理 attestation(schema 3):逐请求凭证,含请求原文绑定,浏览器内 / 离线零依赖验签;
- 同态加密推理链驱动:在自研 RNS-CKKS 核心上把模型逐层跑在密文上(
lay/fin层链 112 个素数,boot自举 2100 个素数)。
第 4 条是研究性质的,不承诺性能,但它证明这套引擎不只会做"省内存"这一件事。
七、跨架构:x86 端我们只敢说"数值一致"
项目目录叫 ARM-X86,但这里必须说清楚边界。
x86-64 分支的定位是功能自检与数值一致性对照,不作性能基准。2026-09-28 我们用真模型做了一次跨架构对拍:同一份字节相同的权重、同一源码、同参数下,2B 模型的贪心 TOKIDS 在第 12 个 token 分歧(x86 44063 / ARM 45181)。
所以文档里的措辞从"位级一致性对照"收窄为"数值一致性对照"——跨架构没有逐位保证。同平台内全层 / 逐层两档仍逐位一致,不受影响。
这条我们主动写出来,因为"AI 推理引擎跨架构逐位一致"这种话,听起来很爽,但经不起一次真模型对拍。
八、泼冷水:四个别误读的地方
- 逐层是"时间换内存",不是免费午餐。 8B 冷页缓存下 decode 代价 +37%~+86%(线程口径不同);30B 冷态首 token 要 202 s,因为要从 64.5 MB/s 的 microSD 读入 17.67 GB 权重。这是一次性成本,但不是零。
- 30B 是能力上限档,不是推荐档。 16 GB 板上,30B 的可用姿势是"关 thinking + 短上下文",长文问答不要指望它。
- short context 打不过 llama.cpp。 2K prefill 慢 1.32 倍是事实,我们的优势在 8K 以上和内存。
- 逐层只支持明文 VQF。 要加密权重,就得全层驻留,内存优势不成立;这是当前架构的取舍,不是配置问题。
九、决赛现场,我们最想被问的三个问题
Q1:这不就是 mmap + MADV_DONTNEED,有什么难的?
机制确实不复杂,难的是"敢不敢把它当默认路径":要保证驱逐后语义不变、要处理 KV 与 L3 的正交、要让冷启动成本可解释、要在 16 GB 板上把 30B 的峰值压到 1.11 GB。仓库里每一组数字都带测点和原始产物,欢迎按图复现、按图打脸。
Q2:没有 GPU,速度这么慢,有意义吗?
看场景。离线巡检、现场问答、隐私敏感数据不出内网,这些场景的第一约束是"能不能部署",不是"首 token 多少毫秒"。8B 热态 tpot 330 ms,对短答可用;30B 用来兜底能力上限。我们从不宣称它能替代 GPU 云。
Q3:开源到什么程度?
代码全部公开,Apache-2.0,可自由使用、修改、分发,只需保留版权与许可声明、标注修改过的文件。
十、如果你愿意支持我们
比赛期间最实在的支持,不是转发,是真的跑一遍:
- 给仓库点个 Star,让更多做边缘部署的人看到;
- 按下面的命令在你自己的板子上复现,跑不通直接提 Issue,我们改;
- 如果你是做工厂 / 车载 / 园区项目的,欢迎说说你的场景,我们想知道下一个该优化什么;
- 10 月 29 日总决赛在上海张江人工智能创新小镇,如果你也在现场,欢迎当面交流。
附:5 分钟跑起来
# 1) 板上原生构建(需 gcc + cmake)
./build_rk3588.sh --run-tests
# 2) 权重转换(safetensors → VQF v2 单文件)
cd vqf_convert && ./build.sh
./vqf_conv --model <safetensors-dir> --convert-vqf <out.vqf> --wmode q4
cd ..
# 3) 启动 OpenAI 兼容服务(8B 建议 --threads 4)
VLLM_VQF_STREAM=1 ./vllm_kestrel --serve --port 8080 \
--model <model-dir> --auto-load --wmode q4 --threads 4
# 4) 验证
curl http://<board>:8080/health
curl http://<board>:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"qwen3-vl","messages":[{"role":"user","content":"你好"}],"max_tokens":64}'
8B 在 RK3588 上务必用 4 线程:
--threads 8会把 4 个 A55 小核拉进 GEMM 并行区,decode 慢 1.8~2.5 倍。这是实测,不是经验。
链接与许可
- 官方入围名单(OSCHINA):https://www.oschina.net/news/503144
- 大赛官网:https://www.oschina.net/os2026/
- 仓库(Gitee,主站):https://gitee.com/pei-xiaoguang/kestrel-llm
- 项目 Wiki:https://gitee.com/pei-xiaoguang/kestrel-llm/wikis/Home
- Issue:https://gitee.com/pei-xiaoguang/kestrel-llm/issues
- 许可:Apache License 2.0(SPDX:
Apache-2.0),代码全部公开 - 当前版本:v1.0(测试版);性能数字未标注版本者均为 v1.0 板端实测,口径以 README「性能」一节为准