导言:这本书回答什么
写作时间:2026-10-18 ~ 2026-10-20 凌晨(北京时间,实际跨了两个日历日;任务下达时说的是"10-18 ~ 10-19",
最后三章与三个附录落在 10-19 深夜到 10-20 02:11 之间 —— 按写作约定 2,这个差异写在这里而不是静默改成原话)
取材:本工作区的源码、配置、测试台、部署脚本、历史报告与工作日志
定位:架构 + 源码走读。既讲清这条链路为什么长成这样,也落到源码的关键行与实测数字。
这本书回答三个问题
一个自建的大模型推理服务,代码散在七个目录,文档散在三十多份报告,常驻进程五个,
引擎主文件 8091 行、支撑代码三万行。新人进来,或者一个 agent 会话开起来,
往往要花半天才能回答三个最基本的问题:
- 一个请求进来之后,到底经过了什么?
- 为什么系统长成这个样子,而不是那个看起来更简单的样子?
- 我们说它「能用」,凭什么?哪些数字是真的,哪些数字已经过期?
这本书就是这三个问题的答案。没做到的部分和做到的部分,用同样的篇幅写。
全书的锚点(一句话定位):
在平台分配的一个固定 GPU 容器上(2× RTX 4090D 24G、cgroup 32 核、216 GiB 内存、
只有一个公网端口 8080),为一个小组织提供对外、多用户并行、支持 1M 级长上下文的
大模型推理服务。资源是固定的,服务质量靠工程挣出来。
阅读顺序
不必从头读到尾。三条路径:
| 你是谁 | 建议顺序 | 大约耗时 |
|---|---|---|
| 刚来,要先能干活 | 01 → 02 → 03 → 15 → 17 → 附录 A | 2 小时 |
| 要改引擎代码 | 03 → 06 → 07 → 08 → 09 → 10 → 20 → 21 → 11 → 12 → 附录 A/B | 1 天 |
| 只想看"慢在哪、先动哪一行" | 20 → 21 → 19.8 | 40 分钟 |
| 要判断这套系统可信不可信 | 01 → 13 → 14 → 18 → 19 | 3 小时 |
目录
第 1 部 全景与约束
- 01 这套系统是什么 — 定位、四个交付目标、三层结构、125B 怎么塞进 24G、1M 从哪来
- 02 硬约束如何塑造了设计 — 十一条改不了的约束,每条逼出了哪个设计
第 2 部 请求的一生
- 03 一个请求的一生 — 从公网 TLS 到引擎的一个 token,再回到客户端
第 3 部 RAG 网关:唯一公网面
- 04 网关:分流与守卫 — 模型名分流、窗口守卫、思考预算守卫、鉴权与 Host 校验;§4.10 是 10-19 新增的「窗口预检与 400 改写」
- 05 网关:检索组装与漂移重建 — 结构单元分块、嵌入、重排、组装块、TTL
第 4 部 引擎内核
- 06 引擎启动与内存计划 — 参数解析、几何契约、权重表、内存预算、冷启动
- 07 专家:三级存储与命中率 — arena、VRAM 热缓存、驻留表、命中率从哪来
- 08 前向通路:内核、量化与图 — GDN / QSA / 门控残差 / MoE,量化内核,CUDA 图
- 09 prefill:最大的瓶颈 — 为什么串行、串行点在哪一行、分段让出、断点续读
- 10 投机解码与批槽 — MTP 草稿链、验证窗口、批槽、链式批槽、GMAX=8 天花板
- 11 多卡与层切分 — layer split、peer 设备、为什么对称共享专家池走不通
第 5 部 会话记忆
- 12 前缀缓存与会话停车 — 复用为什么能省一个数量级、停车快照、驱逐、隔离
第 6 部 测试台与数字
- 13 测试台:数字是怎么挣出来的 — 十场景压测、NIAH、BABILong、浸泡、崩溃注入、A/B 方法学
- 14 实测数字总表 — 每个数字带出处、带日期、带配置;以及哪些数字已过期
第 7 部 运维
- 15 部署与进程拓扑 — supervisord、两条 lane、钉核、引擎命令行每一个参数
- 16 引擎切换与停机边界 — legacy / ssebed 双 profile、switch-engine、为什么做不到零停机
- 17 红线与协作约定 — 九条不能踩的线,以及它们凭什么是红线
第 8 部 复盘与前方
- 18 事故复盘 — 六次事故:9 tok/s 之谜、驱逐风暴、特殊 token 早停、会话 bd7e62ed、写书会话 848a12ed、四层计数打架
- 19 未解问题与路线图 — 十个问题现状、九条观测盲区、优先级、已否决的路、按重启代价分层的待办;§19.8 是 10-21 的路线改写
第 9 部 解剖与动刀(2026-10-21 增补)
- 20 解码窗口的解剖 — 一帧 92.5 ms 里 76% 在 CPU 专家、23% GPU 空转;门铃、
kStagingBlobs=16、并发退化的四行代码 - 21 改造手册 — M0 零代码 → M4 行预算扩容;每步的改动点、成本、风险、验收判据与工作流
附录
三条写作约定
这三条直接沿用项目本身的工作纪律。写进书里,是为了让读者知道该多信这些字。
1. 每个数字带出处。
写法固定为「测于什么时候、什么配置、数字多少」。本书给出的性能数字,都能指回一份报告、
一段日志、或一个可重跑的脚本。找不到出处的数字,本书不写。
2. 口径冲突要写出来,不静默选一个。
历史文档里存在互相矛盾的口径(例如 CPU 配额「16 核」与「32 核」)。本书以
docs/项目背景与问题总览.md §3.1 的 2026-10-15 核实口径为准,并在用到旧口径的地方标明它存在。
3. 密钥不进书。
docs/notes/ 与若干配置文件里存在明文凭据(引擎配置 JSON 里就有 api_key 字段)。
本书一律不抄录,涉及处只写「配置里含明文 key,应改用凭据管理」。
取材清单
| 层 | 位置 | 规模 |
|---|---|---|
| C++ 引擎(上游 fork,2026-10-21 起两条 lane 都不再跑它) | ~/Strata/src、~/Strata/include |
主文件 src/program/generate.cpp 7741 行(legacy-0.1.38-b0);留作对照 |
| C++ 引擎(改造副本,2026-10-21 起 A/B 两条 lane 都跑它) | ~/SSEStraBed |
同源分叉,主文件 8091+ 行(ssebed-0.1.38-b5,带 --mtp-varlen);独立构建、可切进任意 lane;源码存档 archive/patches/mtp-varlen-2026-10-21/ |
| Python 服务层(两条 lane 共用一份) | ~/Strata/serve/ |
server.py 3459 行 / 199 KB、frontend.py 729 行 / 35 KB、Vue3 SPA webapp/ |
| RAG 网关 | ~/rag-proxy/ |
rag_proxy.py 2382 行 + doc_extract.py 698 行 + infer_store.py 881 行 + 二十余份测试 |
| 压测台 | ~/bench/ |
十场景 harness、NIAH / BABILong / 浸泡 / 崩溃注入 |
| 部署 | ~/deploy/、~/Strata/run-*.sh、~/Strata/strata-iq3_xxs-*.json |
supervisord 程序表、lane 分发器、引擎配置 |
| 文档 | ~/docs/(总览 / 部署 / 计划 / 报告 / 服务 / 笔记) |
二十余份 |
| 引擎代码知识库(第 9 部的底稿) | docs/plans/ENGINE-CODEBASE-AND-OPTIMIZATION-PLAN-2026-10-21.md |
999 行 / 24 节:代码地图 + 逐行路径 + 实测归因 + M0–M4 |
| 工具 | ~/Strata/tools/、~/tools/ |
打包、profile、A/B、停车测试、崩溃复现 |
这本书的边界
- 它不教 Transformer / MoE / 量化的基础数学。需要的话见
docs/plans/ENGINE-LEARNING-ROADMAP.md的预备知识节。 - 它不是 API 手册。接口字段以
docs/deployment/STRATA-DEPLOYMENT.md与serve/server.py为准。 - 它写的「现状」是 2026-10-19 全天变更落地之后、2026-10-20 凌晨的现状(RAG 已关闭、窗口预检已上线、
两条 lane 都已重启);第 9 部(20、21 章)与各章2026-10-21增补是在那之后的现状
(两条 lane 都切到ssebed-0.1.38-b5)。项目正在从「学习阶段」转入「改造引擎阶段」,
第 19 章列的问题里,有几个在你读完时可能已被解决或推翻。发现不一致,请更新
docs/项目背景与问题总览.md——那才是权威口径的所在地。 - 第 9 部只给路径,不给战果:M0–M4 在写作时一步都没实施。
完成状态
2026-10-21 增补:两条 lane 都切到
ssebed 0.1.38 build 5(--mtp-varlen)。
「现在线上到底是什么」以docs/reports/CURRENT-VERSION-2026-10-21.md为准(拓扑 / 二进制 sha /
两套 profile 参数 / 新增特性 / 实测 / 已知问题),本书 10、14、15、16、19 章与附录 B 已同步。
全书 25 个文件(README + 正文 01–19 + 20/21 + 附录 A/B/C),6385 行 / 410,104 字节
(wc 实测于 2026-10-21)。
正文 01–19 与附录落款 2026-10-20 02:11;第 9 部(20、21 章)与各章增补落款 2026-10-21 19:00(北京时间)。
目录里的每个链接都与实际文件名一一对应,无缺章、无改名。
2026-10-21 增补(第 9 部)
逐行读完 SSEStraBed 之后补的,动因是:原书能解释"系统怎么运转",但解释不了"解码时 GPU 为什么闲着"。
| 文件 | 改了什么 |
|---|---|
| 20 新章 | 一帧解码的毫秒账(92.5 = 70.0 CPU + 21.1 门铃 + 1.6);门铃协议(verify.cpp:1755-1827 + 单线程等待核);strata batch: 的读法与单位坑;kStagingBlobs=16、dma_src[64]、kVerifyMaxT=8;并发退化的四行代码;step-stats 与压测台两套口径 |
| 21 新章 | M0–M4 改造手册:每步的改动点、显存/风险成本、验收判据、switch_engine.py dev 工作流、四条红线 |
| 07 §7.12 | 三级决策的真实代码(expert_source.cpp:3376-3413)、kStagingBlobs=16 的分配与代价、实测三级配比、命中率斜率的正确用法 |
| 09 §9.9 | prefill 两条专家路径(MMQ 每层 cudaStreamSynchronize vs 融合 kernel)、本包类型全覆盖只差 STRATA_PF_FUSED=1、read_windows 已经存在 |
| 10 §10.8 | L_max = min(4, 8/S) 的浪费、sl.sampled 让整组退化(194 vs 82)、lockstep、与 --mtp-varlen 的关系 |
| 14 §14.13 | lane A 当日实测表(step-stats 中位数 / strata batch: 三条样本 / 命中 88.6% / PCIe 22.7 GB/s)+ 口径差一倍的警告 |
| 19 §19.8 | 路线改写:三个新事实、新增的硬上限、#1 的性质变化、M0–M4 表 |
| 附录 A | A.0 两条 lane 现跑同一份代码;A.1.3 常量从 2 个扩到 6 个;新增 A.1.4 全量重新锚定(8177 行口径) |
| 附录 B | --pcie-frac / --short-read 进入"没设"表;新增 B.1.3 编译期常量;STRATA_PF_FUSED 单列;pool-workers 标注 13 是上限 |
这一轮发现并在书里更正的过期信息(都按写作约定 2 留在原处加注,不静默改):
- 两条 lane 都跑
SSEStraBed(附录 A.0 原写 B 跑/home/cloud/Strata)——源码行号从此对两条 lane 一致。 --batch-groups两条都是 1(10.1 原写 A=1、B=2)。- ssebed 的
strata-b.json已有fit_max_tokens(附录 B 原写"没有这个键")。 --pool-workers 13是对的:taskset把 lane 钉在 16 核,13 worker + 宿主已饱和。
(造这条路时我一度按 cgroup 32 核推断"加到 24 更好"——错的。记在 21.2,防止下一个人再走一遍。)
写作过程中的两点自我修正,如实留在这里:
- 04 章写于 10-19 那次修复之前,§4.3 的三层守卫与行号是修复前口径。已加 §4.10 增补
「2026-10-19 窗口预检与 400 改写」,并在 §4.3 顶部标明"本节保留原样是为了让顺序可读"。 - 附录里的行号全部当场
grep -n重新锚定过,与旧报告引用的行号存在可查证的漂移
(例:clamp_max_tokens243→265、盲重试 1715→1768、rag_proxy.py2206→2382 行)。
引用本书行号前请先按附录 A.6 的方式核实——本书的行号也会腐烂。
尚未覆盖、留给下一版的部分:fit_max_tokens 的行为级验证(需窗口边缘请求)、
overfit_retries / window_guard_rejects 的 1–2 天分布观察、中继窗口 256,000 与引擎 262,144 的对齐结果。