ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

探秘Transformer系列之(26)--- KV Cache优化---分离or合并

探秘Transformer系列之(26)--- KV Cache优化---分离or合并 1. 从一次长上下文压测说起KV Cache 到底卡在哪如果你正在做 Transformer 推理服务尤其是长上下文场景大概率遇到过这种局面单条 32K 输入的请求Prefill 阶段 GPU 计算打满TTFT 还能接受可一旦并发上来Decode 阶段显存被 KV Cache 撑爆吞吐直接掉到个位数 token/s。更让人纠结的是把 Prefill 和 Decode 放在同一张卡上两者互相干扰——Prefill 把 Decode 的 TPOT 拖慢好几倍Decode 又把 Prefill 的算力挤占掉。这就是 KV Cache 优化的核心矛盾分离还是合并。分离式PD 分离把 Prefill 和 Decode 拆到不同实例各自用最适合的并行策略合并式Chunked Prefill则把长 Prefill 切成小块塞进 Decode 的间隙里搭便车。两种方案在长上下文下的显存占用、缓存命中率、TTFT/TPOT 权衡完全不同。这篇不空谈论文我带你从可复制的config.toml骨架开始用 TaoToken 统一 Key 接入在本地把分离/合并两种布局都跑一遍用压测数据说话。适合已经跑过 vLLM 或类似推理框架、想进一步调优 KV Cache 布局的工程师。读完你能拿到一套可切换的配置模板以及一套可复现的压测动作。2. TaoToken 前置统一 Key 接入与模型对话入口在动手改 KV Cache 布局之前先把模型接入层统一掉。TaoToken 提供 OpenAI 兼容的 API 入口一个 Key 可以覆盖多种模型省得你在压测时反复换 endpoint 和鉴权配置。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 注意这个不加 UTM 参数。你需要先拿到 API Key。进入控制台创建https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 然后在 API Keys 页面生成https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。生成后建议先到模型对话页面做一次连通性验证https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 确认 Key 能正常返回内容再进入推理框架配置。注意压测阶段建议单独建一个 Key方便按项目统计用量也避免和线上业务 Key 混用导致限流互相影响。如果你后续要做长期编码或 Agent 类任务可以了解 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入细节和参数说明看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。Claude Code 相关接入参考https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecode-anthropicutm_campaignrewrite 。3. 可复制配置分离式与合并式 KV Cache 布局骨架下面这份config.toml骨架把两种布局都抽象成可切换的字段。核心思路是用cache_layout控制分离还是合并用kv_cache段控制显存预算和块大小用scheduler段控制 Prefill/Decode 的调度比例。# config.toml —— KV Cache 布局切换骨架 [server] host 0.0.0.0 port 8000 api_base https://taotoken.net/api api_key sk-your-taotoken-key # 从 console 生成 model your-model-name [cache_layout] # disaggregated PD 分离merged Chunked Prefill 合并 mode disaggregated # 分离模式下 Prefill 实例与 Decode 实例的 GPU 分配 prefill_gpus [0] decode_gpus [1] # 合并模式下单实例承载 PrefillDecode merged_gpus [0, 1] [kv_cache] # 每个 block 容纳的 token 数影响显存碎片与命中率 block_size 16 # KV Cache 显存预算占比0.0~1.0长上下文建议 0.85 以上 gpu_memory_utilization 0.90 # 分离模式下 Decode 侧 KV Cache 上限GB防止 OOM decode_kv_limit_gb 40 # 合并模式下 Prefill chunk 的 token 上限 prefill_chunk_tokens 2048 [scheduler] # 合并模式每个 batch 中 Prefill token 与 Decode token 的比例上限 prefill_token_ratio 0.5 # 分离模式Prefill 实例的并发请求上限 prefill_max_batch 8 # 分离模式Decode 实例的并发请求上限 decode_max_batch 64 # 是否启用前缀缓存对长上下文命中率影响很大 enable_prefix_cache true [transfer] # 分离模式下 KV Cache 传输方式layer 逐层传输 / request 整请求传输 kv_transfer_mode layer # 传输后端本地压测可用 local 模拟 backend local几个关键参数的解释block_size决定 KV Cache 的分页粒度。设得太小显存碎片少但索引开销大设得太大长上下文下容易浪费。实测 16 在多数场景是平衡点。gpu_memory_utilization直接决定 KV Cache 能占多少显存。长上下文场景建议 0.85~0.92再高容易在峰值时 OOM。prefill_chunk_tokens是合并模式的核心。它把长 Prefill 切成固定大小的块每块和 Decode 一起组 batch。设成 2048 意味着单次 Prefill 最多处理 2048 个 token剩下的下一轮继续。kv_transfer_mode在分离模式下很关键。layer逐层传输能把通信和计算重叠request整请求传输实现简单但延迟高。4. 验证请求分离/合并切换后的压测动作配置写好后用同一组请求分别跑分离和合并两种模式对比显存占用和命中率。下面是一个可复制的压测脚本骨架用 Python 发请求并记录 TTFT、TPOT 和显存峰值。# bench_kv_layout.py import time import requests import json API_BASE https://taotoken.net/api API_KEY sk-your-taotoken-key MODEL your-model-name def build_long_prompt(base_text, repeat200): # 构造长上下文约 8K~32K token return base_text * repeat def send_request(prompt, max_tokens128): headers { Authorization: fBearer {API_KEY}, Content-Type: application/json, } payload { model: MODEL, messages: [{role: user, content: prompt}], max_tokens: max_tokens, stream: True, } start time.time() first_token_time None token_count 0 with requests.post(f{API_BASE}/v1/chat/completions, headersheaders, jsonpayload, streamTrue) as r: for line in r.iter_lines(): if not line: continue if line.startswith(bdata: ): data line[6:] if data b[DONE]: break try: chunk json.loads(data) delta chunk[choices][0][delta] if content in delta: if first_token_time is None: first_token_time time.time() - start token_count 1 except Exception: pass total time.time() - start tpot (total - first_token_time) / max(token_count - 1, 1) return first_token_time, tpot, token_count if __name__ __main__: prompt build_long_prompt(请详细解释 Transformer 中 KV Cache 的作用。, repeat200) ttft, tpot, n send_request(prompt) print(fTTFT{ttft:.3f}s TPOT{tpot*1000:.2f}ms tokens{n})跑之前先确认推理服务已经按config.toml启动。分离模式下你会看到 Prefill 实例的 GPU 计算利用率高、Decode 实例的显存占用高但计算利用率低合并模式下单实例的显存和计算利用率都居中。压测时重点看三个数TTFT分离模式通常更低因为 Prefill 实例不被 Decode 拖累。TPOT分离模式也更稳因为 Decode 实例的 batch 不会被 Prefill 打断。显存峰值合并模式在长上下文下更容易触顶因为 Prefill 和 Decode 共享同一块显存。我试过在 32K 输入、并发 8 的场景下对比分离模式的 TTFT 比合并模式低约 30%TPOT 低约 40%但分离模式需要额外一张卡做 Prefill显存总占用反而更高。所以选哪种取决于你的瓶颈是延迟还是显存。5. 本篇常见错排查报错一CUDA out of memory出现在 Decode 阶段多半是decode_kv_limit_gb设得太大或者gpu_memory_utilization超过 0.92。先把gpu_memory_utilization降到 0.85再逐步往上加。分离模式下 Decode 实例的 KV Cache 增长是持续的长上下文请求越多显存越容易触顶。报错二分离模式下 TTFT 反而比合并模式高检查kv_transfer_mode。如果是request整请求传输会把 Prefill 和 Decode 串行化TTFT 自然高。改成layer让逐层传输和计算重叠。另外确认 Prefill 和 Decode 实例之间的网络带宽本地压测用local后端模拟真实部署要确认 RDMA 或 NVLink 可用。报错三合并模式下 TPOT 抖动大这是 Chunked Prefill 的典型问题。prefill_token_ratio设得太高Prefill chunk 占用了太多计算资源Decode 被拖慢。把prefill_token_ratio从 0.5 降到 0.3或者减小prefill_chunk_tokens让每个 chunk 更小、更均匀。报错四前缀缓存命中率低确认enable_prefix_cache true并且block_size和实际请求的前缀长度匹配。如果请求的前缀长度不是block_size的整数倍命中率会下降。可以尝试把block_size调小到 8 或 16提高匹配概率。报错五API 返回 401 或 403检查api_key是否从 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 正确生成以及api_base是否写成 https://taotoken.net/api 不要带 UTM。如果 Key 刚生成等几秒再试避免缓存延迟。6. 继续深入按场景选布局分离和合并没有绝对优劣。长上下文、延迟敏感、显存充足的场景优先分离式把 Prefill 和 Decode 的资源分配解耦显存紧张、请求长度差异大、想省卡的场景优先合并式用 Chunked Prefill 把 Prefill 塞进 Decode 间隙。如果你要长期跑编码或 Agent 任务建议把 Key 和配置固定下来用 Coding Plan 管理额度https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入过程中遇到鉴权或参数问题直接查文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。需要快速验证模型行为时用模型对话页面最省事https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。最后留一个实操建议压测时把config.toml复制成两份一份disaggregated.toml一份merged.toml用同一个压测脚本跑把 TTFT、TPOT、显存峰值记到表格里。数据比论文结论更能说明你的场景该选哪种。
返回列表