【轻量化复刻大模型 / KIMI K3】Serve 模块交互式演示

【轻量化复刻大模型 / KIMI K3】Serve 模块交互式演示

目录

0x00 概述

K3 Serve 模块的完整交互式演示,14 个 Tab 覆盖投机回放(投影缓存 vs 快照)、重演一致性验证、ReplaySSM 环形缓冲、统一页池(MLA 分页 + KDA 恒定)、前缀缓存两阶段 lookup + KDA checkpoint 原子性、引擎 before/after、Fleet 一致哈希路由 + 预算隔离。全部 CPU 实时运行,复用 decode.py、replayssm.py、paged_cache.py、prefix_cache.py、engine.py、fleet.py 真实源码算子。

注:

  • 项目https://github.com/RossiLH/Model-Viz 和系列博客是我的一个尝试,也是我学习的过程。不确定是否满足读者的需求,我自己会反思改进,也希望大家提出宝贵意见。
  • 涉及 KIMI K3,DeepSeek V4,PI0.5,PI0.7 等模型。后续可能会跟踪新模型。
  • 全 CPU 复刻,不涉及 GPU,也不涉及大规模训练(这是另外一个庞杂深邃的领域)和硬件。
  • 模型的组件尽量是原始大模型的缩小版,如果组件没有开源版本,则用近似组件替代。
  • 会解释每个组件在解决一个什么问题、这个问题难在哪、为什么只能这么解、解法的原理是什么,以及组件之间如何咬合成一个整体。重点不是记名词,而是理解一条主线。
  • 每个主要组件都有可直接运行的 Gradio demo——无需 GPU。另有若干可视化脚本(plot_*.py),可生成静态图。
  • 所有文件行号基于本地源码快照;源码后续变化时,行号可能移动,但函数名和调用关系仍可作为定位入口。
  • 为了保证每个文章可以尽量独立成文,所以有些内容会在不同文章中都存在,可能在系列层面上存在冗余,还请大家理解。

0x01 核心数学

1.1 KDA 投机回放:投影缓存 vs 完整快照

KDA 的递归状态 S 每步就地更新,投机被拒时无法直接回滚。两条策略:

路线 A: 完整快照 (replayssm.py)

每步缓存: S_t ∈ R^{H × dk × dv}

每步字节: H * dk * dv * sizeof (dtype)

回滚: pop 最旧快照 → O (1) 取回,代价是存储翻倍

路线 B: 投影缓存 + 重演 (decode.py)

每步缓存: (q_t, k_t, v_t, g_t, beta_t)

每步字节: H * (3*dk + dv + 1) * sizeof (dtype)

回滚:从 committed 状态用 kda_step 逐位重演 n_accepted 步 → 精确重建

代价比 (draft 长度在分子分母抵消):

snapshot_cost_ratio = (H * dk * dv) / (H * (3*dk + dv + 1))

例: H=16, dk=32, dv=32 → 比值 = 4.0x(投影每步只需快照的 1/4 字节)

  • 直觉: 投影只存 "输入"(5 个小向量),快照存 "整个状态矩阵";dk*dv 越大,投影优势越明显

  • 关键性质: 比值与 draft 长度无关 —"draft 越长越省" 体现在绝对字节差随 draft 线性增大

1.2 verify_and_replay 重演一致性

输入: committed 状态 S_0, DraftProjections (q,k,v,g,beta)[:n_accepted]

输出: (S_new, output_stacked)

S = S_0.clone()
for i in 0..n_accepted‑1:
    out_i, S = kda_step(q[i], k[i], v[i], g[i], beta[i], S)
output_stacked = stack(out_0, ..., out_{n‑1})   # (B, H, n, Dv)
  • 一致性保证: verify_and_replay 的输出与 kda_recurrent 对前 n 个位置的完整递推逐位一致(float64 下 max|diff| < 1e‑12)

  • clone 必要性: committed 是 cache 里共享的对象,必须拷贝一份避免重演污染共享状态

1.3 KDA 递推核心 (kda_step /kda_recurrent)

Delta Rule 递推:
delta_t = v_t − S_{t‑1}^T k_t        # 纠错项
S_t     = Diag(alpha_t) · S_{t‑1} + beta_t · k_t · delta_t^T

读出:
o_t = S_t^T · q_t
  • alpha_t = g_min * sigmoid(...) − 有界衰减,alpha_t ∈ [g_min, 0]

  • beta_t = sigmoid(...) − 写入强度,beta_t ∈ [0, 1]

  • delta‑rule vs 线性注意力: delta_t 是 "新值减去旧预测" 的纠错,而非直接加 k*v

1.4 ReplaySSM 环形缓冲

push(state):
    if len(states) == capacity: states.pop(0)   # 满员覆盖最旧
    states.append(state)

pop() → states.pop(0)                           # 始终返回最旧快照
  • FIFO‑overwrite 语义: 满员时新状态覆盖最旧,pop() 无条件返回队首

  • 为什么不用纯游标环形: 满→pop 再 push 会导致游标错位,pop 取到较新快照而非最旧(test_replayssm.py 的回归测试覆盖此场景)

  • copy_from 深拷贝: 保证两环相互独立,修改一个不影响另一个

1.5 统一页池 (PagedCache)

  1. PagePool:单一 free list 管理两种 page kind(MLA_KV / KDA_STATE)

  2. MLA 分页:append_mla(n_tokens)

    • tokens_per_page=512,每写满 512 token 分配新页

    • 页数 = ceil(n_tokens / tokens_per_page)

  3. KDA 恒定:store_kda(layer, state)

    • 每层 KDA 状态 S (B,H,dk,dv) 固定字节,占一页

    • 页数 = n_layers(与序列长度无关)

pack_heads: (B,H,dk,dv) → flat    # 按 head 连续摊平
unpack_heads: flat → (B,H,dk,dv)  # 无损还原
  • 统一池的价值: 两种 page 共享同一份 free list,上层只需操作 PagePool 一个对象,不必区分 "这是 MLA 页还是 KDA 页"

  • pack/unpack 无损: float64 下 max|diff| < 1e‑12

1.6 前缀缓存:两阶段 lookup + chained hash + KDA checkpoint 原子性

chained hash:

H_0 = sha256("", tokens[0:512])
H_1 = sha256(H_0, tokens[512:1024])
...

H_i 认证 "直到该端点的整个前缀" → hit = 内容完全一致

两阶段 lookup:

阶段 1 (MLA 细粒度): 从 t=0 按 hash_block_tokens=512 逐块计算 chained hash,在 index 中命中且 ready → 继续;miss → 停止

阶段 2 (KDA 原子性): 从最深匹配边界往回退,找到 endpoint 处每个 KDA group 都有 checkpoint → 命中,缺一个 group → 不可用

  • 原子性: KDA 递推状态必须整组一起恢复,只要有一个 group 缺快照,这个边界就不可复用

  • chained hash vs 独立 hash: chained hash 保证 hit = 内容完全一致,不存在 "高 prefix 撞车" 歧义

  • ready 标志: 异步登记时 ready=False,lookup 只认 ready=True 的块,避免 false hit

1.7 引擎 before/after

首请求: prefill 512 token → PagedCache 存 KDA page → register + persist checkpoint
第二请求 (命中): prefix lookup → 复用 MLA page + KDA checkpoint → reused_tokens=512
第二请求 (未命中): 全重算 → reused_tokens=0

KCP 通信量:与序列长度无关 O (1)

comm_bytes = KDAContextParallel.communication_volume(B, H, dk, dv, world)

1.8 Fleet 调度:一致哈希 + 预算隔离

一致哈希环:

add_cluster(id, vnodes=8): 把 id 散布 vnodes 个虚拟节点到环上
route(session_id) → (primary, secondary)
  * primary: session 的 md5 顺时针落入的集群
  * secondary: 顺移下一个不同集群 (primary != secondary) 硬约束
  • hopscotch 性质:移除 1 集群只扰动 O (1/N) 的 session

预算准入:

BudgetController:
    budgets = {"short": S, "long": L}
    weights = {"short": 1, "long": 3}
    admit(class, usage) = usage[class] + weight[class] <= budget[class]

  • 隔离效果: 长突发只消耗自己的配额,短请求配额不受影响 → 短 P95 TTFT 显著更低

0x02 设计思路与实现细节

2.1 文件

experiments/models/llm/kimi_k3/serve/gradio_serve_demo.py

2.2 覆盖范围

serve 模块全部 7 个源文件、6 个测试文件,共 14 个交互 tab:

Tab 函数 覆盖源文件 覆盖测试
1 fig_replay_principle decode.py test_decode.py
2 fig_snapshot_cost decode.py test_decode.py
3 fig_replay_consistency decode.py test_decode.py
4 fig_replayssm replayssm.py test_replayssm.py
5 fig_page_pool paged_cache.py test_paged_cache.py
6 fig_mla_paging paged_cache.py test_paged_cache.py
7 fig_kda_store paged_cache.py test_paged_cache.py
8 fig_prefix_hit prefix_cache.py test_prefix_cache.py
9 fig_prefix_miss prefix_cache.py test_prefix_cache.py
10 fig_engine_before_after engine.py test_demo_engine.py
11 fig_fleet_hash_ring fleet.py test_fleet.py
12 fig_fleet_minimal_perturbation fleet.py test_fleet.py
13 fig_fleet_budget fleet.py test_fleet.py
14 fig_fleet_simulation fleet.py test_fleet.py

2.3 设计决策

  • 纯计算可视化:所有 tab 的数据均来自 verify_and_replay、kda_recurrent、PagePool、PrefixCache、FleetSimulator 等真实模块,无硬编码数据
  • sys.path:5 级上溯至 src/ + 1 级上溯至当前目录(_THIS_DIR)
  • gr.Plot:Gradio 6 内部处理 Figure -> base64,无需手动转换
  • 主题:gr.themes.Soft()(移到 launch() 参数,Gradio 6 规范)

2.4 依赖

  • models.llm.kimi_k3.modules.kda_ref — kda_recurrent, kda_step
  • models.llm.kimi_k3.serve.decode — DraftProjections, verify_and_replay, snapshot_cost_ratio
  • models.llm.kimi_k3.serve.replayssm — ReplaySSM
  • models.llm.kimi_k3.serve.paged_cache — PageKind, PagePool, PagedCache, pack_heads, unpack_heads
  • models.llm.kimi_k3.serve.prefix_cache — PrefixCache, chained_hash
  • models.llm.kimi_k3.serve.engine — run_once
  • models.llm.kimi_k3.serve.fleet — ConsistentHashRing, BudgetController, FleetSimulator, Request

2.5 运行方式

运行demo:

python experiments\models\llm\kimi_k3\serve\gradio_serve_demo.py

启动后访问 http://localhost:7860,14 个 tab 垂直排列,点击切换。

运行所有测试:

python -m pytest tests/models/llm/kimi_k3/serve/ tests/models/llm/kimi_k3/parallel/ -q

2.6 依赖

  • plot_utils.py — 字体配置 + 工具函数
  • plot_decode_replay.py — 快照成本曲线
  • plot_verify_principles.py — 成本对比 + 原理示意图
  • plot_paged_cache.py — 统一页池 MLA vs KDA
  • plot_prefix_cache.py — 前缀缓存命中/未命中
  • plot_fleet.py — 一致哈希 + 预算隔离
  • demo_engine.py — 引擎 before/after
  • tests/.../test_helpers.py — make_projection, to_batch, make_state

0x03 Tab 功能说明

Tab 1 — 投机回放原理

  • 左上:draft 阶段投影缓存 vs 完整状态的内存对比
  • 右上:快照 vs 投影每步字节成本(随 dk 变化)
  • 中左:verify_and_replay 重演流程图
  • 中右:三种接受场景(部分/全部/零接受)的输出对比
  • 底部:代价对比公式

Tab 2 — 快照成本分析

  • 左:比值随 dk 扩展(dv=32 固定)
  • 右:绝对字节差随 draft 线性增大

Tab 3 — 重演一致性

  • 三种场景下 verify_and_replay 输出与 kda_recurrent 逐位对比
  • 状态最大差显示

Tab 4 — ReplaySSM 环形缓冲

  • push/pop 时序、pop 返回最旧、capacity 满覆盖、copy_from 深拷贝独立性

Tab 5 — 统一页池

  • 初始空闲、分配 KDA+MLA、释放回收的三阶段可视化

Tab 6 — MLA 分页

  • append_mla 跨页、pack/unpack 往返验证

Tab 7 — KDA 存储

  • store_kda 流程、load_kda 往返验证

Tab 8 — 前缀缓存命中

  • 两阶段 lookup 流程图、chained hash 链式依赖

Tab 9 — 前缀缓存未命中

  • 无 checkpoint miss、部分 checkpoint 回退

Tab 10 — 引擎 before/after

  • 前缀命中 vs 未命中的复用 token 数、四项指标对比

Tab 11 — Fleet 一致哈希

  • 环分布可视化、600 session 路由均匀性

Tab 12 — Fleet 最小扰动

  • 移除 1 集群的扰动比例、只有指向失效集群的 session 改绑

Tab 13 — Fleet 预算隔离

  • 有/无预算隔离的短请求 P95 TTFT 对比、拒绝数

Tab 14 — Fleet 综合仿真

  • 命中率、集群负载、TTFT 分布、汇总指标

0x04 Tab 1: 投机回放原理

4.1 目的

展示投机解码两条回滚策略的核心设计:投影缓存(decode.py) vs 完整快照,以及 verify_and_replay 的重演流程(KDA‑Infra §4)。

4.2 UI 组件与参数影响

无参数,页面加载时自动运行。

4.3 输出图解读

tab-1

3×2 六联图:

左上 (a): Draft 阶段缓存投影而非完整状态

  • 柱状图,交替蓝色 (Blue)(状态 S)和绿色 (Green)(投影 q/k/v/g/beta)

  • 蓝色柱高 = 1.0(完整状态),绿色柱高 = 0.4(投影更小)

  • 你该看什么: 投影每步远小于完整状态

右上 (b): 快照 vs 投影每步字节成本

  • 分组柱状图,红色 (Red)= 快照 Hdkdv,绿色 (Green)= 投影 H*(3Dk+Dv+1)

  • X 轴 = dk 值 (16/32/64)

  • 你该看什么: dk 越大,快照与投影的字节差距越大

中左 (c): verify_and_replay 重演流程

  • 方框箭头示意图:committed → projections [:n] → kda_step × n → 与 kda_recurrent 逐位对比

  • 你该看什么: 重演路径与完整递推数值一致

中右 (d): 三种接受场景

  • 水平柱状图:部分接受 (n=2) 橙色 (Orange)、全部接受 (n=4) 绿色 (Green)、全部拒绝 (n=0) 红色 (Red)

  • 柱旁标注输出步数

  • 你该看什么: 接受数决定重演步数

底部 (e): 代价 "代价公式"

  • 文字框:快照每步 Hdkdv 字节 | 投影每步 H*(3Dk+Dv+1) 字节 | 比值公式 + 数值示例

  • 你该看什么: 比值与 draft 长度无关

4.4 为什么重要

这是理解 K3 投机解码回滚策略的入口图。投影缓存是 K3 的核心设计选择 — 比 SGLang 的快照策略每步节省数倍内存,代价只是一次短重放 O(n_accepted) 步 kda_step。

0x05 Tab 2: 快照成本分析

5.1 目的

画出 draft 长度 vs 投影/快照字节比,验证比值恒定且 >1(投影永远更省)。

5.2 UI 组件与参数影响

无参数,页面加载时自动运行。

5.3 输出图解读

tab-2

单图(折线图):

  • X 轴 = draft 长度(1/2/4/8/16/32),Y 轴 = 投影 vs 快照字节比
  • 你该看什么:比值是水平线(与 draft 无关),恒 ≈3.94

5.4 为什么重要

量化证明"投影缓存比快照更省"的核心论点。比值与 draft 无关说明优势来自每步字节差,而非 draft 长度。


0x06 Tab 3: 重演一致性

6.1 目的

验证 verify_and_replay 与 kda_recurrent 在三种接受场景下的逐位一致性(float64 精度)。

6.2 UI 组件与参数影响

无参数,页面加载时自动运行。

6.3 输出图解读

tab-3

1×3 布局,每个子图一种场景:

  • 绿色(Green)边框 + "PASS": 输出一致
  • 红色(Red)边框 + "FAIL": 输出不一致(不应出现)
  • 文字标注:场景名、输出一致判定、状态最大差(应为 ~1e‑15)
  • 你该看什么:三种场景全部 PASS,最大差 < 1e‑12。即,三种场景 (部分/全部/零接受) 输出均与 kda_recurrent 逐位一致 最大差: 0.00e+00 (float64 精度)

6.4 三种场景构建方式

verify_and_replay(s0, proj, n) 模拟投机解码的"草稿-验证-回滚"流程。三种场景通过控制 n(实际接受的草稿 token 数)构造:

场景 n 构建方式 验证目标
部分接受 n=2 让 4 个草稿 token 中只有前 2 个通过验证(其余 2 个被拒绝)→ 重演时只回滚这 2 个,S 状态也要回滚到接受第 2 个后的位置 验证"部分接受时,输出和状态都能精确回滚"
全部接受 n=4 4 个草稿 token 全部通过验证 → 无回滚,输出 = 4 个 token 的完整前向,S 推进到第 4 个后的位置 验证"零回滚时输出与 kda_recurrent 完全一致"
全部拒绝 n=0 4 个草稿 token 全部被拒绝 → 完全回滚,输出为空(shape 第 2 维 = 0),S 状态保持为 s0 不变 验证"全拒绝时 S 状态完全不变(s_replay == s0)"

底层机制:投机解码每轮提出 4 个草稿 token,验证后决定接受 0~4 个。kda_recurrent 是"标准答案"(一次性跑完整序列),verify_and_replay 是"工程实现"(按需回滚)。三种场景覆盖全部边界情况:n=0(纯回滚)、n=4(纯前向)、0<n<4(混合),确保实现与参考一致。

6.5 为什么重要

这是重演策略正确性的数值证明。如果 verify_and_replay 与 kda_recurrent 不一致,投机解码的回滚路径会产生错误输出。


0x07 Tab 4: ReplaySSM

7.1 目的

本 Tab 验证 RawInputRing 流式 raw-input 窗口 与 SGLang ReplaySSM fold-every-commit 语义 的一致性(对应 replayssm.py 实现,SGLang server_args.py:2688-2696 与 hybrid_linear_attn_backend.py:1261-1283)。

核心验证逻辑:RawInputRing 与 decode.py 批量构造的 DraftProjections 共享同一个 verify_and_replay 重演引擎,两者在数学上完全等价——缓存内容相同(raw input (q,k,v,g,beta))、回滚结果相同(与 kda_recurrent 参考逐位一致)、差异仅在写入时机(流式 vs 批量)。

7.2 背景知识

SGLang ReplaySSM 不是存快照,而是 fold-every-commit: verify 期间流式存 raw input,commit 时重演 accepted prefix。 与 decode.py 投影重放共享 verify_and_replay,差异只在写入时机。

RawInputRing(raw-input 环形窗口):SGLang ReplaySSM 的真实实现语义——投机验证期间不存完整状态快照,而是把每步 draft 的原始输入投影 (q,k,v,g,beta) 流式写入 per-slot 环形窗口;commit 时取窗口内容,用 kda_step 重演被接受前缀。与 decode.py 的 DraftProjections(批量构造载体)是同一数据的不同封装。

fold-every-commit:SGLang 术语,指"验证期间折叠(不保存中间状态),提交时重演"。这是 KDA 投机回滚的唯一可行方案,因为 KDA 的 delta-rule 状态递推不可加、不可截断(见 kda.py 与 KCP 前缀扫描)。

7.3 设计思路

  • 为什么这样设计实验:采用 2×2 四联图布局,分别展示"时序行为→数据结构→正确性→成本"四个维度。左上用水平条形图展示 push/覆盖时序(直观呈现环形语义);右上用热图展示 window() 输出的 DraftProjections 布局(验证数据格式正确性);左下用双柱对比图展示两条路线的数值误差(验证数学等价性);右下用折线图展示带宽账随 draft 长度的增长趋势(验证成本优势)。本 Tab 是 serve 模块的正确性锚点**,与 Tab 3(verify_and_replay 批量重演)形成"流式 vs 批量"的互补对照。
  • 想验证什么:
    1. RawInputRing 的 push/覆盖时序符合环形缓冲语义(capacity=4 时第 4 步起窗口大小恒为 4)
    2. window() 输出的 DraftProjections 布局为 (draft, B, H, D),且第 i 行对应第 i 步 push 的数据
    3. RawInputRing 与批量构造的 DraftProjections 经 verify_and_replay 后,与 kda_recurrent 参考的 max err = 0
    4. raw input 的缓存字节数恒小于假想快照,比值 = snapshot_cost_ratio
  • 希望读者学到什么:
    1. SGLang ReplaySSM 不是"存快照",而是"存 raw input + commit 时重演"——与 decode.py 投影重放同宗同源
    2. RawInputRing 与 DraftProjections 是协作关系(流式写入管理器 vs 批量数据载体),不是替代关系
  • 希望从图上看到什么:
    • 成功信号:左上 push(3) 起窗口大小恒为 4(红色);右上三行色带分明、数值逐行递增;左下两根柱子均标注"误差 = 0.00e+00";右下蓝线(raw input)始终在红线(假想快照)下方,且差距随 draft 长度线性扩大
    • 失败信号:左上窗口大小超过 capacity;右上数值错乱或布局维度不对;左下误差非零;右下两线交叉或蓝线在上

7.2 UI 组件与参数影响

无参数,页面加载时自动运行。

7.3 输出图解读

tab-4

布局:2×2 四联图。


左上 (a):push/窗口溢出时序(capacity=4)

  • 图类型:水平条形图
  • X/Y 轴:X 轴为"窗口中投影组数"(线性刻度,0-4);Y 轴为操作步骤(push(0) 到 push(6),自下而上)
  • 颜色含义:蓝色 = 窗口未满(大小 < 4);红色 = 窗口已满(大小 = 4),表示最旧投影被覆盖
  • 你该看什么:push(0) 到 push(2) 窗口大小从 1 增至 3(蓝色);push(3) 起窗口大小恒为 4(红色),且后续 push 不再增加——直观展示环形缓冲"满则覆盖最旧"的语义
  • 理想情况:前 3 根蓝色条形高度递增,第 4 根起转为红色且高度恒为 4
  • 异常指示:若窗口大小超过 4,或红色条形高度不恒定,说明 capacity 控制逻辑有 bug

右上 (b):window() → DraftProjections 布局

  • 图类型:热图(heatmap)
  • X/Y 轴:X 轴为"H × D 展平"(0-5,对应 H=2 × D=3);Y 轴为"draft 步"(第 0 步、第 1 步、第 2 步)
  • 颜色/数值含义:viridis 色阶,单元格内白色数字为实际值。第 0 步全为 0,第 1 步全为 1,第 2 步全为 2(代码中刻意用 torch.full(..., float(i)) 填充,便于验证布局)
  • 你该看什么:三行色带分明(紫→青→黄),数值严格逐行递增;每行 6 个单元格(H=2 × D=3 = 6),验证 DraftProjections.q 的形状为 (draft=3, B=1, H=2, D=3)
  • 理想情况:色带整齐、数值与步数一一对应、X 轴单元格数 = H × D
  • 异常指示:若色带混杂、数值跳跃、或单元格数不对,说明 window() 的 torch.stack 布局有 bug

左下 (c):RawInputRing vs 投影重放:共享重演引擎

  • 图类型:双柱对比图(占位柱,因误差为 0 无法显示高度)
  • X/Y 轴:X 轴为两条路线("批量构造 (decode.py)" vs "RawInputRing (replayssm.py)");Y 轴为占位(误差为 0,无实际刻度)
  • 颜色含义:浅蓝柱 = decode.py 批量构造;浅红柱 = RawInputRing 流式写入。柱内绿色文字标注"误差 = 0.00e+00"
  • 你该看什么:两根柱子内均显示"误差 = 0.00e+00"——这是最关键的正确性信号,证明两条路线经 verify_and_replay 后与 kda_recurrent 参考逐位一致
  • 理想情况:两柱等高(占位),内部文字均为绿色"误差 = 0.00e+00"
  • 异常指示:若任一柱内文字非零、或显示红色/警告色,说明重演逻辑或数据传递有 bug

右下 (d):带宽账:raw input vs 假想快照

  • 图类型:双折线对比图(带填充区域)
  • X/Y 轴:X 轴为"draft 长度"(1-8,线性刻度);Y 轴为"缓存字节数 (B)"(0-8000+,线性刻度)
  • 颜色/线型含义:蓝色圆点线 = raw input (q,k,v,g,beta);红色方块线 = 假想快照(完整状态 S)。两线之间粉色填充区域表示成本差距
  • 你该看什么:蓝线始终在红线下方,且差距随 draft 长度线性扩大;右下角注释框标注"快照是 raw input 的 1.94 倍"(H=2, dk=8, dv=8, fp64)及"KDA 的 per-channel gate 让差距更大"
  • 理想情况:蓝线斜率 < 红线斜率,两线间距随 X 增大而扩大,填充区域清晰可见
  • 异常指示:若两线交叉、或蓝线在上、或比值注释与 snapshot_cost_ratio 计算结果不符,说明成本模型有 bug

7.6 调节建议

  • 想看环形覆盖的临界行为 → 调 capacity 到更小值(如 2),观察 push(1) 起即出现红色
  • 想看不同 H/D 下的布局 → 调 _make_projections 的 h/dk 参数,观察右上热图 X 轴单元格数变化
  • 想看更大 draft 下的带宽差距 → 调 draft_lens 范围到 16 或 32,观察右下两线分离程度

7.7 为什么重要

本 Tab 是 KDA 投机解码正确性的主锚点。它验证了 RawInputRing 与 decode.py 批量构造在数学上的完全等价性——如果左下误差非零,说明 verify_and_replay 的重演逻辑或 RawInputRing 的数据封装有 bug,将直接导致在线投机解码产生错误输出。同时,右下的带宽账从工程角度论证了"为什么必须走 raw-input 路线而非快照路线":KDA 的 per-channel gate 让完整状态矩阵的存储成本随 dk·dv 乘积膨胀,而 raw input 仅随 3dk+dv+1 线性增长。若错误地采用快照方案,在大 batch、长 draft 的生产环境中,状态深拷贝的带宽开销将抵消投机解码的全部收益。


0x08 Tab 5: 统一页池

8.1 目的

展示统一页池中 MLA 页随序列长度线性增长 vs KDA 恒定一页(KDA‑Infra §2)。

8.2 UI 组件与参数影响

无参数,页面加载时自动运行。

8.3 输出图解读

tab-5

单图(log‑log 折线图):

  • 蓝色(Blue)折线:MLA 占用 page 数 vs 序列长度(512/1024/4096/16384/65536)
  • 橙色(Orange)虚线:KDA 一层固定 1 page(水平线 y=1)
  • X 轴 = 序列长度(tokens),Y 轴 = 页池 page 数,双对数刻度
  • 你该看什么:MLA 是斜率=1 的直线(线性增长),KDA 是水平线(恒定)

8.4 为什么重要

量化展示混合架构下两种注意力的内存增长行为差异。统一页池让两种 page 共享同一份 free list,上层不必区分类型。


0x09 Tab 6: MLA 分页

9.1 目的

展示 MLA 按 token 分页跨页 + pack_heads/unpack_heads 无损往返。

9.2 UI 组件与参数影响

无参数,页面加载时自动运行。

9.3 输出图解读

tab-6

1×2 布局:
左图:append_mla(600), tokens_per_page=512

  • 柱状图,X 轴 =Page #id,Y 轴 =filled(token 数)
  • 红色(Red)虚线:页容量 512
  • 柱旁标注 "512/512" 和 "88/512"
  • 你该看什么:600 token 跨 2 页,第一页满 512,第二页 88

右图:pack_heads / unpack_heads 无损往返

  • 文字标注:原始形状 → pack → flat 形状 → unpack → 还原形状
  • 最大差 + PASS/FAIL 判定
  • 你该看什么:往返最大差 < 1e‑12,PASS

9.4 为什么重要

MLA 分页是 PagedAttention 语义的基础。pack/unpack 无损是跨节点传输和页池存储正确性的前提。


0x10 Tab 7: KDA 存储

10.1 目的

展示 KDA 状态 store_kda / load_kda 的无损往返。

10.2 UI 组件与参数影响

无参数,页面加载时自动运行。

10.3 输出图解读

tab-7

1×2 布局:
左图:store_kda: (B,H,dk,dv) → flat → page.data

  • 文字标注:state 形状 → pack → flat 形状 → 写入 page.data
  • 底部灰色文字:后续为 pad 零

右图:load_kda 往返验证

  • 蓝色(Blue)文字:load_kda → 还原形状
  • 绿色(Green)/红色(Red)文字:最大差 + PASS/FAIL
  • 你该看什么:往返最大差 < 1e‑12,PASS

10.4 为什么重要

KDA 状态的 store/load 是投机解码回滚和前缀缓存 checkpoint 持久化的基础。如果往返有损,恢复出的状态会偏离正确值。


0x11 Tab 8: 前缀缓存命中

11.1 目的

展示前缀缓存两阶段 lookup 流程 + chained hash 链式依赖(KDA‑Infra §2 双粒度)。

11.2 UI 组件与参数影响

无参数,页面加载时自动运行。

11.3 输出图解读

tab-8

1×2 布局:
左图:两阶段 lookup 流程

  • 方框箭头示意图:
    • 蓝色(Blue): 阶段 1 MLA chained hash 逐块匹配
    • 橙色(Orange): 候选边界 [512, 1024, ...]
    • 紫色(Purple): 阶段 2 KDA 从最深回退找 checkpoint
    • 红色(Red): MLA miss → break
    • 黄色(Yellow): checkpoint 原子性检查
    • 绿色(Green): hit! matched_tokens
  • 你该看什么: 两阶段串行,阶段 2 从阶段 1 的最深匹配往回退

右图:chained hash 链式依赖

  • 文字标注:H1 = sha256("", [0..511]), H2 = sha256(H1, [512..1023])
  • "H2 depends on H1 → entire prefix"
  • 底部:H1 前 12 位 hex
  • 你该看什么: chained hash 保证 hit = 内容完全一致

11.4 为什么重要

前缀缓存是 K3 服务层的关键优化—1M 上下文下 prefix 400K,命中一次避免重算整个前缀,比 miss 便宜几个数量级。两阶段 lookup 是混合架构(KDA+MLA)的必然选择。


0x12 Tab 9: 前缀缓存未命中

12.1 目的

展示前缀缓存两种未命中场景:无 KDA checkpoint → miss,部分 checkpoint → 回退到最近可用边界。

12.2 UI 组件与参数影响

无参数,页面加载时自动运行。

12.3 输出图解读

tab-9

1×2 布局:

左图:场景 1 * 无 KDA checkpoint → miss

  • 红色(Red)边框
  • 文字: matched: 0, checkpoint: None
  • "hit: False → 必须从头重算"
  • 你该看什么: 没有 checkpoint 时即使 MLA hash 匹配也无法复用

右图:场景 2 * checkpoint 仅在 512 → 回退到 512

  • 橙色(Orange)边框
  • 文字: matched: 512, checkpoint: 512
  • "阶段 1 匹配到 1024,但 1024 无 checkpoint → 回退到 512"
  • 你该看什么: 原子性约束导致回退—1024 处缺 checkpoint 则不可用

12.4 为什么重要

理解未命中场景是调试前缀缓存命中率的关键。无 checkpoint 和部分 checkpoint 是生产环境最常见的两种 miss 原因。


0x13 Tab 10: 引擎 before/after

13.1 目的

收官汇总:多请求共享前缀时,前缀缓存到底省了什么—reused_tokens、MLA KV 线性 vs KDA 恒定、KCP 通信量 O(1)。

13.2 UI 组件与参数影响

无参数,页面加载时自动运行。

13.3 输出图解读

tab-10

1×3 布局:
左图 (a): prefix‑cache reuse of 2nd request

  • 柱状图: without_prefix (reused=0) vs with_prefix (reused=512)
  • 柱旁标注数值
  • 你该看什么: 命中时第二请求免重算 512 token

中图 (b): KV cache vs KCP comm

  • 双折线(semilogx): MLA KV (linear) 随序列增长,KDA KCP (constant) 水平
  • 你该看什么: KCP 通信量与序列长度无关

右图 (c): KCP comm is O(1) in length

  • 单折线(semilogx): KCP 通信量水平线
  • 你该看什么: KCP 通信量恒定

13.4 为什么重要

这是前 4 个子系统的收官汇总—量化回答"第二个请求复用前缀时到底省了什么"。reused_tokens=512 vs 0 是前缀缓存收益的直接度量。


0x14 Tab 11: Fleet 一致哈希

14.1 目的

展示一致哈希环的虚拟节点分布 + 600 session 路由分布均匀性(K3 报告 §5.4.3)。

14.2 UI 组件与参数影响

无参数,页面加载时自动运行。

14.3 输出图解读

tab-11

1×2 布局:
左图:一致哈希环分布(8 集群 × 8 vnodes)

  • 圆环散点图,8 种颜色对应 8 个集群
  • 每个集群 8 个虚拟节点均匀散布在环上
  • 你该看什么: 虚拟节点在环上分布均匀

右图:600 session 路由分布

  • 柱状图,8 根柱对应 8 个集群,Y 轴=session 数
  • 灰色虚线:均匀线 (75)
  • 你该看什么: 各集群 session 数接近 75,分布均匀

14.4 为什么重要

一致哈希是 cache‑aware affinity scheduling 的基础—session 稳定路由到持有其 prefix cache 的集群。均匀分布保证负载均衡。


0x15 Tab 12: Fleet 最小扰动

15.1 目的

验证一致哈希的 hopscotch 性质:移除 1 集群只扰动 O(1/N) 的 session。

15.2 UI 组件与参数影响

无参数,页面加载时自动运行。

15.3 输出图解读

tab-12

1×2 布局:
左图:移除 c3 后扰动

  • 柱状图:绿色(Green)=未扰动,红色(Red)=扰动
  • 柱旁标注数值
  • 你该看什么: 扰动数 ≈ 600/8 = 75(理论 12.5%),远小于总数

右图:移除 c3 后无 session 指向 c3

  • 绿色(Green)文字:指向 c3 的 session: 0
  • 蓝色(Blue)文字:改绑比例 = X%(理论 ~1/8 = 12.5%)
  • 你该看什么: 失效集群不再接收任何 session

15.4 为什么重要

最小扰动是 failover 可预期性的基础—集群故障时只有绑定到该集群的 session 需要改绑,re‑prefill 工作量被均匀分散到全 fleet。


0x16 Tab 13: Fleet 预算隔离

16.1 目的

展示预算隔离前后短请求 P95 TTFT 的差异(K3 报告 §5.4.3)。

16.2 UI 组件与参数影响

无参数,页面加载时自动运行。

16.3 输出图解读

tab-13

1×2 布局:

左图:长突发混流 − 隔离后 P95 反而更糟

  • 分组柱状图:红色(Red)=无预算(全通),绿色(Green)=预算隔离
  • X 轴 = 请求类(short/long),Y 轴 = P95 TTFT
  • 你该看什么: 隔离后 short 的 P95 ≈ 2,001,000,反而高于无隔离时的 ~6.0
  • 原因: 预算隔离把大量请求拒绝了(short 拒绝 52 个,long 拒绝 14 个),被拒绝的请求 P95 TTFT 被计为无穷大(或极大值),拉高了整体 P95

右图:预算隔离 − 短请求被拒绝更多

  • 柱状图:rejected(long)=14 和 rejected(short)=52
  • 你该看什么: 短请求被拒绝 52 个,远多于长请求的 14 个——这与"短请求零拒绝"的宣称完全相反
  • 原因: short_budget=8 意味着同时只能有 8 个 short 请求在飞,而场景提交了 60 个 short 请求,超额的 52 个全部被拒绝;long_budget=8 只提交了 20 个 long,所以只拒绝 14 个

真正的预算隔离机制:

  • short_budget / long_budget 是并发上限,不是"保护短请求"的配额
  • 当某类请求超过并发上限时,超额部分直接被拒绝(不是排队等待)
  • 这个 demo 的参数设置(short_budget=8 vs 60 个 short 请求)故意制造了大量拒绝,用来演示"限流"行为,而不是"保护短请求"

实际行为是:预算隔离通过拒绝超额请求来保护系统容量,而不是通过"优先服务短请求"来降低短请求延迟。

16.4 为什么重要

生产流量混着短请求和超长请求,长度横跨 3 个数量级。预算隔离保证长突发不拖累短请求的 TTFT。


0x17 Tab 14: Fleet 综合仿真

17.1 目的

Fleet 综合仿真:8 集群、20 long + 50 short 请求,产出命中率/代价/P95 TTFT/负载均衡/failover 汇总指标。

17.2 UI 组件与参数影响

无参数,页面加载时自动运行。

17.3 输出图解读

tab-14

1×3 布局:
左图:命中率 + 集群负载分布

  • 柱状图,X 轴=集群 id,Y 轴=累计负载
  • 标题显示命中率
  • 你该看什么: 各集群负载接近均匀

中图:TTFT 分布(short)

  • 直方图,X 轴=TTFT,Y 轴=频次
  • 红色(Red)虚线:P95 TTFT
  • 你该看什么: P95 TTFT 越低越好

右图:汇总指标

  • 文字列表:命中率、总代价、短/长 P95 TTFT、拒绝数、Failover 数、负载标准差
  • 你该看什么: 命中率 > 0、负载标准差小(均衡)

17.4 为什么重要

这是 Fleet 层的端到端验证—命中率、P95 TTFT、负载均衡、failover 四个维度的汇总指标直接反映服务层质量。


0x018 验证策略总览

Tab 测试函数 验证点 通过标准
1 投机回放原理 test_verify_replay_partial_matches_full_recurrence verify_and_replay 部分接受与 kda_recurrent 一致
2 快照成本 test_snapshot_cost_ratio_exceeds_one_and_grows_with_state 比值 >1 且随 dk*dv 增大
3 重演一致性 test_verify_replay_accept_all_matches_full 全部接受与完整递推一致
3 重演一致性 test_verify_replay_reject_zero_is_identity 零接受 = 原状态不变
4 ReplaySSM test_ring_evicts_oldest_at_capacity 满员覆盖最旧
4 ReplaySSM test_pop_after_refill_returns_oldest 满pop→push→pop仍返回最旧
4 ReplaySSM test_copy_from_is_deep_and_independent 深拷贝独立
5 统一页池 test_append_mla_increments_pages_across_boundary 600 token 跨 2 页
6 MLA 分页 test_pack_unpack_roundtrip pack→unpack 无损
7 KDA 存储 test_store_and_load_roundtrip store→load 无损
8 前缀命中 test_register_then_lookup_at_same_prefix_hits 同前缀命中
8 前缀命中 test_two_stage_uses_longest_checkpoint_boundary 两阶段回退到有 checkpoint 的边界
9 前缀未命中 test_lookup_without_checkpoint_misses 无 checkpoint → miss
9 前缀未命中 test_checkpoint_atomic_across_groups 原子性:缺一个 group → 不可用
10 引擎 test_engine_returns_hit_stats 命中时 reused=512
10 引擎 test_engine_miss_returns_zero 未命中时 reused=0
11 Fleet 哈希 test_ring_distributes_sessions_uniformly 路由分布均匀
12 Fleet 扰动 test_remove_cluster_only_affects_few_sessions 移除 1 集群扰动 < 60%
13 Fleet 预算 test_budget_isolates_long_burst_from_short 长满不影响短准入
14 Fleet 仿真 test_simulator_routes_to_primary_on_hit 同 session 第二请求命中


TransFormer-封面


0xFF 参考

posted @ 2026-11-08 15:00  罗西的思考  阅读(20)  评论(0)    收藏  举报