Unified Radix Cache: One Tree for Hybrid Model Prefix Caching
Unified Radix Cache: One Tree for Hybrid Model Prefix Caching
发表时间: 2026-08 · Blog post by Zhangheng Huang, Ke Bao, Yi Zhang, Jialin Ouyang, Sicheng Pan (lmsys.org)
原文: https://lmsys.org/blog/2026-08-11-unified-radix-cache
作者/机构:Zhangheng Huang, Ke Bao, Yi Zhang, Jialin Ouyang, Sicheng Pan
发布日期:2026年8月11日
速读
一句话结论
提出 Unified Radix Cache,通过将共享前缀身份与特定组件的复用规则解耦,用一棵统一的基数树支持了混合架构模型的缓存复用,并原生打通了多级存储与会话感知驱逐,大幅提升了长上下文场景的缓存命中率。
要解决什么问题
现有的前缀缓存机制假设所有 Token 遵循单一的复用规则,但这在混合架构模型中失效了。混合模型同时包含全注意力、滑动窗口注意力(SWA)和循环状态(如 Mamba),它们虽然共享相同的 Token 前缀,但复用边界截然不同:全注意力的 KV 在整个匹配前缀上都可复用;SWA 的 KV 仅在尾部窗口有效;循环状态则只在特定的前缀检查点才有效。如果强行对它们使用单一的复用边界,要么会丢弃本可复用的缓存,要么会导致错误的复用。此前,为了支持这些不同的复用规则组合,开发者只能为每种组合编写专门的缓存类。随着模型架构的演进,以及引入多级缓存(HiCache)等正交功能,这种做法导致匹配、插入、锁定和驱逐逻辑被大量重复,形成了一个难以维护的组合爆炸矩阵。
怎么做的
核心思路是将“共享前缀的拓扑结构”与“特定组件的复用语义”彻底解耦。系统维护唯一一棵基于 Token 序列的基数树来提供规范的前缀坐标,而将不同的复用规则抽象为独立的组件(如 FULL、SWA 和 MAMBA)。树的核心引擎负责通用的匹配、分裂、插入和驱逐机制,而组件通过钩子函数控制具体的数据语义。
在寻找安全的复用边界时,树的核心引擎会沿着 FULL 组件的路径遍历,并将经过的每个节点作为候选边界。此时引入了组件投票机制:每个激活的组件都会生成一个验证器,只有当所有验证器都接受该候选节点时,复用边界才会向前推进。如果某个节点被拒绝,遍历不会停止(因为组件可能接受更深的节点),但系统只保留所有组件都通过的最深节点作为最终的安全复用边界。其核心逻辑可表示为寻找满足所有组件验证的最深节点 $N_{safe}$:
这种解耦设计带来了两个关键扩展。首先是原生支持跨存储层级的 HiCache。组件决定“什么可以复用”,而 HiCache 决定“数据存放在哪”(GPU L1、主机 L2 或外部 L3)。系统引入了锚点和附属池(Sidecar)的概念,附属池存储独立的负载(如压缩 KV 池),但直接复用其声明的源组件的索引,跟随源组件移动,从而无需在树中增加新的复用边界。其次是实现了会话感知驱逐。系统为请求绑定会话 ID,在内存紧张时,优先驱逐无引用的缓存条目,将活跃会话的缓存作为最后的备选,利用会话活跃度作为 LRU 之外的复用信号,而不是死板地锁定内存。此外,作者还将树的状态机逻辑(如遍历、锁记账、LRU 更新)用 Rust 进行了重写,以降低长前缀带来的 CPU 调度开销。
效果如何
实验主要在多轮对话和 SWE-bench 任务上进行。多轮对话测试使用了 DeepSeek-V4-Flash(FULL+SWA 组件,4 张 H200,每轮 4096 输入加 16 输出)和 Inkling-Small(FULL+SWA+MAMBA 组件,8 张 H200,每轮 1216 输入加 64 输出)。对比基线为仅使用 GPU L1、使用 L1+Host L2,以及引入 500 GiB Mooncake 分布式存储作为 L3 的三种配置。结果显示,当对话历史增长导致 L1 和 L2 容量耗尽时,L3 缓存能将 DeepSeek-V4-Flash 的后期命中率维持在 98% 左右,有效输入吞吐量达到 145.5K tokens/s(仅 L1 基线为 9.4K);Inkling-Small 的命中率也保持在 96.8%,首字延迟控制在 1.23 秒。
在 SWE-bench 任务中,对比基线是采用普通 LRU 策略的 HiRadixCache。开启会话感知驱逐的 Unified Radix Cache 在 Qwen3.5-397B-A17B(批处理大小 64)上,将设备加主机的总缓存命中率从 58% 提升至 67%,首字延迟降低了 16.6%。针对长前缀开销,作者对比了实验性的 Rust 树核心与 Python 实现,在 200 轮的 SWA 负载测试中,Rust 原型在第 176 至 200 轮间的首字延迟降低了 42%。作者也承认了当前的局限性:Rust 核心目前仅支持 L1 缓存且未覆盖 HiCache,同时会话感知驱逐策略目前仅适用于 L1 和 L2,尚未扩展到 L3 外部存储。
研究贡献与核心创新
在大型语言模型推理中,当请求共享相同的 Token 前缀时,前缀缓存(Prefix caching)可以通过重用键值对(KV)来提升效率。在全注意力(Full attention)机制下,一旦计算出共享前缀的 KV,随着更多 Token 的追加,这些 KV 依然有效。后续具有相同前缀的请求可以在 Prefill 阶段直接重用这些 KV 条目,而无需重新计算。SGLang 传统上通过一个以 Token 序列为键的基数树(Radix tree)来追踪这种映射关系。在 Prefill 之前,基数树会寻找最长的可重用前缀,并将其 KV 位置返回给调度器。
然而,混合架构模型(Hybrid models)打破了这种单一的重用规则。一个请求可能会结合全注意力 KV、滑动窗口注意力(Sliding window attention, SWA)KV 以及循环状态(Recurrent states),其中每一种机制对“重用”的定义都截然不同:
- 全注意力 KV:在整个匹配的前缀范围内保持可重用。
- 滑动窗口注意力 KV:仅在尾部窗口(Trailing window)范围内有效。
- 循环状态:仅在精确的前缀检查点(Checkpoint)处有效。
这些机制虽然共享相同的 Token 前缀,但并不共享相同的可重用边界。如果强制在所有机制中应用单一的重用边界,要么会导致有效的重用被丢弃,要么会允许无效的重用发生。这些不同的重用规则在各个模型家族中以不同的组合形式出现。在早期的实现中,为每种组合编写专门的缓存类会导致组合爆炸(Combinatorial class matrix),特别是当引入如 HiCache 等正交功能时,匹配、插入、锁定和驱逐等逻辑会在各个缓存变体中被大量重复编写。
为了解决这一组合设计难题,本文提出了 Unified Radix Cache,其核心创新点在于将共享前缀身份(Shared prefix identity)与特定组件的重用有效性(Component-specific reuse validity)彻底分离。该设计提供了一个单一的基于 Token 的基数拓扑结构,为每个前缀提供规范的坐标,而全注意力 KV、滑动窗口注意力 KV 和 Mamba 检查点则作为“组件(Components)”附加其上。
- 消除缓存类矩阵:全注意力 KV、滑动窗口注意力 KV 和 Mamba 检查点共享同一个基数拓扑,由各个组件强制执行其独特的重用语义。
- 通过钩子保持树核心的通用性:组件负责控制匹配、拆分、插入、锁定和驱逐逻辑,因此新的混合模型组合无需引入新的树实现。
- HiCache 原生集成于组件生命周期:组件和 Sidecar 在跨越 GPU L1、Host L2 和外部 L3 层移动时,能够保持相同的前缀身份。
- 会话活动指导缓存驱逐:会话感知(Session-aware)的驱逐机制优先保留活跃会话的缓存条目而不对其进行硬绑定(Pinning)。
- 实验性 Rust 树核心降低长前缀开销:通过将树核心逻辑用 Rust 重写,显著降低了长前缀处理时的首字生成时间(TTFT)。
图 1. 单一基数拓扑提供了规范的前缀身份。FULL、SWA 和 MAMBA 组件分别强制执行路径、尾部窗口和检查点的重用语义,而 HiCache 控制它们的有效载荷是驻留在 GPU L1、Host L2 还是外部的 L3 层。Sidecar 跟随声明的源池,而不改变树的行为。
核心方法与系统设计
混合模型结合了多种可缓存的值,这些值虽然共享相同的 Token 前缀,但遵循截然不同的重用规则。Unified Radix Cache 将共享前缀映射到一个单一的基数拓扑结构中,并将每种重用规则映射为一个 TreeComponent。系统中的 UnifiedTreeCore 负责运行公共的匹配、拆分、插入、锁定和驱逐机制。同时,UnifiedRadixCache 负责协调内存池(Pool)的操作,而每个独立的组件仅定义那些会发生变化的语义逻辑。
支持的组件类型及其组合
在系统中,FULL(全注意力)组件始终存在。SGLang 进一步添加了用于混合滑动窗口注意力的 SWA 组件,以及用于混合循环层的 MAMBA 组件。不同的模型可以灵活组合这些组件:例如,DeepSeek-V4 组合了 FULL 和 SWA;Kimi-K3 为其 KDA 循环状态组合了 FULL 和 MAMBA;而 Inkling 则在同一棵树上组合了所有这三个组件。当一个新的模型家族出现时,它可以直接重用现有的组件组合。如果新模型引入了当前组件集无法表达的重用规则,SGLang 可以直接添加一个新的 TreeComponent,而完全无需创建另一种树结构的实现代码。
不同组件的重用规则
FULL 组件提供路径重用(Path reuse)。它为匹配前缀中的每一个 Token 保留 KV,并保护相应的祖先路径。SWA 组件提供窗口重用(Window reuse)。它要求一个连续的尾部窗口,而较旧的 SWA 槽位可能变成空的墓碑(Tombstones),但它们的基数节点依然保留在共享拓扑中。MAMBA 组件提供检查点重用(Checkpoint reuse)。它要求在可重用的前沿位置(Reusable frontier)存在一个循环检查点,并在执行突变(Mutation)之前将共享状态复制到一个私有的请求槽位中。这些不同的组件会对同一个候选边界应用不同的验证规则。
安全重用边界的查找机制
匹配阶段的候选边界遍历
在前缀匹配期间,UnifiedTreeCore 会沿着规范的 FULL 路径进行遍历,并将访问到的每一个节点视为一个候选边界。仅仅满足 FULL 匹配是不够的。每一个处于激活状态的组件都会创建一个验证器(Validator),只有当所有验证器都接受该候选节点时,可重用边界才会向前推进。需要注意的是,某一个组件的拒绝并不会导致遍历停止,因为该组件可能会在后续更深的节点上重新接受匹配。
边界验证示例
如图 2 所示,节点 n1 和 n2 通过了所有验证器的检查,而节点 n3 和 n4 则至少未通过一个组件的检查。虽然遍历过程最终到达了节点 n4,但系统会保留 n2 作为最深的安全可重用结果。
图 2. 组件投票机制将遍历深度与可重用前缀深度分离开来。遍历到达了 n4,而 n2 依然是 FULL、SWA 和 MAMBA 共同接受的最深边界。
匹配结果的构建与终结
在遍历完成之后,树核心会构建一个 MatchResult 对象。接着,各个组件的终结器(Finalizers)会准备被选中的值以供重用。这一过程包括一些特定的操作,例如当一个共享的 MAMBA 检查点需要变为某一个请求的私有状态时所必须执行的复制操作。
贯穿树生命周期的组件钩子
生命周期各阶段的组件决策
相同的组件契约(Component contract)覆盖了树结构的整个生命周期,具体包括:
- 匹配(Match):
create_match_validator决定一个候选节点是否可重用。finalize_match_result_in_tree_core和finalize_match_result_in_cache负责准备被选中的结果。 - 拆分(Split):
redistribute_on_node_split决定当一个基数节点被分割时,组件数据应当如何移动。 - 插入(Insert):
update_component_on_insert_overlap和commit_insert_component_data决定组件拥有哪些池索引,以及新数据应附加在何处。 - 锁定(Lock):
acquire_component_lock和release_component_lock负责保护一条路径、一个尾部窗口或一个检查点。 - 驱逐(Evict):
evict_device_start、evict_device_next_node和evict_device_end负责选择设备上的驱逐候选者。evict_component用于移除组件数据,而drive_host_eviction负责回收主机资源。
通用树核心与独立组件生命周期
这种契约设计使得树核心保持高度通用,同时允许各个组件维持不同的正确性规则。移除某一个组件的有效载荷并不总是意味着需要移除对应的基数节点。剩余的拓扑结构依然可以作为其他组件的锚点,而空出的组件槽位可以作为墓碑保留,直到该组件被恢复,或者该节点变得完全不必要。由于组件语义始终与同一个前缀身份保持绑定,HiCache 能够在不引入另一棵树的情况下,将组件的有效载荷扩展到多个内存层级中。
HiCache 在多级内存中的原生集成
跨内存层的身份保持
组件决定了“什么”可以被重用,而 HiCache 决定了这些可重用的有效载荷“驻留”在何处。Unified Radix Cache 在 GPU L1、Host L2 以及外部的 L3 层之间携带完全相同的组件身份,因此在不同层级之间移动数据绝不会改变其前缀身份或重用规则。组件负责描述所需的传输操作,而 HybridCacheController 负责执行物理的 I/O 操作。
组件、锚点与 Sidecar 的定义
并非每一个物理内存池都需要拥有自己的组件。锚点(Anchor)决定了重用语义,或者提供其他池需要跟随的页面索引。Sidecar 则存储独立的有效载荷,但它完全重用其声明的源池(Source pool)的索引。Sidecar 随着其源池移动,它既不参与可重用边界的投票,也不会在基数拓扑中添加额外的槽位。
DeepSeek-V4 中的组件与 Sidecar 实例
DeepSeek-V4 模型使这种区分变得具体。FULL 覆盖了逻辑前缀,而 SWA 仅覆盖其尾部窗口,因此两者都是独立的组件。它们还使用独立的设备索引空间。在图 3 所示的标准化六页示例中,分配器在运行时将 FULL 的尾部槽位 F4, F5 映射到 SWA 的槽位 S0, S1。而 C4 和 C128 压缩 KV 池、索引器缓冲区(Indexer buffers)以及压缩器状态(Compressor states)并不定义新的重用边界。它们注册为 Sidecar,其中三个池跟随 FULL,另外两个池跟随 SWA。
图 3. 组件可以在独立的索引空间之间进行转换,而每个 sidecar 则精确重用其声明的源池的索引。这两种关系在各个 HiCache 层之间保留了一个共享的前缀身份。
共享树上的会话感知驱逐机制
会话感知驱逐的实现背景
会话感知驱逐(Session-aware eviction)直接在 UnifiedRadixCache 中实现。该机制提供了一个普通 LRU(最近最少使用)算法所缺乏的重用信号。LRU 只能记录哪些缓存条目最近被访问过,但无法识别哪些前缀属于当前活跃的会话且极有可能在下一轮被重用。在内存压力下,LRU 可能会错误地驱逐活跃会话的 GPU KV,同时却保留了不相关的条目。
会话重用区域的注册
应用程序会将一个稳定的 session_id 附加到每一个请求上。当一个请求成功完成后,Unified Radix Cache 会为该会话注册可重用区域。FULL 追踪其前缀路径,SWA 追踪其尾部窗口,而 MAMBA 追踪其可重用前沿。所有会话依然共享同一个基数拓扑,且每一轮对话依然提供其完整的 Prompt。
基于引用的驱逐优先级排序
这些引用关系改变了驱逐的顺序,而不是对内存进行硬绑定(Pinning)。FULL 根据候选者是否被引用、其会话引用计数以及配置的基础驱逐优先级来进行排序。SWA 和 MAMBA 首先扫描其自身可重用区域中未被引用的条目,当需要更多空间时,才会回退到扫描被引用的条目。当前的策略涵盖了 GPU L1 和 Host L2,但不包括外部的 L3 层。
会话关闭与引用清理
当应用程序调用 /close_session 时,Unified Radix Cache 会移除该会话的引用,但不会立即删除其缓存条目。系统通过会话代数(Session generations)和有界闭会话墓碑(Bounded closed-session tombstones)机制,防止那些在会话关闭或重新打开后才完成的过期请求错误地恢复已释放的引用。
图 5. 三个活跃的会话共享一个基数拓扑。FULL 追踪被引用的前缀路径,SWA 追踪尾部窗口,MAMBA 追踪可重用前沿。GPU 和主机驱逐优先考虑未被引用的条目,而被引用的条目作为回退选项依然可被驱逐。关闭一个会话会移除其保留信号,但不会立即删除可重用的缓存条目。
迈向 Rust 树核心
Rust 树核心的演进背景
随着共享前缀的不断增长,树的遍历、锁的账本管理、LRU 更新以及驱逐扫描等操作为调度器的关键路径增加了大量工作负载。UnifiedRadixCache 将这种树状态机与缓存编排逻辑分离开来,这使得树核心成为原生语言(Native implementation)实现的自然目标。
实验性 Rust 统一基数缓存原型
实验性的 Rust Unified Radix Cache 是一个需要选择性开启(Opt-in)的、仅支持 L1 的原型系统。Rust 拥有基数拓扑、每个组件的锁核算、侵入式 LRU 链表以及驱逐遍历逻辑的所有权。而 Python 依然是请求到 Token 映射以及物理 KV 分配的唯一所有者。在对树进行突变操作后,Rust 会返回延迟动作(Deferred actions),交由 Python 应用到物理内存池中。该原型目前支持 FULL、SWA 和 MAMBA,但暂不支持 HiCache。
实验环境配置
本研究针对三种不同的场景进行了广泛的基准测试,具体的实验环境配置如下:
1. HiCache 多轮对话基准测试配置
- 对比配置:仅 GPU L1;GPU L1 + Host L2;GPU L1 + Host L2 + 500 GiB Mooncake Store 分布式内存层(作为 L3)。
-
DeepSeek-V4-Flash 实验:
- 模型/组件:使用 FULL 和 SWA 组件。
- 硬件:4 张 H200 GPU,张量并行(TP)为 4。
- 请求负载:48 个客户端,60 轮对话,每轮包含 4,096 个输入 Token 和 16 个输出 Token。
-
Inkling-Small 实验:
- 模型/组件:使用 FULL、SWA 和 MAMBA 组件。
- 硬件:8 张 H200 GPU,张量并行(TP)为 8。
- 请求负载:64 个客户端,30 轮对话,每轮包含 1,216 个输入 Token 和 64 个输出 Token。
-
软件依赖:执行脚本包含 SGLang 服务端启动及
bench_multiturn.py客户端测试。部分核心代码配置如下(以 DeepSeek-V4 为例):
export MODEL=/path/to/DeepSeek-V4-Flash-FP8 export SGLANG_ENABLE_UNIFIED_RADIX_TREE=1 COMMON="--trust-remote-code --model-path $MODEL --tp 4 --mem-fraction-static 0.9 \ --context-length 262144 --page-size 64 --max-running-requests 16 \ --host 0.0.0.0 --enable-cache-report --enable-metrics \ --enable-metrics-for-all-schedulers" HICACHE="--enable-hierarchical-cache --hicache-ratio 2 --hicache-size 0 \ --hicache-mem-layout page_first --hicache-io-backend kernel \ --hicache-write-policy write_through \ --hicache-storage-prefetch-policy wait_complete" # L1-only sglang serve $COMMON --port 30001 # L2 HiCache sglang serve $COMMON $HICACHE --port 30000 # Start the 500 GiB external Mooncake Store tier first, then add: sglang serve $COMMON $HICACHE --port 30000 \ --hicache-storage-backend mooncake \ --hicache-storage-backend-extra-config "$MOONCAKE_CLIENT_JSON" PORT=30000 python3 benchmark/hicache/bench_multiturn.py \ --host 127.0.0.1 --port "$PORT" --model-path "$MODEL" \ --num-clients 48 --num-rounds 60 --request-length 4096 --output-length 16 \ --max-parallel 16 --request-rate 64 --disable-auto-run \ --disable-random-sample --enable-round-barrier --ready-queue-policy fifo \ --seed 20260626
*(Inkling 的配置脚本类似,增加了 `--mamba-radix-cache-strategy extra_buffer` 等 Mamba 专属参数,并调整了客户端和轮数设置。)*
2. SWE-bench 会话感知缓存基准测试配置
- 模型:DeepSeek-V4-Pro 和 Qwen3.5-397B-A17B。
- 硬件:张量并行(TP)为 8。
- 对比基线:使用带普通 LRU 策略的常规 HiRadixCache。
- 实验组:启用 Unified Radix Cache 及其会话感知缓存功能(
--enable-session-radix-cache)。 - 数据集:SWE-bench 智能体轨迹(Agent trajectories)。
3. Rust 树核心基准测试配置
- 请求负载:200 轮合成对话,每轮增加 100 个输入 Token 并生成 100 个输出 Token。执行 6 次试验取平均。
-
模型及组件:
- 全注意力测试:Qwen3-32B (TP2)。
- SWA 测试:gpt-oss-20b (TP2)。
- 混合 SSM 测试:Qwen3-Next-80B-A3B (TP4)。
-
对比基线:Python 实现的
UnifiedRadixCache。
实验结果与分析
1. HiCache 多轮对话实验结果
实验测量了不同轮次下的平均首字生成时间(TTFT)和 Prompt Token 缓存命中率。对于每一轮,命中率定义为所有请求中被缓存的前缀 Token 总数除以它们完整的 Prompt 长度总和。
图 4. 随着对话历史的增长,L1 和 L1 加 L2 达到了容量极限,之后缓存命中率下降,TTFT 上升。外部的 L3 层在更多轮次中保留了可重用的前缀,并产生了最高的有效输入 Token 吞吐量。这两行使用了不同的模型、GPU 数量、请求形状和规模,因此仅在同一行内比较不同的层级。
实验结论:
- 在两种工作负载中,L1 层最先丢失可重用前缀,L2 层延迟了容量极限的到来,而 L3 层在预热后保持了极高的命中率,并以超过 96% 的命中率结束测试。
- 在 DeepSeek-V4-Flash 上:L3 层的命中率保持在 98% 左右,将平均 TTFT 控制在 9 秒以下,并达到了 145.5K 有效输入 Token/秒的吞吐量;相比之下,L1 仅为 9.4K,L1+L2 为 14.3K。
- 在 Inkling-Small 上:L3 层以 96.8% 的命中率和 1.23 秒的 TTFT 结束测试,有效输入 Token 吞吐量达到 67.1K/秒;相比之下,L1 为 15.5K,L1+L2 为 21.1K。
- 分析:有效输入 Token 吞吐量将缓存命中的前缀 Token 计入在内。L3 带来的巨大收益主要源于在较小内存层达到容量上限后,依然能够保持可重用前缀的可用性。
2. SWE-bench 上的会话感知 HiCache 实验结果
本实验旨在评估会话感知驱逐策略对真实智能体工作负载的影响。
图 6. 顶部面板堆叠了缓存驻留情况:柔和的橙色和蓝色底座显示了基线和 Unified 配置的设备缓存命中率,而灰色的顶部显示了主机缓存命中率。底部面板报告了测量的 TTFT,每对柱状图上方的标签显示了相对于基线的下降幅度。这两个模型使用了独立的 TTFT 比例尺。
实验结论:
- 缓存命中率提升:在 Batch Size 为 128 时,DeepSeek-V4-Pro 的设备命中率从约 42% 提升至 51%。在 Batch Size 为 32 时,Qwen3.5-397B-A17B 的设备命中率从约 5% 大幅提升至 34%。在 Batch Size 为 64 时,Qwen 的总(设备+主机)命中率从约 58% 提升至 67%。
- TTFT 降低:与普通的 HiRadixCache 基线相比,会话感知 Unified Radix Cache 配置在 DeepSeek-V4-Pro 上观察到 TTFT 分别降低了 11.0% (BS=128) 和 2.9% (BS=256)。在 Qwen3.5-397B-A17B 上,TTFT 分别降低了 13.5% (BS=32) 和 16.6% (BS=64)。
3. Rust 树核心原型实验结果
本实验评估了将树状态机迁移至 Rust 原生实现后的性能表现。
图 7. 实验性的仅限 L1 的 Rust 原型与 Python 树的比较。第一行显示了总 TTFT 和通过 CUDA 事件计时的 GPU prefill 间隔。第二行显示了它们的差值,这并非对 CPU 时间的直接测量。这三个模型使用了独立的 Y 轴比例尺。
实验结论:
- 性能提升:Rust 原型在 SWA 工作负载上记录了最大的降幅,在全部 200 轮中 TTFT 降低了 38%,在第 176 至 200 轮中降低了 42%。全注意力测试总体 TTFT 降低了 10%,最后 25 轮降低了 18%。混合 SSM 测试总体降低了 5%,最后 25 轮降低了 7%。
- 分析:图 7 底部的残差(总 TTFT 减去 GPU Prefill 时间)包含了树账本管理、调度、同步、采样等未插桩的工作。在混合 SSM 结果中,残差大幅下降,但由于 GPU 前向计算耗时较大,限制了总 TTFT 中可见的改善幅度。
结论与未来展望
研究结论
混合模型并不存在一个普遍适用的单一可重用边界,但它们同样不需要为每一种注意力机制和循环状态的组合单独构建一棵基数树。Unified Radix Cache 保持了一个规范的基于 Token 的拓扑结构,同时允许 FULL、SWA 和 MAMBA 等组件强制执行它们各自独立的重用、锁定和驱逐语义。
这种共享身份的优势远超出了前缀匹配的范畴。HiCache 利用它在多级内存层之间保持身份的一致性;会话引用利用它将其转化为驱逐时的保留信号;而实验性的 Rust 核心证明了树的账本管理可以独立演进,而无需将内存池的所有权移出 Python。该架构的长期目标是让可重用的缓存状态对整个服务系统可见,而不仅仅局限于本地分配器。
未来工作展望
Unified Radix Cache 确立了共享前缀身份,但系统中仍有三个部分需要围绕它进行融合:
- 完善可替换的 Rust 树核心:后续工作需要将 Rust 核心扩展至支持 SWA、MAMBA 和 HiCache,同时继续将内存池分配和编排逻辑保留在 Python 中。
- 将 GPU L1 直接连接到外部 L3 层:直接的 L3 模式将使 Host L2 成为一个可选的暂存层,并将分布式内存暴露为一个更大的共享缓存。这需要跨层级的准入、预取、传输和驱逐的协同配合,而不仅仅是增加一个存储连接器。
- 在整个服务栈中协调 Agentic KV 缓存:Agentic(智能体)工作负载已经从每个引擎内部的前缀缓存中获益。未来的路线图计划将相同的缓存身份扩展到路由器(Routers)、Prefill 与 Decode 工作节点以及 HiCache 中,以便这些层级能够为会话、子智能体和工具调用协同进行预取、降级和保留操作。
补充信息与致谢
作者在文中对多个团队和个人在系统开发、验证和集成过程中提供的帮助表示了感谢:
- 感谢阿里云 TairKVCache 团队共同领导了 Unified Radix Cache 与 HiCache 在混合模型上的集成,并验证了大规模生产环境的部署。
- 感谢 Thinking Machines Lab 团队在高负载下验证了 Unified Radix Cache,并修复了跨组件组合的正确性问题。
- 感谢 Clank.world 团队在高并发生产部署中验证了 Gemma 4 SWA HiCache。
- 感谢 Mingjun Zhang 在会话感知驱逐工作及其验证方面的贡献。
- 感谢蚂蚁集团 SCT 推理团队的 Tingwei Huang 协助将 Hybrid HiCache 与 Mooncake 进行集成。
- 感谢 Lianmin Zheng, Hanming Lu, Ishan Dhanani, Zhiqiang Xie, Chao Shi, Yanbo Yang, Shangming Cai, Hongjia Zhang 以及整个 SGLang 社区在架构审查、系统集成、基准测试和反馈方面提供的支持。同时感谢所有相关开源路线图的贡献者。
💬 评论讨论
欢迎在这里分享您的想法和见解!