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 前缀缓存是它最亮眼的杀手锏之一通过基数树Radix Tree结构复用历史 KV 缓存让多轮对话、批量提示工程、文档摘要等高频场景的推理吞吐提升数倍最高可达约 5 倍加速。本文不讲空话直接从重复计算有多浪费说起带你走完快速上手 → 原理拆解 → 淘汰机制 → 进阶玩法 → 指标调优 → 实战案例的完整路径读完就能在自己的项目里把前缀缓存用起来。一、先算一笔账你的 GPU 正在做大量无用功想象一个深夜运营的智能客服机器人所有请求都带着同一段冗长的系统提示词比如你是 XX 平台的客服请遵循以下规则……后面再接用户问题。在没有前缀缓存的传统方案里每一个请求都要从第一个 token 开始重新跑一遍注意力计算。系统提示词有 500 个 token一晚上来 10 万个请求这 500 个 token 就被白算 10 万次——它们的结果一模一样却被反复生产、反复丢弃。这正是大模型推理领域著名的前缀重复计算问题。KV 缓存Key-Value Cache技术虽然记住了生成过的内容但传统实现里它只服务单个请求的生命周期请求结束缓存作废。于是典型场景重复计算比例直观感受多轮对话长历史高每轮都重算整段历史批量提示工程极高相同系统提示被批量重算代码补全中文件头被反复重算文档问答高长文档每问一次算一次SGLang 的做法是把缓存从请求级升级为全局级。用一个数据结构记录所有请求算过的前缀新请求来了先查账能复用的部分绝不重算。这个数据结构就是基数树。二、五分钟上手三行代码开启缓存复用先把门槛降到最低。SGLang 的 RadixAttention 在默认配置下就是开启状态你甚至不需要写额外代码from sglang import function, gen, Engine # 1. 定义生成任务框架会自动为相同前缀建立缓存 function def chat_reply(question: str): result gen(answer, max_tokens128) return result # 2. 三个请求共享同一段系统提示词前缀 system_hint 你是一位严谨的Python技术导师请用中文简洁作答。 batch_questions [ system_hint 什么是装饰器, system_hint 什么是生成器, system_hint 什么是上下文管理器, ] # 3. 批量执行后两个请求会命中第一个请求留下的缓存 with Engine() as engine: for q in batch_questions: print(chat_reply.run(q, engineengine))这段代码在做什么它只是普通的批量推理调用但 SGLang 会在内部记录第一个请求生成的前缀 KV让后两个请求直接复用只计算装饰器/生成器/上下文管理器这几个新增 token 的注意力。如果你是自建服务、用命令行启动也只需要关注几个启动参数python3 -m sglang.launch_server \ --model-path your-llm-path \ --enable-metrics # 打开监控便于观察命中率想从源码跑通全流程可以克隆仓库后按官方文档安装git clone https://gitcode.com/GitHub_Trending/sg/sglang三、拆开黑盒基数树到底在管什么光会用不够我们来看它内部长什么样。基数树Radix Tree是字典树Trie的压缩版字典树每个字符一个节点基数树则把没有分支的连续路径合并成一个节点从而省内存、加快查找。3.1 节点缓存的最小管理单元在python/sglang/srt/mem_cache/radix_cache.py中每个节点记录四样关键信息class TreeNode: def __init__(self): self.children {} # 子节点按下一个 token 索引 self.parent None # 父节点指针向上回溯用 self.key None # 本节点对应的 token 序列 self.value None # 这些 token 的 KV 缓存索引 self.lock_ref 0 # 引用锁0 表示正在被使用不可驱逐 self.last_access_time 0.0 # 最近访问时间供 LRU 策略使用可以把它想象成文件系统里的目录树key是目录名value是目录下真正占空间的文件lock_ref是正在被打开的文件不可删除的标记。3.2 匹配一条请求进来后发生了什么新请求的前缀查找走match_prefix流程核心逻辑可以用伪代码讲清楚def 查找最长缓存前缀(root, 请求token序列): 当前节点 root 已命中KV [] while 序列还没匹配完 and 当前节点有匹配的子节点: 子节点 找到对应子节点 if 子节点路径比剩余序列长: 把子节点从匹配点处切开 # 节点分裂见下文 记录分裂后的前半段KV break else: 记录子节点的全部KV 继续往下一层走 return 已命中的KV, 停在哪节点分裂是这里最巧妙的设计比如缓存里存了前缀[1,2,3,4,5]新请求只匹配到[1,2,3]树就会把原节点一分为二——[1,2,3]一段、[4,5]一段。分裂不复制数据KV 索引切片共享只是让树结构更精细方便下次精确命中。这样查前缀从 O(全序列) 变成 O(匹配长度)配合页面对齐性能开销极小。3.3 插入请求结束后的归档动作请求算完它的完整输入输出 token 序列会被insert进树里。如果新序列与已有节点共享前缀就只在分歧处长出新的分支节点尽量复用旧节点避免重复存储。 小知识SGLang 还支持extra_key命名空间可以让不同 LoRA 适配器、不同采样配置的缓存互不干扰。例如按 LoRA ID 隔离缓存行避免张冠李戴。四、内存告急时谁先走淘汰机制的博弈论GPU 显存永远是稀缺资源。基数树里存得越多可用空间越少所以必须有一套驱逐evict规则决定缓存满了以后先丢掉谁。4.1 只从叶子下手SGLang 的驱逐策略有一个硬约束只删除叶子节点没有子节点的节点。原因很直观叶子删掉不影响任何其他前缀的完整性而如果删中间节点等于把它所有后代一起删掉代价太大。4.2 引用锁正在用的缓存受保护def 驱逐(num_tokens): 把当前所有可驱逐的叶子放进最小堆 # 按 LRU/优先级排序 while 还没驱逐够数量 and 堆不为空: 候选节点 堆顶弹出 if 候选节点.lock_ref 0: # 被正在处理的请求引用 continue # 跳过不能碰 释放候选节点的KV内存 把它从树里摘除lock_ref是关键的安全阀当一个请求正在使用某段前缀时该节点及其祖先节点的引用计数都会 1驱逐逻辑看到锁就绕道走。请求结束后引用计数 -1节点重新变为可驱逐。4.3 可选的淘汰策略通过eviction_policy参数可以切换策略SGLang 内置了几种策略名称适用场景lru最近最少使用通用场景兼顾命中率与公平性slru分段 LRU冷热数据区分明显的工作负载priority优先级感知高价值前缀如核心系统提示优先保留选择思路绝大多数场景直接用默认 LRU 即可如果你的请求有明显的热前缀比如永远被引用的系统提示可考虑 priority 策略把热点路径的priority设高让它不容易被挤出去。五、进阶武器库分块缓存、HiCache 与统一基数树基础能力讲完SGLang 前缀缓存还有几件大杀器值得在生产环境里重点考察。5.1 分块前缀缓存Chunked Prefix Cache长序列的缓存命中率往往被最后一小段不匹配拖累——比如两个长文档请求差一个 token整条长前缀就全废了。分块缓存把前缀切成固定大小的块分别管理例如阈值 256 token 一块# 环境变量方式启用仅部分模型支持如 DeepSeek 系列 os.environ[CHUNKED_PREFIX_CACHE_THRESHOLD] 256块与块之间独立缓存、独立命中长序列也能吃到高命中率代价是管理开销略增。5.2 HiCache把缓存搬出 GPU设备显存不够时可以把低频访问的 KV 缓存备份到主机内存CPU 侧构成两级存储命中设备缓存直接使用零拷贝命中主机缓存从主机加载回显存HiCache 加载换取显存空间完全未命中重新计算然后按策略写入设备或主机。这相当于给前缀缓存加了一个冷热分层在显存受限的部署如单卡 24GB 跑大模型里尤其有价值。主机端缓存同样受host_ref_counter保护不会在传输中被误删。5.3 统一基数树与会话感知缓存新版本引入的UnifiedRadixCache通过SGLANG_ENABLE_UNIFIED_RADIX_TREE1开启把全注意力、滑动窗口注意力SWA、Mamba 等多种注意力形态的 KV 统一进同一棵缓存树还支持会话感知驱逐给长会话的缓存打上软引用标签内存紧张时先淘汰无归属的缓存再动活跃会话的缓存避免排队的用户把正在聊天的用户挤下线。启用会话感知只需两个动作# 启动时打开开关 SGLANG_ENABLE_UNIFIED_RADIX_TREE1 python3 -m sglang.launch_server \ --model-path MODEL_PATH --enable-session-radix-cache# 请求时带上 session_id会话结束调用 close_session curl http://localhost:30000/generate \ -H Content-Type: application/json \ -d {text: 完整提示词, sampling_params: {max_new_tokens: 128}, session_id: agent-42} curl -X POST http://localhost:30000/close_session \ -H Content-Type: application/json -d {session_id: agent-42}⚠️ 注意session_id只负责给缓存打标签不会自动拼接历史上下文每轮请求仍需携带完整 prompt。六、用数据说话怎么观测缓存命中率优化没有指标就是盲人摸象。SGLang 会暴露一组关键指标最核心的是缓存命中率它直接决定你能省多少算力cache_hit_rate设备端前缀缓存命中率越高越好一般希望长期高于 0.5evictable_size当前可被驱逐的缓存大小protected_size被引用锁保护的缓存大小total_size缓存总规模命中率和加速比的关系大致是命中率越高重复计算越少延迟与吞吐改善越明显。生产建议先量化启动时加--enable-metrics观察命中率基线再定参页面大小page_size如 16影响对齐粒度一般保持默认或按模型调整后分层显存吃紧时引入 HiCache长序列任务开启分块缓存常态化把命中率纳入服务监控大盘出现异常下滑时优先排查是否误改了前缀结构比如模板里混入了时间戳。七、两个实战场景对照场景一多轮对话——让历史不再是负担history_prefix 用户你好我想了解机器学习。\n助手当然可以请讲\n用户 follow_ups [什么是过拟合, 怎么避免过拟合, 举一个实际例子] for question in follow_ups: full_prompt history_prefix question answer chat_reply.run(full_prompt) # 第一问计算完整前缀后两问直接命中前两轮历史只算新增部分对话越长、轮次越多节省越明显——因为可复用的历史长度随轮次线性增长而每次新增计算的只有本轮新内容。场景二批量提示工程——同一模板 N 次复用template 你是一名资深数据工程师。请解释以下概念 tasks [数据仓库与数据湖的区别, ETL 与 ELT 的区别, 列式存储的适用场景] for task in tasks: prompt template task # 模板部分完全相同 print(chat_reply.run(prompt))三个请求共享全部模板 token理论命中率接近模板长度 / 全长度批量越大、模板越长收益越可观。八、绕不开的难点与路线图前缀缓存不是银弹工程化落地时有几个真实挑战内存碎片化频繁分裂节点可能让缓存碎片化。对策是页面对齐固定 token 粒度分配与智能合并节点让内存分配更规整。并发与一致性多请求同时读写同一棵树靠引用锁 写时复制保证安全跨 TP worker 的缓存同步通过事件队列如 BlockStored / BlockRemoved完成并辅以哈希校验防止数据错位。未来方向社区正在探索跨节点缓存共享、FP8/INT4 量化缓存的兼容、按序列特征自适应页面大小以及基于请求模式预测的预加载。这些方向意味着缓存命中率这个指标仍有继续拉高的空间。九、写在最后现在就去试试前缀缓存解决的是 LLM 推理里最隐蔽的性能浪费——同样的前缀被成千上万次重复计算。SGLang 用一棵基数树把这件事做到了优雅且高效先查再算、能省则省、满了择优驱逐。给你的行动清单克隆仓库git clone https://gitcode.com/GitHub_Trending/sg/sglang跑通一个带共享前缀的批量 demo开启--enable-metrics观察命中率从 0 到逐步爬升的过程换到真实的多轮对话负载对比开启缓存前后的吞吐差异显存紧张时把 HiCache 和分块缓存加进来再看一轮指标。下一步可以深入研究 SGLang 的调度器如何与 RadixCache 协作、UnifiedRadixCache如何统一管理多种注意力形态或者探索 HiCache 在长上下文场景下的完整设计与存储/运行时分离机制。从一棵树的节点开始你正在进入 LLM 推理优化的核心地带。后续预告分布式推理篇——多 GPU 与多节点场景下SGLang 如何继续压榨缓存与并行的双重红利。【免费下载链接】sglangSGLang is a high-performance serving framework for large language models and multimodal models.项目地址: https://gitcode.com/GitHub_Trending/sg/sglang创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考