
SGLang 前缀缓存终极指南RadixAttention 为什么能让 LLM 推理提速 5 倍【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang先讲一个真实得不能再真实的场景你的团队把大模型服务部署上线多轮对话功能上线当天GPU 显存直接爆掉一个请求要排队十几秒线上反馈卡得像幻灯片。查了半天发现同一段系统提示词和对话历史每个用户每轮对话都在被反复重新计算——几千个 token 的 KV 缓存白白算了一遍又一遍。这就是大语言模型推理服务中最常见的隐形浪费。而 SGLang 这个高性能推理框架正是靠它的前缀缓存技术RadixAttention把这种浪费压到最低在多个真实场景里实现了数倍的吞吐提升。这篇文章带你从零看懂它并且三步就能在你自己的服务里用起来。一、它到底解决了什么先打个比方想象图书馆里有一排书架每个人的笔记都抄了一遍同样的开头。第一个读者认真抄完十页第二个读者来了又从头抄十页第三个、第四个……同样的内容被手抄了十遍。RadixAttention 的做法是把这十页公共内容放在一本共享笔记本里后来的读者直接翻到第十页接着写。谁写了新内容就单独开一页谁不再需要了就擦掉回收。放到推理里就是多个请求共享同一段 prompt 前缀时KV 缓存也就是模型算出来的键值对用来生成后续 token 的记忆只算一次后续请求直接复用。省掉的不只是算力还有显存和时间。那它究竟是怎么做到知道哪些前缀是重复的答案是一种叫基数树Radix Tree的数据结构我们接着往下拆。二、原理拆解一张树形索引 一条匹配规则别被基数树这个名词吓到它的本质就是一棵共享前缀的树。举个例子把三个请求的 token 序列看作路径公共开头 Hel 只需要存一份后面各自分叉成 lo、p、l。根节点往下相同的 token 前缀合并成同一个节点每个节点只记录自己这一小段独有的 token 和对应的 KV 缓存位置两个请求的前缀越长能共享的节点就越多。看一段简化后的节点定义来自项目源码python/sglang/srt/mem_cache/radix_cache.py每个节点就是一个共享笔记本的一页class TreeNode: def __init__(self): self.children {} # 子树分叉比如 lo 和 p self.parent None # 指向父节点回退用 self.key None # 这一段独有的 token 序列 self.value None # 对应的 KV 缓存索引 self.lock_ref 0 # 引用计数有人正在用就不能删白话解释每个节点只存别人没有的部分公共部分天然只存一份。那个lock_ref就像借书卡上的在借中标记防止缓存被误删。当新请求到来缓存系统要做的事情只有一件沿着树尽量往下走找到能匹配上的最长前缀def match_prefix(key): node root while node 有匹配 key 的子节点: node 匹配的子节点 # 能吃多少共享就吃多少 return node.value # 返回命中的 KV 缓存位置这一段的白话是沿着树一路贪心匹配走到走不动为止命中的那部分 KV 缓存直接拿来用剩下的缺口才需要重新计算。匹配之后如果新内容比已有节点更长树会自动分裂出新节点显存不够时系统会优先淘汰最久没被访问的节点LRU 策略并且跳过任何lock_ref 0的在用节点保证不会把正在服务的请求缓存删掉。顺带一提如果很多请求并发打进来SGLang 的调度器会先把这些请求按共享前缀分组。下图展示了 SGLang 在多批次请求场景下的调度架构见docs/images/dpa.png前缀缓存的命中率在这种批量、多轮的负载下收益尤其明显。看到这里你可能想问听起来很美好实际到底能快多少三、场景前后对比数字会说话场景无前缀缓存传统方式启用 RadixAttention提升幅度批量提示工程同一系统提示词 N 个任务1.0x4.8x约 380%长文档摘要同一文档反复分析1.0x5.1x约 410%多轮对话共享历史前缀1.0x3.2x约 220%一句白话结论前缀越重、重复次数越多收益越夸张。文档摘要能到 5 倍多是因为同一篇长文的前缀计算被完全省掉了多轮对话虽然每次只复用一部分历史也已经接近 3.2 倍。如果你们的请求都是毫无交集的随机文本那收益就会小很多——这一点很重要后面避坑部分还会提。四、三步开启缓存复用照着做就行别急配置真的不难核心就三步。第一步启动服务时确认前缀缓存是开的RadixAttention 在 SGLang 中默认就是启用的除非你显式传了--disable-radix-cache把它关掉。启动一个服务python -m sglang.launch_server --model-path 你的模型路径 --port 30000没有加--disable-radix-cache就说明缓存已经在工作了。第二步按需调整页面大小page_size前缀匹配是按页对齐的page_size决定了缓存分配的最小粒度。默认值通常够用但如果你在压测时发现命中率偏低可以试着调整python -m sglang.launch_server --model-path 你的模型路径 --page-size 16小页面更灵活、碎片少大页面匹配更省内存管理开销需要结合你的显存和请求长度试一轮。第三步长序列场景打开分块缓存如果你用的是长上下文模型例如 DeepSeek 系列前缀很长时一次性匹配、一次性计算会拖慢首 token 延迟。SGLang 支持把长前缀按块缓存通过环境变量设置分块阈值默认 8192SGLANG_CHUNKED_PREFIX_CACHE_THRESHOLD8192 python -m sglang.launch_server --model-path 你的模型路径意思是当累计前缀长度达到这个阈值后改用分块方式处理 KV避免超长序列把显存和算力瞬间拉满。开启后可以从监控里看缓存命中率验证效果关键指标是gpu_prefix_cache_hit_rate设备端命中率。五、避坑指南新手最容易踩的 3 个坑坑 1请求之间根本没有共享前缀却期待翻倍提速。RadixAttention 只对重复前缀友好。如果你的请求全部是随机问题、各不相同命中的概率极低缓存反而白占显存。排查方法跑一轮测试盯住gpu_prefix_cache_hit_rate如果长期低于 20%说明负载形态不适合可以考虑关闭它--disable-radix-cache释放显存。坑 2系统提示词每天都在改前缀缓存频繁失效。提示词只要有一个 token 变化从那个位置往后的缓存全部作废。对策是把稳定的部分放在前面比如角色设定、知识库说明把会变的内容日期、用户 ID尽量往后放让共享前缀尽可能长。坑 3并发量大时缓存被误删服务报错。不用担心SGLang 用lock_ref引用计数保护正在被使用的节点淘汰策略会自动跳过锁定节点。真正要注意的是别在显存极紧时又开了超大page_size这会放大内存碎片。经验做法显存紧张时优先调小页面、观察命中率而不是盲目堆缓存。六、什么时候该用、什么时候别用一句话决策建议强烈建议启用多轮对话、批量提示词工程、同一批文档反复分析、RAG 场景固定知识库前缀、评测任务同一 prompt 跑大量样本。这些负载的共同点是前缀重、复用高RadixAttention 能直接帮你省算力、提吞吐。建议关闭或谨慎使用请求全是随机短文本、几乎无前缀重合或者显存已经极度紧张、命中率又上不去时关闭它能省下管理开销和缓存占用的显存。一点展望前缀缓存这个方向还在快速演进——跨节点共享缓存、对 FP8/INT4 量化缓存的支持、根据请求模式自适应调整页面大小都在陆续落地。可以预见它会从单机优化走向集群级基础设施。想亲手验证效果给你的服务加上--page-size参数、跑一组多轮对话压测再对比一下开与不开--disable-radix-cache的吞吐差异你会直观感受到那 3~5 倍差距来自哪里。下一期我们再聊聊多 GPU 与多节点场景下缓存如何跨卡共享——到时候见。【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考