行业资讯

SGLang 前缀缓存 RadixAttention 深度拆解:如何把重复推理的成本砍掉一大半

发布时间:2026/8/21 13:26:52
SGLang 前缀缓存 RadixAttention 深度拆解:如何把重复推理的成本砍掉一大半 SGLang 前缀缓存 RadixAttention 深度拆解如何把重复推理的成本砍掉一大半【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglangSGLang 是一个面向大语言模型与多模态模型的高性能推理服务框架它用一套叫 RadixAttention 的前缀缓存机制把重复计算同一段前缀的浪费大幅消除官方报告最高可实现5 倍推理加速。这篇文章不堆名词只讲一件事你的请求为什么会把同一段话反复算好几遍以及 SGLang 怎么用一棵树把这件事治好。先看一个每天都在发生的傻事假设你搭了一个基于大模型的知识库问答机器人每个请求都带一段 500 token 的系统提示词你是一名严谨的客服只能根据以下文档回答……后面再接用户的问题。每来一个用户模型都要把这 500 个 token 从头到尾跑一遍预填充prefill——也就是把这段文字变成模型能用的中间状态。问题是这 500 个 token 每次都一模一样算出来的结果也一模一样。一个 8 卡集群每小时处理 1 万次请求就有 500 万个 token 的预填充在重复烧钱。换算成 GPU 时间可能一半的算力都耗在了重复上。这还只是客服机器人。批量评测、多轮对话、代码补全全是同一种病。为什么传统 KV 缓存治不好这个病先补一个背景大模型每读一个 token都会算出一对 K、V 向量你可以理解成这个词的索引卡片堆在一起叫 KV 缓存。有了它下一个 token 就不用重新读前面所有文字。问题出在怎么存。早期推理框架给每个请求分配连续的一段显存请求结束就整段回收。两个请求就算共享前 500 个 token也没法共用那块显存——地址对不上谁也不敢动谁的。于是每个人都在重算。后来有人想到哈希前缀缓存把提示词算个哈希命中就直接复用。听起来聪明但前缀是活的——用户多问一句前缀就变长一点两个请求共享 300 个 token、到第 301 个分叉哈希就完全对不上了。要么整段复用要么一点不沾太脆。SGLang 的设计哲学就一句话别把整段前缀当成一个整体把它拆成可以自由拼接的积木。这块积木被 100 个请求共享那块积木只有 1 个请求在用都无所谓反正每块都只算一次。承接这个想法的数据结构就是基数树Radix Tree一种按公共前缀分叉的树。解剖一只麻雀三个请求如何走完一棵树想象三个请求的 token 序列用字母代替请求 A系统提示 用户今天天气怎么样请求 B系统提示 用户推荐一本小说请求 C系统提示 用户今天天气怎么样适合跑步吗它们共享同一个开头系统提示 用户。在 SGLang 的基数树里这个共享部分会变成一个节点分叉出的不同后缀各自成节点。核心实现在python/sglang/srt/mem_cache/radix_cache.py节点的骨架长这样class TreeNode: def __init__(self): self.children defaultdict(TreeNode) # 子节点往哪个方向分叉 self.parent None # 指回父节点 self.key None # 这一小段 token 序列 self.value None # 对应的 KV 缓存地址显存里的位置 self.lock_ref 0 # 引用计数有人在用就锁住不许驱逐 self.last_access_time 0 # 上次被访问时间供 LRU 淘汰用第一步请求 B 来了。match_prefix从根节点出发逐段比对 token发现系统提示 用户已经在树里直接返回那段 KV 缓存的地址。B 不需要重新算共享部分只算新增的后缀——预填充量从 500 个 token 降到 50 个。第二步请求 A 已经处理完了把整段系统提示 用户 今天天气怎么样存进树。系统发现共享节点后面已经有了推荐一本小说这个分叉于是在共享节点下再挂一个新的叶子。这一步叫insert只新增别人没有的部分绝不复制共享部分。第三步请求 C 来了命中更长的前缀。它匹配到了 A 存下的整段还差最后几个 token只需要补算尾巴。注意一个细节如果 C 只匹配到了系统提示 用户 今天天气怎么还差一个字正好卡在节点中间SGLang 会调用_split_node把这个节点劈成两半——前一半共享、后一半独有。这样下次不管谁来都能在精确的边界上复用。第四步显存不够了。基数树只复用不释放总得有人让位。驱逐逻辑把树的所有叶子没有子节点的节点按last_access_time排进一个堆heapq优先淘汰最久没被碰过的lock_ref 0的节点正在被某个进行中的请求引用直接跳过。一次淘汰可能牵连父节点变成新叶子继续循环。整个过程在evict方法里几十行代码干净利落。一句话总结这套机制匹配时顺着前缀走存的时候只存增量满了就挑最冷的叶子砍。用数据说话省下来的算力是数量级的官方在 2024 年 1 月发布的博客与 SGLang 论文里报告了 RadixAttention 在典型场景下的加速数据出处LMSYS 官方博客 2024-01-17 及论文SGLang: Efficient Execution of Structured Language Model Programs项目 README 中也引用了同样的 5x 峰值结论场景相对加速比出处文档摘要长前缀复用约 5.1xSGLang 论文批量提示工程约 4.8xSGLang 论文多轮对话约 3.2xSGLang 论文代码生成约 2.7xSGLang 论文理解这张表的关键加速比越高的场景前缀越长、复用率越高。文档摘要里系统提示词几千 token全部命中缓存预填充几乎等于白送。多轮对话每一轮都接在上文后面基数树天然适合这种越来越长的公共前缀。SGLang 服务框架支持从 Llama、Qwen 到 DeepSeek 等大量模型RadixAttention 对这些模型一视同仁——它工作在 KV 缓存层跟模型结构无关这也是它能成为框架级特性的原因。避开这些坑四个翻车现场坑一把 page_size 调大短提示反而彻底失效。SGLang 允许把 token 打包成页--page-size默认 1。页能提升 attention 内核效率但前缀缓存按整页对齐——如果提示只有 32 个 token 而 page_size 是 64凑不满一页一个字节都缓存不了。官方文档docs/docs/advanced_features/attention_backend.mdx说得直白页面不能填充。正确姿势前缀复用是刚需的场景用--page-size 1换取最细粒度的匹配纯高吞吐场景再考虑更大页。坑二把缓存命中率当唯一指标。命中率高不代表快。基数树里同时存在可驱逐和被锁定两类缓存代码里分别用evictable_size_和protected_size_跟踪被引用中的缓存不能逐出否则正在跑的请求会读到被覆盖的数据。调优时先分清命中率是真复用还是挤在热点上。坑三乱开确定性推理。SGLang 的确定性模式会关闭已完成请求的缓存插入disable_finished_insert因为缓存复用可能改变运行时序。你以为关了缓存更稳定结果把所有复用收益也一起关了。只有真正需要逐 token 可复现的场景才开。坑四手动关闭 radix cache 来省内存。反了。--disable-radix-cache是把前缀缓存关掉不是省显存——反而每个请求都得重新计算。如果你发现显存吃紧优先查 page_size 和并发设置而不是关缓存。五分钟上手复制就能跑git clone https://gitcode.com/GitHub_Trending/sg/sglang cd sglang pip install -e python[all] # 启动服务前缀缓存默认开启无需任何额外参数 python3 -m sglang.launch_server \ --model-path meta-llama/Llama-3.1-8B-Instruct \ --port 30000然后连发两个共享前缀的请求第二个的预填充耗时会肉眼可见地下降curl http://localhost:30000/v1/chat/completions \ -H Content-Type: application/json \ -d {model:default,messages:[{role:user,content:系统提示你只回答技术问题。今天天气如何}]} curl http://localhost:30000/v1/chat/completions \ -H Content-Type: application/json \ -d {model:default,messages:[{role:user,content:系统提示你只回答技术问题。推荐几本编程书}]}两条请求共享系统提示你只回答技术问题。这一整段前缀第二次请求只会计算后半截。想亲眼看树长什么样radix_cache 里有现成的pretty_print()方法调试时可以直接把整棵树打印出来。看看未来缓存正在从 GPU 走向整个数据中心RadixAttention 的下一步演进在仓库里已经能看到眉目。代码中的节点多了host_value主机端缓存字段配套的KVCacheEventRecorder会记录缓存的存取事件——这些都是 HiCache 的骨架。HiCache 的设计文档docs/docs/advanced_features/hicache_design.mdx描述了一个参照 CPU 三级缓存架构的多级体系L1GPU 显存最快容量最小L2主机内存容量大一个量级L3分布式存储Mooncake、3FS 等整个集群共享也就是说未来的前缀缓存不只在本机复用还能在跨实例、跨节点的维度复用。A 机器算过的前缀B 机器可以直接从共享存储拉走。配合优先级感知的驱逐策略节点上的priority字段和按命名空间隔离的extra_key机制多 LoRA 场景下互不串扰这套体系正在从单机加速器变成集群级缓存基础设施。收尾下次看到你的 GPU 利用率上不去、请求延迟却很高先别急着换硬件——先问问自己同一段话是不是又被算了一遍想亲手验证这棵树的威力clone 仓库跑一遍上面的例子或者在评论区聊聊你的业务里有多少重复前缀可以挖。点赞收藏下一篇我们拆 SGLang 的调度引擎看看那棵 CPU 侧几乎零开销的调度树是怎么让 GPU 一刻不闲的。【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考