摘要:2026-08-17 ~ 09-12,我用 Trae(Agent 模式 + DeepSeek)从零开发了一个纯 C11、零第三方运行时的 ARM 边缘 LLM 推理引擎。27 天里完成 29 次提交、11 页 Wiki、5 篇技术文档、90 篇教程,并让一块 15.6 GiB 内存的 RK3588 开发板跑起 17.66 GB 的 Qwen3-30B-A3B,服务峰值内存 14.23 GB → 1.11 GB。本文是完整开发实录:时间线、工作流、三个技术转折点、4 个被 AI 坑进文档的错误结论,以及一份可直接复用的规则模板。
关键词:Trae、AI 编程、结对开发、RK3588、ARM、大模型推理、C11、边缘计算、mmap、量化推理
适合读者:正在用 AI 写正经工程的开发者 / 做边缘 AI 部署的工程师 / 对推理引擎感兴趣的同学
目录
- 一、先说结论:这 27 天我做成了什么
- 二、为什么我要手搓一个引擎
- 三、27 天时间线复盘(真实日期)
- 四、我具体是怎么用 Trae 的(工作流)
- 五、三个技术转折点
- 六、4 个被 AI 坑进文档的错误结论
- 七、成果数据(全部标注口径)
- 八、反思:AI 结对把瓶颈搬到了哪里
- 九、可直接复制的规则模板
- 十、诚实边界
一、先说结论:这 27 天我做成了什么
| 周期 | 27 天(2026-08-17 ~ 09-12,其中 23 天有文件改动) |
| 成本 | 约 3000 元 token 费(一个月) |
| 产物 | 纯 C11 引擎,单文件约 0.8 MB(818,872 字节,v0 测点)、28 个 C 文件、零第三方运行时 |
| 看家本事 | 逐层推理:30B-A3B 服务峰值 14.23 GB → 1.11 GB(12.8×),输出与全层档逐位一致 |
| 落地 | RK3588(Orange Pi 5 Plus,15.6 GiB 内存)纯 CPU 跑起 17.66 GB 的 Qwen3-30B-A3B |
| 配套 | 29 次提交 | 11 页 Wiki | 5 篇技术文档 | 90 篇教程 | 一键复现脚本 |
但今天我想讲的不是这些数字,是过程。因为如果只看结果,你会以为“AI 帮我把代码写了,所以我很快”。真实的体感完全不是这样。
二、为什么我要手搓一个引擎
起因很简单:我想在一块几百块的开发板上跑大模型。试过现成方案后,撞上三堵墙:
第一堵是内存墙。主流 ARM 开发板只有 15.6 GiB 可用内存,而一个 q4 量化的 30B MoE 模型权重文件就是 17.66 GB——权重比内存还大。常规“全量加载常驻”路线直接出局(实测全层档服务峰值 14.23 GB,几乎顶满整块板)。
第二堵是体积墙。主流框架型方案(Python + 推理框架 + 加速栈)动辄几 GB,边缘设备的存储和内存都吃紧,而且依赖链条长得没法审计。
第三堵是成本墙。云端 API 按 token 计费,账单随用量持续发生;而我想做的场景(产线问答、离线文档处理)既高频又敏感,既贵又不合规。
想清楚之后我发现:真正要破的不是“把权重压得更小”,而是“取消权重必须同时驻留这个前提”。这个想法,就是我后面 27 天全部工作的主线。
三、27 天时间线复盘(真实日期)
下面的日期来自我本地的 Trae 会话记录与 Git 提交记录,两条线可以互相印证。
| 08-17 | 项目启动。定下三件事:纯 C11、零第三方运行时、目标板 RK3588 |
| 08-18 ~ 08-28 | 内核层攻坚:手写 NEON 量化 GEMM/GEMV、VQF 权重格式、KV 缓存分页、连续批处理 |
| 08-31 | 服务层改造:改为手动加载模式(/admin/api/model/load),解决边缘场景下模型切换的痛点 |
| 09-01 | 并发模型改造:把 vllm_batch.c 里的轮询睡眠换成 pthread_cond_t 事件驱动 |
| 09-05 | 首次开源发布(v0),同时补上模型支持范围声明与口径说明 |
| 09-06 ~ 09-10 | v1 大重构:纯 VQF 运行时、逐层推理、KV v2 惰性分配、独立转换工具、attestation |
| 09-11 | v1.0 测试版发布 |
| 09-12 | 板端实测矩阵:14 个 serve 配置点 + 一键复现脚本 + Wiki 收口 |
一个细节,能说明 AI 结对最大的价值:9 月 1 日那条改造——我在会话里只写了一句“把轮询睡眠换成事件驱动机制”,它给出的是 pthread_cond_wait(&b->cv, &b->cv_mu) 的完整实现,到今天我文档里记的还是这句话,而代码在 src/serve/vllm_batch.c:209 原样躺着。
这种“当时的记录 → 现在还在的代码”的一致性,是 AI 结对最被低估的好处:它让“我当时的想法”和“最后落地的实现”之间,几乎没有损耗。
四、我具体是怎么用 Trae 的(工作流)
这一段是本文最实用的部分。我不是“打开对话问它怎么写代码”,而是把它当成一个需要被约束的工程师。
4.1 第一步:把它当项目,不是当搜索框
在 Trae 里以独立项目打开工作目录(我的项目目录名会出现在 Trae 的 MCP 配置目录里,这说明它是以项目为单位管理的,而不是临时会话)。好处:项目记忆会累积。我后面定的口径规则、踩坑记录,它会一直带着。
4.2 第二步:先给规则,再给任务
这是最关键的一步。我不会直接说“帮我写个 KV 缓存”,我会先把规则文件摆好(见第九节模板)。规则里最重要的三类:
4.3 第三步:给它一条“上板”的通道
这是我做得最对的一个决定。我给项目加了 tools/rk_remote.py——一个 SSH 执行/上传工具。它就能自己完成“写脚本 → 传到板子 → 执行 → 读日志 → 改代码”的闭环。一句提醒:Windows 侧写的 .sh 传到 Linux 后要先去 CR(sed -i "s/\\r$//"),否则报 not found——这个坑我踩过。
4.4 第四步:让它自己证明自己
我要求每个功能都要有自证日志。比如启用逐层推理时,引擎会打印:
[VQF-STREAM] enabled keep=1 nl=48 segs=11 per-layer=334.1MB data=16847.2MB resident~808.4MB rss=988kB
data=16847.2MB 是权重总量,resident~808.4MB 是实际常驻。有了这行日志,“AI 说它生效了”这个问题,就从信任问题变成了读日志问题。
五、三个技术转折点
转折点一:把“量化 + 布局重排”从推理期挪到转换期
最初的做法是常规流程:启动时读权重 → 逐层量化 → 重排布局。结果 2B 模型在板端光加载就要 20 多秒。后来我把量化与 8×8/4×4 布局重排全部固化到转换期,推理时只需 mmap + 指针直挂。意外收获:转换与推理共用同一套量化代码,这直接消灭了“两套实现漂移”的风险,也是后来“逐层档与全层档输出逐位一致”能成立的前提。
转折点二:发现“驱逐是免费的”
逐层推理的核心是:每层权重算完就 madvise(MADV_DONTNEED) 释放,只留 keep 层常驻。为什么这个设计能成立?因为映射是只读的,页面是干净页——驱逐不需要回写。下次用到再从文件重建。所以它是时间换内存,不是有损近似。这个认识一旦成立,后面的一切就顺了:权重常驻内存不再随模型体积线性增长。
转折点三:发现“最贵的优化”是一个环境变量
我的 30B 多轮追问 prefill 原来是 722 秒 / 822 秒——基本等于不可用。后来发现引擎里 L3 驱逐与前缀复用默认是互斥的,置上 VLLM_L3_PREFIX_REUSE=1 让二者共存后,同样的请求变成 4.7 秒 / 3.2 秒。一个环境变量,150 倍。这个坑的教训是:“优化不生效”往往不是优化没用,而是它被另一个机制静默关掉了。
六、4 个被 AI 坑进文档的错误结论
这一段是我写这篇文章的真正原因。AI 从没对我撒过谎。它只是特别擅长把错的结论,写得像对的一样自信、一样完整、一样有条理。下面 4 个错误结论,每一个都进过我的文档。
坑一:同一个数字,我写了三遍,三遍都对,但都不一样
我要写“逐层推理的 decode 代价”。AI 给了我 +37%,我信了,写进文档。后来自己核对,发现同一指标在不同口径下是:
| 冷页缓存 + –threads 4 | +86%(207 → 385 ms/tok) |
| 冷页缓存 + –threads 8 | +37%(429 → 586 ms/tok) |
| serve 稳态热档 | +34.6%(458.4 → 617.2 ms/tok) |
三个数字都是真的。 +37% 没错,+86% 也没错——它们只是问的不是同一个问题。如果我当初只写 +37% 发出去,我就是在用最漂亮的那个口径,去描述一个跨口径的事实。这不是撒谎,但比撒谎更糟——因为它看起来严谨,还有数据支撑。
七、成果数据(全部标注口径)
本节所有数字均标注测量口径,避免跨口径混用。
| 引擎体积 | 0.8 MB(818,872 字节) | v0 测点,单文件 |
| 服务峰值内存 | 14.23 GB → 1.11 GB | 30B-A3B,全层档 vs 逐层档 |
| 内存降幅 | 12.8× | 同上 |
| decode 代价 | +34.6% | serve 稳态热档(458.4 → 617.2 ms/tok) |
| prefill 耗时 | 722 s → 4.7 s | 30B 多轮追问,置 VLLM_L3_PREFIX_REUSE=1 |
八、反思:AI 结对把瓶颈搬到了哪里
这 27 天下来,我最大的感受是:AI 结对并没有让“写代码”消失,它只是把瓶颈从“写”搬到了“审”。以前我花时间写,现在我花时间验证它写的是不是我要的。数字口径、日志自证、跨口径核对——这些原本是工程素养,现在成了 AI 结对时代的核心技能。AI 负责把想法变成代码,我负责把代码变成事实。
九、可直接复制的规则模板
下面是我在 Trae 项目里实际使用的规则模板,可直接复制使用。
# 项目规则
## 1. 数字口径规则
– 任何数字必须标注测量口径(环境、线程数、冷/热缓存、模型档位)
– 禁止跨口径混表;同一




