第 1 章 这套系统是什么
MoE 大模型低成本部署框架第 1 章 这套系统是什么
CHAPTER 01

第 1 章 这套系统是什么

9 分钟阅读 · 2,384 字

本章读完你应该能回答:我们在做什么、给谁用、系统分几层、
一个 125B 的 MoE 模型凭什么能跑在 24G 显存的卡上、1M 上下文是从哪来的。


1.1 一句话,和它的每一个限定词

在平台分配的一个固定 GPU 容器上,为小组织提供对外、多用户并行、支持 1M 级长上下文的
大模型推理服务。

每个限定词都在缩小问题,也都在制造困难:

限定词 它排除了什么 它制造了什么
一个固定 GPU 容器 不能加机器、不能换卡、不能弹性扩容 所有性能问题只能在软件里解决
2× RTX 4090D 24G 不能跑未量化的大模型、不能开大 KV 窗口 必须量化、必须把权重放到 CPU 内存甚至磁盘
对外 不是本地玩具,要经公网给真人用 鉴权、稳定性、降级路径、故障自愈全都变成必须项
多用户并行 不是单会话 demo 并发、上下文隔离、排队而不是拒绝
1M 级长上下文 远超模型原生 256K 窗口 引擎外必须有一套「把超长会话变短」的机制
小组织 用户量不大但真实(课程 / 团队) 可以接受排队,不能接受长期不可用

使命陈述(docs/项目背景与问题总览.md §1、.agent/goal.md):

资源是固定的,服务质量靠工程挣出来。

这句话是全书的因果解释来源。后面每一章的每一个「为什么这么绕」,追到底都是这句话。


1.2 四个交付目标,和它们的验收方式

# 目标 含义 怎么验收
1 可用 OpenAI /v1/chat/completions + Anthropic /v1/messages 双协议;流式、多模态、思考模式 用真实客户端(含 Claude Code)连上就能用
2 并行 多用户同时用,互不阻塞、互不串上下文 并发压测 + 会话隔离测试
3 长上下文 远超原生 256K 窗口的会话与粘贴(1M token 级),且永不 400 拒 1M 埋针套件、单条 1,000,046 token 粘贴
4 可信 每项能力有实测数字与测试台背书;故障自愈;依赖不可达时有降级 压测台报告、浸泡测试、kill -9 注入

第 4 条是这个项目最不寻常的一条:它要求自己的每个能力声明都能指回一个可重跑的测量。
第 13、14 章专门讲这件事怎么落地,以及它在哪里失守过。


1.3 三层结构

用户 / 客户端(OpenAI・Anthropic SDK、Claude Code)
   │  https://ssemarket.cn:23034      外网模型名:qwen3.8-flash / qwen3.8-flash-fast
   ▼
frps 中继(TLS 在这里终结)
   ▼
Pod :8080 ── RAG 网关 rag-proxy(唯一公网面)
   │           · 模型 ID 分流 · 窗口守卫 · 思考预算守卫
   │           · 超窗会话 → 检索组装(见 §1.5)
   │           · 鉴权严格透传 · 并发监控数据源 /concurrency
   ├──────────► strata-a 快道  127.0.0.1:8091  GPU0  钉核 0-15   模型名 *-fast
   └──────────► strata-b 普道  127.0.0.1:8092  GPU1  钉核 38-53  默认通道
                引擎只监听回环,外部不可达(排障时直连它)

出处:docs/项目背景与问题总览.md §3.2、deploy/supervisord.conf、Strata/run-iq3_xxs-a.sh。

每一层是什么

① RAG 网关(~/rag-proxy/rag_proxy.py)
唯一暴露到公网的进程。它做四件事:分流、守卫、超窗组装、鉴权透传。
它不改引擎——这是刻意的,第 5 章会解释为什么「零引擎改动」是这个方案的核心优点。

② Python 服务层(~/Strata/serve/server.py)
每条 lane 一个进程。它把 HTTP 世界的东西(JSON、SSE 流、chat template、tool call 解析、
图片预处理)翻译成引擎世界的东西(token 序列、GEN/BGEN 行协议),并把引擎吐出的
token 流翻译回去。它还负责生老病死:拉起引擎子进程、看它有没有死、死了怎么办。

③ C++ 引擎(~/Strata/build/strata,生产用 ~/Strata/engine/strata)
真正做前向计算的东西。它只认 stdin/stdout 上的行协议,只认回环地址,
不知道 HTTP 是什么。

为什么分成三层

因为改动成本不同。改网关只要 supervisorctl restart rag-proxy(秒级);
改 Python 服务层不用重编引擎;改引擎要重编 20–40 分钟 + 冷启动 30 秒到 8 分钟。
把「经常改的东西」放在上层、「慢而贵」的东西压到最底层,是这个分层最实际的收益。


1.4 125B 模型凭什么跑进 24G 显存

这是新人最容易误解的地方。模型并没有「跑进 24G 显存」——它大部分时间不在显存里。

模型是 Qwen3.8-Flash-Next,IQ3_XXS 量化。它的几何(include/strata/core/layout.hpp:26-58):

参数 值 说明
n_embd 2560
n_layers 48
qsa_interval 4 每第 4 层是全注意力:3, 7, …, 47 → 12 层 QSA + 36 层 GDN
n_expert 512 每层 512 个专家
n_ff 640 每个专家的中间维度
n_head / n_head_kv / head_dim 24 / 2 / 128 GQA
hc 4 门控残差(Hyper-Connections),每层都有

算一下参数分布:每层专家参数 = 3 × 2560 × 640 × 512 ≈ 25.2 亿,48 层 ≈ 1210 亿。
也就是说,这个模型的参数几乎全在专家里,稠密部分只占很小一块。

专家权重在 pack 里的实际字节数写在 Strata-data/packs/iq3_xxs/native_experts.txt 头部:

# strata native experts v3: layer gu_type d_type offset blob_bytes gate_off up_off down_off
# (n_expert 512, total 42912972800; absolute offsets in ...IQ3_XXS-00001-of-00002.gguf)
0 17 20 0 1868800 1227833216 1473813376 755052416
1 16 42 956825600 1305600 2016152832 2235918592 1779301632

专家全量 = 42.9 GB,单个专家 blob 约 1.3–1.9 MB,且不同层的量化种类不同
(第 0 层 gu_type 17 / d_type 20,第 1 层 16 / 42,blob 大小随之不同)。

42.9 GB 塞不进 24 GB。所以有了六个机制,每个都在换一部分:

机制 它换来什么 它的代价
MoE 稀疏 每 token 每层只激活 10 个专家(512 里选 10)→ 不需要同时持有全部 需要路由,需要缓存策略
专家三级存储 热专家在 VRAM、全量在 RAM arena、磁盘兜底 未命中的专家要走 PCIe,慢
3-bit 量化(IQ3_XXS,imatrix 校准) 76.7 GB 模型压到能装 质量损失,需要实测确认能接受
KV 流式 常驻窗口 32768 token 在显存,其余 int8 放内存 长上下文的 KV 不在显存里
MTP 投机解码 一次草稿 4 个 token,验证接受率 ~65% → 解码速度翻倍 多一个草稿头、多一层复杂度
PLE 表入内存 28.8 GB 逐层位置嵌入表走页缓存(--ple-io ram) 机械盘随机读 6.9 ms 是性能命门

出处:docs/项目背景与问题总览.md §3.3、include/strata/core/expert_cache.hpp:5-16。

最关键的量化事实(include/strata/core/expert_cache.hpp 开头,作者自己写进注释的):

The CPU expert pool is the engine’s largest single cost: measured, 663.6 MB of expert bytes
per token at ~40 GB/s = 16.2 ms
, on a token of ~53 ms, and test_expert_pool says the pipeline
hides 1.055 ms of 19.035 — the CPU work is 96% exposed because the residual chain is
strictly serial.

三句话交代了整个项目的性能主线:

  • 一个 token 约 53 ms,其中 16.2 ms 是从内存读专家字节;
  • 流水线只藏住了 19.035 ms 里的 1.055 ms —— 96% 的 CPU 工作是暴露的;
  • 所以唯一的出路是少读这些字节:把一部分专家放进显存。

这就是 --expert-cache 存在的全部理由,也是第 7 章的主题。


1.5 1M 上下文是从哪来的

引擎的原生窗口硬固定 262144,而且引擎从不截断、超窗即 400。这是引擎的设计选择,
不是 bug(见第 2 章约束 1)。

所以 1M 能力不在引擎里,在网关里:

会话历史 → 按结构单元分块(不跨回合)→ bge-m3 嵌入 → bge-reranker 重排(候选 200,MMR)
        → 组装 = 最近窗口 65K 逐字 + 检索块(带回合标签、结构补全)
        → 引擎永远收到 ≤ 262144

这个方案最漂亮的地方是它零引擎改动:引擎以为自己只是在处理一个正常的 262K 以内的会话。

它的代价是一条硬推论(docs/项目背景与问题总览.md §3.4):

1M 能力 = 检索质量。

引擎看不到全部 1M token,它看到的是网关替它选出来的那 262K。选得好,答得对;
选得不好,模型会自信地答错。这条推论在第 5 章展开,也是问题 #2(BABILong 2/15)的根因。


1.6 目录地图:代码散在哪

目录 是什么 生产在跑吗
~/Strata/ 引擎 fork + Python 服务层 + 前端 + 工具 是(两条 lane 都在这)
~/SSEStraBed/ 引擎 0.1.38 的独立改造副本,只含 C++ 引擎 可切进 lane(第 16 章)
~/rag-proxy/ RAG 网关 是(唯一公网面)
~/bench/ 压测台 按需跑(只打普道)
~/deploy/ supervisord 配置、lane 分发、引擎 profile 是
~/docs/ 项目文档(总览 / 部署 / 计划 / 报告 / 服务 / 笔记) —
~/tools/、~/Strata/tools/ 打包、profile、A/B、停车测试、崩溃复现脚本 按需
~/Strata-data/ 模型权重、pack、MTP 草稿层(只读共享盘) 是
~/archive/ 补丁与快照(回滚可重放) —

~/SSEStraBed/MANIFEST-SSEStraBed.txt 明确写了副本的边界:

contents: src/ include/ tests/ third_party/ cmake/ CMakeLists.txt LICENSE tools/{iq_fixture,gguf_writer,gguf_reader}.py deploy/ build/ 切换引擎用户手册.md
not_included: serve/ docs/ bench/ ref/ data/ sse-deploy/ setup.py Dockerfile *.bat run scripts .venv logs configs
python_layer: /home/cloud/Strata/serve/server.py (shared)
runtime_data: /home/cloud/Strata-data + /home/cloud/Strata/data (shared)

关键认知:改造副本只换 C++ 二进制,Python 服务层和运行时数据是共用的。
这条边界让「改引擎」这件事的成本从「重做整个系统」降到「换一个二进制 + 重启一条 lane」。


1.7 现在在哪个阶段

docs/项目背景与问题总览.md §2 说得很直白:

当前处于学习阶段:先把系统跑通、读懂链路与引擎源码、能复现压测,再动手。
下一步的主线任务:改造当前的推理引擎。

三层递进:

① 学习项目          →   ② 改造推理引擎(当前主线)   →   ③ 扩展模型
读懂链路与源码         治 prefill 串行、批槽能力、          异模型双通道、
能复现压测             补可观测性(前置工作)              适配更多 MoE、争取第三张卡

这本书本身属于①的产出,也是②的输入。


1.8 本章小结

  • 这是一个资源固定的生产服务,不是实验台。所有性能问题只能在软件里解决。
  • 三层结构:网关(唯一公网面)→ Python 服务层 → C++ 引擎(只听回环)。分层是按「改动成本」切的。
  • 125B 能跑起来靠六个机制叠加,核心是 MoE 稀疏 + 专家三级存储;
    一个 token 53 ms 里有 16.2 ms 是从内存读专家,且 96% 暴露。
  • 1M 上下文不在引擎里,在网关的检索组装里;因此 1M 能力 = 检索质量。
  • 项目正在从「读懂它」转向「改它」。

下一章讲那些改不了的约束——它们是理解后面所有章节的钥匙。

全部章节